Skip to content

Commit dd514e0

Browse files
committed
Merged csm branch with minor fixes.
2 parents 799cc8a + 36c5560 commit dd514e0

File tree

84 files changed

+7076
-999
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+7076
-999
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#shader vertex
2+
#version 460 core
3+
4+
layout(location = 0) in vec3 position;
5+
layout(location = 1) in vec2 texCoords;
6+
7+
out vec2 texCoordsOut;
8+
9+
void main()
10+
{
11+
texCoordsOut = texCoords;
12+
gl_Position = vec4(position, 1.0);
13+
}
14+
15+
#shader fragment
16+
#version 460 core
17+
18+
uniform vec2 scale;
19+
uniform int inputIndex;
20+
uniform sampler2DArray inputTextureArray;
21+
22+
in vec2 texCoordsOut;
23+
24+
layout(location = 0) out vec2 frag;
25+
26+
void main()
27+
{
28+
frag =
29+
texture(inputTextureArray, vec3(texCoordsOut + vec2(-3.0) * scale, float(inputIndex))).xy * (1.0 / 64.0) +
30+
texture(inputTextureArray, vec3(texCoordsOut + vec2(-2.0) * scale, float(inputIndex))).xy * (6.0 / 64.0) +
31+
texture(inputTextureArray, vec3(texCoordsOut + vec2(-1.0) * scale, float(inputIndex))).xy * (15.0 / 64.0) +
32+
texture(inputTextureArray, vec3(texCoordsOut + vec2(0.0) * scale, float(inputIndex))).xy * (20.0 / 64.0) +
33+
texture(inputTextureArray, vec3(texCoordsOut + vec2(1.0) * scale, float(inputIndex))).xy * (15.0 / 64.0) +
34+
texture(inputTextureArray, vec3(texCoordsOut + vec2(2.0) * scale, float(inputIndex))).xy * (6.0 / 64.0) +
35+
texture(inputTextureArray, vec3(texCoordsOut + vec2(3.0) * scale, float(inputIndex))).xy * (1.0 / 64.0);
36+
}

Nu/Nu.Gaia/Assets/Default/PhysicallyBasedDeferredLighting.glsl

Lines changed: 140 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@ const float PI = 3.141592654;
1919
const float PI_OVER_2 = PI / 2.0;
2020
const float ATTENUATION_CONSTANT = 1.0;
2121
const int LIGHTS_MAX = 64;
22-
const int SHADOW_TEXTURES_MAX = 9;
23-
const int SHADOW_MAPS_MAX = 9;
22+
const int SHADOW_TEXTURES_MAX = 8;
23+
const int SHADOW_MAPS_MAX = 8;
24+
const float SHADOW_DIRECTIONAL_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size.
25+
const int SHADOW_CASCADES_MAX = 2;
26+
const int SHADOW_CASCADE_LEVELS = 3;
27+
const float SHADOW_CASCADE_SEAM_INSET = 0.001;
2428
const float SHADOW_FOV_MAX = 2.1;
25-
const float SHADOW_SEAM_INSET = 0.05; // TODO: see if this should be proportionate to shadow texel size.
2629

2730
const vec4 SSVF_DITHERING[4] =
2831
vec4[](
@@ -55,6 +58,7 @@ uniform sampler2D subdermalPlusTexture;
5558
uniform sampler2D scatterPlusTexture;
5659
uniform sampler2D shadowTextures[SHADOW_TEXTURES_MAX];
5760
uniform samplerCube shadowMaps[SHADOW_MAPS_MAX];
61+
uniform sampler2DArray shadowCascades[SHADOW_CASCADES_MAX];
5862
uniform vec3 lightOrigins[LIGHTS_MAX];
5963
uniform vec3 lightDirections[LIGHTS_MAX];
6064
uniform vec3 lightColors[LIGHTS_MAX];
@@ -69,7 +73,7 @@ uniform int lightDesireFogs[LIGHTS_MAX];
6973
uniform int lightShadowIndices[LIGHTS_MAX];
7074
uniform int lightsCount;
7175
uniform float shadowNear;
72-
uniform mat4 shadowMatrices[SHADOW_TEXTURES_MAX];
76+
uniform mat4 shadowMatrices[SHADOW_TEXTURES_MAX + SHADOW_CASCADES_MAX * SHADOW_CASCADE_LEVELS];
7377

7478
in vec2 texCoordsOut;
7579

@@ -186,7 +190,7 @@ float fadeShadowScalar(vec2 shadowTexCoords, float shadowScalar)
186190
return 1.0 - (1.0 - shadowScalar) * (1.0 - fadeScalar);
187191
}
188192

189-
float computeShadowScalarPoint(vec4 position, vec3 lightOrigin, int shadowMapIndex)
193+
float computeShadowScalarPoint(vec4 position, vec3 lightOrigin, int shadowIndex)
190194
{
191195
vec3 positionShadow = position.xyz - lightOrigin;
192196
float shadowZ = length(positionShadow);
@@ -198,7 +202,7 @@ float computeShadowScalarPoint(vec4 position, vec3 lightOrigin, int shadowMapInd
198202
for (int k = 0; k < lightShadowSamples; ++k)
199203
{
200204
vec3 offset = (vec3(i, j, k) - vec3(lightShadowSamples / 2.0)) * (lightShadowSampleScalar / lightShadowSamples);
201-
shadowHits += shadowZ - lightShadowBias > texture(shadowMaps[shadowMapIndex], positionShadow + offset).x ? 1.0 : 0.0;
205+
shadowHits += shadowZ - lightShadowBias > texture(shadowMaps[shadowIndex - SHADOW_TEXTURES_MAX], positionShadow + offset).x ? 1.0 : 0.0;
202206
}
203207
}
204208
}
@@ -232,9 +236,9 @@ float computeShadowScalarDirectional(vec4 position, int shadowIndex)
232236
vec4 positionShadowClip = shadowMatrix * position;
233237
vec3 shadowTexCoordsProj = positionShadowClip.xyz / positionShadowClip.w;
234238
vec3 shadowTexCoords = shadowTexCoordsProj * 0.5 + 0.5;
235-
if (shadowTexCoords.x > SHADOW_SEAM_INSET && shadowTexCoords.x < 1.0 - SHADOW_SEAM_INSET &&
236-
shadowTexCoords.y > SHADOW_SEAM_INSET && shadowTexCoords.y < 1.0 - SHADOW_SEAM_INSET &&
237-
shadowTexCoords.z > 0.5 + SHADOW_SEAM_INSET && shadowTexCoords.z < 1.0 - SHADOW_SEAM_INSET) // TODO: figure out why shadowTexCoords.z range is 0.5 to 1.0.
239+
if (shadowTexCoords.x > SHADOW_DIRECTIONAL_SEAM_INSET && shadowTexCoords.x < 1.0 - SHADOW_DIRECTIONAL_SEAM_INSET &&
240+
shadowTexCoords.y > SHADOW_DIRECTIONAL_SEAM_INSET && shadowTexCoords.y < 1.0 - SHADOW_DIRECTIONAL_SEAM_INSET &&
241+
shadowTexCoords.z > 0.5 + SHADOW_DIRECTIONAL_SEAM_INSET && shadowTexCoords.z < 1.0 - SHADOW_DIRECTIONAL_SEAM_INSET) // TODO: figure out why shadowTexCoords.z range is 0.5 to 1.0.
238242
{
239243
float shadowZ = shadowTexCoords.z;
240244
float shadowZExp = exp(-lightShadowExponent * shadowZ);
@@ -246,7 +250,30 @@ float computeShadowScalarDirectional(vec4 position, int shadowIndex)
246250
return 1.0;
247251
}
248252

249-
float geometryTravelPoint(vec4 position, int lightIndex, int shadowMapIndex)
253+
float computeShadowScalarCascaded(vec4 position, float shadowCutoff, int shadowIndex)
254+
{
255+
for (int i = 0; i < SHADOW_CASCADE_LEVELS; ++i)
256+
{
257+
mat4 shadowMatrix = shadowMatrices[SHADOW_TEXTURES_MAX + (shadowIndex - SHADOW_TEXTURES_MAX) * SHADOW_CASCADE_LEVELS + i];
258+
vec4 positionShadowClip = shadowMatrix * position;
259+
vec3 shadowTexCoordsProj = positionShadowClip.xyz / positionShadowClip.w;
260+
vec3 shadowTexCoords = shadowTexCoordsProj * 0.5 + 0.5;
261+
if (shadowTexCoords.x > SHADOW_CASCADE_SEAM_INSET && shadowTexCoords.x < 1.0 - SHADOW_CASCADE_SEAM_INSET &&
262+
shadowTexCoords.y > SHADOW_CASCADE_SEAM_INSET && shadowTexCoords.y < 1.0 - SHADOW_CASCADE_SEAM_INSET &&
263+
shadowTexCoords.z > 0.5 + SHADOW_CASCADE_SEAM_INSET && shadowTexCoords.z < 1.0 - SHADOW_CASCADE_SEAM_INSET) // TODO: figure out why shadowTexCoords.z range is 0.5 to 1.0.
264+
{
265+
float shadowZ = shadowTexCoordsProj.z * 0.5 + 0.5;
266+
float shadowZExp = exp(-lightShadowExponent * shadowZ);
267+
float shadowDepthExp = texture(shadowCascades[shadowIndex - SHADOW_TEXTURES_MAX], vec3(shadowTexCoords.xy, float(i))).y;
268+
float shadowScalar = clamp(shadowZExp * shadowDepthExp, 0.0, 1.0);
269+
shadowScalar = pow(shadowScalar, lightShadowDensity);
270+
return shadowScalar;
271+
}
272+
}
273+
return 1.0;
274+
}
275+
276+
float geometryTravelPoint(vec4 position, int lightIndex, int shadowIndex)
250277
{
251278
// compute travel average in world space
252279
vec3 lightOrigin = lightOrigins[lightIndex];
@@ -260,7 +287,7 @@ float geometryTravelPoint(vec4 position, int lightIndex, int shadowMapIndex)
260287
for (int k = -1; k <= 1; k += 2)
261288
{
262289
vec3 offset = vec3(i, j, k) * lightShadowSampleScalar;
263-
float shadowDepth = texture(shadowMaps[shadowMapIndex], positionShadow + offset).x;
290+
float shadowDepth = texture(shadowMaps[shadowIndex - SHADOW_TEXTURES_MAX], positionShadow + offset).x;
264291
float delta = shadowZ - shadowDepth;
265292
travel += max(0.0, delta);
266293
}
@@ -330,6 +357,34 @@ float geometryTravelDirectional(vec4 position, int lightIndex, int shadowIndex)
330357
return 1.0;
331358
}
332359

360+
float geometryTravelCascaded(vec4 position, int lightIndex, int shadowIndex)
361+
{
362+
for (int i = 0; i < SHADOW_CASCADE_LEVELS; ++i)
363+
{
364+
// attempt to compute travel average in view space
365+
mat4 shadowMatrix = shadowMatrices[SHADOW_TEXTURES_MAX + (shadowIndex - SHADOW_TEXTURES_MAX) * SHADOW_CASCADE_LEVELS + i];
366+
vec4 positionShadowClip = shadowMatrix * position;
367+
vec3 shadowTexCoordsProj = positionShadowClip.xyz / positionShadowClip.w; // ndc space
368+
vec3 shadowTexCoords = shadowTexCoordsProj * 0.5 + 0.5; // adj-ndc space
369+
if (shadowTexCoords.x > 0.0 && shadowTexCoords.x < 1.0 &&
370+
shadowTexCoords.y > 0.0 && shadowTexCoords.y < 1.0 &&
371+
shadowTexCoords.z > 0.5 && shadowTexCoords.z < 1.0) // TODO: figure out why shadowTexCoords.z range is 0.5 to 1.0.
372+
{
373+
// compute light distance travel through surface (not accounting for incidental surface concavity)
374+
float shadowZScreen = shadowTexCoords.z; // linear, screen space
375+
vec2 shadowTextureSize = textureSize(shadowCascades[shadowIndex - SHADOW_TEXTURES_MAX], 0).xy;
376+
vec2 shadowTexelSize = 1.0 / shadowTextureSize;
377+
float shadowDepthScreen = texture(shadowCascades[shadowIndex - SHADOW_TEXTURES_MAX], vec3(shadowTexCoords.xy, float(i))).x; // linear, screen space
378+
float delta = shadowZScreen - shadowDepthScreen;
379+
float shadowFar = lightCutoffs[lightIndex];
380+
return max(0.0, delta * shadowFar);
381+
}
382+
}
383+
384+
// tracing out of range, return default
385+
return 1.0;
386+
}
387+
333388
vec3 computeSubsurfaceScatter(vec4 position, vec3 albedo, vec4 subdermalPlus, vec4 scatterPlus, float nDotL, vec2 texCoords, int lightIndex)
334389
{
335390
// retrieve light and shadow values
@@ -343,14 +398,17 @@ vec3 computeSubsurfaceScatter(vec4 position, vec3 albedo, vec4 subdermalPlus, ve
343398
switch (lightType)
344399
{
345400
case 0: // point light
346-
travel = geometryTravelPoint(position, lightIndex, shadowIndex - SHADOW_TEXTURES_MAX);
401+
travel = geometryTravelPoint(position, lightIndex, shadowIndex);
347402
break;
348403
case 1: // spot light
349404
travel = geometryTravelSpot(position, lightIndex, shadowIndex);
350405
break;
351-
default: // directional light
406+
case 2: // directional light
352407
travel = geometryTravelDirectional(position, lightIndex, shadowIndex);
353408
break;
409+
default: // cascaded light
410+
travel = geometryTravelCascaded(position, lightIndex, shadowIndex);
411+
break;
354412
}
355413
}
356414

@@ -601,6 +659,66 @@ vec3 computeFogAccumDirectional(vec4 position, int lightIndex)
601659
return result;
602660
}
603661

662+
vec3 computeFogAccumCascaded(vec4 position, int lightIndex)
663+
{
664+
vec3 result = vec3(0.0);
665+
int shadowIndex = lightShadowIndices[lightIndex];
666+
if (shadowIndex >= 0)
667+
{
668+
// grab light values
669+
vec3 lightOrigin = lightOrigins[lightIndex];
670+
vec3 lightDirection = lightDirections[lightIndex];
671+
672+
// compute ray info
673+
vec3 startPosition = eyeCenter;
674+
vec3 rayVector = position.xyz - startPosition;
675+
float rayLength = length(rayVector);
676+
vec3 rayDirection = rayVector / rayLength;
677+
678+
// compute step info
679+
float stepLength = rayLength / ssvfSteps;
680+
vec3 step = rayDirection * stepLength;
681+
682+
// compute light view term
683+
float theta = dot(-rayDirection, lightDirection);
684+
685+
// compute dithering
686+
float dithering = SSVF_DITHERING[int(gl_FragCoord.x) % 4][int(gl_FragCoord.y) % 4];
687+
688+
// march over ray, accumulating fog light value
689+
vec3 currentPosition = startPosition + step * dithering;
690+
for (int i = 0; i < ssvfSteps; ++i)
691+
{
692+
// use the nearest available cascade for this step
693+
for (int j = 0; j < SHADOW_CASCADE_LEVELS; ++j)
694+
{
695+
// compute depths
696+
mat4 shadowMatrix = shadowMatrices[SHADOW_TEXTURES_MAX + (shadowIndex - SHADOW_TEXTURES_MAX) * SHADOW_CASCADE_LEVELS + j];
697+
vec4 positionShadowClip = shadowMatrix * vec4(currentPosition, 1.0);
698+
vec3 shadowTexCoordsProj = positionShadowClip.xyz / positionShadowClip.w;
699+
vec3 shadowTexCoords = shadowTexCoordsProj * 0.5 + 0.5;
700+
bool shadowTexCoordsInRange = shadowTexCoords.x >= 0.0 && shadowTexCoords.x < 1.0 && shadowTexCoords.y >= 0.0 && shadowTexCoords.y < 1.0;
701+
float shadowZ = shadowTexCoords.z;
702+
float shadowDepth = shadowTexCoordsInRange ? texture(shadowCascades[shadowIndex - SHADOW_TEXTURES_MAX], vec3(shadowTexCoords.xy, float(i))).x : 1.0;
703+
704+
// step through ray, accumulating fog light moment
705+
if (shadowZ <= shadowDepth || shadowZ >= 1.0f)
706+
{
707+
// mie scaterring approximated with Henyey-Greenstein phase function
708+
float asymmetrySquared = ssvfAsymmetry * ssvfAsymmetry;
709+
float fogMoment = (1.0 - asymmetrySquared) / (4.0 * PI * pow(1.0 + asymmetrySquared - 2.0 * ssvfAsymmetry * theta, 1.5));
710+
result += fogMoment;
711+
}
712+
}
713+
714+
// step
715+
currentPosition += step;
716+
}
717+
result = smoothstep(0.0, 1.0, result / (ssvfSteps * SHADOW_CASCADE_LEVELS)) * lightColors[lightIndex] * lightBrightnesses[lightIndex] * ssvfIntensity;
718+
}
719+
return result;
720+
}
721+
604722
void main()
605723
{
606724
// ensure fragment was written
@@ -634,19 +752,20 @@ void main()
634752
{
635753
// per-light radiance
636754
vec3 lightOrigin = lightOrigins[i];
755+
float lightCutoff = lightCutoffs[i];
637756
int lightType = lightTypes[i];
638757
bool lightDirectional = lightType == 2;
758+
bool lightCascaded = lightType == 3;
639759
vec3 l, h, radiance;
640760
float intensity = 0.0;
641-
if (!lightDirectional)
761+
if (!lightDirectional && !lightCascaded)
642762
{
643763
vec3 d = lightOrigin - position.xyz;
644764
l = normalize(d);
645765
h = normalize(v + l);
646766
float distanceSquared = dot(d, d);
647767
float distance = sqrt(distanceSquared);
648-
float cutoff = lightCutoffs[i];
649-
float cutoffScalar = 1.0 - smoothstep(cutoff * (1.0 - lightCutoffMargin), cutoff, distance);
768+
float cutoffScalar = 1.0 - smoothstep(lightCutoff * (1.0 - lightCutoffMargin), lightCutoff, distance);
650769
float attenuation = 1.0 / (ATTENUATION_CONSTANT + lightAttenuationLinears[i] * distance + lightAttenuationQuadratics[i] * distanceSquared);
651770
float angle = acos(dot(l, -lightDirections[i]));
652771
float halfConeInner = lightConeInners[i] * 0.5;
@@ -672,9 +791,10 @@ void main()
672791
{
673792
switch (lightType)
674793
{
675-
case 0: { shadowScalar = computeShadowScalarPoint(position, lightOrigin, shadowIndex - SHADOW_TEXTURES_MAX); break; } // point
794+
case 0: { shadowScalar = computeShadowScalarPoint(position, lightOrigin, shadowIndex); break; } // point
676795
case 1: { shadowScalar = computeShadowScalarSpot(position, lightConeOuters[i], shadowIndex); break; } // spot
677-
default: { shadowScalar = computeShadowScalarDirectional(position, shadowIndex); break; } // directional
796+
case 2: { shadowScalar = computeShadowScalarDirectional(position, shadowIndex); break; } // directional
797+
default: { shadowScalar = computeShadowScalarCascaded(position, lightCutoff, shadowIndex); break; } // cascaded
678798
}
679799
}
680800

@@ -713,7 +833,8 @@ void main()
713833
{
714834
case 0: { fogAccum.rgb += computeFogAccumPoint(position, i); break; } // point
715835
case 1: { fogAccum.rgb += computeFogAccumSpot(position, i); break; } // spot
716-
default: { fogAccum.rgb += computeFogAccumDirectional(position, i); break; } // directional
836+
case 2: { fogAccum.rgb += computeFogAccumDirectional(position, i); break; } // directional
837+
default: { fogAccum.rgb += computeFogAccumCascaded(position, i); break; } // cascaded
717838
}
718839
}
719840
}

0 commit comments

Comments
 (0)