instancesBlock.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import { NodeMaterialBlock } from '../../nodeMaterialBlock';
  2. import { NodeMaterialBlockTargets } from '../../nodeMaterialBlockTargets';
  3. import { NodeMaterialBlockConnectionPointTypes } from '../../nodeMaterialBlockConnectionPointTypes';
  4. import { NodeMaterialConnectionPoint } from '../../nodeMaterialBlockConnectionPoint';
  5. import { NodeMaterialBuildState } from '../../nodeMaterialBuildState';
  6. import { AbstractMesh } from '../../../../Meshes/abstractMesh';
  7. import { NodeMaterial, NodeMaterialDefines } from '../../nodeMaterial';
  8. import { NodeMaterialWellKnownValues } from '../../nodeMaterialWellKnownValues';
  9. import { InputBlock } from '../Input/inputBlock';
  10. /**
  11. * Block used to add support for instances
  12. * @see https://doc.babylonjs.com/how_to/how_to_use_instances
  13. */
  14. export class InstancesBlock extends NodeMaterialBlock {
  15. /**
  16. * Creates a new InstancesBlock
  17. * @param name defines the block name
  18. */
  19. public constructor(name: string) {
  20. super(name, NodeMaterialBlockTargets.Vertex);
  21. this.registerInput("world0", NodeMaterialBlockConnectionPointTypes.Vector4);
  22. this.registerInput("world1", NodeMaterialBlockConnectionPointTypes.Vector4);
  23. this.registerInput("world2", NodeMaterialBlockConnectionPointTypes.Vector4);
  24. this.registerInput("world3", NodeMaterialBlockConnectionPointTypes.Vector4);
  25. this.registerInput("world", NodeMaterialBlockConnectionPointTypes.Matrix, true);
  26. this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.Matrix);
  27. }
  28. /**
  29. * Gets the current class name
  30. * @returns the class name
  31. */
  32. public getClassName() {
  33. return "InstancesBlock";
  34. }
  35. /**
  36. * Gets the first world row input component
  37. */
  38. public get world0(): NodeMaterialConnectionPoint {
  39. return this._inputs[0];
  40. }
  41. /**
  42. * Gets the second world row input component
  43. */
  44. public get world1(): NodeMaterialConnectionPoint {
  45. return this._inputs[1];
  46. }
  47. /**
  48. * Gets the third world row input component
  49. */
  50. public get world2(): NodeMaterialConnectionPoint {
  51. return this._inputs[2];
  52. }
  53. /**
  54. * Gets the forth world row input component
  55. */
  56. public get world3(): NodeMaterialConnectionPoint {
  57. return this._inputs[3];
  58. }
  59. /**
  60. * Gets the world input component
  61. */
  62. public get world(): NodeMaterialConnectionPoint {
  63. return this._inputs[4];
  64. }
  65. /**
  66. * Gets the output component
  67. */
  68. public get output(): NodeMaterialConnectionPoint {
  69. return this._outputs[0];
  70. }
  71. public autoConfigure() {
  72. if (!this.world0.connectedPoint) {
  73. let world0Input = new InputBlock("world0");
  74. world0Input.setAsAttribute("world0");
  75. world0Input.output.connectTo(this.world0);
  76. }
  77. if (!this.world1.connectedPoint) {
  78. let world1Input = new InputBlock("world1");
  79. world1Input.setAsAttribute("world1");
  80. world1Input.output.connectTo(this.world1);
  81. }
  82. if (!this.world2.connectedPoint) {
  83. let world2Input = new InputBlock("world2");
  84. world2Input.setAsAttribute("world2");
  85. world2Input.output.connectTo(this.world2);
  86. }
  87. if (!this.world3.connectedPoint) {
  88. let world3Input = new InputBlock("world3");
  89. world3Input.setAsAttribute("world3");
  90. world3Input.output.connectTo(this.world3);
  91. }
  92. if (!this.world.connectedPoint) {
  93. let worldInput = new InputBlock("world");
  94. worldInput.setAsWellKnownValue(NodeMaterialWellKnownValues.World);
  95. worldInput.output.connectTo(this.world);
  96. }
  97. this.world.define = "!INSTANCES";
  98. }
  99. public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances: boolean = false) {
  100. let changed = false;
  101. if (defines["INSTANCES"] !== useInstances) {
  102. defines.setValue("INSTANCES", useInstances);
  103. changed = true;
  104. }
  105. if (changed) {
  106. defines.markAsUnprocessed();
  107. }
  108. }
  109. protected _buildBlock(state: NodeMaterialBuildState) {
  110. super._buildBlock(state);
  111. // Register for defines
  112. state.sharedData.blocksWithDefines.push(this);
  113. // Emit code
  114. let output = this._outputs[0];
  115. let world0 = this.world0;
  116. let world1 = this.world1;
  117. let world2 = this.world2;
  118. let world3 = this.world3;
  119. state.compilationString += `#ifdef INSTANCES\r\n`;
  120. state.compilationString += this._declareOutput(output, state) + ` = mat4(${world0.associatedVariableName}, ${world1.associatedVariableName}, ${world2.associatedVariableName}, ${world3.associatedVariableName});\r\n`;
  121. state.compilationString += `#else\r\n`;
  122. state.compilationString += this._declareOutput(output, state) + ` = ${this.world.associatedVariableName};\r\n`;
  123. state.compilationString += `#endif\r\n`;
  124. return this;
  125. }
  126. }