-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
环境搭建 & 项目架构介绍 #1
Comments
Typescript绝大部分关于Typescript语言本身的问题,建议查询官方文档: 至于如何实现某种功能/怎样做才是最佳实践,建议多查Google与Stack Overflow。 tsconfig.json我们的 {
"compilerOptions": {
"noImplicitAny": false, // 可以有隐式any, 方便导入js文件
"watch": true, // 监视模式,当ts文件更改时会自动重新编译
"sourceMap": true, // 可以通过ts代码来调试实际运行的js
"target": "es2018", // ts将编译到最新的es2018 js代码
"outDir": "./dist", // 所有编译出来的文件将送到dist文件夹,免得跟ts源代码纠缠在一起
"rootDir": "./", // 当前目录是我们的工作根目录
"declaration": true // 编译出js的同时附上带有声明的.d.ts文件(相当于头文件)
}
} |
Gulp.jsGulp是一个自动化构建工具。在本项目中我们利用Gulp来实现自动化编译、更新文件、刷新页面等功能。Gulp的构建流由 Gulp的API文档请参阅:https://www.gulpjs.com.cn/docs/api/ 下面通过介绍 gulp.task('connect')我们定义一个运行服务器的任务,这个服务器的根目录在 let gulp = require('gulp');
let connect = require('gulp-connect');
gulp.task('connect', () =>
connect.server({
root: './dist',
livereload: true
})
); gulp.task('reload')我们定义一个刷新页面的任务: gulp.task('reload', () => {
return gulp.src('./dist/**/*.html').pipe(connect.reload());
});
gulp.task('copy')我们定义一个拷贝非ts源代码(ts代码是被编译去的)至发布文件夹的任务: gulp.task('copy', () => {
gulp.src('./@(core|+([0-9]).+(?))/**/*.@(html|js|json|glsl[vf])').pipe(gulp.dest('./dist'));
});
匹配的内容通过 gulp.task('watch')我们定义一个监视任务,从而正式实现自动刷新效果: gulp.task('watch', () => {
gulp.watch(['./@(core|+([0-9]).+(?))/**/*.@(html|js|json|glsl[vf])'], ['copy']);
gulp.watch(['./dist/**/*.@(html|js|json|glsl?)'], ['reload']);
}); 当源代码( gulp.task('compile')我们定义一个typescript实时编译的任务,借 gulp.task('compile', () => {
const cmd = os.platform() == 'win32' ? 'tsc.cmd' : 'tsc';
const childProcess = require('child_process');
const child = childProcess.spawn(cmd, []);
return child;
}); 当ts文件发生变化时,处于 gulp.task('default')最后,我们定义一个默认任务,将以上各任务串接起来,提供一个总入口: gulp.task('default', ['connect', 'copy', 'watch', 'compile']); 之后,我们可以在命令行中通过 {
"type": "gulp",
"task": "default",
"group": {
"kind": "build",
"isDefault": true
}
} 这样,就可以通过 {
"name": "2.i-is-fish",
"type": "chrome",
"request": "launch",
"webRoot": "${workspaceRoot}/dist",
"sourceMaps": true,
"url": "http://localhost:8080/2.i-is-fish"
} |
WebGL Extension原生的WebGL接口太弱,简直如编写汇编一般,一个函数只完成一个极其小的功能点。因此, 有必要对其进行初步封装。WebGL Extension模块提供了如下功能的包装:
|
Rendering Object本模块对WebGL中的一些基础概念进行层层包装,最终得到一个用来进行画图的可渲染对象。 Uniform一个Uniform属性像是一个全局变量,仅仅用一个number或是一个Array就可表示,没有其他的多余信息。 因此,Uniform可被声明为一个复合类型: type WebGLUniformType = number | Array<number> | WebGLArray; Attribute & BufferInfo一个Attribute是一系列顶点拥有的数据集合。它包含以下几个重要属性:
一个渲染模型仅仅只有一系列Attributes是不够的。一个
因此,我们还需要一个 interface WebGLBufferInfo {
numElements: number, // 顶点数量
indices?: WebGLBuffer, // 索引,若没有则使用drawArray绘制,否则用drawElement
attributes: Map<string, WebGLAttribute>; // 根据名字索引属性
} ProgramInfo
interface WebGLProgramInfo {
program: WebGLProgram;
mode?: number,
attributeSetters: { [key: string]: (info: WebGLAttribute) => void };
uniformSetters: { [key: string]: (info: WebGLUniformType) => void };
}
这说明在 TextureInfo
interface WebGLTextureInfo {
frameBuffer?: WebGLFramebuffer;
renderBuffer?: WebGLRenderbuffer;
texture: WebGLTexture;
level: number;
} 其中,帧缓冲和渲染缓冲是可选的,只在材质并没有绑定在某个具体数据上时被使用。 RenderingObject现在,我们将以上定义好的概念包装起来,构造一个WebGL里的”可渲染对象“: class WebGLRenderingObject {
programInfo: WebGLProgramInfo;
bufferInfo: WebGLBufferInfo;
uniforms: WebGLUniformMap;
worldMatrix: MV.Matrix = MV.mat4(); // 初始为恒等矩阵
center: MV.Vector3D = MV.vec3(); // 初始为坐标原点
setModel(m: MV.Matrix); // 设置变换矩阵
transform(m: MV.Matrix); // 应用变换矩阵
draw(); // 正式绘图
}
最终,可以通过 OrientedObject
class WebGLOrientedObject extends WebGLRenderingObject {
sideAxis: MV.Vector3D; // 朝向 × 法线形成的第三条轴
direction: MV.Vector3D;
normal: MV.Vector3D;
} 其中, |
Canvas
class Canvas {
public canvas: HTMLCanvasElement;
public gl: WebGLRenderingContext;
public matrixStack: MatrixStack = new MatrixStack();
public textureInfos: Array<WebGLTextureInfo> = Array(32).fill(null);
public objectsToDraw: Array<WebGLRenderingObject> = [];
public updatePipeline: Array<(c: Canvas, time?, deltaTime?) => void> = [];
public newObject(source, mode, attributes?, uniforms?);
public newTexture(image?, level, size);
public render(anime?);
} Canvas构造了一个绘图的渲染管道,介绍如下: Initializer这是一个尚未实现,但应存在的功能。主要作用是在正式调用 比如,先制作一个Rendering Object,接下来为其绑定光照、阴影、材质、控制器,最后调用render(),则Initializer为前述配置生成着色器代码并正式初始化,接下来才进入渲染流程。 Rendering
一轮
Update Pipeline在每帧渲染前,都会进行一轮更新流程,更新相关Rendering Object对象的状态,从而实现动态效果。 为了提高扩展性,我们将更新流程拆成一系列子过程,并用一个队列串接起来。这便是Update Pipeline机制: 一轮 for (let update of this.updatePipeline) {
update(this, now, then - now);
} 也即通过Canvas的引用、当前时间以及两帧之间的时间差,轮流调用更新管道中的每个回调函数。 例如,我们可以通过以下代码,完成让光源绕Y轴持续旋转: canvas.updatePipeline.push((cv, time, deltaTime) => {
const R = MV.rotateY(2 * deltaTime);
lighting.transform(R);
}); Source LoadingCanvas提供了若干个函数用于读取、创建资源:
目前,Model的最佳支持格式是具有 以后从 |
复述一下环境配置过程:
Prerequisites
npm install -g gulp typescript
launch.json
相关设置。Development
git clone
到本地后,用 VSCode 打开文件夹,在终端中运行npm install
;Ctrl+Shift+B
或终端->运行生成任务
运行 Gulp Server (端口为8080);F5/Ctrl+F5
便可直接运行当前任务;launch.json
中新增一个条目即可。The text was updated successfully, but these errors were encountered: