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