import Node from './Node'; import Matrix4 from './math/Matrix4'; import Frustum from './math/Frustum'; import Ray from './math/Ray'; import vec4 from './glmatrix/vec4'; import vec3 from './glmatrix/vec3'; /** * @constructor clay.Camera * @extends clay.Node */ var Camera = Node.extend(function () { return /** @lends clay.Camera# */ { /** * Camera projection matrix * @type {clay.Matrix4} */ projectionMatrix: new Matrix4(), /** * Inverse of camera projection matrix * @type {clay.Matrix4} */ invProjectionMatrix: new Matrix4(), /** * View matrix, equal to inverse of camera's world matrix * @type {clay.Matrix4} */ viewMatrix: new Matrix4(), /** * Camera frustum in view space * @type {clay.Frustum} */ frustum: new Frustum() }; }, function () { this.update(true); }, /** @lends clay.Camera.prototype */ { update: function (force) { Node.prototype.update.call(this, force); Matrix4.invert(this.viewMatrix, this.worldTransform); this.updateProjectionMatrix(); Matrix4.invert(this.invProjectionMatrix, this.projectionMatrix); this.frustum.setFromProjection(this.projectionMatrix); }, /** * Set camera view matrix */ setViewMatrix: function (viewMatrix) { Matrix4.copy(this.viewMatrix, viewMatrix); Matrix4.invert(this.worldTransform, viewMatrix); this.decomposeWorldTransform(); }, /** * Decompose camera projection matrix */ decomposeProjectionMatrix: function () {}, /** * Set camera projection matrix * @param {clay.Matrix4} projectionMatrix */ setProjectionMatrix: function (projectionMatrix) { Matrix4.copy(this.projectionMatrix, projectionMatrix); Matrix4.invert(this.invProjectionMatrix, projectionMatrix); this.decomposeProjectionMatrix(); }, /** * Update projection matrix, called after update */ updateProjectionMatrix: function () {}, /** * Cast a picking ray from camera near plane to far plane * @function * @param {clay.Vector2} ndc * @param {clay.Ray} [out] * @return {clay.Ray} */ castRay: (function () { var v4 = vec4.create(); return function (ndc, out) { var ray = out !== undefined ? out : new Ray(); var x = ndc.array[0]; var y = ndc.array[1]; vec4.set(v4, x, y, -1, 1); vec4.transformMat4(v4, v4, this.invProjectionMatrix.array); vec4.transformMat4(v4, v4, this.worldTransform.array); vec3.scale(ray.origin.array, v4, 1 / v4[3]); vec4.set(v4, x, y, 1, 1); vec4.transformMat4(v4, v4, this.invProjectionMatrix.array); vec4.transformMat4(v4, v4, this.worldTransform.array); vec3.scale(v4, v4, 1 / v4[3]); vec3.sub(ray.direction.array, v4, ray.origin.array); vec3.normalize(ray.direction.array, ray.direction.array); ray.direction._dirty = true; ray.origin._dirty = true; return ray; }; })(), /** * @function * @name clone * @return {clay.Camera} * @memberOf clay.Camera.prototype */ }); export default Camera;