UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

194 lines (191 loc) 6.82 kB
import { RefCountedObject } from '../core/ref-counted-object.js'; import { Vec3 } from '../core/math/vec3.js'; import { FloatPacking } from '../core/math/float-packing.js'; import { BoundingBox } from '../core/shape/bounding-box.js'; import { PIXELFORMAT_RGBA16F, TYPE_UINT32, SEMANTIC_ATTR15, ADDRESS_CLAMP_TO_EDGE, FILTER_NEAREST, PIXELFORMAT_RGBA32F, PIXELFORMAT_RGBA16U, isIntegerPixelFormat } from '../platform/graphics/constants.js'; import { Texture } from '../platform/graphics/texture.js'; import { VertexBuffer } from '../platform/graphics/vertex-buffer.js'; import { VertexFormat } from '../platform/graphics/vertex-format.js'; class Morph extends RefCountedObject { get aabb() { if (!this._aabb) { var min = new Vec3(); var max = new Vec3(); for(var i = 0; i < this._targets.length; i++){ var targetAabb = this._targets[i].aabb; min.min(targetAabb.getMin()); max.max(targetAabb.getMax()); } this._aabb = new BoundingBox(); this._aabb.setMinMax(min, max); } return this._aabb; } get morphPositions() { return this._morphPositions; } get morphNormals() { return this._morphNormals; } _init() { this._initTextureBased(); for(var i = 0; i < this._targets.length; i++){ this._targets[i]._postInit(); } } _findSparseSet(deltaArrays, ids, usedDataIndices) { var freeIndex = 1; var dataCount = deltaArrays[0].length; for(var v = 0; v < dataCount; v += 3){ var vertexUsed = false; for(var i = 0; i < deltaArrays.length; i++){ var data = deltaArrays[i]; if (data[v] !== 0 || data[v + 1] !== 0 || data[v + 2] !== 0) { vertexUsed = true; break; } } if (vertexUsed) { ids.push(freeIndex); usedDataIndices.push(v / 3); freeIndex++; } else { ids.push(0); } } return freeIndex; } _initTextureBased() { var deltaArrays = [], deltaInfos = []; for(var i = 0; i < this._targets.length; i++){ var target = this._targets[i]; if (target.options.deltaPositions) { deltaArrays.push(target.options.deltaPositions); deltaInfos.push({ target: target, name: 'texturePositions' }); } if (target.options.deltaNormals) { deltaArrays.push(target.options.deltaNormals); deltaInfos.push({ target: target, name: 'textureNormals' }); } } var ids = [], usedDataIndices = []; var freeIndex = this._findSparseSet(deltaArrays, ids, usedDataIndices); var maxTextureSize = this.device.maxTextureSize; var morphTextureWidth = Math.ceil(Math.sqrt(freeIndex)); morphTextureWidth = Math.min(morphTextureWidth, maxTextureSize); var morphTextureHeight = Math.ceil(freeIndex / morphTextureWidth); if (morphTextureHeight > maxTextureSize) { return false; } this.morphTextureWidth = morphTextureWidth; this.morphTextureHeight = morphTextureHeight; var halfFloat = false; var float2Half = FloatPacking.float2Half; if (this._textureFormat === PIXELFORMAT_RGBA16F) { halfFloat = true; } var textures = []; for(var i1 = 0; i1 < deltaArrays.length; i1++){ textures.push(this._createTexture('MorphTarget', this._textureFormat)); } for(var i2 = 0; i2 < deltaArrays.length; i2++){ var data = deltaArrays[i2]; var texture = textures[i2]; var textureData = texture.lock(); if (halfFloat) { for(var v = 0; v < usedDataIndices.length; v++){ var index = usedDataIndices[v] * 3; var dstIndex = v * 4 + 4; textureData[dstIndex] = float2Half(data[index]); textureData[dstIndex + 1] = float2Half(data[index + 1]); textureData[dstIndex + 2] = float2Half(data[index + 2]); } } else { for(var v1 = 0; v1 < usedDataIndices.length; v1++){ var index1 = usedDataIndices[v1] * 3; var dstIndex1 = v1 * 4 + 4; textureData[dstIndex1] = data[index1]; textureData[dstIndex1 + 1] = data[index1 + 1]; textureData[dstIndex1 + 2] = data[index1 + 2]; } } texture.unlock(); var target1 = deltaInfos[i2].target; target1._setTexture(deltaInfos[i2].name, texture); } var formatDesc = [ { semantic: SEMANTIC_ATTR15, components: 1, type: TYPE_UINT32, asInt: true } ]; this.vertexBufferIds = new VertexBuffer(this.device, new VertexFormat(this.device, formatDesc, ids.length), ids.length, { data: new Uint32Array(ids) }); return true; } destroy() { var _this_vertexBufferIds; (_this_vertexBufferIds = this.vertexBufferIds) == null ? void 0 : _this_vertexBufferIds.destroy(); this.vertexBufferIds = null; for(var i = 0; i < this._targets.length; i++){ this._targets[i].destroy(); } this._targets.length = 0; } get targets() { return this._targets; } _updateMorphFlags() { this._morphPositions = false; this._morphNormals = false; for(var i = 0; i < this._targets.length; i++){ var target = this._targets[i]; if (target.morphPositions) { this._morphPositions = true; } if (target.morphNormals) { this._morphNormals = true; } } } _createTexture(name, format) { return new Texture(this.device, { width: this.morphTextureWidth, height: this.morphTextureHeight, format: format, cubemap: false, mipmaps: false, minFilter: FILTER_NEAREST, magFilter: FILTER_NEAREST, addressU: ADDRESS_CLAMP_TO_EDGE, addressV: ADDRESS_CLAMP_TO_EDGE, name: name }); } constructor(targets, graphicsDevice, { preferHighPrecision = false } = {}){ super(); this.device = graphicsDevice; var device = graphicsDevice; this.preferHighPrecision = preferHighPrecision; this._targets = targets.slice(); var renderableHalf = device.textureHalfFloatRenderable ? PIXELFORMAT_RGBA16F : undefined; var renderableFloat = device.textureFloatRenderable ? PIXELFORMAT_RGBA32F : undefined; this._renderTextureFormat = this.preferHighPrecision ? renderableFloat != null ? renderableFloat : renderableHalf : renderableHalf != null ? renderableHalf : renderableFloat; var _this__renderTextureFormat; this._renderTextureFormat = (_this__renderTextureFormat = this._renderTextureFormat) != null ? _this__renderTextureFormat : PIXELFORMAT_RGBA16U; this.intRenderFormat = isIntegerPixelFormat(this._renderTextureFormat); this._textureFormat = this.preferHighPrecision ? PIXELFORMAT_RGBA32F : PIXELFORMAT_RGBA16F; this._init(); this._updateMorphFlags(); } } export { Morph };