perturbNormalBlock.ts 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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 { _TypeStore } from '../../../../Misc/typeStore';
  7. import { NodeMaterial, NodeMaterialDefines } from '../../nodeMaterial';
  8. import { AbstractMesh } from '../../../../Meshes/abstractMesh';
  9. import { InputBlock } from '../Input/inputBlock';
  10. import { Effect } from '../../../effect';
  11. import { Mesh } from '../../../../Meshes/mesh';
  12. import { Scene } from '../../../../scene';
  13. /**
  14. * Block used to pertub normals based on a normal map
  15. */
  16. export class PerturbNormalBlock extends NodeMaterialBlock {
  17. private _tangentSpaceParameterName = "";
  18. /** Gets or sets a boolean indicating that normal should be inverted on X axis */
  19. public invertX = false;
  20. /** Gets or sets a boolean indicating that normal should be inverted on Y axis */
  21. public invertY = false;
  22. /**
  23. * Create a new PerturbNormalBlock
  24. * @param name defines the block name
  25. */
  26. public constructor(name: string) {
  27. super(name, NodeMaterialBlockTargets.Neutral);
  28. // Vertex
  29. this.registerInput("worldPosition", NodeMaterialBlockConnectionPointTypes.Vector4, false);
  30. this.registerInput("worldNormal", NodeMaterialBlockConnectionPointTypes.Vector4, false);
  31. this.registerInput("uv", NodeMaterialBlockConnectionPointTypes.Vector2, false);
  32. this.registerInput("normalMapColor", NodeMaterialBlockConnectionPointTypes.Color3, false);
  33. this.registerInput("strength", NodeMaterialBlockConnectionPointTypes.Float, false);
  34. // Fragment
  35. this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.Vector4);
  36. }
  37. /**
  38. * Gets the current class name
  39. * @returns the class name
  40. */
  41. public getClassName() {
  42. return "PerturbNormalBlock";
  43. }
  44. /**
  45. * Gets the world position input component
  46. */
  47. public get worldPosition(): NodeMaterialConnectionPoint {
  48. return this._inputs[0];
  49. }
  50. /**
  51. * Gets the world normal input component
  52. */
  53. public get worldNormal(): NodeMaterialConnectionPoint {
  54. return this._inputs[1];
  55. }
  56. /**
  57. * Gets the uv input component
  58. */
  59. public get uv(): NodeMaterialConnectionPoint {
  60. return this._inputs[2];
  61. }
  62. /**
  63. * Gets the normal map color input component
  64. */
  65. public get normalMapColor(): NodeMaterialConnectionPoint {
  66. return this._inputs[3];
  67. }
  68. /**
  69. * Gets the strength input component
  70. */
  71. public get strength(): NodeMaterialConnectionPoint {
  72. return this._inputs[4];
  73. }
  74. /**
  75. * Gets the output component
  76. */
  77. public get output(): NodeMaterialConnectionPoint {
  78. return this._outputs[0];
  79. }
  80. public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
  81. defines.setValue("BUMP", true);
  82. }
  83. public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh) {
  84. effect.setFloat2(this._tangentSpaceParameterName, this.invertX ? -1 : 1, this.invertY ? -1 : 1);
  85. }
  86. public autoConfigure(material: NodeMaterial) {
  87. if (!this.uv.isConnected) {
  88. let uvInput = material.getInputBlockByPredicate((b) => b.isAttribute && b.name === "uv");
  89. if (!uvInput) {
  90. uvInput = new InputBlock("uv");
  91. uvInput.setAsAttribute();
  92. }
  93. uvInput.output.connectTo(this.uv);
  94. }
  95. if (!this.strength.isConnected) {
  96. let strengthInput = new InputBlock("strength");
  97. strengthInput.value = 1.0;
  98. strengthInput.output.connectTo(this.strength);
  99. }
  100. }
  101. protected _buildBlock(state: NodeMaterialBuildState) {
  102. super._buildBlock(state);
  103. let comments = `//${this.name}`;
  104. let uv = this.uv;
  105. let worldPosition = this.worldPosition;
  106. let worldNormal = this.worldNormal;
  107. state.sharedData.blocksWithDefines.push(this);
  108. state.sharedData.bindableBlocks.push(this);
  109. this._tangentSpaceParameterName = state._getFreeDefineName("tangentSpaceParameter");
  110. state._emitUniformFromString(this._tangentSpaceParameterName, "vec2");
  111. state._emitExtension("bump", "#extension GL_OES_standard_derivatives : enable");
  112. state._emitFunctionFromInclude("bumpFragmentFunctions", comments, {
  113. replaceStrings: [
  114. { search: /vBumpInfos.y/g, replace: `1.0 / ${this.strength.associatedVariableName}`},
  115. { search: /vTangentSpaceParams/g, replace: this._tangentSpaceParameterName},
  116. { search: /vPositionW/g, replace: worldPosition.associatedVariableName + ".xyz"}
  117. ]
  118. });
  119. state.compilationString += this._declareOutput(this.output, state) + " = vec4(0.);\r\n";
  120. state.compilationString += state._emitCodeFromInclude("bumpFragment", comments, {
  121. replaceStrings: [
  122. { search: /perturbNormal\(TBN,vBumpUV\+uvOffset\)/g, replace: `perturbNormal(TBN, ${this.normalMapColor.associatedVariableName})` },
  123. { search: /vBumpInfos.y/g, replace: `1.0 / ${this.strength.associatedVariableName}`},
  124. { search: /vBumpUV/g, replace: uv.associatedVariableName},
  125. { search: /vPositionW/g, replace: worldPosition.associatedVariableName + ".xyz"},
  126. { search: /normalW=/g, replace: this.output.associatedVariableName + ".xyz = " },
  127. { search: /normalW/g, replace: worldNormal.associatedVariableName + ".xyz" }
  128. ]
  129. });
  130. return this;
  131. }
  132. protected _dumpPropertiesCode() {
  133. var codeString = `${this._codeVariableName}.invertX = ${this.invertX};\r\n`;
  134. codeString += `${this._codeVariableName}.invertY = ${this.invertY};\r\n`;
  135. return codeString;
  136. }
  137. public serialize(): any {
  138. let serializationObject = super.serialize();
  139. serializationObject.invertX = this.invertX;
  140. serializationObject.invertY = this.invertY;
  141. return serializationObject;
  142. }
  143. public _deserialize(serializationObject: any, scene: Scene, rootUrl: string) {
  144. super._deserialize(serializationObject, scene, rootUrl);
  145. this.invertX = serializationObject.invertX;
  146. this.invertY = serializationObject.invertY;
  147. }
  148. }
  149. _TypeStore.RegisteredTypes["BABYLON.PerturbNormalBlock"] = PerturbNormalBlock;