Browse Source

完成Frustum

master
blobt 3 years ago
parent
commit
6b3ca41fdd
  1. 5
      src/render/common.ts
  2. 4
      src/render/core/Application.ts
  3. 367
      src/render/core/Camera.ts
  4. 170
      src/render/core/Frustum.ts

5
src/render/common.ts

@ -36,4 +36,9 @@ export enum EPlaneLoc {
FRONT, // 在平面的正面
BACK, // 在平面的背面
COPLANAR // 与平面共面
}
export enum ECameraType {
FPSCAMERA,
FLYCAMERA
}

4
src/render/core/Application.ts

@ -21,9 +21,9 @@ export class Application implements EventListenerObject {
private _fps: number = 0;
/**
* @var
* @var y轴
*/
public isFlipYCoord: boolean = false;
public isFlipYCoord: boolean = false;
/**
* @var

367
src/render/core/Camera.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);
}
}

170
src/render/core/Frustum.ts

@ -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;
}
}
Loading…
Cancel
Save