reflectionBlock.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. import { NodeMaterialBlockConnectionPointTypes } from '../../Enums/nodeMaterialBlockConnectionPointTypes';
  2. import { NodeMaterialBuildState } from '../../nodeMaterialBuildState';
  3. import { NodeMaterialConnectionPoint, NodeMaterialConnectionPointDirection } from '../../nodeMaterialBlockConnectionPoint';
  4. import { NodeMaterialBlockTargets } from '../../Enums/nodeMaterialBlockTargets';
  5. import { NodeMaterial, NodeMaterialDefines } from '../../nodeMaterial';
  6. import { _TypeStore } from '../../../../Misc/typeStore';
  7. import { NodeMaterialConnectionPointCustomObject } from "../../nodeMaterialConnectionPointCustomObject";
  8. import { ReflectionTextureBaseBlock } from '../Dual/reflectionTextureBaseBlock';
  9. import { AbstractMesh } from '../../../../Meshes/abstractMesh';
  10. import { Nullable } from '../../../../types';
  11. import { Texture } from '../../../Textures/texture';
  12. import { BaseTexture } from '../../../Textures/baseTexture';
  13. import { Mesh } from '../../../../Meshes/mesh';
  14. import { SubMesh } from '../../../../Meshes/subMesh';
  15. import { Effect } from '../../../effect';
  16. import { editableInPropertyPage, PropertyTypeForEdition } from "../../nodeMaterialDecorator";
  17. import { Scene } from '../../../../scene';
  18. export class ReflectionBlock extends ReflectionTextureBaseBlock {
  19. private _defineLODReflectionAlpha: string;
  20. private _defineLinearSpecularReflection: string;
  21. private _defineLODBasedMicroSurface: string;
  22. private _vEnvironmentIrradianceName: string;
  23. private _vReflectionMicrosurfaceInfosName: string;
  24. private _scene: Scene;
  25. public worldPositionConnectionPoint: NodeMaterialConnectionPoint;
  26. public worldNormalConnectionPoint: NodeMaterialConnectionPoint;
  27. public cameraPositionConnectionPoint: NodeMaterialConnectionPoint;
  28. @editableInPropertyPage("Spherical Harmonics", PropertyTypeForEdition.Boolean, "ADVANCED", { "notifiers": { "update": true }})
  29. public useSphericalHarmonics: boolean = true;
  30. @editableInPropertyPage("Force irradiance in fragment", PropertyTypeForEdition.Boolean, "ADVANCED", { "notifiers": { "update": true }})
  31. public forceIrradianceInFragment: boolean = false;
  32. public constructor(name: string) {
  33. super(name);
  34. this._isUnique = true;
  35. this.registerInput("position", NodeMaterialBlockConnectionPointTypes.Vector3, false, NodeMaterialBlockTargets.Vertex);
  36. this.registerInput("world", NodeMaterialBlockConnectionPointTypes.Matrix, false, NodeMaterialBlockTargets.Vertex);
  37. this.registerInput("view", NodeMaterialBlockConnectionPointTypes.Matrix, false, NodeMaterialBlockTargets.Fragment);
  38. this.registerInput("color", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
  39. this.registerOutput("reflection", NodeMaterialBlockConnectionPointTypes.Object, NodeMaterialBlockTargets.Fragment, new NodeMaterialConnectionPointCustomObject("reflection", this, NodeMaterialConnectionPointDirection.Output, ReflectionBlock, "ReflectionBlock"));
  40. }
  41. /**
  42. * Gets the current class name
  43. * @returns the class name
  44. */
  45. public getClassName() {
  46. return "ReflectionBlock";
  47. }
  48. /**
  49. * Gets the world position input component
  50. */
  51. public get position(): NodeMaterialConnectionPoint {
  52. return this._inputs[0];
  53. }
  54. /**
  55. * Gets the world position input component
  56. */
  57. public get worldPosition(): NodeMaterialConnectionPoint {
  58. return this.worldPositionConnectionPoint;
  59. }
  60. /**
  61. * Gets the world normal input component
  62. */
  63. public get worldNormal(): NodeMaterialConnectionPoint {
  64. return this.worldNormalConnectionPoint;
  65. }
  66. /**
  67. * Gets the world input component
  68. */
  69. public get world(): NodeMaterialConnectionPoint {
  70. return this._inputs[1];
  71. }
  72. /**
  73. * Gets the camera (or eye) position component
  74. */
  75. public get cameraPosition(): NodeMaterialConnectionPoint {
  76. return this.cameraPositionConnectionPoint;
  77. }
  78. /**
  79. * Gets the view input component
  80. */
  81. public get view(): NodeMaterialConnectionPoint {
  82. return this._inputs[2];
  83. }
  84. public get color(): NodeMaterialConnectionPoint {
  85. return this._inputs[3];
  86. }
  87. public get reflection(): NodeMaterialConnectionPoint {
  88. return this._outputs[0];
  89. }
  90. public get hasTexture(): boolean {
  91. return !!this._getTexture();
  92. }
  93. protected _getTexture(): Nullable<BaseTexture> {
  94. if (this.texture) {
  95. return this.texture;
  96. }
  97. return this._scene.environmentTexture;
  98. }
  99. public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
  100. super.prepareDefines(mesh, nodeMaterial, defines);
  101. const reflectionTexture = this._getTexture();
  102. const reflection = reflectionTexture && reflectionTexture.getTextureMatrix;
  103. defines.setValue("REFLECTION", reflection);
  104. if (!reflection) {
  105. return;
  106. }
  107. defines.setValue(this._defineLODReflectionAlpha, reflectionTexture!.lodLevelInAlpha);
  108. defines.setValue(this._defineLinearSpecularReflection, reflectionTexture!.linearSpecularLOD);
  109. defines.setValue(this._defineLODBasedMicroSurface, this._scene.getEngine().getCaps().textureLOD);
  110. defines.setValue("SPHERICAL_HARMONICS", this.useSphericalHarmonics);
  111. if (reflectionTexture && reflectionTexture.coordinatesMode !== Texture.SKYBOX_MODE) {
  112. if (reflectionTexture.isCube) {
  113. defines.setValue("USESPHERICALFROMREFLECTIONMAP", true);
  114. defines.setValue("USEIRRADIANCEMAP", false);
  115. if (this.forceIrradianceInFragment || this._scene.getEngine().getCaps().maxVaryingVectors <= 8) {
  116. defines.setValue("USESPHERICALINVERTEX", false);
  117. }
  118. else {
  119. defines.setValue("USESPHERICALINVERTEX", true);
  120. }
  121. }
  122. }
  123. }
  124. public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh, subMesh?: SubMesh) {
  125. super.bind(effect, nodeMaterial, mesh);
  126. const reflectionTexture = this._getTexture();
  127. if (!reflectionTexture || !subMesh) {
  128. return;
  129. }
  130. if (reflectionTexture.isCube) {
  131. effect.setTexture(this._cubeSamplerName, reflectionTexture);
  132. } else {
  133. effect.setTexture(this._2DSamplerName, reflectionTexture);
  134. }
  135. effect.setFloat3("vReflectionMicrosurfaceInfos", reflectionTexture.getSize().width, reflectionTexture.lodGenerationScale, reflectionTexture.lodGenerationOffset);
  136. const defines = subMesh._materialDefines as NodeMaterialDefines;
  137. const polynomials = reflectionTexture.sphericalPolynomial;
  138. if (defines.USESPHERICALFROMREFLECTIONMAP && polynomials) {
  139. if (defines.SPHERICAL_HARMONICS) {
  140. const preScaledHarmonics = polynomials.preScaledHarmonics;
  141. effect.setVector3("vSphericalL00", preScaledHarmonics.l00);
  142. effect.setVector3("vSphericalL1_1", preScaledHarmonics.l1_1);
  143. effect.setVector3("vSphericalL10", preScaledHarmonics.l10);
  144. effect.setVector3("vSphericalL11", preScaledHarmonics.l11);
  145. effect.setVector3("vSphericalL2_2", preScaledHarmonics.l2_2);
  146. effect.setVector3("vSphericalL2_1", preScaledHarmonics.l2_1);
  147. effect.setVector3("vSphericalL20", preScaledHarmonics.l20);
  148. effect.setVector3("vSphericalL21", preScaledHarmonics.l21);
  149. effect.setVector3("vSphericalL22", preScaledHarmonics.l22);
  150. }
  151. else {
  152. effect.setFloat3("vSphericalX", polynomials.x.x, polynomials.x.y, polynomials.x.z);
  153. effect.setFloat3("vSphericalY", polynomials.y.x, polynomials.y.y, polynomials.y.z);
  154. effect.setFloat3("vSphericalZ", polynomials.z.x, polynomials.z.y, polynomials.z.z);
  155. effect.setFloat3("vSphericalXX_ZZ", polynomials.xx.x - polynomials.zz.x,
  156. polynomials.xx.y - polynomials.zz.y,
  157. polynomials.xx.z - polynomials.zz.z);
  158. effect.setFloat3("vSphericalYY_ZZ", polynomials.yy.x - polynomials.zz.x,
  159. polynomials.yy.y - polynomials.zz.y,
  160. polynomials.yy.z - polynomials.zz.z);
  161. effect.setFloat3("vSphericalZZ", polynomials.zz.x, polynomials.zz.y, polynomials.zz.z);
  162. effect.setFloat3("vSphericalXY", polynomials.xy.x, polynomials.xy.y, polynomials.xy.z);
  163. effect.setFloat3("vSphericalYZ", polynomials.yz.x, polynomials.yz.y, polynomials.yz.z);
  164. effect.setFloat3("vSphericalZX", polynomials.zx.x, polynomials.zx.y, polynomials.zx.z);
  165. }
  166. }
  167. }
  168. public handleVertexSide(state: NodeMaterialBuildState): string {
  169. let code = super.handleVertexSide(state);
  170. state._emitFunctionFromInclude("harmonicsFunctions", `//${this.name}`, {
  171. replaceStrings: [
  172. { search: /uniform vec3 vSphericalL00;[\s\S]*?uniform vec3 vSphericalL22;/g, replace: "" },
  173. { search: /uniform vec3 vSphericalX;[\s\S]*?uniform vec3 vSphericalZX;/g, replace: "" },
  174. ]
  175. });
  176. const reflectionVectorName = state._getFreeVariableName("reflectionVector");
  177. this._vEnvironmentIrradianceName = state._getFreeVariableName("vEnvironmentIrradiance");
  178. state._emitVaryingFromString(this._vEnvironmentIrradianceName, "vec3", "defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX");
  179. state._emitUniformFromString("vSphericalL00", "vec3", "SPHERICAL_HARMONICS");
  180. state._emitUniformFromString("vSphericalL1_1", "vec3", "SPHERICAL_HARMONICS");
  181. state._emitUniformFromString("vSphericalL10", "vec3", "SPHERICAL_HARMONICS");
  182. state._emitUniformFromString("vSphericalL11", "vec3", "SPHERICAL_HARMONICS");
  183. state._emitUniformFromString("vSphericalL2_2", "vec3", "SPHERICAL_HARMONICS");
  184. state._emitUniformFromString("vSphericalL2_1", "vec3", "SPHERICAL_HARMONICS");
  185. state._emitUniformFromString("vSphericalL20", "vec3", "SPHERICAL_HARMONICS");
  186. state._emitUniformFromString("vSphericalL21", "vec3", "SPHERICAL_HARMONICS");
  187. state._emitUniformFromString("vSphericalL22", "vec3", "SPHERICAL_HARMONICS");
  188. state._emitUniformFromString("vSphericalX", "vec3", "SPHERICAL_HARMONICS", true);
  189. state._emitUniformFromString("vSphericalY", "vec3", "SPHERICAL_HARMONICS", true);
  190. state._emitUniformFromString("vSphericalZ", "vec3", "SPHERICAL_HARMONICS", true);
  191. state._emitUniformFromString("vSphericalXX_ZZ", "vec3", "SPHERICAL_HARMONICS", true);
  192. state._emitUniformFromString("vSphericalYY_ZZ", "vec3", "SPHERICAL_HARMONICS", true);
  193. state._emitUniformFromString("vSphericalZZ", "vec3", "SPHERICAL_HARMONICS", true);
  194. state._emitUniformFromString("vSphericalXY", "vec3", "SPHERICAL_HARMONICS", true);
  195. state._emitUniformFromString("vSphericalYZ", "vec3", "SPHERICAL_HARMONICS", true);
  196. state._emitUniformFromString("vSphericalZX", "vec3", "SPHERICAL_HARMONICS", true);
  197. code +=
  198. `#if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX)
  199. vec3 ${reflectionVectorName} = vec3(${this._reflectionMatrixName} * vec4(${this.worldNormal.associatedVariableName}.xyz, 0)).xyz;
  200. #ifdef REFLECTIONMAP_OPPOSITEZ
  201. ${reflectionVectorName}.z *= -1.0;
  202. #endif
  203. ${this._vEnvironmentIrradianceName} = computeEnvironmentIrradiance(${reflectionVectorName});
  204. #endif\r\n`;
  205. return code;
  206. }
  207. public getCode(state: NodeMaterialBuildState, normalVarName: string, finalColorVarName: string, finalIrradianceVector: string, finalIrradianceVarName: string): string {
  208. let code = "";
  209. code += `
  210. struct reflectionOutParams
  211. {
  212. vec4 environmentRadiance;
  213. vec3 environmentIrradiance;
  214. #ifdef ${this._define3DName}
  215. vec3 reflectionCoords;
  216. #else
  217. vec2 reflectionCoords;
  218. #endif
  219. #ifdef SS_TRANSLUCENCY
  220. #ifdef USESPHERICALFROMREFLECTIONMAP
  221. #if !defined(NORMAL) || !defined(USESPHERICALINVERTEX)
  222. vec3 irradianceVector;
  223. #endif
  224. #endif
  225. #endif
  226. };\r\n`;
  227. code += `reflectionOutParams reflectionOut;\r\n`;
  228. this.handleFragmentSideInits(state);
  229. state._emitFunctionFromInclude("harmonicsFunctions", `//${this.name}`, {
  230. replaceStrings: [
  231. { search: /uniform vec3 vSphericalL00;[\s\S]*?uniform vec3 vSphericalL22;/g, replace: "" },
  232. { search: /uniform vec3 vSphericalX;[\s\S]*?uniform vec3 vSphericalZX;/g, replace: "" },
  233. ]
  234. });
  235. code += this.handleFragmentSideCodeReflectionCoords(normalVarName);
  236. const varLOD = state._getFreeVariableName("reflectionLOD");
  237. const varRequestedLOD = state._getFreeVariableName("requestedReflectionLOD");
  238. const varAutomaticLOD = state._getFreeVariableName("automaticReflectionLOD");
  239. this._vReflectionMicrosurfaceInfosName = state._getFreeVariableName("vReflectionMicrosurfaceInfos");
  240. state._emitUniformFromString(this._vReflectionMicrosurfaceInfosName, "vec3");
  241. code += `
  242. vec4 ${finalColorVarName} = vec4(0.);
  243. #if defined(${this._defineLODReflectionAlpha}) && !defined(${this._defineSkyboxName})
  244. float ${varLOD} = getLodFromAlphaG(${this._vReflectionMicrosurfaceInfosName}.x, alphaG, NdotVUnclamped);
  245. #elif defined(${this._defineLinearSpecularReflection})
  246. float ${varLOD} = getLinearLodFromRoughness(${this._vReflectionMicrosurfaceInfosName}.x, roughness);
  247. #else
  248. float ${varLOD} = getLodFromAlphaG(${this._vReflectionMicrosurfaceInfosName}.x, alphaG);
  249. #endif
  250. #ifdef ${this._defineLODBasedMicroSurface}
  251. ${varLOD} = ${varLOD} * ${this._vReflectionMicrosurfaceInfosName}.y + ${this._vReflectionMicrosurfaceInfosName}.z;
  252. #ifdef ${this._defineLODReflectionAlpha}
  253. #ifdef ${this._define3DName}
  254. float ${varAutomaticLOD} = UNPACK_LOD(textureCube(${this._cubeSamplerName}, ${this._reflectionCoordsName}).a);
  255. #else
  256. float ${varAutomaticLOD} = UNPACK_LOD(texture2D(${this._2DSamplerName}, ${this._reflectionCoordsName}).a);
  257. #endif
  258. float ${varRequestedLOD} = max(${varAutomaticLOD}, ${varLOD});
  259. #else
  260. float ${varRequestedLOD} = ${varLOD};
  261. #endif\r\n`;
  262. code += this.handleFragmentSideCodeReflectionColor(varRequestedLOD, "");
  263. code += `
  264. ${finalColorVarName} = ${this._reflectionColorName}${this.color.isConnected ? " * vec4(" + this.color.associatedVariableName + ", 1.)" : ""};
  265. #else
  266. // ***not handled***
  267. #endif\r\n`;
  268. code += `
  269. vec3 ${finalIrradianceVarName} = vec3(0.);
  270. #ifdef USESPHERICALFROMREFLECTIONMAP
  271. #if defined(USESPHERICALINVERTEX)
  272. ${finalIrradianceVarName} = ${this._vEnvironmentIrradianceName};
  273. #else
  274. #ifdef ANISOTROPIC
  275. vec3 ${finalIrradianceVector} = vec3(${this._reflectionMatrixName} * vec4(anisotropicOut.anisotropicNormal, 0)).xyz;
  276. #else
  277. vec3 ${finalIrradianceVector} = vec3(${this._reflectionMatrixName} * vec4(${normalVarName}.xyz, 0)).xyz;
  278. #endif
  279. #ifdef REFLECTIONMAP_OPPOSITEZ
  280. ${finalIrradianceVector}.z *= -1.0;
  281. #endif
  282. ${finalIrradianceVarName} = computeEnvironmentIrradiance(${finalIrradianceVector});
  283. #endif
  284. #endif\r\n`;
  285. code += `
  286. #ifdef SS_TRANSLUCENCY
  287. reflectionOut.irradianceVector = irradianceVector;
  288. #endif
  289. reflectionOut.environmentRadiance = environmentRadiance;
  290. reflectionOut.environmentIrradiance = environmentIrradiance;
  291. reflectionOut.reflectionCoords = ${this._reflectionCoordsName};\r\n`;
  292. return code;
  293. }
  294. protected _buildBlock(state: NodeMaterialBuildState) {
  295. this._scene = state.sharedData.scene;
  296. if (state.target !== NodeMaterialBlockTargets.Fragment) {
  297. this._defineLODReflectionAlpha = state._getFreeDefineName("LODINREFLECTIONALPHA");
  298. this._defineLinearSpecularReflection = state._getFreeDefineName("LINEARSPECULARREFLECTION");
  299. this._defineLODBasedMicroSurface = state._getFreeDefineName("LODBASEDMICROSFURACE");
  300. }
  301. return this;
  302. }
  303. protected _dumpPropertiesCode() {
  304. let codeString: string = super._dumpPropertiesCode();
  305. codeString += `${this._codeVariableName}.useSphericalHarmonics = ${this.useSphericalHarmonics};\r\n`;
  306. codeString += `${this._codeVariableName}.forceIrradianceInFragment = ${this.forceIrradianceInFragment};\r\n`;
  307. return codeString;
  308. }
  309. public serialize(): any {
  310. let serializationObject = super.serialize();
  311. serializationObject.useSphericalHarmonics = this.useSphericalHarmonics;
  312. serializationObject.forceIrradianceInFragment = this.forceIrradianceInFragment;
  313. return serializationObject;
  314. }
  315. public _deserialize(serializationObject: any, scene: Scene, rootUrl: string) {
  316. super._deserialize(serializationObject, scene, rootUrl);
  317. this.useSphericalHarmonics = serializationObject.useSphericalHarmonics;
  318. this.forceIrradianceInFragment = serializationObject.forceIrradianceInFragment;
  319. }
  320. }
  321. _TypeStore.RegisteredTypes["BABYLON.ReflectionBlock"] = ReflectionBlock;