blobt
4 years ago
4 changed files with 544 additions and 2 deletions
-
5src/render/common.ts
-
4src/render/core/Application.ts
-
367src/render/core/Camera.ts
-
170src/render/core/Frustum.ts
@ -0,0 +1,367 @@ |
|||||
|
import { vec3, vec4, mat4, Util } from "../math"; |
||||
|
import { Frustum } from "./Frustum"; |
||||
|
import { ECameraType } from "../common"; |
||||
|
|
||||
|
export class Camera { |
||||
|
/** |
||||
|
* @var 摄像机类型 |
||||
|
*/ |
||||
|
private _type: ECameraType = ECameraType.FLYCAMERA; |
||||
|
|
||||
|
/** |
||||
|
* @var 摄像机位置 |
||||
|
*/ |
||||
|
private _position: vec3 = new vec3(); |
||||
|
|
||||
|
/** |
||||
|
* @var x轴 |
||||
|
*/ |
||||
|
private _xAxis: vec3 = new vec3([1, 0, 0]); |
||||
|
|
||||
|
/** |
||||
|
* @var y轴 |
||||
|
*/ |
||||
|
private _yAxis: vec3 = new vec3([0, 1, 0]); |
||||
|
|
||||
|
/** |
||||
|
* @var z轴 |
||||
|
*/ |
||||
|
private _zAxis: vec3 = new vec3([0, 0, 1]); |
||||
|
|
||||
|
/** |
||||
|
* @var 近剪裁面 |
||||
|
*/ |
||||
|
private _near: number; |
||||
|
|
||||
|
/** |
||||
|
* @var 远剪裁面 |
||||
|
*/ |
||||
|
private _far: number; |
||||
|
|
||||
|
/** |
||||
|
* @var |
||||
|
*/ |
||||
|
private _left: number; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* @var |
||||
|
*/ |
||||
|
private _right: number; |
||||
|
|
||||
|
/** |
||||
|
* @var |
||||
|
*/ |
||||
|
private _bottom: number; |
||||
|
|
||||
|
/** |
||||
|
* @var |
||||
|
*/ |
||||
|
private _top: number; |
||||
|
|
||||
|
/** |
||||
|
* @var fov角度 |
||||
|
*/ |
||||
|
private _fovY: number; |
||||
|
|
||||
|
/** |
||||
|
* @var 宽高比 |
||||
|
*/ |
||||
|
private _aspectRatio: number; |
||||
|
|
||||
|
/** |
||||
|
* @var 投影矩阵 |
||||
|
*/ |
||||
|
private _projectionMatrix: mat4; |
||||
|
|
||||
|
/** |
||||
|
* @var 视口矩阵 |
||||
|
*/ |
||||
|
private _viewMatrix: mat4; |
||||
|
|
||||
|
/** |
||||
|
* @var 视口矩阵逆矩阵 |
||||
|
*/ |
||||
|
private _invViewMatrix: mat4; |
||||
|
|
||||
|
/** |
||||
|
* @var 视口投影矩阵 |
||||
|
*/ |
||||
|
private _viewProjMatrix: mat4; |
||||
|
|
||||
|
/** |
||||
|
* @var 视口投影矩阵逆矩阵 |
||||
|
*/ |
||||
|
private _invViewProjMatrix: mat4; |
||||
|
|
||||
|
/** |
||||
|
* @var 视锥体 |
||||
|
*/ |
||||
|
private _frustum: Frustum; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* @var 渲染上下文 |
||||
|
*/ |
||||
|
public gl: WebGLRenderingContext; |
||||
|
|
||||
|
/** |
||||
|
* @var |
||||
|
*/ |
||||
|
public controlByMouse: boolean; |
||||
|
|
||||
|
public constructor(gl: WebGLRenderingContext, width: number, height: number, fovY: number = 45.0, zNear: number = 1, zFar: number = 1000) { |
||||
|
this.gl = gl; |
||||
|
this._aspectRatio = width / height; |
||||
|
this._fovY = Util.toRadian(fovY); |
||||
|
|
||||
|
this._near = zNear; |
||||
|
this._far = zFar; |
||||
|
|
||||
|
this._top = this._near * Math.tan(this._fovY * 0.5); |
||||
|
this._right = this._top * this._aspectRatio; |
||||
|
this._bottom = -this._top; |
||||
|
this._left = -this._right; |
||||
|
this._frustum = new Frustum(); |
||||
|
|
||||
|
this._projectionMatrix = new mat4(); |
||||
|
this._viewMatrix = new mat4(); |
||||
|
this._invViewMatrix = new mat4(); |
||||
|
this._viewProjMatrix = new mat4(); |
||||
|
this._invViewProjMatrix = new mat4(); |
||||
|
|
||||
|
this.controlByMouse = false; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取fov |
||||
|
*/ |
||||
|
public get fovY(): number { |
||||
|
return this._fovY; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置fov |
||||
|
*/ |
||||
|
public set fovY(value: number) { |
||||
|
this._fovY = value; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取近剪裁面 |
||||
|
*/ |
||||
|
public get near(): number { |
||||
|
return this._near |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置近剪裁面 |
||||
|
*/ |
||||
|
public set near(value: number) { |
||||
|
this._near = value; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取远剪裁面 |
||||
|
*/ |
||||
|
public get far(): number { |
||||
|
return this._far |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置远剪裁面 |
||||
|
*/ |
||||
|
public set far(value: number) { |
||||
|
this._far = value; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取宽高比 |
||||
|
*/ |
||||
|
public get aspectRatio(): number { |
||||
|
return this._aspectRatio; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置宽高比 |
||||
|
*/ |
||||
|
public set aspectRatio(value: number) { |
||||
|
this._aspectRatio = value; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取相机位置 |
||||
|
*/ |
||||
|
public get position(): vec3 { |
||||
|
return this._position; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置相机位置 |
||||
|
*/ |
||||
|
public set position(value: vec3) { |
||||
|
this._position = value; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置视口 |
||||
|
* @param x |
||||
|
* @param y |
||||
|
* @param width |
||||
|
* @param height |
||||
|
*/ |
||||
|
public setViewport(x: number, y: number, width: number, height: number): void { |
||||
|
this.gl.viewport(x, y, width, height); |
||||
|
this.gl.scissor(x, y, width, height); |
||||
|
this.aspectRatio = width / height; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取视口 |
||||
|
* @returns |
||||
|
*/ |
||||
|
public getViewport(): Int32Array { |
||||
|
return this.gl.getParameter(this.gl.VIEWPORT); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置相机位置 |
||||
|
*/ |
||||
|
public set x(value: number) { |
||||
|
this._position.x = value; |
||||
|
} |
||||
|
|
||||
|
public set y(value: number) { |
||||
|
this._position.y = value; |
||||
|
} |
||||
|
|
||||
|
public set z(value: number) { |
||||
|
this._position.z = value; |
||||
|
} |
||||
|
|
||||
|
public get x(): number { |
||||
|
return this._position.x; |
||||
|
} |
||||
|
|
||||
|
public get y(): number { |
||||
|
return this._position.y; |
||||
|
} |
||||
|
|
||||
|
public get z(): number { |
||||
|
return this._position.z; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取x轴 |
||||
|
*/ |
||||
|
public get xAxis(): vec3 { |
||||
|
return this._xAxis; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取y轴 |
||||
|
*/ |
||||
|
public get yAxis(): vec3 { |
||||
|
return this._yAxis; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取z轴 |
||||
|
*/ |
||||
|
public get zAxis(): vec3 { |
||||
|
return this._zAxis; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取相机类型 |
||||
|
*/ |
||||
|
public get type(): ECameraType { |
||||
|
return this._type; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置相机类型 |
||||
|
*/ |
||||
|
public set type(value: ECameraType) { |
||||
|
this._type = value; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取相机 近剪裁面的 left right bottom top |
||||
|
*/ |
||||
|
public get left(): number { |
||||
|
return this._left; |
||||
|
} |
||||
|
|
||||
|
public get right(): number { |
||||
|
return this._right; |
||||
|
} |
||||
|
|
||||
|
public get bottom(): number { |
||||
|
return this._bottom; |
||||
|
} |
||||
|
|
||||
|
public get top(): number { |
||||
|
return this._top; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取世界坐标逆矩阵 |
||||
|
*/ |
||||
|
public get invViewMatrix(): mat4 { |
||||
|
return this._invViewMatrix; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 更新相机状态 |
||||
|
* @param intervaleSec 更新间隔 |
||||
|
*/ |
||||
|
public update(intervaleSec: number): void { |
||||
|
this._projectionMatrix = mat4.perspective(this.fovY, this.aspectRatio, this.near, this.far); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 从当前轴以及postion合成view矩阵 |
||||
|
*/ |
||||
|
private _calcViewMatrix(): void { |
||||
|
// 固定forward方向
|
||||
|
this._zAxis.normalize(); |
||||
|
|
||||
|
// 获取up方向
|
||||
|
vec3.cross(this._zAxis, this._xAxis, this._yAxis); |
||||
|
this._yAxis.normalize(); |
||||
|
|
||||
|
// 获取right方向
|
||||
|
vec3.cross(this._yAxis, this._zAxis, this._xAxis); |
||||
|
this._xAxis.normalize(); |
||||
|
|
||||
|
let x: number = -vec3.dot(this._xAxis, this._position); |
||||
|
let y: number = -vec3.dot(this._yAxis, this._position); |
||||
|
let z: number = -vec3.dot(this._zAxis, this._position); |
||||
|
|
||||
|
this._viewMatrix.values[0] = this._xAxis.x; |
||||
|
this._viewMatrix.values[1] = this._yAxis.x; |
||||
|
this._viewMatrix.values[2] = this._zAxis.x; |
||||
|
this._viewMatrix.values[3] = 0.0; |
||||
|
|
||||
|
this._viewMatrix.values[4] = this._xAxis.y; |
||||
|
this._viewMatrix.values[5] = this._yAxis.y; |
||||
|
this._viewMatrix.values[6] = this._zAxis.y; |
||||
|
this._viewMatrix.values[7] = 0.0; |
||||
|
|
||||
|
this._viewMatrix.values[8] = this._xAxis.z; |
||||
|
this._viewMatrix.values[9] = this._yAxis.z; |
||||
|
this._viewMatrix.values[10] = this._zAxis.z; |
||||
|
this._viewMatrix.values[11] = 0.0; |
||||
|
|
||||
|
this._viewMatrix.values[12] = x; |
||||
|
this._viewMatrix.values[13] = y; |
||||
|
this._viewMatrix.values[14] = z; |
||||
|
this._viewMatrix.values[15] = 1.0; |
||||
|
|
||||
|
//生成view的逆矩阵,其实就是世界矩阵
|
||||
|
this._viewMatrix.inverse(this._invViewMatrix); |
||||
|
|
||||
|
//TODO this._frustum.buildFromCamera(this);
|
||||
|
} |
||||
|
} |
@ -0,0 +1,170 @@ |
|||||
|
import { vec3, vec4, Util } from "../math"; |
||||
|
import { Camera } from "./Camera"; |
||||
|
|
||||
|
export class Frustum { |
||||
|
/** |
||||
|
* @var 原点桌标 |
||||
|
*/ |
||||
|
private _origin: vec3; |
||||
|
|
||||
|
/** |
||||
|
* @var 视锥体的8个顶点, 0~3是近剪裁面, 4~7是远剪裁面 |
||||
|
*/ |
||||
|
private _points: vec3[]; |
||||
|
|
||||
|
/** |
||||
|
* @var 视锥体的上,下,左,右,远,近 6个平面,其法向量都是朝视锥体内部 |
||||
|
*/ |
||||
|
private _planes: vec4[]; |
||||
|
|
||||
|
public constructor(origin: vec3 | null = null, points8: vec3[] | null = null) { |
||||
|
//预先内存分配8个点
|
||||
|
if (origin !== null) { |
||||
|
this._origin = origin; |
||||
|
} else { |
||||
|
this._origin = new vec3(); |
||||
|
} |
||||
|
if (points8 !== null && points8.length === 8) { |
||||
|
this._points = points8; |
||||
|
} else { |
||||
|
this._points = new Array(8); |
||||
|
for (let i = 0; i < this._points.length; i++) { |
||||
|
this._points[i] = new vec3(); |
||||
|
} |
||||
|
} |
||||
|
this._planes = new Array(6); |
||||
|
for (let i = 0; i < this._planes.length; i++) { |
||||
|
this._planes[i] = new vec4(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 从摄像机参数建立视锥体 |
||||
|
* @param camera |
||||
|
*/ |
||||
|
public buildFromCamera(camera: Camera): void { |
||||
|
|
||||
|
let left: number = camera.left * camera.far / camera.near; |
||||
|
let right: number = camera.right * camera.far / camera.near; |
||||
|
let bottom: number = camera.bottom * camera.far / camera.near; |
||||
|
let top: number = camera.top * camera.far / camera.near; |
||||
|
|
||||
|
//计算近剪裁面的4个点
|
||||
|
this.points[0].x = left; |
||||
|
this.points[0].y = bottom; |
||||
|
this.points[0].z = -camera.near; |
||||
|
this.points[1].x = right; |
||||
|
this.points[1].y = bottom; |
||||
|
this.points[1].z = -camera.near; |
||||
|
this.points[2].x = right; |
||||
|
this.points[2].y = top; |
||||
|
this.points[2].z = -camera.near; |
||||
|
this.points[3].x = left; |
||||
|
this.points[3].y = top; |
||||
|
this.points[3].z = -camera.near; |
||||
|
|
||||
|
//计算远剪裁面的4个点
|
||||
|
this.points[4].x = left; |
||||
|
this.points[4].y = bottom; |
||||
|
this.points[4].z = -camera.far; |
||||
|
this.points[5].x = right; |
||||
|
this.points[5].y = bottom; |
||||
|
this.points[5].z = -camera.far; |
||||
|
this.points[6].x = right; |
||||
|
this.points[6].y = top; |
||||
|
this.points[6].z = -camera.far; |
||||
|
this.points[7].x = left; |
||||
|
this.points[7].y = top; |
||||
|
this.points[7].z = -camera.far; |
||||
|
|
||||
|
//将摄像机的原点变换到世界坐标系
|
||||
|
this._origin.x = this._origin.y = this._origin.z = 0; |
||||
|
this._origin = camera.invViewMatrix.multiplyVec3(this.origin); |
||||
|
|
||||
|
//将8个顶点的坐标系变换都世界坐标系
|
||||
|
for (let i = 0; i < this._points.length; i++) { |
||||
|
this._points[i] = camera.invViewMatrix.multiplyVec3(this.points[i]); |
||||
|
} |
||||
|
|
||||
|
//构建世界坐标系表示的6个平面,法线朝内
|
||||
|
Util.planeFromPoints(this._origin, this._points[0], this._points[3], this._planes[0]); |
||||
|
Util.planeFromPoints(this._origin, this._points[2], this._points[1], this._planes[1]); |
||||
|
Util.planeFromPoints(this._origin, this._points[3], this._points[2], this._planes[2]); |
||||
|
Util.planeFromPoints(this._origin, this._points[1], this._points[0], this._planes[3]); |
||||
|
Util.planeFromPoints(this._points[0], this._points[2], this._points[1], this._planes[4]); |
||||
|
Util.planeFromPoints(this._points[5], this._points[7], this._points[4], this._planes[5]); |
||||
|
//平面单位化
|
||||
|
for (let i: number = 0; i < this._planes.length; i++) { |
||||
|
Util.planeNormalize(this._planes[i]); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判定6个平面与中心点距离???? |
||||
|
* @param center |
||||
|
* @param radius |
||||
|
* @returns |
||||
|
*/ |
||||
|
public isSphereVisible(center: vec3, radius: number): boolean { |
||||
|
radius = -radius; |
||||
|
for (let i: number = 0; i < this._planes.length; i++) { |
||||
|
if (Util.planeDistanceFromPoint(this._planes[i], center) < radius) { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* ????? |
||||
|
* @param mins |
||||
|
* @param maxs |
||||
|
* @returns |
||||
|
*/ |
||||
|
public isBoundBoxVisible(mins: vec3, maxs: vec3): boolean { |
||||
|
for (let i: number = 0; i < this._planes.length; i++) { |
||||
|
let current: vec4 = this._planes[i]; |
||||
|
vec3.v0.x = (current.x > 0.0) ? maxs.x : mins.x; |
||||
|
vec3.v0.y = (current.y > 0.0) ? maxs.y : mins.x; |
||||
|
vec3.v0.z = (current.z > 0.0) ? maxs.z : mins.z; |
||||
|
if (Util.planeDistanceFromPoint(current, vec3.v0) < 0.0) { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* ????? |
||||
|
* @param a |
||||
|
* @param b |
||||
|
* @param c |
||||
|
* @returns |
||||
|
*/ |
||||
|
public isTriangleVisible(a: vec3, b: vec3, c: vec3): boolean { |
||||
|
for (let i: number = 0; i < this._planes.length; i++) { |
||||
|
let current: vec4 = this._planes[i]; |
||||
|
if (Util.planeDistanceFromPoint(current, a) >= 0.0) { |
||||
|
continue; |
||||
|
} |
||||
|
if (Util.planeDistanceFromPoint(current, b) >= 0.0) { |
||||
|
continue; |
||||
|
} |
||||
|
if (Util.planeDistanceFromPoint(current, c) >= 0.0) { |
||||
|
continue; |
||||
|
} |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public get origin(): vec3 { |
||||
|
return this._origin; |
||||
|
} |
||||
|
public get points(): vec3[] { |
||||
|
return this._points; |
||||
|
} |
||||
|
public get planes(): vec4[] { |
||||
|
return this._planes; |
||||
|
} |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue