SkinningNode.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import Node from '../core/Node.js';
  2. import {
  3. ShaderNode,
  4. attribute,
  5. buffer,
  6. mat4,
  7. uniform,
  8. positionLocal,
  9. normalLocal,
  10. tangentLocal,
  11. assign,
  12. element,
  13. add,
  14. mul,
  15. transformDirection
  16. } from '../shadernode/ShaderNodeBaseElements.js';
  17. import { NodeUpdateType } from '../core/constants.js';
  18. const Skinning = new ShaderNode( ( inputs, builder ) => {
  19. const { index, weight, bindMatrix, bindMatrixInverse, boneMatrices } = inputs;
  20. const boneMatX = element( boneMatrices, index.x );
  21. const boneMatY = element( boneMatrices, index.y );
  22. const boneMatZ = element( boneMatrices, index.z );
  23. const boneMatW = element( boneMatrices, index.w );
  24. // POSITION
  25. const skinVertex = mul( bindMatrix, positionLocal );
  26. const skinned = add(
  27. mul( mul( boneMatX, skinVertex ), weight.x ),
  28. mul( mul( boneMatY, skinVertex ), weight.y ),
  29. mul( mul( boneMatZ, skinVertex ), weight.z ),
  30. mul( mul( boneMatW, skinVertex ), weight.w )
  31. );
  32. const skinPosition = mul( bindMatrixInverse, skinned ).xyz;
  33. // NORMAL
  34. let skinMatrix = add(
  35. mul( weight.x, boneMatX ),
  36. mul( weight.y, boneMatY ),
  37. mul( weight.z, boneMatZ ),
  38. mul( weight.w, boneMatW )
  39. );
  40. skinMatrix = mul( mul( bindMatrixInverse, skinMatrix ), bindMatrix );
  41. const skinNormal = transformDirection( skinMatrix, normalLocal ).xyz;
  42. // ASSIGNS
  43. assign( positionLocal, skinPosition ).build( builder );
  44. assign( normalLocal, skinNormal ).build( builder );
  45. if ( builder.hasGeometryAttribute( 'tangent' ) ) {
  46. assign( tangentLocal, skinNormal ).build( builder );
  47. }
  48. } );
  49. class SkinningNode extends Node {
  50. constructor( skinnedMesh ) {
  51. super( 'void' );
  52. this.skinnedMesh = skinnedMesh;
  53. this.updateType = NodeUpdateType.OBJECT;
  54. //
  55. this.skinIndexNode = attribute( 'skinIndex', 'uvec4' );
  56. this.skinWeightNode = attribute( 'skinWeight', 'vec4' );
  57. this.bindMatrixNode = uniform( mat4( skinnedMesh.bindMatrix ) );
  58. this.bindMatrixInverseNode = uniform( mat4( skinnedMesh.bindMatrixInverse ) );
  59. this.boneMatricesNode = buffer( skinnedMesh.skeleton.boneMatrices, 'mat4', skinnedMesh.skeleton.bones.length );
  60. }
  61. generate( 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;