blobt
4 years ago
27 changed files with 956 additions and 21638 deletions
-
BINdata/pic0.png
-
BINdata/pic1.jpg
-
1data/test.txt
-
BINdata/textureUV.jpg
-
20102package-lock.json
-
1public/index.html
-
BINpublic/pic0.png
-
BINpublic/pic1.jpg
-
13src/App.tsx
-
299src/examples/Demo1.ts
-
7src/render/common.ts
-
347src/render/common/DrawHelper.ts
-
78src/render/common/HttpRequest.ts
-
9src/render/common/ImageInfo.ts
-
6src/render/core/Application.ts
-
53src/render/core/CameraApplication.ts
-
2src/render/core/Event.ts
-
2src/render/core/Primitives.ts
-
4src/render/ds/TypedArrayList.ts
-
2src/render/math/Mat4.ts
-
1545src/render/math/TSM.ts
-
5src/render/math/Util.ts
-
91src/render/webgl/WebGLApplication.ts
-
2src/render/webgl/WebGLMatrixStack.ts
-
3src/render/webgl/WebGLMesh.ts
-
6src/render/webgl/WebGLShaderSource.ts
-
10src/render/webgl/index.ts
After Width: 886 | Height: 584 | Size: 100 KiB |
After Width: 256 | Height: 192 | Size: 25 KiB |
@ -0,0 +1 @@ |
|||||
|
test.txt测试文件 |
After Width: 1024 | Height: 1024 | Size: 636 KiB |
20102
package-lock.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
After Width: 886 | Height: 584 | Size: 100 KiB |
After Width: 256 | Height: 192 | Size: 25 KiB |
@ -0,0 +1,299 @@ |
|||||
|
import { vec3, vec4, Util } from "../render/math"; |
||||
|
import { GLProgram, GLTexture, GLStaticMesh, GLtextureCache, GLProgramCache } from "../render/webgl"; |
||||
|
import { CameraApplication } from "../render/core/CameraApplication"; |
||||
|
import { HttpRequest } from "../render/common/HttpRequest"; |
||||
|
import { DrawHelper } from "../render/common/DrawHelper"; |
||||
|
import { CanvasKeyBoardEvent } from "../render/core/Event"; |
||||
|
import { Cube, GeometryData } from "../render/core/Primitives"; |
||||
|
import { EAxisType } from "../render/common"; |
||||
|
import { mat4 } from "../render/math/Mat4"; |
||||
|
|
||||
|
export class Demo1 extends CameraApplication { |
||||
|
/** |
||||
|
* @var 纹理GPU Program对象 |
||||
|
*/ |
||||
|
colorProgram: GLProgram; |
||||
|
|
||||
|
/** |
||||
|
* @var 颜色GPU Program对象 |
||||
|
*/ |
||||
|
textureProgram: GLProgram |
||||
|
|
||||
|
/** |
||||
|
* @var 当前纹理对象的索引hao |
||||
|
*/ |
||||
|
currentTexIdx: number; |
||||
|
|
||||
|
/** |
||||
|
* @var 纹理贴图 |
||||
|
*/ |
||||
|
textures: GLTexture[]; |
||||
|
|
||||
|
/** |
||||
|
* @var 立方体 |
||||
|
*/ |
||||
|
cube: Cube; |
||||
|
|
||||
|
/** |
||||
|
* @var 几何立方体渲染数据 |
||||
|
*/ |
||||
|
cubeVAO: GLStaticMesh; |
||||
|
|
||||
|
/** |
||||
|
* @var cube的角位移 |
||||
|
*/ |
||||
|
cubeAngle: number; |
||||
|
|
||||
|
/** |
||||
|
* @var cube位移速度 |
||||
|
*/ |
||||
|
cubeSpeed: number; |
||||
|
|
||||
|
/** |
||||
|
* @var 位移矩阵 |
||||
|
*/ |
||||
|
cubeMatrix: mat4 |
||||
|
|
||||
|
/** |
||||
|
* @var 三角形的角位移 |
||||
|
*/ |
||||
|
triAngle: number; |
||||
|
|
||||
|
/** |
||||
|
* @var 三角形的位移速度 |
||||
|
*/ |
||||
|
triSpeed: number; |
||||
|
|
||||
|
/** |
||||
|
* @var 三角形的定时器 |
||||
|
*/ |
||||
|
triTimerId: number; |
||||
|
|
||||
|
/** |
||||
|
* @var 三角形的位移矩阵 |
||||
|
*/ |
||||
|
triMatrix: mat4; |
||||
|
|
||||
|
/** |
||||
|
* @var 为了支持鼠标点选,记录选中的坐标轴enum值 |
||||
|
*/ |
||||
|
private _hitAxis: EAxisType; |
||||
|
|
||||
|
public constructor(canvas: HTMLCanvasElement) { |
||||
|
super(canvas, { premultipliedAlpha: false }, true); |
||||
|
|
||||
|
this.cubeAngle = 0; |
||||
|
this.cubeSpeed = 100; |
||||
|
|
||||
|
this.triAngle = 0; |
||||
|
this.triSpeed = 1; |
||||
|
this.triTimerId = -1; |
||||
|
|
||||
|
this.currentTexIdx = 0; |
||||
|
this.textures = []; |
||||
|
this.textures.push(GLtextureCache.instance.getMust("default")); |
||||
|
|
||||
|
this.textureProgram = GLProgramCache.instance.getMust("texture"); |
||||
|
this.colorProgram = GLProgramCache.instance.getMust("color"); |
||||
|
|
||||
|
this.cube = new Cube(0.5, 0.5, 0.5); |
||||
|
let data: GeometryData = this.cube.makeGeometryData(); |
||||
|
this.cubeVAO = data.makeStaticVAO(this.gl); |
||||
|
|
||||
|
this._hitAxis = EAxisType.NONE; |
||||
|
|
||||
|
this.cubeMatrix = new mat4(); |
||||
|
this.triMatrix = new mat4(); |
||||
|
|
||||
|
this.camera.z = 8; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 绘制立方体 |
||||
|
*/ |
||||
|
private _renderCube(): void { |
||||
|
//绑定textture 和 program
|
||||
|
this.textures[this.currentTexIdx].bind(); |
||||
|
this.textureProgram.bind(); |
||||
|
this.textureProgram.loadSampler(); |
||||
|
|
||||
|
//绘制立方体
|
||||
|
this.matStack.loadIdentity(); |
||||
|
this.matStack.pushMatrix();//矩阵进栈
|
||||
|
this.matStack.rotate(this.cubeAngle, vec3.up, false); |
||||
|
//合成mvp矩阵
|
||||
|
mat4.product(this.camera.viewProjecttionMatrix, this.matStack.modelViewMatrix, this.cubeMatrix); |
||||
|
//将合成矩阵作用到GLProgram
|
||||
|
this.textureProgram.setMatrix4(GLProgram.MVPMatrix, this.cubeMatrix); |
||||
|
//使用当前绑定的texture和program绘制cubeVao对象
|
||||
|
this.cubeVAO.draw(); |
||||
|
|
||||
|
//绘制坐标系
|
||||
|
DrawHelper.drawCoordSystem(this.builder, this.cubeMatrix, this._hitAxis, 1); |
||||
|
|
||||
|
//释放资源
|
||||
|
this.matStack.popMatrix(); |
||||
|
this.textureProgram.unbind(); |
||||
|
this.textures[this.currentTexIdx].unbind(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 绘制三角形 |
||||
|
*/ |
||||
|
private _renderTriangle(): void { |
||||
|
//关闭背面剔除
|
||||
|
this.gl.disable(this.gl.CULL_FACE); |
||||
|
|
||||
|
//绑定gpu program和color program
|
||||
|
this.colorProgram.bind(); |
||||
|
|
||||
|
//生成一个矩阵 并 旋转
|
||||
|
this.matStack.pushMatrix(); |
||||
|
this.matStack.translate(new vec3([-2, 0, 0])); |
||||
|
this.matStack.rotate(this.triAngle, vec3.forward, true); |
||||
|
|
||||
|
//使用类似opengl1.1的立即绘制模式,默认使用gl.TRIANGLES方式绘制
|
||||
|
this.builder.begin(); |
||||
|
this.builder.color(1, 0, 0).vertex(-0.5, 0, 0); |
||||
|
this.builder.color(0, 1, 0).vertex(0.5, 0, 0); |
||||
|
this.builder.color(0, 0, 1).vertex(0, 0.5, 0); |
||||
|
|
||||
|
//合成mvp矩阵
|
||||
|
mat4.product(this.camera.viewProjecttionMatrix, this.matStack.modelViewMatrix, this.triMatrix); |
||||
|
//绘制
|
||||
|
this.builder.end(this.triMatrix); |
||||
|
|
||||
|
//释放资源
|
||||
|
this.matStack.popMatrix(); |
||||
|
this.colorProgram.unbind(); |
||||
|
this.gl.enable(this.gl.CULL_FACE); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 渲染字体 |
||||
|
* @param text |
||||
|
* @param x |
||||
|
* @param y |
||||
|
*/ |
||||
|
private _renderText(text: string, x: number = this.canvas.width * 0.5, y: number = 150): void { |
||||
|
if (this.ctx2D !== null) { |
||||
|
this.ctx2D.clearRect(0, 0, this.canvas.width, this.canvas.height); |
||||
|
this.ctx2D.save(); |
||||
|
this.ctx2D.fillStyle = "red"; |
||||
|
this.ctx2D.textAlign = "center"; |
||||
|
this.ctx2D.textBaseline = "top"; |
||||
|
this.ctx2D.font = "30px Arial"; |
||||
|
this.ctx2D.fillText(text, x, y); |
||||
|
this.ctx2D.restore(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 绘制坐标轴的文字 |
||||
|
* @param pos |
||||
|
* @param axis |
||||
|
* @param mvp |
||||
|
* @param inverse |
||||
|
*/ |
||||
|
public drawText(pos: vec3, axis: EAxisType, mvp: mat4, inverse: boolean = false): void { |
||||
|
if (this.ctx2D === null) { |
||||
|
return; |
||||
|
} |
||||
|
let out: vec3 = new vec3(); |
||||
|
|
||||
|
if (Util.obj2GLViewportSpace(pos, mvp, this.camera.getViewport(), out)) { |
||||
|
out.y = this.canvas.height - out.y;//变换到屏幕坐标系,左手系,原点再左上角,x向右,有向下
|
||||
|
|
||||
|
this.ctx2D.save(); |
||||
|
this.ctx2D.font = "30px Arial"; |
||||
|
|
||||
|
if (axis === EAxisType.XAXIS) { |
||||
|
this.ctx2D.textBaseline = "top"; |
||||
|
this.ctx2D.fillStyle = "red"; |
||||
|
if (inverse === true) { |
||||
|
this.ctx2D.textAlign = "right"; |
||||
|
this.ctx2D.fillText("-x", out.x, out.y); |
||||
|
} else { |
||||
|
this.ctx2D.textAlign = "left"; |
||||
|
this.ctx2D.fillText("x", out.x, out.y); |
||||
|
} |
||||
|
} else if (axis === EAxisType.YAXIS) { |
||||
|
this.ctx2D.textAlign = "center"; |
||||
|
this.ctx2D.fillStyle = "green"; |
||||
|
if (inverse === true) { |
||||
|
this.ctx2D.textBaseline = "top"; |
||||
|
this.ctx2D.fillText("-y", out.x, out.y); |
||||
|
} else { |
||||
|
this.ctx2D.textBaseline = "bottom"; |
||||
|
this.ctx2D.fillText("y", out.x, out.y); |
||||
|
} |
||||
|
} else { |
||||
|
this.ctx2D.fillStyle = "blue"; |
||||
|
this.ctx2D.textBaseline = "top"; |
||||
|
if (inverse === true) { |
||||
|
this.ctx2D.textAlign = "right"; |
||||
|
this.ctx2D.fillText("-z", out.x, out.y); |
||||
|
} else { |
||||
|
this.ctx2D.textAlign = "left"; |
||||
|
this.ctx2D.fillText("z", out.x, out.y); |
||||
|
} |
||||
|
} |
||||
|
this.ctx2D.restore(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public render(): void { |
||||
|
//this._renderCube();
|
||||
|
this._renderTriangle(); |
||||
|
//this._renderText("Hello world!");
|
||||
|
} |
||||
|
|
||||
|
public update(elapsecMsec: number, intervalSec: number): void { |
||||
|
this.cubeAngle += this.cubeSpeed * intervalSec; |
||||
|
super.update(elapsecMsec, intervalSec); |
||||
|
} |
||||
|
|
||||
|
public cubeTimeCallback(id: number, data: any): void { |
||||
|
this.currentTexIdx++; |
||||
|
this.currentTexIdx %= this.textures.length; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 加载纹理 |
||||
|
*/ |
||||
|
public async run(): Promise<void> { |
||||
|
// let img: HTMLImageElement = await HttpRequest.loadImageAsync("pic0.png");
|
||||
|
// let tex: GLTexture = new GLTexture(this.gl);
|
||||
|
// tex.upload(img, 0, true);
|
||||
|
// tex.filter();
|
||||
|
// this.textures.push(tex);
|
||||
|
|
||||
|
// img = await HttpRequest.loadImageAsync("pic1.jpg");
|
||||
|
// tex = new GLTexture(this.gl);
|
||||
|
// tex.upload(img, 0, true);
|
||||
|
// tex.filter();
|
||||
|
// this.textures.push(tex);
|
||||
|
|
||||
|
//this.addTimer(this.cubeTimeCallback.bind(this), 2, false);
|
||||
|
|
||||
|
super.run(); |
||||
|
} |
||||
|
|
||||
|
public triTimeCallback(id: number, data: any): void { |
||||
|
this.triAngle += this.triSpeed; |
||||
|
} |
||||
|
|
||||
|
public onKeyDown(evt: CanvasKeyBoardEvent): void { |
||||
|
if (evt.key === "q") { |
||||
|
if (this.triTimerId === -1) { |
||||
|
this.triTimerId = this.addTimer(this.triTimeCallback.bind(this), 100.25, false); |
||||
|
} |
||||
|
} else if (evt.key === "e") { |
||||
|
if (this.triTimerId !== -1) { |
||||
|
if (this.removeTimer(this.triTimerId)) { |
||||
|
this.triTimerId = -1; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,347 @@ |
|||||
|
import { TypedArrayList } from "../ds/TypedArrayList"; |
||||
|
import { EAxisType } from "../common"; |
||||
|
import { GLMeshBuilder } from "../webgl" |
||||
|
import { mat4, vec3, vec4 } from "../math"; |
||||
|
|
||||
|
export class CoordSystem { |
||||
|
/** |
||||
|
* @var 当前坐标系被绘制到那个视口中 |
||||
|
*/ |
||||
|
public viewport: number[] = []; |
||||
|
|
||||
|
/** |
||||
|
* @var 当前坐标系绕那个轴旋转 |
||||
|
*/ |
||||
|
public axis: vec3; |
||||
|
|
||||
|
/** |
||||
|
* @var 当前坐标系的旋转角度 |
||||
|
*/ |
||||
|
public angle: number; |
||||
|
|
||||
|
/** |
||||
|
* @var 当前坐标系的位置,如果是多视口的话,就为[0,0,0] |
||||
|
*/ |
||||
|
public pos: vec3; |
||||
|
|
||||
|
/** |
||||
|
* @var 是否绘制旋转轴 |
||||
|
*/ |
||||
|
public isDrawAxis: boolean; |
||||
|
|
||||
|
/** |
||||
|
* @var 是否绘制左手系 |
||||
|
*/ |
||||
|
public isD3D: boolean; |
||||
|
|
||||
|
public constructor(viewport: number[], pos: vec3 = vec3.zero, axis: vec3 = vec3.up, angle: number = 0, isDrawAxis: boolean = false, isD3D: boolean = false) { |
||||
|
this.viewport = viewport; |
||||
|
this.axis = axis; |
||||
|
this.angle = angle; |
||||
|
this.pos = pos; |
||||
|
this.isDrawAxis = isDrawAxis; |
||||
|
this.isD3D = isD3D; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export class DrawHelper { |
||||
|
/** |
||||
|
* @var |
||||
|
*/ |
||||
|
public static defaultHitCollor: vec4 = new vec4([1, 1, 0]); |
||||
|
|
||||
|
/** |
||||
|
* 获取xy平面上的圆的点 |
||||
|
* @param pts |
||||
|
* @param radius |
||||
|
* @param segment |
||||
|
*/ |
||||
|
public static getCirclePointsOnXYPlane(pts: TypedArrayList<Float32Array>, radius: number, segment: number = 32): void { |
||||
|
pts.clear(); |
||||
|
let step: number = Math.PI / segment; |
||||
|
let ang: number = 0; |
||||
|
for (let i: number = 0; i < segment; i++) { |
||||
|
ang = i * step; |
||||
|
pts.push(Math.cos(ang)); |
||||
|
pts.push(Math.sin(ang)); |
||||
|
pts.push(0.0); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 绘制坐标轴full |
||||
|
* @param builder |
||||
|
* @param mat |
||||
|
* @param len |
||||
|
* @param rotateAxis |
||||
|
*/ |
||||
|
public static drawFullCoordSystem(builder: GLMeshBuilder, mat: mat4, len: number = 1, rotateAxis: vec3 | null = null): void { |
||||
|
|
||||
|
builder.gl.lineWidth(5);//用5个像素大小的直径绘制线段,但是目前仅Safari支持
|
||||
|
builder.gl.disable(builder.gl.DEPTH_TEST);//关闭深度测试
|
||||
|
builder.begin(builder.gl.LINES);//开始绘制
|
||||
|
|
||||
|
//+x轴
|
||||
|
builder.color(1.0, 0.0, 0.0).vertex(0.0, 0.0, 0.0); |
||||
|
builder.color(1.0, 0.0, 0.0).vertex(len, 0.0, 0.0); |
||||
|
//-x轴
|
||||
|
builder.color(1.0, 0.0, 0.0).vertex(0.0, 0.0, 0.0); |
||||
|
builder.color(1.0, 0.0, 0.0).vertex(-len, 0.0, 0.0); |
||||
|
|
||||
|
//+y轴
|
||||
|
builder.color(0.0, 1.0, 0.0).vertex(0.0, 0.0, 0.0); |
||||
|
builder.color(0.0, 1.0, 0.0).vertex(0.0, len, 0.0); |
||||
|
//-y轴
|
||||
|
builder.color(0.0, 1.0, 0.0).vertex(0.0, 0.0, 0.0); |
||||
|
builder.color(0.0, 1.0, 0.0).vertex(0.0, -len, 0.0); |
||||
|
|
||||
|
//+z轴
|
||||
|
builder.color(0.0, 0.0, 1.0).vertex(0.0, 0.0, 0.0); |
||||
|
builder.color(0.0, 0.0, 1.0).vertex(0.0, 0.0, len); |
||||
|
//-z轴
|
||||
|
builder.color(0.0, 0.0, 1.0).vertex(0.0, 0.0, 0.0); |
||||
|
builder.color(0.0, 0.0, 1.0).vertex(0.0, 0.0, len); |
||||
|
|
||||
|
//绘制旋转轴
|
||||
|
if (rotateAxis !== null) { |
||||
|
let scale: vec3 = rotateAxis.scale(len); |
||||
|
builder.color(0.0, 0.0, 0.0).vertex(0.0, 0.0, 0.0); |
||||
|
builder.color(0.0, 0.0, 0.0).vertex(scale.x, scale.y, scale.z); |
||||
|
} |
||||
|
|
||||
|
builder.end(mat);//结束绘制
|
||||
|
builder.gl.enable(builder.gl.DEPTH_TEST);//开启深度测试
|
||||
|
builder.gl.lineWidth(1); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 绘制系统坐标轴 |
||||
|
* @param builder |
||||
|
* @param mat |
||||
|
* @param hitAxis |
||||
|
* @param len |
||||
|
* @param rotateAxis |
||||
|
* @param isLeftHandness |
||||
|
*/ |
||||
|
public static drawCoordSystem(builder: GLMeshBuilder, mat: mat4, hitAxis: EAxisType, len: number = 5, rotateAxis: vec3 | null = null, isLeftHandness: boolean = false): void { |
||||
|
builder.gl.lineWidth(5);//用5个像素大小的直径绘制线段,但是目前仅Safari支持
|
||||
|
builder.gl.disable(builder.gl.DEPTH_TEST);//关闭深度测试
|
||||
|
builder.begin(builder.gl.LINES);//开始绘制
|
||||
|
|
||||
|
//+x轴
|
||||
|
if (hitAxis === EAxisType.XAXIS) { |
||||
|
builder.color(DrawHelper.defaultHitCollor.r, DrawHelper.defaultHitCollor.g, DrawHelper.defaultHitCollor.b).vertex(0.0, 0.0, 0.0); |
||||
|
builder.color(DrawHelper.defaultHitCollor.r, DrawHelper.defaultHitCollor.g, DrawHelper.defaultHitCollor.b).vertex(len, 0.0, 0.0); |
||||
|
} else { |
||||
|
builder.color(1.0, 0.0, 0.0).vertex(0.0, 0.0, 0.0); |
||||
|
builder.color(1.0, 0.0, 0.0).vertex(len, 0.0, 0.0); |
||||
|
} |
||||
|
|
||||
|
//+y轴
|
||||
|
if (hitAxis === EAxisType.YAXIS) { |
||||
|
builder.color(DrawHelper.defaultHitCollor.r, DrawHelper.defaultHitCollor.g, DrawHelper.defaultHitCollor.b).vertex(0.0, 0.0, 0.0); |
||||
|
builder.color(DrawHelper.defaultHitCollor.r, DrawHelper.defaultHitCollor.g, DrawHelper.defaultHitCollor.b).vertex(0.0, len, 0.0); |
||||
|
} else { |
||||
|
builder.color(0.0, 1.0, 0.0).vertex(0.0, 0.0, 0.0); |
||||
|
builder.color(0.0, 1.0, 0.0).vertex(0.0, len, 0.0); |
||||
|
} |
||||
|
|
||||
|
//+z轴
|
||||
|
if (hitAxis === EAxisType.ZAXIS) { |
||||
|
builder.color(DrawHelper.defaultHitCollor.r, DrawHelper.defaultHitCollor.g, DrawHelper.defaultHitCollor.b).vertex(0.0, 0.0, 0.0); |
||||
|
if (isLeftHandness === true) { |
||||
|
builder.color(DrawHelper.defaultHitCollor.r, DrawHelper.defaultHitCollor.g, DrawHelper.defaultHitCollor.b).vertex(0.0, 0.0, -len); |
||||
|
} else { |
||||
|
builder.color(DrawHelper.defaultHitCollor.r, DrawHelper.defaultHitCollor.g, DrawHelper.defaultHitCollor.b).vertex(0.0, 0.0, len); |
||||
|
} |
||||
|
} else { |
||||
|
builder.color(0.0, 0.0, 1.0).vertex(0.0, 0.0, 0.0); |
||||
|
if (isLeftHandness === true) { |
||||
|
builder.color(0.0, 0.0, 1.0).vertex(0.0, 0.0, -len); |
||||
|
} else { |
||||
|
builder.color(0.0, 0.0, 1.0).vertex(0.0, 0.0, len); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//绘制旋转轴
|
||||
|
if (rotateAxis !== null) { |
||||
|
let scale: vec3 = rotateAxis.scale(len); |
||||
|
builder.color(0.0, 0.0, 0.0).vertex(0.0, 0.0, 0.0); |
||||
|
if (isLeftHandness === true) { |
||||
|
builder.color(0.0, 0.0, 0.0).vertex(scale.x, scale.y, -scale.z); |
||||
|
} else { |
||||
|
builder.color(0.0, 0.0, 0.0).vertex(scale.x, scale.y, scale.z); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
builder.end(mat);//结束绘制
|
||||
|
builder.gl.enable(builder.gl.DEPTH_TEST);//开启深度测试
|
||||
|
builder.gl.lineWidth(1); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 绘制一个包围盒 |
||||
|
* 根据mins点(下图中的顶点2,左下后)和maxs(下图中的顶点5,右上前)点的坐标,使用参数指定的颜色绘制线框绑定盒,它是一个立方体 |
||||
|
* /3--------/7 | |
||||
|
* / | / | |
||||
|
* / | / | |
||||
|
* 1---------5 | |
||||
|
* | /2- - -|- -6 |
||||
|
* | / | / |
||||
|
* |/ | / |
||||
|
* 0---------4/ |
||||
|
* @param builder |
||||
|
* @param mat |
||||
|
* @param mins |
||||
|
* @param maxs |
||||
|
* @param color |
||||
|
*/ |
||||
|
public static drawBoundBox(builder: GLMeshBuilder, mat: mat4, mins: vec3, maxs: vec3, color: vec4 = vec4.red): void { |
||||
|
builder.gl.disable(builder.gl.DEPTH_TEST);//关闭深度测试
|
||||
|
|
||||
|
//使用LINE_LOOP绘制底面
|
||||
|
builder.begin(builder.gl.LINE_LOOP); |
||||
|
builder.color(color.r, color.g, color.b).vertex(mins.x, mins.y, mins.z); // 2 - - -
|
||||
|
builder.color(color.r, color.g, color.b).vertex(mins.x, mins.y, maxs.z); // 0 - - +
|
||||
|
builder.color(color.r, color.g, color.b).vertex(maxs.x, mins.y, maxs.z); // 4 + - +
|
||||
|
builder.color(color.r, color.g, color.b).vertex(maxs.x, mins.y, mins.z); // 6 + - -
|
||||
|
builder.end(mat); |
||||
|
|
||||
|
//使用LINE_LOOP绘制顶面
|
||||
|
builder.begin(builder.gl.LINE_LOOP); |
||||
|
builder.color(color.r, color.g, color.b).vertex(mins.x, maxs.y, mins.z); // 3 - + -
|
||||
|
builder.color(color.r, color.g, color.b).vertex(maxs.x, maxs.y, mins.z); // 7 + + -
|
||||
|
builder.color(color.r, color.g, color.b).vertex(maxs.x, maxs.y, maxs.z); // 5 + + +
|
||||
|
builder.color(color.r, color.g, color.b).vertex(mins.x, maxs.y, maxs.z); // 1 - + +
|
||||
|
builder.end(mat); |
||||
|
|
||||
|
//使用LINES绘制侧四个面
|
||||
|
builder.begin(builder.gl.LINES); |
||||
|
builder.color(color.r, color.g, color.b).vertex(mins.x, mins.y, mins.z); // 2 - - -
|
||||
|
builder.color(color.r, color.g, color.b).vertex(mins.x, maxs.y, mins.z); // 3 - + -
|
||||
|
builder.color(color.r, color.g, color.b).vertex(mins.x, mins.y, maxs.z); // 0 - - +
|
||||
|
builder.color(color.r, color.g, color.b).vertex(mins.x, maxs.y, maxs.z); // 1 - + +
|
||||
|
builder.color(color.r, color.g, color.b).vertex(maxs.x, mins.y, maxs.z); // 4 + - +
|
||||
|
builder.color(color.r, color.g, color.b).vertex(maxs.x, maxs.y, maxs.z); // 5 + + +
|
||||
|
builder.color(color.r, color.g, color.b).vertex(maxs.x, mins.y, mins.z); // 6 + - -
|
||||
|
builder.color(color.r, color.g, color.b).vertex(maxs.x, maxs.y, mins.z); // 7 + + -
|
||||
|
builder.end(mat); |
||||
|
|
||||
|
builder.gl.enable(builder.gl.DEPTH_TEST); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* |
||||
|
* @param builder |
||||
|
* @param mat |
||||
|
* @param halfLen |
||||
|
* @param color |
||||
|
*/ |
||||
|
public static drawWireFrameCubeBox(builder: GLMeshBuilder, mat: mat4, halfLen: number = 0.2, color: vec4 = vec4.red): void { |
||||
|
let mins: vec3 = new vec3([-halfLen, -halfLen, -halfLen]); |
||||
|
let maxs: vec3 = new vec3([halfLen, halfLen, halfLen]); |
||||
|
DrawHelper.drawBoundBox(builder, mat, mins, maxs, color); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* /3--------/7 | |
||||
|
* / | / | |
||||
|
* / | / | |
||||
|
* 1---------5 | |
||||
|
* | /2- - -|- -6 |
||||
|
* | / | / |
||||
|
* |/ | / |
||||
|
* 0---------4/ |
||||
|
* @param builder |
||||
|
* @param mat |
||||
|
* @param halfLen |
||||
|
* @param tc |
||||
|
*/ |
||||
|
public static drawTextureCubeBox(builder: GLMeshBuilder, mat: mat4, halfLen: number = 0.2, tc: number[] = [ |
||||
|
0, 0, 1, 0, 1, 1, 0, 1, // 前面
|
||||
|
0, 0, 1, 0, 1, 1, 0, 1, // 右面
|
||||
|
0, 0, 1, 0, 1, 1, 0, 1, // 后面
|
||||
|
0, 0, 1, 0, 1, 1, 0, 1, // 左面
|
||||
|
0, 0, 1, 0, 1, 1, 0, 1, // 上面
|
||||
|
0, 0, 1, 0, 1, 1, 0, 1, // 下面
|
||||
|
]): void { |
||||
|
//绘制前面
|
||||
|
builder.begin(builder.gl.TRIANGLE_FAN); |
||||
|
builder.texcoord(tc[0], tc[1]).vertex(-halfLen, -halfLen, halfLen); // 0 - - +
|
||||
|
builder.texcoord(tc[2], tc[3]).vertex(halfLen, -halfLen, halfLen); // 4 + - +
|
||||
|
builder.texcoord(tc[4], tc[5]).vertex(halfLen, halfLen, halfLen); // 5 + + +
|
||||
|
builder.texcoord(tc[6], tc[7]).vertex(-halfLen, halfLen, halfLen); // 1 - + +
|
||||
|
builder.end(mat); |
||||
|
//绘制右边
|
||||
|
builder.begin(builder.gl.TRIANGLE_FAN); |
||||
|
builder.texcoord(tc[8], tc[9]).vertex(halfLen, -halfLen, halfLen); // 4 + - +
|
||||
|
builder.texcoord(tc[10], tc[11]).vertex(halfLen, -halfLen, -halfLen); // 6 + - -
|
||||
|
builder.texcoord(tc[12], tc[13]).vertex(halfLen, halfLen, -halfLen); // 7 + + -
|
||||
|
builder.texcoord(tc[14], tc[15]).vertex(halfLen, halfLen, halfLen); // 5 + + +
|
||||
|
builder.end(mat); |
||||
|
// 后面
|
||||
|
builder.begin(builder.gl.TRIANGLE_FAN); |
||||
|
builder.texcoord(tc[16], tc[17]).vertex(halfLen, -halfLen, -halfLen); // 6 + - -
|
||||
|
builder.texcoord(tc[18], tc[19]).vertex(-halfLen, -halfLen, -halfLen); // 2 - - -
|
||||
|
builder.texcoord(tc[20], tc[21]).vertex(-halfLen, halfLen, -halfLen); // 3 - + -
|
||||
|
builder.texcoord(tc[22], tc[23]).vertex(halfLen, halfLen, -halfLen); // 7 + + -
|
||||
|
builder.end(mat); |
||||
|
// 左面
|
||||
|
builder.begin(builder.gl.TRIANGLE_FAN); |
||||
|
builder.texcoord(tc[24], tc[25]).vertex(-halfLen, -halfLen, -halfLen); // 2 - - -
|
||||
|
builder.texcoord(tc[26], tc[27]).vertex(-halfLen, -halfLen, halfLen); // 0 - - +
|
||||
|
builder.texcoord(tc[28], tc[29]).vertex(-halfLen, halfLen, halfLen); // 1 - + +
|
||||
|
builder.texcoord(tc[30], tc[31]).vertex(-halfLen, halfLen, -halfLen); // 3 - + -
|
||||
|
builder.end(mat); |
||||
|
// 上面
|
||||
|
builder.begin(builder.gl.TRIANGLE_FAN); |
||||
|
builder.texcoord(tc[32], tc[33]).vertex(-halfLen, halfLen, halfLen); // 1 - + +
|
||||
|
builder.texcoord(tc[34], tc[35]).vertex(halfLen, halfLen, halfLen); // 5 + + +
|
||||
|
builder.texcoord(tc[36], tc[37]).vertex(halfLen, halfLen, -halfLen); // 7 + + -
|
||||
|
builder.texcoord(tc[38], tc[39]).vertex(-halfLen, halfLen, -halfLen); // 3 - + -
|
||||
|
builder.end(mat); |
||||
|
// 下面
|
||||
|
builder.begin(builder.gl.TRIANGLE_FAN); |
||||
|
builder.texcoord(tc[40], tc[41]).vertex(-halfLen, -halfLen, halfLen); // 0 - - +
|
||||
|
builder.texcoord(tc[42], tc[43]).vertex(-halfLen, -halfLen, -halfLen); // 2 - - -
|
||||
|
builder.texcoord(tc[44], tc[45]).vertex(halfLen, -halfLen, -halfLen); // 6 + - -
|
||||
|
builder.texcoord(tc[46], tc[47]).vertex(halfLen, -halfLen, halfLen); // 4 + - +
|
||||
|
builder.end(mat); |
||||
|
} |
||||
|
|
||||
|
public static drawWireFrameFrustum(builder: GLMeshBuilder, mat: mat4, pts: vec3[], color: vec4 = vec4.red): void { |
||||
|
builder.gl.disable(builder.gl.DEPTH_TEST); |
||||
|
|
||||
|
//使用LINE_LOOP绘制近平面四边形
|
||||
|
builder.begin(builder.gl.LINE_LOOP); |
||||
|
builder.color(color.r, color.g, color.b).vertex(pts[0].x, pts[0].y, pts[0].z); |
||||
|
builder.color(color.r, color.g, color.b).vertex(pts[1].x, pts[1].y, pts[1].z); |
||||
|
builder.color(color.r, color.g, color.b).vertex(pts[2].x, pts[2].y, pts[2].z); |
||||
|
builder.color(color.r, color.g, color.b).vertex(pts[3].x, pts[3].y, pts[3].z); |
||||
|
builder.end(mat); |
||||
|
|
||||
|
//使用LINE_LOOP绘制远平面四边形
|
||||
|
builder.begin(builder.gl.LINE_LOOP); |
||||
|
builder.color(color.r, color.g, color.b).vertex(pts[4].x, pts[4].y, pts[4].z); |
||||
|
builder.color(color.r, color.g, color.b).vertex(pts[5].x, pts[5].y, pts[5].z); |
||||
|
builder.color(color.r, color.g, color.b).vertex(pts[6].x, pts[6].y, pts[6].z); |
||||
|
builder.color(color.r, color.g, color.b).vertex(pts[7].x, pts[7].y, pts[7].z); |
||||
|
builder.end(mat); |
||||
|
|
||||
|
// 使用LINES绘制绘制近平面与远平面的四条边
|
||||
|
builder.begin(builder.gl.LINES); // 使用的是LINES图元绘制模式
|
||||
|
builder.color(color.r, color.g, color.b).vertex(pts[0].x, pts[0].y, pts[0].z); //
|
||||
|
builder.color(color.r, color.g, color.b).vertex(pts[4].x, pts[4].y, pts[4].z); //
|
||||
|
builder.color(color.r, color.g, color.b).vertex(pts[1].x, pts[1].y, pts[1].z); //
|
||||
|
builder.color(color.r, color.g, color.b).vertex(pts[5].x, pts[5].y, pts[5].z); //
|
||||
|
builder.color(color.r, color.g, color.b).vertex(pts[2].x, pts[2].y, pts[2].z); //
|
||||
|
builder.color(color.r, color.g, color.b).vertex(pts[6].x, pts[6].y, pts[6].z); //
|
||||
|
builder.color(color.r, color.g, color.b).vertex(pts[3].x, pts[3].y, pts[3].z); //
|
||||
|
builder.color(color.r, color.g, color.b).vertex(pts[7].x, pts[7].y, pts[7].z); //
|
||||
|
builder.end(mat); |
||||
|
|
||||
|
builder.gl.enable(builder.gl.DEPTH_TEST); |
||||
|
} |
||||
|
} |
@ -0,0 +1,78 @@ |
|||||
|
import { rejects } from "node:assert"; |
||||
|
import { ImageInfo } from "./ImageInfo"; |
||||
|
|
||||
|
export class HttpRequest { |
||||
|
/** |
||||
|
* 读取图片 |
||||
|
* 这个函数要起作用,必须要在tsconfig.json中将default的es5改成ES2015 |
||||
|
* @param url |
||||
|
*/ |
||||
|
public static loadImageAsync(url: string): Promise<HTMLImageElement> { |
||||
|
return new Promise((resolve, reject): void => { |
||||
|
const image: HTMLImageElement = new Image(); |
||||
|
image.onload = function () { |
||||
|
resolve(image); |
||||
|
} |
||||
|
image.onerror = function () { |
||||
|
reject(new Error("Cloud not load image '" + url + "'.")); |
||||
|
} |
||||
|
image.src = url; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 安全读取图片 |
||||
|
* @param url |
||||
|
* @param name |
||||
|
* @returns |
||||
|
*/ |
||||
|
public static loadImageAsyncSafe(url: string, name: string = url): Promise<ImageInfo | null> { |
||||
|
return new Promise((resolve, rehect): void => { |
||||
|
let image: HTMLImageElement = new Image(); |
||||
|
image.onload = function () { |
||||
|
let info: ImageInfo = new ImageInfo(name, image); |
||||
|
resolve(info); |
||||
|
} |
||||
|
|
||||
|
image.onerror = function () { |
||||
|
resolve(null); |
||||
|
} |
||||
|
image.src = url; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 读取文档 |
||||
|
* @param url |
||||
|
*/ |
||||
|
public static loadTextFileAsync(url: string): Promise<string> { |
||||
|
return new Promise((resolve, reject): void => { |
||||
|
let xhr: XMLHttpRequest = new XMLHttpRequest(); |
||||
|
xhr.onreadystatechange = (ev: Event): any => { |
||||
|
if (xhr.readyState === 4 && xhr.status === 200) { |
||||
|
resolve(xhr.responseText); |
||||
|
} |
||||
|
} |
||||
|
xhr.open("get", url, true, null, null); |
||||
|
xhr.send(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* |
||||
|
* @param url |
||||
|
*/ |
||||
|
public static loadArrayBufferAsync(url: string): Promise<ArrayBuffer> { |
||||
|
return new Promise((resolve, reject): void => { |
||||
|
let xhr: XMLHttpRequest = new XMLHttpRequest(); |
||||
|
xhr.responseType = "arraybuffer"; |
||||
|
xhr.onreadystatechange = (ev: Event): any => { |
||||
|
if (xhr.readyState === 4 && xhr.status === 2000) { |
||||
|
resolve(xhr.response as ArrayBuffer); |
||||
|
} |
||||
|
} |
||||
|
xhr.open("get", url, true, null, null); |
||||
|
xhr.send(); |
||||
|
}); |
||||
|
} |
||||
|
} |
@ -0,0 +1,9 @@ |
|||||
|
export class ImageInfo { |
||||
|
public name: string; |
||||
|
public image: HTMLElement; |
||||
|
|
||||
|
public constructor(path: string, image: HTMLElement) { |
||||
|
this.name = path; |
||||
|
this.image = image; |
||||
|
} |
||||
|
} |
@ -0,0 +1,53 @@ |
|||||
|
import { WebGLApplication } from "../webgl/WebGLApplication"; |
||||
|
import { CanvasKeyBoardEvent } from "./Event"; |
||||
|
import { Camera } from "./Camera"; |
||||
|
|
||||
|
export class CameraApplication extends WebGLApplication { |
||||
|
/** |
||||
|
* @var 相机控制 |
||||
|
*/ |
||||
|
public camera: Camera; |
||||
|
|
||||
|
public constructor(canvas: HTMLCanvasElement, contextAttributes: WebGLContextAttributes = { premultipliedAlpha: false }, need2d: boolean = false) { |
||||
|
super(canvas, contextAttributes, need2d); |
||||
|
this.camera = new Camera(this.gl, canvas.width, canvas.height, 45, 1, 200); |
||||
|
this.camera.z = 4; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 调用camera的update,这样才能实时计算camera的投影和视图矩阵,这样才能保证计算机的正常运行 |
||||
|
* 如果要做CameraApplication的子类复写本函数,记得在函数最后调用: super.update(elapsedMsec, intervalSec) |
||||
|
* @param elapsedMsec |
||||
|
* @param intervalSec |
||||
|
*/ |
||||
|
public update(elapsedMsec: number, intervalSec: number) { |
||||
|
this.camera.update(intervalSec); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 复写onKeyPress |
||||
|
* @param evt |
||||
|
*/ |
||||
|
public onKeyPress(evt: CanvasKeyBoardEvent): void { |
||||
|
if (evt.key === "w") { |
||||
|
this.camera.moveForward(-1);//摄像机前行
|
||||
|
} else if (evt.key === "s") { |
||||
|
this.camera.moveForward(1);//摄像机后退
|
||||
|
} else if (evt.key === "a") { |
||||
|
this.camera.moveRightward(1);//摄像机向左运行
|
||||
|
} else if (evt.key === "d") { |
||||
|
this.camera.moveRightward(-1);//摄像机向右运行
|
||||
|
} else if (evt.key === "z") { |
||||
|
this.camera.moveUpward(1);//摄像机升高
|
||||
|
} else if (evt.key === "x") { |
||||
|
this.camera.moveUpward(-1);//摄像机降低
|
||||
|
} else if (evt.key === "y") { |
||||
|
this.camera.yaw(1); //摄像机绕本身y轴旋转
|
||||
|
} else if (evt.key === "r") { |
||||
|
this.camera.roll(1); //摄像机绕本身z轴旋转
|
||||
|
} else if (evt.key === "p") { |
||||
|
this.camera.pitch(1); //摄像机绕本身x轴旋转
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
1545
src/render/math/TSM.ts
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,10 +1,99 @@ |
|||||
import { Application } from "../core/Application"; |
import { Application } from "../core/Application"; |
||||
|
import { GLMatrixStack, GLWordMatrixStack } from "./WebGLMatrixStack"; |
||||
|
import { GLTexture } from "./WebGLTexture"; |
||||
|
import { GLtextureCache } from "./WebGLTextureCache"; |
||||
|
import { GLProgram } from "./WebGLProgram"; |
||||
|
import { GLProgramCache } from "./WebGLProgramCache"; |
||||
|
import { GLMeshBuilder } from "./WebGLMesh"; |
||||
|
import { GLAttribState } from "./WebGLAttribState"; |
||||
|
import { GLHelper } from "./WebGLHepler"; |
||||
|
|
||||
export class WebGLApplication extends Application { |
export class WebGLApplication extends Application { |
||||
/** |
/** |
||||
* @var WebGL |
* @var WebGL |
||||
*/ |
*/ |
||||
//public gl: WebGLRenderingContext;
|
|
||||
|
public gl: WebGLRenderingContext; |
||||
|
|
||||
|
/** |
||||
|
* @var 模拟OpenGL1.1中的矩阵堆栈 |
||||
|
*/ |
||||
|
public matStack: GLWordMatrixStack; |
||||
|
|
||||
|
/** |
||||
|
* @var 模拟OpenGL1.1的立即绘制模式 |
||||
|
*/ |
||||
|
public builder: GLMeshBuilder; |
||||
|
|
||||
|
/** |
||||
|
* @var canvas 用来绘制文字 |
||||
|
*/ |
||||
|
protected canvas2D: HTMLCanvasElement | null = null; |
||||
|
protected ctx2D: CanvasRenderingContext2D | null = null; |
||||
|
|
||||
|
public constructor(canvas: HTMLCanvasElement, contextAttributes: WebGLContextAttributes = { premultipliedAlpha: false }, need2D: boolean = false) { |
||||
|
super(canvas); |
||||
|
|
||||
|
//创建渲染上下文
|
||||
|
let ctx: WebGLRenderingContext | null = this.canvas.getContext("webgl", contextAttributes); |
||||
|
if (ctx === null) { |
||||
|
throw new Error("create WebGLRenderingContext falied."); |
||||
|
} |
||||
|
this.gl = ctx; |
||||
|
|
||||
|
//2维渲染
|
||||
|
if (need2D === true) { |
||||
|
let canvasElem: HTMLCanvasElement = document.createElement("canvas") as HTMLCanvasElement; |
||||
|
canvasElem.width = this.canvas.width; |
||||
|
canvasElem.height = this.canvas.height; |
||||
|
canvasElem.style.backgroundColor = "transparent"; |
||||
|
canvasElem.style.position = "absolute"; |
||||
|
canvasElem.style.left = "0px"; |
||||
|
canvasElem.style.top = "0px"; |
||||
|
|
||||
|
let parent: HTMLElement | null = this.canvas.parentElement; |
||||
|
if (parent === null) { |
||||
|
throw new Error("The canvas element must have a father."); |
||||
|
} |
||||
|
|
||||
|
parent.appendChild(canvasElem); |
||||
|
|
||||
|
this.ctx2D = canvasElem.getContext("2d"); |
||||
|
|
||||
|
canvasElem.addEventListener("mousedown", this, false); |
||||
|
canvasElem.addEventListener("mouseup", this, false); |
||||
|
canvasElem.addEventListener("mousemove", this, false); |
||||
|
|
||||
|
this.canvas.removeEventListener("mousedown", this); |
||||
|
this.canvas.removeEventListener("mouseup", this); |
||||
|
this.canvas.removeEventListener("mousemove", this); |
||||
|
|
||||
|
this.canvas2D = canvasElem; |
||||
|
} |
||||
|
|
||||
|
//初始化矩阵栈
|
||||
|
this.matStack = new GLWordMatrixStack(); |
||||
|
|
||||
|
//初始化渲染状态
|
||||
|
GLHelper.setDefaultState(this.gl); |
||||
|
|
||||
|
//由于canva是左手系,而webgl是右手系
|
||||
|
this.isFlipYCoord = true; |
||||
|
|
||||
|
//初始化默认纹理
|
||||
|
GLtextureCache.instance.set("default", GLTexture.createDefaultTexture(this.gl)); |
||||
|
|
||||
|
//初始化颜色和纹理program
|
||||
|
GLProgramCache.instance.set("color", GLProgram.createDefaultColorProgram(this.gl)); |
||||
|
GLProgramCache.instance.set("texture", GLProgram.createDefaultTextureProgram(this.gl)); |
||||
|
|
||||
|
this.builder = new GLMeshBuilder(this.gl, GLAttribState.POSITION_BIT | GLAttribState.COLOR_BIT, GLProgramCache.instance.getMust("color")); |
||||
|
} |
||||
|
|
||||
|
protected getMouseCanvas(): HTMLCanvasElement { |
||||
|
if (this.canvas2D !== null && this.ctx2D !== null) { |
||||
|
return this.canvas2D; |
||||
|
} else { |
||||
|
return this.canvas; |
||||
|
} |
||||
|
} |
||||
} |
} |
@ -0,0 +1,10 @@ |
|||||
|
export * from './WebGLProgram'; |
||||
|
export * from './WebGLApplication'; |
||||
|
export * from './WebGLAttribState'; |
||||
|
export * from './WebGLHepler'; |
||||
|
export * from './WebGLMatrixStack'; |
||||
|
export * from './WebGLMesh'; |
||||
|
export * from './WebGLProgramCache'; |
||||
|
export * from './WebGLShaderSource'; |
||||
|
export * from './WebGLTexture'; |
||||
|
export * from './WebGLTextureCache'; |
Write
Preview
Loading…
Cancel
Save
Reference in new issue