morphTargetsBlock.ts 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. import { NodeMaterialBlock } from '../../nodeMaterialBlock';
  2. import { NodeMaterialBlockConnectionPointTypes } from '../../nodeMaterialBlockConnectionPointTypes';
  3. import { NodeMaterialBuildState } from '../../nodeMaterialBuildState';
  4. import { NodeMaterialBlockTargets } from '../../nodeMaterialBlockTargets';
  5. import { NodeMaterialConnectionPoint } from '../../nodeMaterialBlockConnectionPoint';
  6. import { AbstractMesh } from '../../../../Meshes/abstractMesh';
  7. import { NodeMaterial, NodeMaterialDefines } from '../../nodeMaterial';
  8. import { Effect } from '../../../effect';
  9. import { Mesh } from '../../../../Meshes/mesh';
  10. import { MaterialHelper } from '../../../materialHelper';
  11. import { VertexBuffer } from '../../../../Meshes/buffer';
  12. /**
  13. * Block used to add morph targets support to vertex shader
  14. */
  15. export class MorphTargetsBlock extends NodeMaterialBlock {
  16. private _repeatableContentAnchor: string;
  17. private _repeatebleContentGenerated = 0;
  18. /**
  19. * Create a new MorphTargetsBlock
  20. * @param name defines the block name
  21. */
  22. public constructor(name: string) {
  23. super(name, NodeMaterialBlockTargets.Vertex);
  24. this.registerInput("position", NodeMaterialBlockConnectionPointTypes.Vector3);
  25. this.registerInput("normal", NodeMaterialBlockConnectionPointTypes.Vector3);
  26. this.registerInput("tangent", NodeMaterialBlockConnectionPointTypes.Vector3);
  27. this.registerOutput("positionOutput", NodeMaterialBlockConnectionPointTypes.Vector3);
  28. this.registerOutput("normalOutput", NodeMaterialBlockConnectionPointTypes.Vector3);
  29. this.registerOutput("tangentOutput", NodeMaterialBlockConnectionPointTypes.Vector3);
  30. }
  31. /**
  32. * Gets the current class name
  33. * @returns the class name
  34. */
  35. public getClassName() {
  36. return "MorphTargetsBlock";
  37. }
  38. /**
  39. * Gets the position input component
  40. */
  41. public get position(): NodeMaterialConnectionPoint {
  42. return this._inputs[0];
  43. }
  44. /**
  45. * Gets the normal input component
  46. */
  47. public get normal(): NodeMaterialConnectionPoint {
  48. return this._inputs[1];
  49. }
  50. /**
  51. * Gets the tangent input component
  52. */
  53. public get tangent(): NodeMaterialConnectionPoint {
  54. return this._inputs[2];
  55. }
  56. /**
  57. * Gets the position output component
  58. */
  59. public get positionOutput(): NodeMaterialConnectionPoint {
  60. return this._outputs[0];
  61. }
  62. /**
  63. * Gets the normal output component
  64. */
  65. public get normalOutput(): NodeMaterialConnectionPoint {
  66. return this._outputs[1];
  67. }
  68. /**
  69. * Gets the tangent output component
  70. */
  71. public get tangentOutput(): NodeMaterialConnectionPoint {
  72. return this._outputs[2];
  73. }
  74. public initialize(state: NodeMaterialBuildState) {
  75. state._excludeVariableName("morphTargetInfluences");
  76. }
  77. public autoConfigure() {
  78. if (!this.position.connectedPoint) {
  79. this.position.setAsAttribute();
  80. }
  81. if (!this.normal.connectedPoint) {
  82. this.normal.setAsAttribute();
  83. this.normal.define = "NORMAL";
  84. }
  85. if (!this.tangent.connectedPoint) {
  86. this.tangent.setAsAttribute();
  87. this.tangent.define = "TANGENT";
  88. }
  89. }
  90. public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
  91. if (!defines._areAttributesDirty) {
  92. return;
  93. }
  94. MaterialHelper.PrepareDefinesForMorphTargets(mesh, defines);
  95. }
  96. public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh) {
  97. if (mesh && this._repeatebleContentGenerated) {
  98. MaterialHelper.BindMorphTargetParameters(mesh, effect);
  99. }
  100. }
  101. public replaceRepeatableContent(vertexShaderState: NodeMaterialBuildState, fragmentShaderState: NodeMaterialBuildState, mesh: AbstractMesh, defines: NodeMaterialDefines) {
  102. let position = this.position;
  103. let normal = this.normal;
  104. let tangent = this.tangent;
  105. let positionOutput = this.positionOutput;
  106. let normalOutput = this.normalOutput;
  107. let tangentOutput = this.tangentOutput;
  108. let state = vertexShaderState;
  109. let repeatCount = defines.NUM_MORPH_INFLUENCERS as number;
  110. this._repeatebleContentGenerated = repeatCount;
  111. var manager = (<Mesh>mesh).morphTargetManager;
  112. var hasNormals = manager && manager.supportsNormals && defines["NORMAL"];
  113. var hasTangents = manager && manager.supportsTangents && defines["TANGENT"];
  114. let injectionCode = "";
  115. for (var index = 0; index < repeatCount; index++) {
  116. injectionCode += `#ifdef MORPHTARGETS\r\n`;
  117. injectionCode += `${positionOutput.associatedVariableName} += (position${index} - ${position.associatedVariableName}) * morphTargetInfluences[${index}];\r\n`;
  118. if (hasNormals) {
  119. injectionCode += `#ifdef MORPHTARGETS_NORMAL\r\n`;
  120. injectionCode += `${normalOutput.associatedVariableName} += (normal${index} - ${normal.associatedVariableName}) * morphTargetInfluences[${index}];\r\n`;
  121. injectionCode += `#endif\r\n`;
  122. }
  123. if (hasTangents) {
  124. injectionCode += `#ifdef MORPHTARGETS_TANGENT\r\n`;
  125. injectionCode += `${tangentOutput.associatedVariableName}.xyz += (tangent${index} - ${tangent.associatedVariableName}.xyz) * morphTargetInfluences[${index}];\r\n`;
  126. injectionCode += `#endif\r\n`;
  127. }
  128. injectionCode += `#endif\r\n`;
  129. }
  130. state.compilationString = state.compilationString.replace(this._repeatableContentAnchor, injectionCode);
  131. if (repeatCount > 0) {
  132. for (var index = 0; index < repeatCount; index++) {
  133. state.attributes.push(VertexBuffer.PositionKind + index);
  134. if (hasNormals) {
  135. state.attributes.push(VertexBuffer.NormalKind + index);
  136. }
  137. if (hasTangents) {
  138. state.attributes.push(VertexBuffer.TangentKind + index);
  139. }
  140. }
  141. }
  142. }
  143. protected _buildBlock(state: NodeMaterialBuildState) {
  144. super._buildBlock(state);
  145. // Register for defines
  146. state.sharedData.blocksWithDefines.push(this);
  147. // Register for binding
  148. state.sharedData.bindableBlocks.push(this);
  149. // Register for repeatable content generation
  150. state.sharedData.repeatableContentBlocks.push(this);
  151. // Emit code
  152. let position = this.position;
  153. let normal = this.normal;
  154. let tangent = this.tangent;
  155. let positionOutput = this.positionOutput;
  156. let normalOutput = this.normalOutput;
  157. let tangentOutput = this.tangentOutput;
  158. let comments = `//${this.name}`;
  159. state.uniforms.push("morphTargetInfluences");
  160. state._emitFunctionFromInclude("morphTargetsVertexGlobalDeclaration", comments);
  161. state._emitFunctionFromInclude("morphTargetsVertexDeclaration", comments, {
  162. repeatKey: "maxSimultaneousMorphTargets"
  163. });
  164. state.compilationString += `${this._declareOutput(positionOutput, state)} = ${position.associatedVariableName};\r\n`;
  165. state.compilationString += `#ifdef NORMAL\r\n`;
  166. state.compilationString += `${this._declareOutput(normalOutput, state)} = ${normal.associatedVariableName};\r\n`;
  167. state.compilationString += `#endif\r\n`;
  168. state.compilationString += `#ifdef TANGENT\r\n`;
  169. state.compilationString += `${this._declareOutput(tangentOutput, state)} = ${tangent.associatedVariableName};\r\n`;
  170. state.compilationString += `#endif\r\n`;
  171. // Repeatable content
  172. this._repeatableContentAnchor = state._repeatableContentAnchor;
  173. state.compilationString += this._repeatableContentAnchor;
  174. return this;
  175. }
  176. }