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 );