perturbNormalBlock.ts 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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.Neutral);
  30. // Vertex
  31. this.registerInput("worldPosition", NodeMaterialBlockConnectionPointTypes.Vector4, false);
  32. this.registerInput("worldNormal", NodeMaterialBlockConnectionPointTypes.Vector4, false);
  33. this.registerInput("uv", NodeMaterialBlockConnectionPointTypes.Vector2, false);
  34. this.registerInput("normalMapColor", NodeMaterialBlockConnectionPointTypes.Color3, false);
  35. this.registerInput("strength", NodeMaterialBlockConnectionPointTypes.Float, false);
  36. // Fragment
  37. this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.Vector4);
  38. }
  39. /**
  40. * Gets the current class name
  41. * @returns the class name
  42. */
  43. public getClassName() {
  44. return "PerturbNormalBlock";
  45. }
  46. /**
  47. * Gets the world position input component
  48. */
  49. public get worldPosition(): NodeMaterialConnectionPoint {
  50. return this._inputs[0];
  51. }
  52. /**
  53. * Gets the world normal input component
  54. */
  55. public get worldNormal(): NodeMaterialConnectionPoint {
  56. return this._inputs[1];
  57. }
  58. /**
  59. * Gets the uv input component
  60. */
  61. public get uv(): NodeMaterialConnectionPoint {
  62. return this._inputs[2];
  63. }
  64. /**
  65. * Gets the normal map color input component
  66. */
  67. public get normalMapColor(): NodeMaterialConnectionPoint {
  68. return this._inputs[3];
  69. }
  70. /**
  71. * Gets the strength input component
  72. */
  73. public get strength(): NodeMaterialConnectionPoint {
  74. return this._inputs[4];
  75. }
  76. /**
  77. * Gets the output component
  78. */
  79. public get output(): NodeMaterialConnectionPoint {
  80. return this._outputs[0];
  81. }
  82. public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
  83. defines.setValue("BUMP", true);
  84. }
  85. public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh) {
  86. if (nodeMaterial.getScene()._mirroredCameraPosition) {
  87. effect.setFloat2(this._tangentSpaceParameterName, this.invertX ? 1.0 : -1.0, this.invertY ? 1.0 : -1.0);
  88. } else {
  89. effect.setFloat2(this._tangentSpaceParameterName, this.invertX ? -1.0 : 1.0, this.invertY ? -1.0 : 1.0);
  90. }
  91. }
  92. public autoConfigure(material: NodeMaterial) {
  93. if (!this.uv.isConnected) {
  94. let uvInput = material.getInputBlockByPredicate((b) => b.isAttribute && b.name === "uv");
  95. if (!uvInput) {
  96. uvInput = new InputBlock("uv");
  97. uvInput.setAsAttribute();
  98. }
  99. uvInput.output.connectTo(this.uv);
  100. }
  101. if (!this.strength.isConnected) {
  102. let strengthInput = new InputBlock("strength");
  103. strengthInput.value = 1.0;
  104. strengthInput.output.connectTo(this.strength);
  105. }
  106. }
  107. protected _buildBlock(state: NodeMaterialBuildState) {
  108. super._buildBlock(state);
  109. let comments = `//${this.name}`;
  110. let uv = this.uv;
  111. let worldPosition = this.worldPosition;
  112. let worldNormal = this.worldNormal;
  113. state.sharedData.blocksWithDefines.push(this);
  114. state.sharedData.bindableBlocks.push(this);
  115. this._tangentSpaceParameterName = state._getFreeDefineName("tangentSpaceParameter");
  116. state._emitUniformFromString(this._tangentSpaceParameterName, "vec2");
  117. let replaceForBumpInfos = this.strength.isConnectedToInputBlock && this.strength.connectInputBlock!.isConstant ? `${state._emitFloat(1.0 / this.strength.connectInputBlock!.value)}` : `1.0 / ${this.strength.associatedVariableName}`;
  118. state._emitExtension("bump", "#extension GL_OES_standard_derivatives : enable");
  119. state._emitFunctionFromInclude("bumpFragmentFunctions", comments, {
  120. replaceStrings: [
  121. { search: /vBumpInfos.y/g, replace: replaceForBumpInfos},
  122. { search: /vTangentSpaceParams/g, replace: this._tangentSpaceParameterName},
  123. { search: /vPositionW/g, replace: worldPosition.associatedVariableName + ".xyz"},
  124. { search: /defined\(TANGENT\)/g, replace: "defined(IGNORE)" }
  125. ]
  126. });
  127. state.compilationString += this._declareOutput(this.output, state) + " = vec4(0.);\r\n";
  128. state.compilationString += state._emitCodeFromInclude("bumpFragment", comments, {
  129. replaceStrings: [
  130. { search: /perturbNormal\(TBN,vBumpUV\+uvOffset\)/g, replace: `perturbNormal(TBN, ${this.normalMapColor.associatedVariableName})` },
  131. { search: /vBumpInfos.y/g, replace: replaceForBumpInfos},
  132. { search: /vBumpUV/g, replace: uv.associatedVariableName},
  133. { search: /vPositionW/g, replace: worldPosition.associatedVariableName + ".xyz"},
  134. { search: /normalW=/g, replace: this.output.associatedVariableName + ".xyz = " },
  135. { search: /normalW/g, replace: worldNormal.associatedVariableName + ".xyz" },
  136. { search: /defined\(TANGENT\)/g, replace: "defined(IGNORE)" }
  137. ]
  138. });
  139. return this;
  140. }
  141. protected _dumpPropertiesCode() {
  142. var codeString = `${this._codeVariableName}.invertX = ${this.invertX};\r\n`;
  143. codeString += `${this._codeVariableName}.invertY = ${this.invertY};\r\n`;
  144. return codeString;
  145. }
  146. public serialize(): any {
  147. let serializationObject = super.serialize();
  148. serializationObject.invertX = this.invertX;
  149. serializationObject.invertY = this.invertY;
  150. return serializationObject;
  151. }
  152. public _deserialize(serializationObject: any, scene: Scene, rootUrl: string) {
  153. super._deserialize(serializationObject, scene, rootUrl);
  154. this.invertX = serializationObject.invertX;
  155. this.invertY = serializationObject.invertY;
  156. }
  157. }
  158. _TypeStore.RegisteredTypes["BABYLON.PerturbNormalBlock"] = PerturbNormalBlock;