morphTargetsBlock.ts 9.4 KB

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