UNPKG

ogl

Version:
67 lines (57 loc) 2.41 kB
import { Mesh } from '../core/Mesh.js'; import { Mat4 } from '../math/Mat4.js'; import { Texture } from '../core/Texture.js'; const tempMat4 = /* @__PURE__ */ new Mat4(); const identity = /* @__PURE__ */ new Mat4(); export class GLTFSkin extends Mesh { constructor(gl, { skeleton, geometry, program, mode = gl.TRIANGLES } = {}) { super(gl, { geometry, program, mode }); this.skeleton = skeleton; this.program = program; this.createBoneTexture(); } createBoneTexture() { if (!this.skeleton.joints.length) return; const size = Math.max(4, Math.pow(2, Math.ceil(Math.log(Math.sqrt(this.skeleton.joints.length * 4)) / Math.LN2))); this.boneMatrices = new Float32Array(size * size * 4); this.boneTextureSize = size; this.boneTexture = new Texture(this.gl, { image: this.boneMatrices, generateMipmaps: false, type: this.gl.FLOAT, internalFormat: this.gl.renderer.isWebgl2 ? this.gl.RGBA32F : this.gl.RGBA, minFilter: this.gl.NEAREST, magFilter: this.gl.NEAREST, flipY: false, width: size, }); } updateUniforms() { // Update bone texture this.skeleton.joints.forEach((bone, i) => { // Find difference between current and bind pose tempMat4.multiply(bone.worldMatrix, bone.bindInverse); this.boneMatrices.set(tempMat4, i * 16); }); this.boneTexture.needsUpdate = true; // Reset for programs shared between multiple skins this.program.uniforms.boneTexture.value = this.boneTexture; this.program.uniforms.boneTextureSize.value = this.boneTextureSize; } draw({ camera } = {}) { if (!this.program.uniforms.boneTexture) { Object.assign(this.program.uniforms, { boneTexture: { value: this.boneTexture }, boneTextureSize: { value: this.boneTextureSize }, }); } this.updateUniforms(); // Switch the world matrix with identity to ignore any transforms // on the mesh itself - only use skeleton's transforms const _worldMatrix = this.worldMatrix; this.worldMatrix = identity; super.draw({ camera }); // Switch back to leave identity untouched this.worldMatrix = _worldMatrix; } }