diff --git a/data/__internal/shaders/EnvironmentProbe/EnvironmentProbe.frag.glsl b/data/__internal/shaders/EnvironmentProbe/EnvironmentProbe.frag.glsl index acd70f1b..21b42023 100644 --- a/data/__internal/shaders/EnvironmentProbe/EnvironmentProbe.frag.glsl +++ b/data/__internal/shaders/EnvironmentProbe/EnvironmentProbe.frag.glsl @@ -66,14 +66,14 @@ subroutine uniform srtAmbient ambient; uniform sampler2D ambientBRDF; uniform bool haveAmbientBRDF; +uniform vec3 boxExtents; + // Model-space box projection -vec3 bpcem(in vec3 pos, in vec3 v) +vec3 bpcem(in vec3 pos, in vec3 v, in vec3 boxExtents) { - const vec3 boxMax = vec3(1.0, 1.0, 1.0); - const vec3 boxMin = vec3(-1.0, -1.0, -1.0); vec3 nrdir = v; - vec3 rbmax = (boxMax - pos) / nrdir; - vec3 rbmin = (boxMin - pos) / nrdir; + vec3 rbmax = (boxExtents - pos) / nrdir; + vec3 rbmin = (-boxExtents - pos) / nrdir; vec3 rbminmax; rbminmax.x = (nrdir.x > 0.0)? rbmax.x : rbmin.x; rbminmax.y = (nrdir.y > 0.0)? rbmax.y : rbmin.y; @@ -83,6 +83,11 @@ vec3 bpcem(in vec3 pos, in vec3 v) return posOnBox; } +float fresnelR(float cosTheta, float f0, float r) +{ + return f0 + (1.0 - f0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), r); +} + layout(location = 0) out vec4 fragColor; void main() @@ -99,9 +104,9 @@ void main() vec3 objPos = (invModelMatrix * vec4(worldPos, 1.0)).xyz; // Perform bounds check to discard fragments outside the probe geometry - if (abs(objPos.x) > 1.0) discard; - if (abs(objPos.y) > 1.0) discard; - if (abs(objPos.z) > 1.0) discard; + if (abs(objPos.x) > boxExtents.x) discard; + if (abs(objPos.y) > boxExtents.y) discard; + if (abs(objPos.z) > boxExtents.z) discard; // TODO: make uniform float alpha = 1.0; @@ -118,27 +123,28 @@ void main() vec3 worldN = normalize((vec4(N, 0.0) * viewMatrix).xyz); vec3 worldR = reflect(worldE, worldN); + float reflectivity = 1.0; + if (useBoxProjection) { vec3 objN = (invModelMatrix * vec4(worldN, 0.0)).xyz; - worldN = normalize(bpcem(objPos, objN)); + worldN = normalize(bpcem(objPos, objN, boxExtents)); vec3 objR = (invModelMatrix * vec4(worldR, 0.0)).xyz; - worldR = normalize(bpcem(objPos, objR)); + worldR = normalize(bpcem(objPos, objR, boxExtents)); } vec4 pbr = texture(pbrBuffer, gbufTexCoord); float roughness = pbr.r; float metallic = pbr.g; - float reflectivity = 1.0; float occlusion = haveOcclusionBuffer? texture(occlusionBuffer, gbufTexCoord).r : 1.0; vec3 f0 = mix(vec3(0.04), albedo, metallic); // Ambient light - vec3 irradiance = ambient(worldN, 0.99); // TODO: support separate irradiance map - vec3 reflection = ambient(worldR, sqrt(roughness)) * reflectivity; vec3 F = clamp(fresnelRoughness(NE, f0, roughness), 0.0, 1.0); + vec3 irradiance = ambient(worldN, 0.9); // TODO: support separate irradiance map + vec3 reflection = ambient(worldR, 1.0 - fresnelR(NE, 0.04, roughness)) * reflectivity; vec3 kD = (1.0 - F) * (1.0 - metallic); vec2 brdf = haveAmbientBRDF? texture(ambientBRDF, vec2(NE, roughness)).rg : vec2(1.0, 0.0); vec3 specular = reflection * clamp(F * brdf.x + brdf.y, 0.0, 1.0); diff --git a/data/__internal/shaders/include/envMapEquirect.glsl b/data/__internal/shaders/include/envMapEquirect.glsl index c0537ab4..62144bb6 100644 --- a/data/__internal/shaders/include/envMapEquirect.glsl +++ b/data/__internal/shaders/include/envMapEquirect.glsl @@ -2,5 +2,5 @@ vec2 envMapEquirect(in vec3 dir) { float phi = acos(dir.y); float theta = atan(dir.x, dir.z) + PI; - return vec2(theta / PI2, phi / PI); + return vec2(1.0 - theta / PI2, phi / PI); } diff --git a/data/__internal/shaders/include/fresnel.glsl b/data/__internal/shaders/include/fresnel.glsl index 38b17e93..430e5b97 100644 --- a/data/__internal/shaders/include/fresnel.glsl +++ b/data/__internal/shaders/include/fresnel.glsl @@ -8,6 +8,11 @@ vec3 fresnel(float cosTheta, vec3 f0) return f0 + (1.0 - f0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); } +float fresnelRoughness(float cosTheta, float f0, float roughness) +{ + return f0 + (max(1.0 - roughness, f0) - f0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); +} + vec3 fresnelRoughness(float cosTheta, vec3 f0, float roughness) { return f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); diff --git a/src/dagon/graphics/entity.d b/src/dagon/graphics/entity.d index 473034df..97ea6588 100644 --- a/src/dagon/graphics/entity.d +++ b/src/dagon/graphics/entity.d @@ -75,6 +75,7 @@ class Entity: Owner, Updateable bool dynamic = true; bool decal = false; bool probe = false; + Vector3f probeExtents = Vector3f(1.0f, 1.0f, 1.0f); bool probeUseBoxProjection = false; bool transparent = false; float opacity = 1.0f; diff --git a/src/dagon/render/deferred/passes/probe.d b/src/dagon/render/deferred/passes/probe.d index b52111b7..c978340f 100644 --- a/src/dagon/render/deferred/passes/probe.d +++ b/src/dagon/render/deferred/passes/probe.d @@ -85,6 +85,7 @@ class PassEnvironmentProbe: RenderPass if (entity.visible && entity.drawable) { environmentProbeShader.useBoxProjection = entity.probeUseBoxProjection; + environmentProbeShader.boxExtents = entity.probeExtents; renderEntity(entity, environmentProbeShader); } } diff --git a/src/dagon/render/deferred/shaders/probe.d b/src/dagon/render/deferred/shaders/probe.d index c76bb157..4552e1e4 100644 --- a/src/dagon/render/deferred/shaders/probe.d +++ b/src/dagon/render/deferred/shaders/probe.d @@ -49,6 +49,7 @@ class EnvironmentProbeShader: Shader String vs, fs; bool useBoxProjection = false; + Vector3f boxExtents = Vector3f(1.0f, 1.0f, 1.0f); this(Owner owner) { @@ -158,6 +159,7 @@ class EnvironmentProbeShader: Shader setParameter("ambientEnergy", mat.emissionEnergy); setParameter("useBoxProjection", useBoxProjection); + setParameter("boxExtents", boxExtents); // Texture 6 - occlusion buffer glActiveTexture(GL_TEXTURE6);