Skip to content

Commit

Permalink
Add ground projection support (#14470)
Browse files Browse the repository at this point in the history
* Add ground projection support

* fix format

* fix

* PR feedback

* doc links
  • Loading branch information
sebavan committed Oct 26, 2023
1 parent 040fe2c commit 7037387
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 20 deletions.
44 changes: 44 additions & 0 deletions packages/dev/core/src/Materials/Background/backgroundMaterial.ts
Expand Up @@ -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;
Expand Down Expand Up @@ -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<RenderTargetTexture>(16);
private _reflectionControls = Vector4.Zero();
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -919,6 +956,8 @@ export class BackgroundMaterial extends PushMaterial {

"vDiffuseInfos",
"diffuseMatrix",

"projectedGroundInfos",
];

addClipPlaneUniforms(uniforms);
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -1159,6 +1199,10 @@ export class BackgroundMaterial extends PushMaterial {
);
}
}

if (defines.PROJECTED_GROUND) {
this._uniformBuffer.updateFloat2("projectedGroundInfos", this.projectedGroundRadius, this.projectedGroundHeight);
}
}

// Clip plane
Expand Down
Expand Up @@ -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" }],
Expand Down
Expand Up @@ -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
Expand Up @@ -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<sceneUboDeclaration>
@@ -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;
Expand Down
@@ -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

Expand Down
87 changes: 84 additions & 3 deletions packages/dev/core/src/Shaders/background.fragment.fx
Expand Up @@ -7,8 +7,6 @@ precision highp float;
#include<__decl__backgroundFragment>
#include<helperFunctions>

#define RECIPROCAL_PI2 0.15915494

// Input
varying vec3 vPositionW;

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
3 changes: 0 additions & 3 deletions packages/dev/core/src/Shaders/default.fragment.fx
Expand Up @@ -13,9 +13,6 @@
#extension GL_EXT_frag_depth : enable
#endif

// Constants
#define RECIPROCAL_PI2 0.15915494

// Input
varying vec3 vPositionW;

Expand Down
Expand Up @@ -107,6 +107,36 @@ export class BackgroundMaterialPropertyGridComponent extends React.Component<IBa
</LineContainerComponent>
{this.renderTextures()}
<LineContainerComponent title="RENDERING" closed={true} selection={this.props.globalState}>
<CheckBoxLineComponent
label="Ground Projection"
target={material}
propertyName="enableGroundProjection"
onPropertyChangedObservable={this.props.onPropertyChangedObservable}
/>
{material.enableGroundProjection && (
<div className="fragment">
<SliderLineComponent
lockObject={this.props.lockObject}
label="Ground radius"
target={material}
propertyName="projectedGroundRadius"
minimum={0}
maximum={10000}
step={10}
onPropertyChangedObservable={this.props.onPropertyChangedObservable}
/>
<SliderLineComponent
lockObject={this.props.lockObject}
label="Ground height"
target={material}
propertyName="projectedGroundHeight"
minimum={1}
maximum={1000}
step={10}
onPropertyChangedObservable={this.props.onPropertyChangedObservable}
/>
</div>
)}
<CheckBoxLineComponent label="Enable noise" target={material} propertyName="enableNoise" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
<CheckBoxLineComponent
label="Opacity fresnel"
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions packages/tools/tests/test/visualization/config.json
@@ -1,6 +1,11 @@
{
"root": "https://cdn.babylonjs.com",
"tests": [
{
"title": "Ground Projection",
"playgroundId": "#XG08YC#0",
"referenceImage": "groundProjection.png"
},
{
"title": "Node geometry",
"playgroundId": "#WGZLGJ#9152",
Expand Down

0 comments on commit 7037387

Please sign in to comment.