ts-game-engine
Version:
Simple WebGL game/render engine written in TypeScript
112 lines (111 loc) • 6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const Entity_1 = require("./Entity");
const gl_matrix_1 = require("gl-matrix");
const Frustum_1 = require("../Math/Frustum");
class Camera extends Entity_1.Entity {
constructor(scene, name) {
super(scene, name);
this.fov = 45;
this.near = 0.1;
this.far = 1000;
this.viewMatrix = gl_matrix_1.mat4.create();
this.projectionMatrix = gl_matrix_1.mat4.create();
this.viewDirectionProjectionInverseMatrix = gl_matrix_1.mat4.create();
this.frustum = new Frustum_1.Frustum();
this.isViewMatrixDirty = true;
this.isProjectionMatrixDirty = true;
this.isViewDirectionProjectionDirty = true;
this.isFrustumDirty = true;
this.Transform.OnTransformChange = () => this.isViewMatrixDirty = true;
}
get FOV() { return this.fov; }
set FOV(fov) { if (this.fov === fov)
return; this.fov = fov; this.isProjectionMatrixDirty = true; }
get Near() { return this.near; }
set Near(near) { if (this.near === near)
return; this.near = near; this.isProjectionMatrixDirty = true; }
get Far() { return this.far; }
set Far(far) { if (this.far === far)
return; this.far = far; this.isProjectionMatrixDirty = true; }
get ViewMatrix() { return this.viewMatrix; }
get ProjectionMatrix() { return this.projectionMatrix; }
get ViewDirectionProjectionInverseMatrix() { return this.viewDirectionProjectionInverseMatrix; }
get Frustum() { return this.frustum; }
Update(deltaTime) {
super.Update(deltaTime);
if (this.isViewMatrixDirty)
this.UpdateViewMatrix();
if (this.isProjectionMatrixDirty)
this.UpdateProjectionMatrix();
if (this.isViewDirectionProjectionDirty)
this.UpdateViewDirectionProjectionMatrices();
if (this.isFrustumDirty)
this.UpdateFrustum();
}
Resize(width, height) {
this.isProjectionMatrixDirty = true;
}
UpdateViewMatrix() {
let position = this.Transform.Position;
let target = gl_matrix_1.vec3.create();
gl_matrix_1.vec3.add(target, position, this.Transform.Forward);
gl_matrix_1.mat4.lookAt(this.viewMatrix, position, target, this.Transform.Up);
this.isViewDirectionProjectionDirty = true;
this.isFrustumDirty = true;
this.isViewMatrixDirty = false;
}
UpdateProjectionMatrix() {
gl_matrix_1.mat4.perspective(this.projectionMatrix, gl_matrix_1.glMatrix.toRadian(this.fov), this.Scene.Game.GraphicsSystem.AspectRatio, this.near, this.far);
this.isViewDirectionProjectionDirty = true;
this.isFrustumDirty = true;
this.isProjectionMatrixDirty = false;
}
UpdateViewDirectionProjectionMatrices() {
gl_matrix_1.mat4.copy(this.viewDirectionProjectionInverseMatrix, this.viewMatrix);
this.viewDirectionProjectionInverseMatrix[12] = 0;
this.viewDirectionProjectionInverseMatrix[13] = 0;
this.viewDirectionProjectionInverseMatrix[14] = 0;
gl_matrix_1.mat4.multiply(this.viewDirectionProjectionInverseMatrix, this.projectionMatrix, this.viewDirectionProjectionInverseMatrix);
gl_matrix_1.mat4.invert(this.viewDirectionProjectionInverseMatrix, this.viewDirectionProjectionInverseMatrix);
this.isViewDirectionProjectionDirty = false;
}
UpdateFrustum() {
let t = 2 * Math.tan(gl_matrix_1.glMatrix.toRadian(this.fov) / 2);
const aspectRatio = this.Scene.Game.GraphicsSystem.AspectRatio;
let Hnear = t * this.near;
let Wnear = Hnear * aspectRatio;
let Hfar = t * this.far;
let Wfar = Hfar * aspectRatio;
let fc = gl_matrix_1.vec3.create();
gl_matrix_1.vec3.scaleAndAdd(fc, this.Transform.Position, this.Transform.Forward, this.far);
let temp1 = gl_matrix_1.vec3.create();
let temp2 = gl_matrix_1.vec3.create();
let ftl = gl_matrix_1.vec3.create();
gl_matrix_1.vec3.add(ftl, fc, gl_matrix_1.vec3.subtract(ftl, gl_matrix_1.vec3.scale(temp1, this.Transform.Up, Hfar / 2), gl_matrix_1.vec3.scale(temp2, this.Transform.Right, Wfar / 2)));
let ftr = gl_matrix_1.vec3.create();
gl_matrix_1.vec3.scaleAndAdd(ftr, ftl, this.Transform.Right, Wfar);
let fbl = gl_matrix_1.vec3.create();
gl_matrix_1.vec3.subtract(fbl, ftl, gl_matrix_1.vec3.scale(fbl, this.Transform.Up, Hfar));
let fbr = gl_matrix_1.vec3.create();
gl_matrix_1.vec3.subtract(fbr, ftr, gl_matrix_1.vec3.scale(fbr, this.Transform.Up, Hfar));
let nc = gl_matrix_1.vec3.create();
gl_matrix_1.vec3.scaleAndAdd(nc, this.Transform.Position, this.Transform.Forward, this.near);
let ntl = gl_matrix_1.vec3.create();
gl_matrix_1.vec3.add(ntl, nc, gl_matrix_1.vec3.subtract(ntl, gl_matrix_1.vec3.scale(temp1, this.Transform.Up, Hnear / 2), gl_matrix_1.vec3.scale(temp2, this.Transform.Right, Wnear / 2)));
let ntr = gl_matrix_1.vec3.create();
gl_matrix_1.vec3.scaleAndAdd(ntr, ntl, this.Transform.Right, Wnear);
let nbl = gl_matrix_1.vec3.create();
gl_matrix_1.vec3.subtract(nbl, ntl, gl_matrix_1.vec3.scale(nbl, this.Transform.Up, Hnear));
let nbr = gl_matrix_1.vec3.create();
gl_matrix_1.vec3.subtract(nbr, ntr, gl_matrix_1.vec3.scale(nbr, this.Transform.Up, Hnear));
this.frustum.Planes[0].SetPoints(ntr, ntl, ftl); //Top
this.frustum.Planes[1].SetPoints(nbl, nbr, fbr); //Bottom
this.frustum.Planes[2].SetPoints(ntl, nbl, fbl); //Left
this.frustum.Planes[3].SetPoints(nbr, ntr, fbr); //Right
this.frustum.Planes[4].SetPoints(ntl, ntr, nbr); //Near
this.frustum.Planes[5].SetPoints(ftr, ftl, fbl); //Far
this.isFrustumDirty = false;
}
}
exports.Camera = Camera;