SkinningNode.js 3.4 KB

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