pertubNormalBlock.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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. /**
  11. * Block used to pertub normals based on a normal map
  12. */
  13. export class PertubNormalBlock extends NodeMaterialBlock {
  14. /**
  15. * Create a new PertubNormalBlock
  16. * @param name defines the block name
  17. */
  18. public constructor(name: string) {
  19. super(name, NodeMaterialBlockTargets.Fragment);
  20. // Vertex
  21. this.registerInput("worldPosition", NodeMaterialBlockConnectionPointTypes.Vector4, false, NodeMaterialBlockTargets.Fragment);
  22. this.registerInput("worldNormal", NodeMaterialBlockConnectionPointTypes.Vector4, false, NodeMaterialBlockTargets.Fragment);
  23. this.registerInput("uv", NodeMaterialBlockConnectionPointTypes.Vector2, false, NodeMaterialBlockTargets.Fragment);
  24. this.registerInput("normalMapColor", NodeMaterialBlockConnectionPointTypes.Color3, false, NodeMaterialBlockTargets.Fragment);
  25. this.registerInput("strength", NodeMaterialBlockConnectionPointTypes.Float, false, NodeMaterialBlockTargets.Fragment);
  26. // Fragment
  27. this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.Vector4, NodeMaterialBlockTargets.Fragment);
  28. }
  29. /**
  30. * Gets the current class name
  31. * @returns the class name
  32. */
  33. public getClassName() {
  34. return "PertubNormalBlock";
  35. }
  36. /**
  37. * Gets the world position input component
  38. */
  39. public get worldPosition(): NodeMaterialConnectionPoint {
  40. return this._inputs[0];
  41. }
  42. /**
  43. * Gets the world normal input component
  44. */
  45. public get worldNormal(): NodeMaterialConnectionPoint {
  46. return this._inputs[1];
  47. }
  48. /**
  49. * Gets the uv input component
  50. */
  51. public get uv(): NodeMaterialConnectionPoint {
  52. return this._inputs[2];
  53. }
  54. /**
  55. * Gets the normal map color input component
  56. */
  57. public get normalMapColor(): NodeMaterialConnectionPoint {
  58. return this._inputs[3];
  59. }
  60. /**
  61. * Gets the strength input component
  62. */
  63. public get strength(): NodeMaterialConnectionPoint {
  64. return this._inputs[4];
  65. }
  66. /**
  67. * Gets the output component
  68. */
  69. public get output(): NodeMaterialConnectionPoint {
  70. return this._outputs[0];
  71. }
  72. public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
  73. defines.setValue("BUMP", true);
  74. }
  75. public autoConfigure(material: NodeMaterial) {
  76. if (!this.uv.isConnected) {
  77. let uvInput = material.getInputBlockByPredicate((b) => b.isAttribute && b.name === "uv");
  78. if (!uvInput) {
  79. uvInput = new InputBlock("uv");
  80. uvInput.setAsAttribute();
  81. }
  82. uvInput.output.connectTo(this.uv);
  83. }
  84. if (!this.strength.isConnected) {
  85. let strengthInput = new InputBlock("strength");
  86. strengthInput.value = 1.0;
  87. strengthInput.output.connectTo(this.strength);
  88. }
  89. }
  90. protected _buildBlock(state: NodeMaterialBuildState) {
  91. super._buildBlock(state);
  92. let comments = `//${this.name}`;
  93. let uv = this.uv;
  94. let worldPosition = this.worldPosition;
  95. let worldNormal = this.worldNormal;
  96. state.sharedData.blocksWithDefines.push(this);
  97. state._emitExtension("bump", "#extension GL_OES_standard_derivatives : enable");
  98. state._emitFunctionFromInclude("bumpFragmentFunctions", comments, {
  99. replaceStrings: [
  100. { search: /vBumpInfos.y/g, replace: `1.0 / ${this.strength.associatedVariableName}`},
  101. { search: /vTangentSpaceParams/g, replace: "vec2(1.0, 1.0)"},
  102. { search: /vPositionW/g, replace: worldPosition.associatedVariableName + ".xyz"}
  103. ]
  104. });
  105. state.compilationString += this._declareOutput(this.output, state) + " = vec4(0.);\r\n";
  106. state.compilationString += state._emitCodeFromInclude("bumpFragment", comments, {
  107. replaceStrings: [
  108. { search: /perturbNormal\(TBN,vBumpUV\+uvOffset\)/g, replace: `perturbNormal(TBN, ${this.normalMapColor.associatedVariableName})` },
  109. { search: /vBumpInfos.y/g, replace: `1.0 / ${this.strength.associatedVariableName}`},
  110. { search: /vBumpUV/g, replace: uv.associatedVariableName},
  111. { search: /vPositionW/g, replace: worldPosition.associatedVariableName + ".xyz"},
  112. { search: /normalW=/g, replace: this.output.associatedVariableName + ".xyz = " },
  113. { search: /normalW/g, replace: worldNormal.associatedVariableName + ".xyz" }
  114. ]
  115. });
  116. return this;
  117. }
  118. }
  119. _TypeStore.RegisteredTypes["BABYLON.PertubNormalBlock"] = PertubNormalBlock;