123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460 |
- import { NodeMaterialBlockConnectionPointTypes } from '../../Enums/nodeMaterialBlockConnectionPointTypes';
- import { NodeMaterialBuildState } from '../../nodeMaterialBuildState';
- import { NodeMaterialConnectionPoint, NodeMaterialConnectionPointDirection } from '../../nodeMaterialBlockConnectionPoint';
- import { NodeMaterialBlockTargets } from '../../Enums/nodeMaterialBlockTargets';
- import { NodeMaterial, NodeMaterialDefines } from '../../nodeMaterial';
- import { _TypeStore } from '../../../../Misc/typeStore';
- import { NodeMaterialConnectionPointCustomObject } from "../../nodeMaterialConnectionPointCustomObject";
- import { ReflectionTextureBaseBlock } from '../Dual/reflectionTextureBaseBlock';
- import { AbstractMesh } from '../../../../Meshes/abstractMesh';
- import { Nullable } from '../../../../types';
- import { Texture } from '../../../Textures/texture';
- import { BaseTexture } from '../../../Textures/baseTexture';
- import { Mesh } from '../../../../Meshes/mesh';
- import { SubMesh } from '../../../../Meshes/subMesh';
- import { Effect } from '../../../effect';
- import { editableInPropertyPage, PropertyTypeForEdition } from "../../nodeMaterialDecorator";
- import { Scene } from '../../../../scene';
- import { Scalar } from '../../../../Maths/math.scalar';
- /**
- * Block used to implement the reflection module of the PBR material
- */
- export class ReflectionBlock extends ReflectionTextureBaseBlock {
- /** @hidden */
- public _defineLODReflectionAlpha: string;
- /** @hidden */
- public _defineLinearSpecularReflection: string;
- private _vEnvironmentIrradianceName: string;
- /** @hidden */
- public _vReflectionMicrosurfaceInfosName: string;
- /** @hidden */
- public _vReflectionInfosName: string;
- /** @hidden */
- public _vReflectionFilteringInfoName: string;
- private _scene: Scene;
- /**
- * The properties below are set by the main PBR block prior to calling methods of this class.
- * This is to avoid having to add them as inputs here whereas they are already inputs of the main block, so already known.
- * It's less burden on the user side in the editor part.
- */
- /** @hidden */
- public worldPositionConnectionPoint: NodeMaterialConnectionPoint;
- /** @hidden */
- public worldNormalConnectionPoint: NodeMaterialConnectionPoint;
- /** @hidden */
- public cameraPositionConnectionPoint: NodeMaterialConnectionPoint;
- /** @hidden */
- public viewConnectionPoint: NodeMaterialConnectionPoint;
- /**
- * Defines if the material uses spherical harmonics vs spherical polynomials for the
- * diffuse part of the IBL.
- */
- @editableInPropertyPage("Spherical Harmonics", PropertyTypeForEdition.Boolean, "ADVANCED", { "notifiers": { "update": true }})
- public useSphericalHarmonics: boolean = true;
- /**
- * Force the shader to compute irradiance in the fragment shader in order to take bump in account.
- */
- @editableInPropertyPage("Force irradiance in fragment", PropertyTypeForEdition.Boolean, "ADVANCED", { "notifiers": { "update": true }})
- public forceIrradianceInFragment: boolean = false;
- /**
- * Create a new ReflectionBlock
- * @param name defines the block name
- */
- public constructor(name: string) {
- super(name);
- this._isUnique = true;
- this.registerInput("position", NodeMaterialBlockConnectionPointTypes.Vector3, false, NodeMaterialBlockTargets.Vertex);
- this.registerInput("world", NodeMaterialBlockConnectionPointTypes.Matrix, false, NodeMaterialBlockTargets.Vertex);
- this.registerInput("color", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
- this.registerOutput("reflection", NodeMaterialBlockConnectionPointTypes.Object, NodeMaterialBlockTargets.Fragment,
- new NodeMaterialConnectionPointCustomObject("reflection", this, NodeMaterialConnectionPointDirection.Output, ReflectionBlock, "ReflectionBlock"));
- }
- /**
- * Gets the current class name
- * @returns the class name
- */
- public getClassName() {
- return "ReflectionBlock";
- }
- /**
- * Gets the position input component
- */
- public get position(): NodeMaterialConnectionPoint {
- return this._inputs[0];
- }
- /**
- * Gets the world position input component
- */
- public get worldPosition(): NodeMaterialConnectionPoint {
- return this.worldPositionConnectionPoint;
- }
- /**
- * Gets the world normal input component
- */
- public get worldNormal(): NodeMaterialConnectionPoint {
- return this.worldNormalConnectionPoint;
- }
- /**
- * Gets the world input component
- */
- public get world(): NodeMaterialConnectionPoint {
- return this._inputs[1];
- }
- /**
- * Gets the camera (or eye) position component
- */
- public get cameraPosition(): NodeMaterialConnectionPoint {
- return this.cameraPositionConnectionPoint;
- }
- /**
- * Gets the view input component
- */
- public get view(): NodeMaterialConnectionPoint {
- return this.viewConnectionPoint;
- }
- /**
- * Gets the color input component
- */
- public get color(): NodeMaterialConnectionPoint {
- return this._inputs[2];
- }
- /**
- * Gets the reflection object output component
- */
- public get reflection(): NodeMaterialConnectionPoint {
- return this._outputs[0];
- }
- /**
- * Returns true if the block has a texture (either its own texture or the environment texture from the scene, if set)
- */
- public get hasTexture(): boolean {
- return !!this._getTexture();
- }
- /**
- * Gets the reflection color (either the name of the variable if the color input is connected, else a default value)
- */
- public get reflectionColor(): string {
- return this.color.isConnected ? this.color.associatedVariableName : "vec3(1., 1., 1.)";
- }
- protected _getTexture(): Nullable<BaseTexture> {
- if (this.texture) {
- return this.texture;
- }
- return this._scene.environmentTexture;
- }
- public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
- super.prepareDefines(mesh, nodeMaterial, defines);
- const reflectionTexture = this._getTexture();
- const reflection = reflectionTexture && reflectionTexture.getTextureMatrix;
- defines.setValue("REFLECTION", reflection, true);
- if (!reflection) {
- return;
- }
- defines.setValue(this._defineLODReflectionAlpha, reflectionTexture!.lodLevelInAlpha, true);
- defines.setValue(this._defineLinearSpecularReflection, reflectionTexture!.linearSpecularLOD, true);
- defines.setValue(this._defineOppositeZ, this._scene.useRightHandedSystem ? !reflectionTexture!.invertZ : reflectionTexture!.invertZ, true);
- defines.setValue("SPHERICAL_HARMONICS", this.useSphericalHarmonics, true);
- defines.setValue("GAMMAREFLECTION", reflectionTexture!.gammaSpace, true);
- defines.setValue("RGBDREFLECTION", reflectionTexture!.isRGBD, true);
- if (reflectionTexture && reflectionTexture.coordinatesMode !== Texture.SKYBOX_MODE) {
- if (reflectionTexture.isCube) {
- defines.setValue("USESPHERICALFROMREFLECTIONMAP", true);
- defines.setValue("USEIRRADIANCEMAP", false);
- if (this.forceIrradianceInFragment || this._scene.getEngine().getCaps().maxVaryingVectors <= 8) {
- defines.setValue("USESPHERICALINVERTEX", false);
- }
- else {
- defines.setValue("USESPHERICALINVERTEX", true);
- }
- }
- }
- }
- public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh, subMesh?: SubMesh) {
- super.bind(effect, nodeMaterial, mesh);
- const reflectionTexture = this._getTexture();
- if (!reflectionTexture || !subMesh) {
- return;
- }
- if (reflectionTexture.isCube) {
- effect.setTexture(this._cubeSamplerName, reflectionTexture);
- } else {
- effect.setTexture(this._2DSamplerName, reflectionTexture);
- }
- const width = reflectionTexture.getSize().width;
- effect.setFloat3(this._vReflectionMicrosurfaceInfosName, width, reflectionTexture.lodGenerationScale, reflectionTexture.lodGenerationOffset);
- effect.setFloat2(this._vReflectionFilteringInfoName, width, Scalar.Log2(width));
- const defines = subMesh._materialDefines as NodeMaterialDefines;
- const polynomials = reflectionTexture.sphericalPolynomial;
- if (defines.USESPHERICALFROMREFLECTIONMAP && polynomials) {
- if (defines.SPHERICAL_HARMONICS) {
- const preScaledHarmonics = polynomials.preScaledHarmonics;
- effect.setVector3("vSphericalL00", preScaledHarmonics.l00);
- effect.setVector3("vSphericalL1_1", preScaledHarmonics.l1_1);
- effect.setVector3("vSphericalL10", preScaledHarmonics.l10);
- effect.setVector3("vSphericalL11", preScaledHarmonics.l11);
- effect.setVector3("vSphericalL2_2", preScaledHarmonics.l2_2);
- effect.setVector3("vSphericalL2_1", preScaledHarmonics.l2_1);
- effect.setVector3("vSphericalL20", preScaledHarmonics.l20);
- effect.setVector3("vSphericalL21", preScaledHarmonics.l21);
- effect.setVector3("vSphericalL22", preScaledHarmonics.l22);
- }
- else {
- effect.setFloat3("vSphericalX", polynomials.x.x, polynomials.x.y, polynomials.x.z);
- effect.setFloat3("vSphericalY", polynomials.y.x, polynomials.y.y, polynomials.y.z);
- effect.setFloat3("vSphericalZ", polynomials.z.x, polynomials.z.y, polynomials.z.z);
- effect.setFloat3("vSphericalXX_ZZ", polynomials.xx.x - polynomials.zz.x,
- polynomials.xx.y - polynomials.zz.y,
- polynomials.xx.z - polynomials.zz.z);
- effect.setFloat3("vSphericalYY_ZZ", polynomials.yy.x - polynomials.zz.x,
- polynomials.yy.y - polynomials.zz.y,
- polynomials.yy.z - polynomials.zz.z);
- effect.setFloat3("vSphericalZZ", polynomials.zz.x, polynomials.zz.y, polynomials.zz.z);
- effect.setFloat3("vSphericalXY", polynomials.xy.x, polynomials.xy.y, polynomials.xy.z);
- effect.setFloat3("vSphericalYZ", polynomials.yz.x, polynomials.yz.y, polynomials.yz.z);
- effect.setFloat3("vSphericalZX", polynomials.zx.x, polynomials.zx.y, polynomials.zx.z);
- }
- }
- }
- /**
- * Gets the code to inject in the vertex shader
- * @param state current state of the node material building
- * @returns the shader code
- */
- public handleVertexSide(state: NodeMaterialBuildState): string {
- let code = super.handleVertexSide(state);
- state._emitFunctionFromInclude("harmonicsFunctions", `//${this.name}`, {
- replaceStrings: [
- { search: /uniform vec3 vSphericalL00;[\s\S]*?uniform vec3 vSphericalL22;/g, replace: "" },
- { search: /uniform vec3 vSphericalX;[\s\S]*?uniform vec3 vSphericalZX;/g, replace: "" },
- ]
- });
- const reflectionVectorName = state._getFreeVariableName("reflectionVector");
- this._vEnvironmentIrradianceName = state._getFreeVariableName("vEnvironmentIrradiance");
- state._emitVaryingFromString(this._vEnvironmentIrradianceName, "vec3", "defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX)");
- state._emitUniformFromString("vSphericalL00", "vec3", "SPHERICAL_HARMONICS");
- state._emitUniformFromString("vSphericalL1_1", "vec3", "SPHERICAL_HARMONICS");
- state._emitUniformFromString("vSphericalL10", "vec3", "SPHERICAL_HARMONICS");
- state._emitUniformFromString("vSphericalL11", "vec3", "SPHERICAL_HARMONICS");
- state._emitUniformFromString("vSphericalL2_2", "vec3", "SPHERICAL_HARMONICS");
- state._emitUniformFromString("vSphericalL2_1", "vec3", "SPHERICAL_HARMONICS");
- state._emitUniformFromString("vSphericalL20", "vec3", "SPHERICAL_HARMONICS");
- state._emitUniformFromString("vSphericalL21", "vec3", "SPHERICAL_HARMONICS");
- state._emitUniformFromString("vSphericalL22", "vec3", "SPHERICAL_HARMONICS");
- state._emitUniformFromString("vSphericalX", "vec3", "SPHERICAL_HARMONICS", true);
- state._emitUniformFromString("vSphericalY", "vec3", "SPHERICAL_HARMONICS", true);
- state._emitUniformFromString("vSphericalZ", "vec3", "SPHERICAL_HARMONICS", true);
- state._emitUniformFromString("vSphericalXX_ZZ", "vec3", "SPHERICAL_HARMONICS", true);
- state._emitUniformFromString("vSphericalYY_ZZ", "vec3", "SPHERICAL_HARMONICS", true);
- state._emitUniformFromString("vSphericalZZ", "vec3", "SPHERICAL_HARMONICS", true);
- state._emitUniformFromString("vSphericalXY", "vec3", "SPHERICAL_HARMONICS", true);
- state._emitUniformFromString("vSphericalYZ", "vec3", "SPHERICAL_HARMONICS", true);
- state._emitUniformFromString("vSphericalZX", "vec3", "SPHERICAL_HARMONICS", true);
- code +=
- `#if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX)
- vec3 ${reflectionVectorName} = vec3(${this._reflectionMatrixName} * vec4(normalize(${this.worldNormal.associatedVariableName}).xyz, 0)).xyz;
- #ifdef ${this._defineOppositeZ}
- ${reflectionVectorName}.z *= -1.0;
- #endif
- ${this._vEnvironmentIrradianceName} = computeEnvironmentIrradiance(${reflectionVectorName});
- #endif\r\n`;
- return code;
- }
- /**
- * Gets the main code of the block (fragment side)
- * @param state current state of the node material building
- * @param normalVarName name of the existing variable corresponding to the normal
- * @returns the shader code
- */
- public getCode(state: NodeMaterialBuildState, normalVarName: string): string {
- let code = "";
- this.handleFragmentSideInits(state);
- state._emitFunctionFromInclude("harmonicsFunctions", `//${this.name}`, {
- replaceStrings: [
- { search: /uniform vec3 vSphericalL00;[\s\S]*?uniform vec3 vSphericalL22;/g, replace: "" },
- { search: /uniform vec3 vSphericalX;[\s\S]*?uniform vec3 vSphericalZX;/g, replace: "" },
- ]
- });
- state._emitFunction("sampleReflection", `
- #ifdef ${this._define3DName}
- #define sampleReflection(s, c) textureCube(s, c)
- #else
- #define sampleReflection(s, c) texture2D(s, c)
- #endif\r\n`, `//${this.name}`);
- state._emitFunction("sampleReflectionLod", `
- #ifdef ${this._define3DName}
- #define sampleReflectionLod(s, c, l) textureCubeLodEXT(s, c, l)
- #else
- #define sampleReflectionLod(s, c, l) texture2DLodEXT(s, c, l)
- #endif\r\n`, `//${this.name}`);
- const computeReflectionCoordsFunc = `
- vec3 computeReflectionCoordsPBR(vec4 worldPos, vec3 worldNormal) {
- ${this.handleFragmentSideCodeReflectionCoords('worldNormal', 'worldPos', true)}
- return ${this._reflectionVectorName};
- }\r\n`;
- state._emitFunction("computeReflectionCoordsPBR", computeReflectionCoordsFunc, `//${this.name}`);
- this._vReflectionMicrosurfaceInfosName = state._getFreeVariableName("vReflectionMicrosurfaceInfos");
- state._emitUniformFromString(this._vReflectionMicrosurfaceInfosName, "vec3");
- this._vReflectionInfosName = state._getFreeVariableName("vReflectionInfos");
- this._vReflectionFilteringInfoName = state._getFreeVariableName("vReflectionFilteringInfo");
- state._emitUniformFromString(this._vReflectionFilteringInfoName, "vec2");
- code += `#ifdef REFLECTION
- vec2 ${this._vReflectionInfosName} = vec2(1., 0.);
- reflectionOutParams reflectionOut;
- reflectionBlock(
- ${"v_" + this.worldPosition.associatedVariableName + ".xyz"},
- ${normalVarName},
- alphaG,
- ${this._vReflectionMicrosurfaceInfosName},
- ${this._vReflectionInfosName},
- ${this.reflectionColor},
- #ifdef ANISOTROPIC
- anisotropicOut,
- #endif
- #if defined(${this._defineLODReflectionAlpha}) && !defined(${this._defineSkyboxName})
- NdotVUnclamped,
- #endif
- #ifdef ${this._defineLinearSpecularReflection}
- roughness,
- #endif
- #ifdef ${this._define3DName}
- ${this._cubeSamplerName},
- #else
- ${this._2DSamplerName},
- #endif
- #if defined(NORMAL) && defined(USESPHERICALINVERTEX)
- ${this._vEnvironmentIrradianceName},
- #endif
- #ifdef USESPHERICALFROMREFLECTIONMAP
- #if !defined(NORMAL) || !defined(USESPHERICALINVERTEX)
- ${this._reflectionMatrixName},
- #endif
- #endif
- #ifdef USEIRRADIANCEMAP
- irradianceSampler, // ** not handled **
- #endif
- #ifndef LODBASEDMICROSFURACE
- #ifdef ${this._define3DName}
- ${this._cubeSamplerName},
- ${this._cubeSamplerName},
- #else
- ${this._2DSamplerName},
- ${this._2DSamplerName},
- #endif
- #endif
- #ifdef REALTIME_FILTERING
- ${this._vReflectionFilteringInfoName},
- #endif
- reflectionOut
- );
- #endif\r\n`;
- return code;
- }
- protected _buildBlock(state: NodeMaterialBuildState) {
- this._scene = state.sharedData.scene;
- if (state.target !== NodeMaterialBlockTargets.Fragment) {
- this._defineLODReflectionAlpha = state._getFreeDefineName("LODINREFLECTIONALPHA");
- this._defineLinearSpecularReflection = state._getFreeDefineName("LINEARSPECULARREFLECTION");
- }
- return this;
- }
- protected _dumpPropertiesCode() {
- let codeString: string = super._dumpPropertiesCode();
- if (this.texture) {
- codeString += `${this._codeVariableName}.texture.gammaSpace = ${this.texture.gammaSpace};\r\n`;
- }
- codeString += `${this._codeVariableName}.useSphericalHarmonics = ${this.useSphericalHarmonics};\r\n`;
- codeString += `${this._codeVariableName}.forceIrradianceInFragment = ${this.forceIrradianceInFragment};\r\n`;
- return codeString;
- }
- public serialize(): any {
- let serializationObject = super.serialize();
- serializationObject.useSphericalHarmonics = this.useSphericalHarmonics;
- serializationObject.forceIrradianceInFragment = this.forceIrradianceInFragment;
- serializationObject.gammaSpace = this.texture?.gammaSpace ?? true;
- return serializationObject;
- }
- public _deserialize(serializationObject: any, scene: Scene, rootUrl: string) {
- super._deserialize(serializationObject, scene, rootUrl);
- this.useSphericalHarmonics = serializationObject.useSphericalHarmonics;
- this.forceIrradianceInFragment = serializationObject.forceIrradianceInFragment;
- if (this.texture) {
- this.texture.gammaSpace = serializationObject.gammaSpace;
- }
- }
- }
- _TypeStore.RegisteredTypes["BABYLON.ReflectionBlock"] = ReflectionBlock;
|