UNPKG

@animech-public/playcanvas

Version:
150 lines (140 loc) 5.44 kB
import { Debug } from '../core/debug.js'; import { BoundingBox } from '../core/shape/bounding-box.js'; import { TYPE_FLOAT32, SEMANTIC_ATTR0 } from '../platform/graphics/constants.js'; import { VertexBuffer } from '../platform/graphics/vertex-buffer.js'; import { VertexFormat } from '../platform/graphics/vertex-format.js'; /** * A Morph Target (also known as Blend Shape) contains deformation data to apply to existing mesh. * Multiple morph targets can be blended together on a mesh. This is useful for effects that are * hard to achieve with conventional animation and skinning. * * @category Graphics */ class MorphTarget { /** * Create a new MorphTarget instance. * * @param {object} options - Object for passing optional arguments. * @param {ArrayBuffer} options.deltaPositions - An array of 3-dimensional vertex position * offsets. * @param {number} options.deltaPositionsType - A format to store position offsets inside * {@link VertexBuffer}. Defaults to {@link TYPE_FLOAT32} if not provided. * @param {ArrayBuffer} [options.deltaNormals] - An array of 3-dimensional vertex normal * offsets. * @param {number} options.deltaNormalsType - A format to store normal offsets inside * {@link VertexBuffer}. Defaults to {@link TYPE_FLOAT32} if not provided. * @param {string} [options.name] - Name. * @param {BoundingBox} [options.aabb] - Bounding box. Will be automatically generated, if * undefined. * @param {number} [options.defaultWeight] - Default blend weight to use for this morph target. * @param {boolean} [options.preserveData] - When true, the morph target keeps its data passed using the options, * allowing the clone operation. */ constructor(options) { /** * A used flag. A morph target can be used / owned by the Morph class only one time. * * @type {boolean} */ this.used = false; if (arguments.length === 2) { Debug.deprecated('Passing graphicsDevice to MorphTarget is deprecated, please remove the parameter.'); options = arguments[1]; } this.options = options; this._name = options.name; this._defaultWeight = options.defaultWeight || 0; // bounds this._aabb = options.aabb; // store delta positions, used by aabb evaluation this.deltaPositions = options.deltaPositions; } destroy() { var _this$_vertexBufferPo, _this$_vertexBufferNo, _this$texturePosition, _this$textureNormals; (_this$_vertexBufferPo = this._vertexBufferPositions) == null || _this$_vertexBufferPo.destroy(); this._vertexBufferPositions = null; (_this$_vertexBufferNo = this._vertexBufferNormals) == null || _this$_vertexBufferNo.destroy(); this._vertexBufferNormals = null; (_this$texturePosition = this.texturePositions) == null || _this$texturePosition.destroy(); this.texturePositions = null; (_this$textureNormals = this.textureNormals) == null || _this$textureNormals.destroy(); this.textureNormals = null; } /** * Gets the name of the morph target. * * @type {string} */ get name() { return this._name; } /** * Gets the default weight of the morph target. * * @type {number} */ get defaultWeight() { return this._defaultWeight; } get aabb() { // lazy evaluation, which allows us to skip this completely if customAABB is used if (!this._aabb) { this._aabb = new BoundingBox(); if (this.deltaPositions) { this._aabb.compute(this.deltaPositions); } } return this._aabb; } get morphPositions() { return !!this._vertexBufferPositions || !!this.texturePositions; } get morphNormals() { return !!this._vertexBufferNormals || !!this.textureNormals; } /** * Returns an identical copy of the specified morph target. This can only be used if the morph target * was created with options.preserveData set to true. * * @returns {MorphTarget} A morph target instance containing the result of the cloning. */ clone() { Debug.assert(this.options, 'MorphTarget cannot be cloned, was it created with a preserveData option?'); return new MorphTarget(this.options); } _postInit() { // release original data if (!this.options.preserveData) { this.options = null; } // mark it as used this.used = true; } _initVertexBuffers(graphicsDevice) { const options = this.options; this._vertexBufferPositions = this._createVertexBuffer(graphicsDevice, options.deltaPositions, options.deltaPositionsType); this._vertexBufferNormals = this._createVertexBuffer(graphicsDevice, options.deltaNormals, options.deltaNormalsType); // access positions from vertex buffer when needed if (this._vertexBufferPositions) { this.deltaPositions = this._vertexBufferPositions.lock(); } } _createVertexBuffer(device, data, dataType = TYPE_FLOAT32) { if (data) { // create vertex buffer with specified type (or float32), and semantic of ATTR0 which gets replaced at runtime with actual semantic const formatDesc = [{ semantic: SEMANTIC_ATTR0, components: 3, type: dataType }]; return new VertexBuffer(device, new VertexFormat(device, formatDesc), data.length / 3, { data: data }); } return null; } _setTexture(name, texture) { this[name] = texture; } } export { MorphTarget };