UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

181 lines (166 loc) 5.72 kB
import TempNode from '../core/TempNode.js'; import { modelViewMatrix } from './ModelNode.js'; import { positionLocal, positionPrevious } from './Position.js'; import { nodeImmutable } from '../tsl/TSLBase.js'; import { NodeUpdateType } from '../core/constants.js'; import { Matrix4 } from '../../math/Matrix4.js'; import { uniform } from '../core/UniformNode.js'; import { sub } from '../math/OperatorNode.js'; import { cameraProjectionMatrix } from './Camera.js'; import { renderGroup } from '../core/UniformGroupNode.js'; const _objectData = new WeakMap(); /** * A node for representing motion or velocity vectors. Foundation * for advanced post processing effects like motion blur or TRAA. * * The node keeps track of the model, view and projection matrices * of the previous frame and uses them to compute offsets in NDC space. * These offsets represent the final velocity. * * @augments TempNode */ class VelocityNode extends TempNode { static get type() { return 'VelocityNode'; } /** * Constructs a new vertex color node. */ constructor() { super('vec2'); /** * The current projection matrix. * * @type {?Matrix4} * @default null */ this.projectionMatrix = null; /** * Overwritten since velocity nodes are updated per object. * * @type {string} * @default 'object' */ this.updateType = NodeUpdateType.OBJECT; /** * Overwritten since velocity nodes save data after the update. * * @type {string} * @default 'object' */ this.updateAfterType = NodeUpdateType.OBJECT; /** * Uniform node representing the previous model matrix in world space. * * @type {UniformNode<mat4>} * @default null */ this.previousModelWorldMatrix = uniform(new Matrix4()); /** * Uniform node representing the previous projection matrix. * * @type {UniformNode<mat4>} * @default null */ this.previousProjectionMatrix = uniform(new Matrix4()).setGroup(renderGroup); /** * Uniform node representing the previous view matrix. * * @type {UniformNode<mat4>} * @default null */ this.previousCameraViewMatrix = uniform(new Matrix4()); } /** * Sets the given projection matrix. * * @param {Matrix4} projectionMatrix - The projection matrix to set. */ setProjectionMatrix(projectionMatrix) { this.projectionMatrix = projectionMatrix; } /** * Updates velocity specific uniforms. * * @param {NodeFrame} frame - A reference to the current node frame. */ update({ frameId, camera, object }) { const previousModelMatrix = getPreviousMatrix(object); this.previousModelWorldMatrix.value.copy(previousModelMatrix); // const cameraData = getData(camera); if (cameraData.frameId !== frameId) { cameraData.frameId = frameId; if (cameraData.previousProjectionMatrix === undefined) { cameraData.previousProjectionMatrix = new Matrix4(); cameraData.previousCameraViewMatrix = new Matrix4(); cameraData.currentProjectionMatrix = new Matrix4(); cameraData.currentCameraViewMatrix = new Matrix4(); cameraData.previousProjectionMatrix.copy(this.projectionMatrix || camera.projectionMatrix); cameraData.previousCameraViewMatrix.copy(camera.matrixWorldInverse); } else { cameraData.previousProjectionMatrix.copy(cameraData.currentProjectionMatrix); cameraData.previousCameraViewMatrix.copy(cameraData.currentCameraViewMatrix); } cameraData.currentProjectionMatrix.copy(this.projectionMatrix || camera.projectionMatrix); cameraData.currentCameraViewMatrix.copy(camera.matrixWorldInverse); this.previousProjectionMatrix.value.copy(cameraData.previousProjectionMatrix); this.previousCameraViewMatrix.value.copy(cameraData.previousCameraViewMatrix); } } /** * Overwritten to updated velocity specific uniforms. * * @param {NodeFrame} frame - A reference to the current node frame. */ updateAfter({ object }) { getPreviousMatrix(object).copy(object.matrixWorld); } /** * Implements the velocity computation based on the previous and current vertex data. * * @param {NodeBuilder} builder - A reference to the current node builder. * @return {Node<vec2>} The motion vector. */ setup( /*builder*/ ) { const projectionMatrix = this.projectionMatrix === null ? cameraProjectionMatrix : uniform(this.projectionMatrix); const previousModelViewMatrix = this.previousCameraViewMatrix.mul(this.previousModelWorldMatrix); const clipPositionCurrent = projectionMatrix.mul(modelViewMatrix).mul(positionLocal); const clipPositionPrevious = this.previousProjectionMatrix.mul(previousModelViewMatrix).mul(positionPrevious); const ndcPositionCurrent = clipPositionCurrent.xy.div(clipPositionCurrent.w); const ndcPositionPrevious = clipPositionPrevious.xy.div(clipPositionPrevious.w); const velocity = sub(ndcPositionCurrent, ndcPositionPrevious); return velocity; } } function getData(object) { let objectData = _objectData.get(object); if (objectData === undefined) { objectData = {}; _objectData.set(object, objectData); } return objectData; } function getPreviousMatrix(object, index = 0) { const objectData = getData(object); let matrix = objectData[index]; if (matrix === undefined) { objectData[index] = matrix = new Matrix4(); } return matrix; } export default VelocityNode; /** * TSL object that represents the velocity of a render pass. * * @tsl * @type {VelocityNode} */ export const velocity = /*@__PURE__*/nodeImmutable(VelocityNode);