three
Version:
JavaScript 3D library
113 lines (76 loc) • 3.11 kB
JavaScript
import Node, { addNodeClass } from '../core/Node.js';
import { NodeUpdateType } from '../core/constants.js';
import { ShaderNode, nodeProxy } from '../shadernode/ShaderNode.js';
import { attribute } from '../core/AttributeNode.js';
import { uniform } from '../core/UniformNode.js';
import { add } from '../math/OperatorNode.js';
import { buffer } from './BufferNode.js';
import { normalLocal } from './NormalNode.js';
import { positionLocal } from './PositionNode.js';
import { tangentLocal } from './TangentNode.js';
const Skinning = new ShaderNode( ( inputs, {}, builder ) => {
const { index, weight, bindMatrix, bindMatrixInverse, boneMatrices } = inputs;
const boneMatX = boneMatrices.element( index.x );
const boneMatY = boneMatrices.element( index.y );
const boneMatZ = boneMatrices.element( index.z );
const boneMatW = boneMatrices.element( index.w );
// POSITION
const skinVertex = bindMatrix.mul( positionLocal );
const skinned = add(
boneMatX.mul( skinVertex ).mul( weight.x ),
boneMatY.mul( skinVertex ).mul( weight.y ),
boneMatZ.mul( skinVertex ).mul( weight.z ),
boneMatW.mul( skinVertex ).mul( weight.w )
);
const skinPosition = bindMatrixInverse.mul( skinned ).xyz;
// NORMAL
let skinMatrix = add(
weight.x.mul( boneMatX ),
weight.y.mul( boneMatY ),
weight.z.mul( boneMatZ ),
weight.w.mul( boneMatW )
);
skinMatrix = bindMatrixInverse.mul( skinMatrix ).mul( bindMatrix );
const skinNormal = skinMatrix.transformDirection( normalLocal ).xyz;
// ASSIGNS
positionLocal.assign( skinPosition ).build( builder ); // @TODO: For some reason this doesn't work as stack.assign( positionLocal, skinPosition )?
normalLocal.assign( skinNormal ).build( builder );
if ( builder.hasGeometryAttribute( 'tangent' ) ) {
tangentLocal.assign( skinNormal ).build( builder );
}
} );
class SkinningNode extends Node {
constructor( skinnedMesh ) {
super( 'void' );
this.skinnedMesh = skinnedMesh;
this.updateType = NodeUpdateType.OBJECT;
//
this.skinIndexNode = attribute( 'skinIndex', 'uvec4' );
this.skinWeightNode = attribute( 'skinWeight', 'vec4' );
this.bindMatrixNode = uniform( skinnedMesh.bindMatrix, 'mat4' );
this.bindMatrixInverseNode = uniform( skinnedMesh.bindMatrixInverse, 'mat4' );
this.boneMatricesNode = buffer( skinnedMesh.skeleton.boneMatrices, 'mat4', skinnedMesh.skeleton.bones.length );
}
generate( builder ) {
/*return new ShaderNode( ( {}, stack, builder ) => Skinning.call( {
index: this.skinIndexNode,
weight: this.skinWeightNode,
bindMatrix: this.bindMatrixNode,
bindMatrixInverse: this.bindMatrixInverseNode,
boneMatrices: this.boneMatricesNode
}, stack, builder ) ).build( builder );*/
Skinning.call( {
index: this.skinIndexNode,
weight: this.skinWeightNode,
bindMatrix: this.bindMatrixNode,
bindMatrixInverse: this.bindMatrixInverseNode,
boneMatrices: this.boneMatricesNode
}, {}, builder );
}
update() {
this.skinnedMesh.skeleton.update();
}
}
export default SkinningNode;
export const skinning = nodeProxy( SkinningNode );
addNodeClass( SkinningNode );