perturbNormalBlock.ts 8.3 KB

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