@openhps/core
Version:
Open Hybrid Positioning System - Core component
244 lines (229 loc) • 8.82 kB
JavaScript
;
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);