SkinningNode.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import Node, { addNodeClass } from '../core/Node.js';
  2. import { NodeUpdateType } from '../core/constants.js';
  3. import { ShaderNode, nodeProxy } from '../shadernode/ShaderNode.js';
  4. import { attribute } from '../core/AttributeNode.js';
  5. import { uniform } from '../core/UniformNode.js';
  6. import { add } from '../math/OperatorNode.js';
  7. import { buffer } from './BufferNode.js';
  8. import { normalLocal } from './NormalNode.js';
  9. import { positionLocal } from './PositionNode.js';
  10. import { tangentLocal } from './TangentNode.js';
  11. const Skinning = new ShaderNode( ( inputs, {}, builder ) => {
  12. const { index, weight, bindMatrix, bindMatrixInverse, boneMatrices } = inputs;
  13. const boneMatX = boneMatrices.element( index.x );
  14. const boneMatY = boneMatrices.element( index.y );
  15. const boneMatZ = boneMatrices.element( index.z );
  16. const boneMatW = boneMatrices.element( index.w );
  17. // POSITION
  18. const skinVertex = bindMatrix.mul( positionLocal );
  19. const skinned = add(
  20. boneMatX.mul( skinVertex ).mul( weight.x ),
  21. boneMatY.mul( skinVertex ).mul( weight.y ),
  22. boneMatZ.mul( skinVertex ).mul( weight.z ),
  23. boneMatW.mul( skinVertex ).mul( weight.w )
  24. );
  25. const skinPosition = bindMatrixInverse.mul( skinned ).xyz;
  26. // NORMAL
  27. let skinMatrix = add(
  28. weight.x.mul( boneMatX ),
  29. weight.y.mul( boneMatY ),
  30. weight.z.mul( boneMatZ ),
  31. weight.w.mul( boneMatW )
  32. );
  33. skinMatrix = bindMatrixInverse.mul( skinMatrix ).mul( bindMatrix );
  34. const skinNormal = skinMatrix.transformDirection( normalLocal ).xyz;
  35. // ASSIGNS
  36. positionLocal.assign( skinPosition ).build( builder ); // @TODO: For some reason this doesn't work as stack.assign( positionLocal, skinPosition )?
  37. normalLocal.assign( skinNormal ).build( builder );
  38. if ( builder.hasGeometryAttribute( 'tangent' ) ) {
  39. tangentLocal.assign( skinNormal ).build( builder );
  40. }
  41. } );
  42. class SkinningNode extends Node {
  43. constructor( skinnedMesh ) {
  44. super( 'void' );
  45. this.skinnedMesh = skinnedMesh;
  46. this.updateType = NodeUpdateType.OBJECT;
  47. //
  48. this.skinIndexNode = attribute( 'skinIndex', 'uvec4' );
  49. this.skinWeightNode = attribute( 'skinWeight', 'vec4' );
  50. this.bindMatrixNode = uniform( skinnedMesh.bindMatrix, 'mat4' );
  51. this.bindMatrixInverseNode = uniform( skinnedMesh.bindMatrixInverse, 'mat4' );
  52. this.boneMatricesNode = buffer( skinnedMesh.skeleton.boneMatrices, 'mat4', skinnedMesh.skeleton.bones.length );
  53. }
  54. generate( builder ) {
  55. /*return new ShaderNode( ( {}, stack, builder ) => Skinning.call( {
  56. index: this.skinIndexNode,
  57. weight: this.skinWeightNode,
  58. bindMatrix: this.bindMatrixNode,
  59. bindMatrixInverse: this.bindMatrixInverseNode,
  60. boneMatrices: this.boneMatricesNode
  61. }, stack, builder ) ).build( builder );*/
  62. Skinning.call( {
  63. index: this.skinIndexNode,
  64. weight: this.skinWeightNode,
  65. bindMatrix: this.bindMatrixNode,
  66. bindMatrixInverse: this.bindMatrixInverseNode,
  67. boneMatrices: this.boneMatricesNode
  68. }, {}, builder );
  69. }
  70. update() {
  71. this.skinnedMesh.skeleton.update();
  72. }
  73. }
  74. export default SkinningNode;
  75. export const skinning = nodeProxy( SkinningNode );
  76. addNodeClass( SkinningNode );