UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

115 lines (112 loc) 3.25 kB
import { math } from '../core/math/math.js'; import { Mat4 } from '../core/math/mat4.js'; import { FILTER_NEAREST, PIXELFORMAT_RGBA32F, TEXTURELOCK_READ } from '../platform/graphics/constants.js'; import { Texture } from '../platform/graphics/texture.js'; const _invMatrix = new Mat4(); class SkinInstance { constructor(skin){ this._dirty = true; this._rootBone = null; this._skinUpdateIndex = -1; this._updateBeforeCull = true; if (skin) { this.initSkin(skin); } } set rootBone(rootBone) { this._rootBone = rootBone; } get rootBone() { return this._rootBone; } init(device, numBones) { const numPixels = numBones * 3; let width = Math.ceil(Math.sqrt(numPixels)); width = math.roundUp(width, 3); const height = Math.ceil(numPixels / width); this.boneTexture = new Texture(device, { width: width, height: height, format: PIXELFORMAT_RGBA32F, mipmaps: false, minFilter: FILTER_NEAREST, magFilter: FILTER_NEAREST, name: 'skin' }); this.matrixPalette = this.boneTexture.lock({ mode: TEXTURELOCK_READ }); this.boneTexture.unlock(); } destroy() { if (this.boneTexture) { this.boneTexture.destroy(); this.boneTexture = null; } } resolve(rootBone, entity) { this.rootBone = rootBone; const skin = this.skin; const bones = []; for(let j = 0; j < skin.boneNames.length; j++){ const boneName = skin.boneNames[j]; let bone = rootBone.findByName(boneName); if (!bone) { bone = entity; } bones.push(bone); } this.bones = bones; } initSkin(skin) { this.skin = skin; this.bones = []; const numBones = skin.inverseBindPose.length; this.init(skin.device, numBones); this.matrices = []; for(let i = 0; i < numBones; i++){ this.matrices[i] = new Mat4(); } } uploadBones(device) { this.boneTexture.upload(); } _updateMatrices(rootNode, skinUpdateIndex) { if (this._skinUpdateIndex !== skinUpdateIndex) { this._skinUpdateIndex = skinUpdateIndex; _invMatrix.copy(rootNode.getWorldTransform()).invert(); for(let i = this.bones.length - 1; i >= 0; i--){ this.matrices[i].mulAffine2(_invMatrix, this.bones[i].getWorldTransform()); this.matrices[i].mulAffine2(this.matrices[i], this.skin.inverseBindPose[i]); } } } updateMatrices(rootNode, skinUpdateIndex) { if (this._updateBeforeCull) { this._updateMatrices(rootNode, skinUpdateIndex); } } updateMatrixPalette(rootNode, skinUpdateIndex) { this._updateMatrices(rootNode, skinUpdateIndex); const mp = this.matrixPalette; const count = this.bones.length; for(let i = 0; i < count; i++){ const pe = this.matrices[i].data; const base = i * 12; mp[base] = pe[0]; mp[base + 1] = pe[4]; mp[base + 2] = pe[8]; mp[base + 3] = pe[12]; mp[base + 4] = pe[1]; mp[base + 5] = pe[5]; mp[base + 6] = pe[9]; mp[base + 7] = pe[13]; mp[base + 8] = pe[2]; mp[base + 9] = pe[6]; mp[base + 10] = pe[10]; mp[base + 11] = pe[14]; } this.uploadBones(this.skin.device); } } export { SkinInstance };