UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

244 lines (229 loc) 8.82 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.morphReference = exports.default = void 0; var _Node = _interopRequireDefault(require("../core/Node.js")); var _constants = require("../core/constants.js"); var _TSLBase = require("../tsl/TSLBase.js"); var _UniformNode = require("../core/UniformNode.js"); var _ReferenceNode = require("./ReferenceNode.js"); var _Position = require("./Position.js"); var _Normal = require("./Normal.js"); var _TextureNode = require("./TextureNode.js"); var _IndexNode = require("../core/IndexNode.js"); var _LoopNode = require("../utils/LoopNode.js"); var _DataArrayTexture = require("../../textures/DataArrayTexture.js"); var _Vector = require("../../math/Vector2.js"); var _Vector2 = require("../../math/Vector4.js"); var _constants2 = require("../../constants.js"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const _morphTextures = /*@__PURE__*/new WeakMap(); const _morphVec4 = /*@__PURE__*/new _Vector2.Vector4(); const getMorph = /*@__PURE__*/(0, _TSLBase.Fn)(({ bufferMap, influence, stride, width, depth, offset }) => { const texelIndex = (0, _TSLBase.int)(_IndexNode.vertexIndex).mul(stride).add(offset); const y = texelIndex.div(width); const x = texelIndex.sub(y.mul(width)); const bufferAttrib = (0, _TextureNode.textureLoad)(bufferMap, (0, _TSLBase.ivec2)(x, y)).depth(depth).xyz; return bufferAttrib.mul(influence); }); function getEntry(geometry) { const hasMorphPosition = geometry.morphAttributes.position !== undefined; const hasMorphNormals = geometry.morphAttributes.normal !== undefined; const hasMorphColors = geometry.morphAttributes.color !== undefined; // instead of using attributes, the WebGL 2 code path encodes morph targets // into an array of data textures. Each layer represents a single morph target. const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; const morphTargetsCount = morphAttribute !== undefined ? morphAttribute.length : 0; let entry = _morphTextures.get(geometry); if (entry === undefined || entry.count !== morphTargetsCount) { if (entry !== undefined) entry.texture.dispose(); const morphTargets = geometry.morphAttributes.position || []; const morphNormals = geometry.morphAttributes.normal || []; const morphColors = geometry.morphAttributes.color || []; let vertexDataCount = 0; if (hasMorphPosition === true) vertexDataCount = 1; if (hasMorphNormals === true) vertexDataCount = 2; if (hasMorphColors === true) vertexDataCount = 3; let width = geometry.attributes.position.count * vertexDataCount; let height = 1; const maxTextureSize = 4096; // @TODO: Use 'capabilities.maxTextureSize' if (width > maxTextureSize) { height = Math.ceil(width / maxTextureSize); width = maxTextureSize; } const buffer = new Float32Array(width * height * 4 * morphTargetsCount); const bufferTexture = new _DataArrayTexture.DataArrayTexture(buffer, width, height, morphTargetsCount); bufferTexture.type = _constants2.FloatType; bufferTexture.needsUpdate = true; // fill buffer const vertexDataStride = vertexDataCount * 4; for (let i = 0; i < morphTargetsCount; i++) { const morphTarget = morphTargets[i]; const morphNormal = morphNormals[i]; const morphColor = morphColors[i]; const offset = width * height * 4 * i; for (let j = 0; j < morphTarget.count; j++) { const stride = j * vertexDataStride; if (hasMorphPosition === true) { _morphVec4.fromBufferAttribute(morphTarget, j); buffer[offset + stride + 0] = _morphVec4.x; buffer[offset + stride + 1] = _morphVec4.y; buffer[offset + stride + 2] = _morphVec4.z; buffer[offset + stride + 3] = 0; } if (hasMorphNormals === true) { _morphVec4.fromBufferAttribute(morphNormal, j); buffer[offset + stride + 4] = _morphVec4.x; buffer[offset + stride + 5] = _morphVec4.y; buffer[offset + stride + 6] = _morphVec4.z; buffer[offset + stride + 7] = 0; } if (hasMorphColors === true) { _morphVec4.fromBufferAttribute(morphColor, j); buffer[offset + stride + 8] = _morphVec4.x; buffer[offset + stride + 9] = _morphVec4.y; buffer[offset + stride + 10] = _morphVec4.z; buffer[offset + stride + 11] = morphColor.itemSize === 4 ? _morphVec4.w : 1; } } } entry = { count: morphTargetsCount, texture: bufferTexture, stride: vertexDataCount, size: new _Vector.Vector2(width, height) }; _morphTextures.set(geometry, entry); function disposeTexture() { bufferTexture.dispose(); _morphTextures.delete(geometry); geometry.removeEventListener('dispose', disposeTexture); } geometry.addEventListener('dispose', disposeTexture); } return entry; } /** * This node implements the vertex transformation shader logic which is required * for morph target animation. * * @augments Node */ class MorphNode extends _Node.default { static get type() { return 'MorphNode'; } /** * Constructs a new morph node. * * @param {Mesh} mesh - The mesh holding the morph targets. */ constructor(mesh) { super('void'); /** * The mesh holding the morph targets. * * @type {Mesh} */ this.mesh = mesh; /** * A uniform node which represents the morph base influence value. * * @type {UniformNode<float>} */ this.morphBaseInfluence = (0, _UniformNode.uniform)(1); /** * The update type overwritten since morph nodes are updated per object. * * @type {string} */ this.updateType = _constants.NodeUpdateType.OBJECT; } /** * Setups the morph node by assigning the transformed vertex data to predefined node variables. * * @param {NodeBuilder} builder - The current node builder. */ setup(builder) { const { geometry } = builder; const hasMorphPosition = geometry.morphAttributes.position !== undefined; const hasMorphNormals = geometry.hasAttribute('normal') && geometry.morphAttributes.normal !== undefined; const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; const morphTargetsCount = morphAttribute !== undefined ? morphAttribute.length : 0; // nodes const { texture: bufferMap, stride, size } = getEntry(geometry); if (hasMorphPosition === true) _Position.positionLocal.mulAssign(this.morphBaseInfluence); if (hasMorphNormals === true) _Normal.normalLocal.mulAssign(this.morphBaseInfluence); const width = (0, _TSLBase.int)(size.width); (0, _LoopNode.Loop)(morphTargetsCount, ({ i }) => { const influence = (0, _TSLBase.float)(0).toVar(); if (this.mesh.count > 1 && this.mesh.morphTexture !== null && this.mesh.morphTexture !== undefined) { influence.assign((0, _TextureNode.textureLoad)(this.mesh.morphTexture, (0, _TSLBase.ivec2)((0, _TSLBase.int)(i).add(1), (0, _TSLBase.int)(_IndexNode.instanceIndex))).r); } else { influence.assign((0, _ReferenceNode.reference)('morphTargetInfluences', 'float').element(i).toVar()); } (0, _TSLBase.If)(influence.notEqual(0), () => { if (hasMorphPosition === true) { _Position.positionLocal.addAssign(getMorph({ bufferMap, influence, stride, width, depth: i, offset: (0, _TSLBase.int)(0) })); } if (hasMorphNormals === true) { _Normal.normalLocal.addAssign(getMorph({ bufferMap, influence, stride, width, depth: i, offset: (0, _TSLBase.int)(1) })); } }); }); } /** * Updates the state of the morphed mesh by updating the base influence. * * @param {NodeFrame} frame - The current node frame. */ update( /*frame*/ ) { const morphBaseInfluence = this.morphBaseInfluence; if (this.mesh.geometry.morphTargetsRelative) { morphBaseInfluence.value = 1; } else { morphBaseInfluence.value = 1 - this.mesh.morphTargetInfluences.reduce((a, b) => a + b, 0); } } } var _default = exports.default = MorphNode; /** * TSL function for creating a morph node. * * @tsl * @function * @param {Mesh} mesh - The mesh holding the morph targets. * @returns {MorphNode} */ const morphReference = exports.morphReference = /*@__PURE__*/(0, _TSLBase.nodeProxy)(MorphNode).setParameterLength(1);