subSurfaceBlock.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import { NodeMaterialBlock } from '../../nodeMaterialBlock';
  2. import { NodeMaterialBlockConnectionPointTypes } from '../../Enums/nodeMaterialBlockConnectionPointTypes';
  3. import { NodeMaterialBuildState } from '../../nodeMaterialBuildState';
  4. import { NodeMaterialConnectionPoint, NodeMaterialConnectionPointDirection } from '../../nodeMaterialBlockConnectionPoint';
  5. import { NodeMaterialBlockTargets } from '../../Enums/nodeMaterialBlockTargets';
  6. import { _TypeStore } from '../../../../Misc/typeStore';
  7. import { InputBlock } from '../Input/inputBlock';
  8. import { NodeMaterialConnectionPointCustomObject } from "../../nodeMaterialConnectionPointCustomObject";
  9. import { NodeMaterial, NodeMaterialDefines } from '../../nodeMaterial';
  10. import { AbstractMesh } from '../../../../Meshes/abstractMesh';
  11. import { ReflectionBlock } from './reflectionBlock';
  12. import { Nullable } from '../../../../types';
  13. import { RefractionBlock } from './refractionBlock';
  14. /**
  15. * Block used to implement the sub surface module of the PBR material
  16. */
  17. export class SubSurfaceBlock extends NodeMaterialBlock {
  18. /**
  19. * Create a new SubSurfaceBlock
  20. * @param name defines the block name
  21. */
  22. public constructor(name: string) {
  23. super(name, NodeMaterialBlockTargets.Fragment);
  24. this._isUnique = true;
  25. this.registerInput("thickness", NodeMaterialBlockConnectionPointTypes.Float, false, NodeMaterialBlockTargets.Fragment);
  26. this.registerInput("tintColor", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
  27. this.registerInput("translucencyIntensity", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
  28. this.registerInput("translucencyDiffusionDist", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
  29. this.registerInput("refraction", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment,
  30. new NodeMaterialConnectionPointCustomObject("refraction", this, NodeMaterialConnectionPointDirection.Input, RefractionBlock, "RefractionBlock"));
  31. this.registerOutput("subsurface", NodeMaterialBlockConnectionPointTypes.Object, NodeMaterialBlockTargets.Fragment,
  32. new NodeMaterialConnectionPointCustomObject("subsurface", this, NodeMaterialConnectionPointDirection.Output, SubSurfaceBlock, "SubSurfaceBlock"));
  33. }
  34. /**
  35. * Initialize the block and prepare the context for build
  36. * @param state defines the state that will be used for the build
  37. */
  38. public initialize(state: NodeMaterialBuildState) {
  39. state._excludeVariableName("subSurfaceOut");
  40. state._excludeVariableName("vThicknessParam");
  41. state._excludeVariableName("vTintColor");
  42. state._excludeVariableName("vSubSurfaceIntensity");
  43. }
  44. /**
  45. * Gets the current class name
  46. * @returns the class name
  47. */
  48. public getClassName() {
  49. return "SubSurfaceBlock";
  50. }
  51. /**
  52. * Gets the thickness component
  53. */
  54. public get thickness(): NodeMaterialConnectionPoint {
  55. return this._inputs[0];
  56. }
  57. /**
  58. * Gets the tint color input component
  59. */
  60. public get tintColor(): NodeMaterialConnectionPoint {
  61. return this._inputs[1];
  62. }
  63. /**
  64. * Gets the translucency intensity input component
  65. */
  66. public get translucencyIntensity(): NodeMaterialConnectionPoint {
  67. return this._inputs[2];
  68. }
  69. /**
  70. * Gets the translucency diffusion distance input component
  71. */
  72. public get translucencyDiffusionDist(): NodeMaterialConnectionPoint {
  73. return this._inputs[3];
  74. }
  75. /**
  76. * Gets the refraction object parameters
  77. */
  78. public get refraction(): NodeMaterialConnectionPoint {
  79. return this._inputs[4];
  80. }
  81. /**
  82. * Gets the sub surface object output component
  83. */
  84. public get subsurface(): NodeMaterialConnectionPoint {
  85. return this._outputs[0];
  86. }
  87. public autoConfigure(material: NodeMaterial) {
  88. if (!this.thickness.isConnected) {
  89. let thicknessInput = new InputBlock("SubSurface thickness", NodeMaterialBlockTargets.Fragment, NodeMaterialBlockConnectionPointTypes.Float);
  90. thicknessInput.value = 0;
  91. thicknessInput.output.connectTo(this.thickness);
  92. }
  93. }
  94. public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
  95. super.prepareDefines(mesh, nodeMaterial, defines);
  96. const translucencyEnabled = this.translucencyDiffusionDist.isConnected || this.translucencyIntensity.isConnected;
  97. defines.setValue("SUBSURFACE", translucencyEnabled || this.refraction.isConnected, true);
  98. defines.setValue("SS_TRANSLUCENCY", translucencyEnabled, true);
  99. defines.setValue("SS_THICKNESSANDMASK_TEXTURE", false, true);
  100. defines.setValue("SS_MASK_FROM_THICKNESS_TEXTURE", false, true);
  101. }
  102. /**
  103. * Gets the main code of the block (fragment side)
  104. * @param state current state of the node material building
  105. * @param ssBlock instance of a SubSurfaceBlock or null if the code must be generated without an active sub surface module
  106. * @param reflectionBlock instance of a ReflectionBlock null if the code must be generated without an active reflection module
  107. * @param worldPosVarName name of the variable holding the world position
  108. * @returns the shader code
  109. */
  110. public static GetCode(state: NodeMaterialBuildState, ssBlock: Nullable<SubSurfaceBlock>, reflectionBlock: Nullable<ReflectionBlock>, worldPosVarName: string): string {
  111. let code = "";
  112. const thickness = ssBlock?.thickness.isConnected ? ssBlock.thickness.associatedVariableName : "0.";
  113. const tintColor = ssBlock?.tintColor.isConnected ? ssBlock.tintColor.associatedVariableName : "vec3(1.)";
  114. const translucencyIntensity = ssBlock?.translucencyIntensity.isConnected ? ssBlock?.translucencyIntensity.associatedVariableName : "1.";
  115. const translucencyDiffusionDistance = ssBlock?.translucencyDiffusionDist.isConnected ? ssBlock?.translucencyDiffusionDist.associatedVariableName : "vec3(1.)";
  116. const refractionBlock: Nullable<RefractionBlock> = (ssBlock?.refraction.isConnected ? ssBlock?.refraction.connectedPoint?.ownerBlock : null) as Nullable<RefractionBlock>;
  117. const refractionTintAtDistance = refractionBlock?.tintAtDistance.isConnected ? refractionBlock.tintAtDistance.associatedVariableName : "1.";
  118. const refractionIntensity = refractionBlock?.intensity.isConnected ? refractionBlock.intensity.associatedVariableName : "1.";
  119. const refractionView = refractionBlock?.view.isConnected ? refractionBlock.view.associatedVariableName : "";
  120. code += refractionBlock?.getCode(state) ?? "";
  121. code += `subSurfaceOutParams subSurfaceOut;
  122. #ifdef SUBSURFACE
  123. vec2 vThicknessParam = vec2(0., ${thickness});
  124. vec4 vTintColor = vec4(${tintColor}, ${refractionTintAtDistance});
  125. vec3 vSubSurfaceIntensity = vec3(${refractionIntensity}, ${translucencyIntensity}, 0.);
  126. subSurfaceBlock(
  127. vSubSurfaceIntensity,
  128. vThicknessParam,
  129. vTintColor,
  130. normalW,
  131. specularEnvironmentReflectance,
  132. #ifdef SS_THICKNESSANDMASK_TEXTURE
  133. vec4(0.),
  134. #endif
  135. #ifdef REFLECTION
  136. #ifdef SS_TRANSLUCENCY
  137. ${reflectionBlock?._reflectionMatrixName},
  138. #ifdef USESPHERICALFROMREFLECTIONMAP
  139. #if !defined(NORMAL) || !defined(USESPHERICALINVERTEX)
  140. reflectionOut.irradianceVector,
  141. #endif
  142. #endif
  143. #ifdef USEIRRADIANCEMAP
  144. irradianceSampler,
  145. #endif
  146. #endif
  147. #endif
  148. #ifdef SS_REFRACTION
  149. ${worldPosVarName}.xyz,
  150. viewDirectionW,
  151. ${refractionView},
  152. surfaceAlbedo,
  153. ${refractionBlock?._vRefractionInfosName ?? ""},
  154. ${refractionBlock?._refractionMatrixName ?? ""},
  155. ${refractionBlock?._vRefractionMicrosurfaceInfosName ?? ""},
  156. vLightingIntensity,
  157. #ifdef SS_LINKREFRACTIONTOTRANSPARENCY
  158. alpha,
  159. #endif
  160. #ifdef ${refractionBlock?._defineLODRefractionAlpha ?? "IGNORE"}
  161. NdotVUnclamped,
  162. #endif
  163. #ifdef ${refractionBlock?._defineLinearSpecularRefraction ?? "IGNORE"}
  164. roughness,
  165. #else
  166. alphaG,
  167. #endif
  168. #ifdef ${refractionBlock?._define3DName ?? "IGNORE"}
  169. ${refractionBlock?._cubeSamplerName ?? ""},
  170. #else
  171. ${refractionBlock?._2DSamplerName ?? ""},
  172. #endif
  173. #ifndef LODBASEDMICROSFURACE
  174. #ifdef ${refractionBlock?._define3DName ?? "IGNORE"}
  175. ${refractionBlock?._cubeSamplerName ?? ""},
  176. ${refractionBlock?._cubeSamplerName ?? ""},
  177. #else
  178. ${refractionBlock?._2DSamplerName ?? ""},
  179. ${refractionBlock?._2DSamplerName ?? ""},
  180. #endif
  181. #endif
  182. #ifdef ANISOTROPIC
  183. anisotropicOut,
  184. #endif
  185. #endif
  186. #ifdef SS_TRANSLUCENCY
  187. ${translucencyDiffusionDistance},
  188. #endif
  189. subSurfaceOut
  190. );
  191. #ifdef SS_REFRACTION
  192. surfaceAlbedo = subSurfaceOut.surfaceAlbedo;
  193. #ifdef SS_LINKREFRACTIONTOTRANSPARENCY
  194. alpha = subSurfaceOut.alpha;
  195. #endif
  196. #endif
  197. #else
  198. subSurfaceOut.specularEnvironmentReflectance = specularEnvironmentReflectance;
  199. #endif\r\n`;
  200. return code;
  201. }
  202. protected _buildBlock(state: NodeMaterialBuildState) {
  203. if (state.target === NodeMaterialBlockTargets.Fragment) {
  204. state.sharedData.blocksWithDefines.push(this);
  205. }
  206. return this;
  207. }
  208. }
  209. _TypeStore.RegisteredTypes["BABYLON.SubSurfaceBlock"] = SubSurfaceBlock;