ogl
Version:
WebGL Library
67 lines (57 loc) • 2.41 kB
JavaScript
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;
}
}