You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
2.4 KiB
110 lines
2.4 KiB
2 years ago
|
import Node from '../core/Node.js';
|
||
|
import {
|
||
|
ShaderNode,
|
||
|
attribute,
|
||
|
buffer,
|
||
|
mat4,
|
||
|
uniform,
|
||
|
positionLocal,
|
||
|
normalLocal,
|
||
|
tangentLocal,
|
||
|
assign,
|
||
|
element,
|
||
|
add,
|
||
|
mul,
|
||
|
transformDirection
|
||
|
} from '../shadernode/ShaderNodeBaseElements.js';
|
||
|
|
||
|
import { NodeUpdateType } from '../core/constants.js';
|
||
|
|
||
|
const Skinning = new ShaderNode( ( inputs, builder ) => {
|
||
|
|
||
|
const { index, weight, bindMatrix, bindMatrixInverse, boneMatrices } = inputs;
|
||
|
|
||
|
const boneMatX = element( boneMatrices, index.x );
|
||
|
const boneMatY = element( boneMatrices, index.y );
|
||
|
const boneMatZ = element( boneMatrices, index.z );
|
||
|
const boneMatW = element( boneMatrices, index.w );
|
||
|
|
||
|
// POSITION
|
||
|
|
||
|
const skinVertex = mul( bindMatrix, positionLocal );
|
||
|
|
||
|
const skinned = add(
|
||
|
mul( mul( boneMatX, skinVertex ), weight.x ),
|
||
|
mul( mul( boneMatY, skinVertex ), weight.y ),
|
||
|
mul( mul( boneMatZ, skinVertex ), weight.z ),
|
||
|
mul( mul( boneMatW, skinVertex ), weight.w )
|
||
|
);
|
||
|
|
||
|
const skinPosition = mul( bindMatrixInverse, skinned ).xyz;
|
||
|
|
||
|
// NORMAL
|
||
|
|
||
|
let skinMatrix = add(
|
||
|
mul( weight.x, boneMatX ),
|
||
|
mul( weight.y, boneMatY ),
|
||
|
mul( weight.z, boneMatZ ),
|
||
|
mul( weight.w, boneMatW )
|
||
|
);
|
||
|
|
||
|
skinMatrix = mul( mul( bindMatrixInverse, skinMatrix ), bindMatrix );
|
||
|
|
||
|
const skinNormal = transformDirection( skinMatrix, normalLocal ).xyz;
|
||
|
|
||
|
// ASSIGNS
|
||
|
|
||
|
assign( positionLocal, skinPosition ).build( builder );
|
||
|
assign( normalLocal, skinNormal ).build( builder );
|
||
|
|
||
|
if ( builder.hasGeometryAttribute( 'tangent' ) ) {
|
||
|
|
||
|
assign( tangentLocal, 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( mat4( skinnedMesh.bindMatrix ) );
|
||
|
this.bindMatrixInverseNode = uniform( mat4( skinnedMesh.bindMatrixInverse ) );
|
||
|
this.boneMatricesNode = buffer( skinnedMesh.skeleton.boneMatrices, 'mat4', skinnedMesh.skeleton.bones.length );
|
||
|
|
||
|
}
|
||
|
|
||
|
generate( 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;
|