diff --git a/packages/dev/core/src/Materials/Background/backgroundMaterial.ts b/packages/dev/core/src/Materials/Background/backgroundMaterial.ts index a4ff2734499..befaab8f951 100644 --- a/packages/dev/core/src/Materials/Background/backgroundMaterial.ts +++ b/packages/dev/core/src/Materials/Background/backgroundMaterial.ts @@ -122,6 +122,11 @@ class BackgroundMaterialDefines extends MaterialDefines implements IImageProcess */ public REFLECTIONBGR = false; + /** + * True if ground projection has been enabled. + */ + public PROJECTED_GROUND = false; + public IMAGEPROCESSING = false; public VIGNETTE = false; public VIGNETTEBLENDMODEMULTIPLY = false; @@ -609,6 +614,29 @@ export class BackgroundMaterial extends PushMaterial { */ public switchToBGR: boolean = false; + private _enableGroundProjection: boolean = false; + /** + * Enables the ground projection mode on the material. + * @see https://doc.babylonjs.com/features/featuresDeepDive/environment/skybox#ground-projection + */ + @serialize() + @expandToProperty("_markAllSubMeshesAsMiscDirty") + public enableGroundProjection: boolean = false; + + /** + * Defines the radius of the projected ground if enableGroundProjection is true. + * @see https://doc.babylonjs.com/features/featuresDeepDive/environment/skybox#ground-projection + */ + @serialize() + public projectedGroundRadius = 1000; + + /** + * Defines the height of the projected ground if enableGroundProjection is true. + * @see https://doc.babylonjs.com/features/featuresDeepDive/environment/skybox#ground-projection + */ + @serialize() + public projectedGroundHeight = 10; + // Temp values kept as cache in the material. private _renderTargets = new SmartArray(16); private _reflectionControls = Vector4.Zero(); @@ -838,6 +866,15 @@ export class BackgroundMaterial extends PushMaterial { this._imageProcessingConfiguration.prepareDefines(defines); } + if (defines._areMiscDirty) { + if (defines.REFLECTIONMAP_3D && this._enableGroundProjection) { + defines.PROJECTED_GROUND = true; + defines.REFLECTIONMAP_SKYBOX = true; + } else { + defines.PROJECTED_GROUND = false; + } + } + // Misc. MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines); @@ -919,6 +956,8 @@ export class BackgroundMaterial extends PushMaterial { "vDiffuseInfos", "diffuseMatrix", + + "projectedGroundInfos", ]; addClipPlaneUniforms(uniforms); @@ -1030,6 +1069,7 @@ export class BackgroundMaterial extends PushMaterial { this._uniformBuffer.addUniform("alpha", 1); this._uniformBuffer.addUniform("vBackgroundCenter", 3); this._uniformBuffer.addUniform("vReflectionControl", 4); + this._uniformBuffer.addUniform("projectedGroundInfos", 2); this._uniformBuffer.create(); } @@ -1159,6 +1199,10 @@ export class BackgroundMaterial extends PushMaterial { ); } } + + if (defines.PROJECTED_GROUND) { + this._uniformBuffer.updateFloat2("projectedGroundInfos", this.projectedGroundRadius, this.projectedGroundHeight); + } } // Clip plane diff --git a/packages/dev/core/src/Materials/Node/Blocks/Dual/reflectionTextureBaseBlock.ts b/packages/dev/core/src/Materials/Node/Blocks/Dual/reflectionTextureBaseBlock.ts index 101dfa9cf9d..b69d8e570ee 100644 --- a/packages/dev/core/src/Materials/Node/Blocks/Dual/reflectionTextureBaseBlock.ts +++ b/packages/dev/core/src/Materials/Node/Blocks/Dual/reflectionTextureBaseBlock.ts @@ -346,7 +346,6 @@ export abstract class ReflectionTextureBaseBlock extends NodeMaterialBlock { state.sharedData.bindableBlocks.push(this); const comments = `//${this.name}`; - state._emitFunction("ReciprocalPI", "#define RECIPROCAL_PI2 0.15915494", ""); state._emitFunctionFromInclude("helperFunctions", comments); state._emitFunctionFromInclude("reflectionFunction", comments, { replaceStrings: [{ search: /vec3 computeReflectionCoords/g, replace: "void DUMMYFUNC" }], diff --git a/packages/dev/core/src/Shaders/ShadersInclude/backgroundFragmentDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/backgroundFragmentDeclaration.fx index 2eb4e8e9f06..82b1137ee91 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/backgroundFragmentDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/backgroundFragmentDeclaration.fx @@ -26,5 +26,9 @@ #endif #if defined(REFLECTIONMAP_SPHERICAL) || defined(REFLECTIONMAP_PROJECTION) || defined(REFRACTION) -uniform mat4 view; + uniform mat4 view; +#endif + +#ifdef PROJECTED_GROUND + uniform vec2 projectedGroundInfos; #endif \ No newline at end of file diff --git a/packages/dev/core/src/Shaders/ShadersInclude/backgroundUboDeclaration.fx b/packages/dev/core/src/Shaders/ShadersInclude/backgroundUboDeclaration.fx index 9e697f1223b..549fcfa18e6 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/backgroundUboDeclaration.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/backgroundUboDeclaration.fx @@ -14,14 +14,9 @@ uniform Material uniform float pointSize; uniform float shadowLevel; uniform float alpha; - - #if defined(REFLECTIONFRESNEL) || defined(OPACITYFRESNEL) - uniform vec3 vBackgroundCenter; - #endif - - #ifdef REFLECTIONFRESNEL - uniform vec4 vReflectionControl; - #endif + uniform vec3 vBackgroundCenter; + uniform vec4 vReflectionControl; + uniform vec2 projectedGroundInfos; }; #include diff --git a/packages/dev/core/src/Shaders/ShadersInclude/helperFunctions.fx b/packages/dev/core/src/Shaders/ShadersInclude/helperFunctions.fx index 47fb3d1feec..a358e68adcb 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/helperFunctions.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/helperFunctions.fx @@ -1,4 +1,6 @@ const float PI = 3.1415926535897932384626433832795; +const float RECIPROCAL_PI = 0.3183098861837907; +const float RECIPROCAL_PI2 = 0.15915494309189535; const float HALF_MIN = 5.96046448e-08; // Smallest positive half. const float LinearEncodePowerApprox = 2.2; diff --git a/packages/dev/core/src/Shaders/ShadersInclude/pbrHelperFunctions.fx b/packages/dev/core/src/Shaders/ShadersInclude/pbrHelperFunctions.fx index fa57618220d..4c2562e040a 100644 --- a/packages/dev/core/src/Shaders/ShadersInclude/pbrHelperFunctions.fx +++ b/packages/dev/core/src/Shaders/ShadersInclude/pbrHelperFunctions.fx @@ -1,7 +1,3 @@ -// Constants -#define RECIPROCAL_PI2 0.15915494 -#define RECIPROCAL_PI 0.31830988618 - // AlphaG epsilon to avoid numerical issues #define MINIMUMVARIANCE 0.0005 diff --git a/packages/dev/core/src/Shaders/background.fragment.fx b/packages/dev/core/src/Shaders/background.fragment.fx index 9026827b664..e303cd61d10 100644 --- a/packages/dev/core/src/Shaders/background.fragment.fx +++ b/packages/dev/core/src/Shaders/background.fragment.fx @@ -7,8 +7,6 @@ precision highp float; #include<__decl__backgroundFragment> #include -#define RECIPROCAL_PI2 0.15915494 - // Input varying vec3 vPositionW; @@ -108,6 +106,83 @@ varying vec3 vNormalW; } #endif +#ifdef PROJECTED_GROUND + // From: https://www.shadertoy.com/view/4tsBD7 + // keeping for reference the general formula for a disk + // float diskIntersectWithBackFaceCulling(vec3 ro, vec3 rd, vec3 c, vec3 n, float r) { + // float d = dot(rd, n); + // if(d > 0.0) { return 1e6; } + // vec3 o = ro - c; + // float t = -dot(n, o) / d; + // vec3 q = o + rd * t; + // return (dot(q, q) < r * r) ? t : 1e6; + // } + // optimized for a disk on the ground facing up + float diskIntersectWithBackFaceCulling(vec3 ro, vec3 rd, vec3 c, float r) { + float d = rd.y; + if(d > 0.0) { return 1e6; } + vec3 o = ro - c; + float t = -o.y / d; + vec3 q = o + rd * t; + return (dot(q, q) < r * r) ? t : 1e6; + } + + // From: https://www.iquilezles.org/www/articles/intersectors/intersectors.htm + // keeping for reference the general formula for a sphere + // float sphereIntersect(vec3 ro, vec3 rd, vec3 ce, float ra) { + // vec3 oc = ro - ce; + // float b = dot(oc, rd); + // float c = dot(oc, oc) - ra * ra; + // float h = b * b - c; + // if(h < 0.0) { return -1.0; } + // h = sqrt(h); + // return - b + h; + // } + // optimized for a sphere centered at the origin + float sphereIntersect(vec3 ro, vec3 rd, float ra) { + float b = dot(ro, rd); + float c = dot(ro, ro) - ra * ra; + float h = b * b - c; + + if(h < 0.0) { return -1.0; } + + h = sqrt(h); + + return - b + h; + } + + vec3 project(vec3 viewDirectionW, vec3 eyePosition) { + float radius = projectedGroundInfos.x; + float height = projectedGroundInfos.y; + + // reproject the cube ground to a sky sphere + // to help with shadows + // vec3 p = normalize(vPositionW); + vec3 camDir = -viewDirectionW; + float skySphereDistance = sphereIntersect(eyePosition, camDir, radius); + vec3 skySpherePositionW = eyePosition + camDir * skySphereDistance; + + vec3 p = normalize(skySpherePositionW); + eyePosition.y -= height; + + // Let s remove extra conditions in the following block + // float intersection = sphereIntersect(eyePosition, p, radius); + // if(intersection > 0.0) { + // vec3 h = vec3(0.0, -height, 0.0); + // float intersection2 = diskIntersectWithBackFaceCulling(eyePosition, p, h, radius); + // p = (eyePosition + min(intersection, intersection2) * p) / radius; + // } else { + // p = vec3(0.0, 1.0, 0.0); + // } + + float sIntersection = sphereIntersect(eyePosition, p, radius); + vec3 h = vec3(0.0, -height, 0.0); + float dIntersection = diskIntersectWithBackFaceCulling(eyePosition, p, h, radius); + p = (eyePosition + min(sIntersection, dIntersection) * p); + + return p; + } +#endif #define CUSTOM_FRAGMENT_DEFINITIONS @@ -145,7 +220,13 @@ void main(void) { // _____________________________ REFLECTION ______________________________________ vec4 reflectionColor = vec4(1., 1., 1., 1.); #ifdef REFLECTION - vec3 reflectionVector = computeReflectionCoords(vec4(vPositionW, 1.0), normalW); + #ifdef PROJECTED_GROUND + vec3 reflectionVector = project(viewDirectionW, vEyePosition.xyz); + reflectionVector = vec3(reflectionMatrix * vec4(reflectionVector, 1.)); + #else + vec3 reflectionVector = computeReflectionCoords(vec4(vPositionW, 1.0), normalW); + #endif + #ifdef REFLECTIONMAP_OPPOSITEZ reflectionVector.z *= -1.0; #endif diff --git a/packages/dev/core/src/Shaders/default.fragment.fx b/packages/dev/core/src/Shaders/default.fragment.fx index f637340127c..c75f702b25c 100644 --- a/packages/dev/core/src/Shaders/default.fragment.fx +++ b/packages/dev/core/src/Shaders/default.fragment.fx @@ -13,9 +13,6 @@ #extension GL_EXT_frag_depth : enable #endif -// Constants -#define RECIPROCAL_PI2 0.15915494 - // Input varying vec3 vPositionW; diff --git a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGrids/materials/backgroundMaterialPropertyGridComponent.tsx b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGrids/materials/backgroundMaterialPropertyGridComponent.tsx index c826641338c..d4b61fa1310 100644 --- a/packages/dev/inspector/src/components/actionTabs/tabs/propertyGrids/materials/backgroundMaterialPropertyGridComponent.tsx +++ b/packages/dev/inspector/src/components/actionTabs/tabs/propertyGrids/materials/backgroundMaterialPropertyGridComponent.tsx @@ -107,6 +107,36 @@ export class BackgroundMaterialPropertyGridComponent extends React.Component {this.renderTextures()} + + {material.enableGroundProjection && ( +
+ + +
+ )}