Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rendering): Add Shadow Normal Offset Bias in the deferred shading #1370

Merged
merged 1 commit into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Audio asset (#230, **@Dageus**, **@diogomsmiranda**).
- Compatibility with CMake find_package (#1326, **@RiscadoA**).
- A proper Nix package which can be used to install Cubos and Tesseratos (#1327, **RiscadoA**).
- Added the option to use Shadow Normal Offset Bias algorithm (#1308, **@GalaxyCrush**)

### Changed

Expand Down
24 changes: 21 additions & 3 deletions engine/assets/render/deferred_shading.fs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct DirectionalLight
vec4 shadowFarSplitDistances[3]; // intended to be a float array, but std140 layout aligns array elements
// to vec4 size; number of vec4s = ceiling(MaxCascades / 4 components)
int numCascades;
float normalOffsetScale;
};

struct PointLight
Expand All @@ -49,6 +50,7 @@ struct SpotLight
vec2 shadowMapSize;
float shadowBias;
float shadowBlurRadius;
float normalOffsetScale;
};

layout(std140) uniform PerScene
Expand Down Expand Up @@ -80,13 +82,27 @@ float remap(float value, float min1, float max1, float min2, float max2)
return max2 + (value - min1) * (max2 - min2) / (max1 - min1);
}

vec3 applyNormalOffset(vec3 normal, vec3 lightDir, vec3 position, float normalOffsetScale) {

float prod = dot(normal, lightDir);
prod = max(0.0, prod);

float slopeScale = 0.02;
float offset = slopeScale * prod + normalOffsetScale;

vec3 offsetPosition = position + normal * offset;
return offsetPosition;
}

vec3 spotLightCalc(vec3 fragPos, vec3 fragNormal, uint lightI)
{
// Shadows
float shadow = 0.0;
if (spotLights[lightI].shadowMapSize.x > 0.0)
{
vec4 positionLightSpace = spotLights[lightI].matrix * vec4(fragPos, 1.0);
float normalOffsetScale = spotLights[lightI].normalOffsetScale;
vec3 offsetFragPos = normalOffsetScale > 0.0 ? applyNormalOffset(fragNormal, spotLights[lightI].direction.xyz, fragPos, normalOffsetScale) : fragPos;
vec4 positionLightSpace = spotLights[lightI].matrix * vec4(offsetFragPos, 1.0);
vec3 projCoords = positionLightSpace.xyz / positionLightSpace.w;
projCoords = projCoords * 0.5 + 0.5;
vec2 uv = projCoords.xy * spotLights[lightI].shadowMapSize + spotLights[lightI].shadowMapOffset;
Expand Down Expand Up @@ -136,12 +152,14 @@ vec3 spotLightCalc(vec3 fragPos, vec3 fragNormal, uint lightI)

vec3 directionalLightCalc(vec3 fragPos, vec3 fragNormal, uint lightI, bool drawShadows)
{
float normalOffsetScale = directionalLights[lightI].normalOffsetScale;
vec3 offsetFragPos = normalOffsetScale > 0.0 ? applyNormalOffset(fragNormal, directionalLights[lightI].direction.xyz, fragPos, normalOffsetScale) : fragPos;
// Shadows
float shadow = 0.0;
if (drawShadows)
{
// Select split
vec4 positionCameraSpace = inverse(inverseView) * vec4(fragPos, 1.0);
vec4 positionCameraSpace = inverse(inverseView) * vec4(offsetFragPos, 1.0);
float depthCameraSpace = abs(positionCameraSpace.z);
int split = directionalLights[lightI].numCascades - 1;
for (int i = 0; i < directionalLights[lightI].numCascades; i++)
Expand All @@ -155,7 +173,7 @@ vec3 directionalLightCalc(vec3 fragPos, vec3 fragNormal, uint lightI, bool drawS
}

// Sample shadow map
vec4 positionLightSpace = directionalLights[lightI].matrices[split] * vec4(fragPos, 1.0);
vec4 positionLightSpace = directionalLights[lightI].matrices[split] * vec4(offsetFragPos, 1.0);
vec3 projCoords = positionLightSpace.xyz / positionLightSpace.w;
projCoords = projCoords * 0.5 + 0.5;
if (projCoords.z < 1.0)
Expand Down
7 changes: 4 additions & 3 deletions engine/include/cubos/engine/render/shadows/caster.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ namespace cubos::engine
{
CUBOS_REFLECT;

float bias = 0.002F; ///< Shadow bias.
float blurRadius = 1.0F; ///< Shadow blur radius.
int id = -1; ///< Caster id for the shadow atlas.
float bias = 0.001F; ///< Shadow bias.
float blurRadius = 0.005F; ///< Shadow blur radius.
int id = -1; ///< Caster id for the shadow atlas.
float normalOffsetScale = 0.007F; ///< Scale of the normal offset.
};
} // namespace cubos::engine
8 changes: 6 additions & 2 deletions engine/src/render/deferred_shading/plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@
4]; // intended to be a float array, but std140 layout aligns array elements
// to vec4 size; number of vec4s = ceiling(MaxCascades / 4 components)
int numCascades;
int padding2[3];
float normalOffsetScale;
int padding2[2];
};

struct PerPointLight
Expand All @@ -86,7 +87,8 @@
glm::vec2 shadowMapSize;
float shadowBias;
float shadowBlurRadius;
float padding[2];
float normalOffsetScale;
float padding[1];
};

struct PerScene
Expand Down Expand Up @@ -332,6 +334,7 @@
perLight.shadowBlurRadius = caster.value().baseSettings.blurRadius;
perLight.numCascades = numCascades;
perScene.directionalLightWithShadowsId = directionalLightIndex;
perLight.normalOffsetScale = caster.value().baseSettings.normalOffsetScale;

Check warning on line 337 in engine/src/render/deferred_shading/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/render/deferred_shading/plugin.cpp#L337

Added line #L337 was not covered by tests
directionalShadowMap = caster.value().shadowMaps.at(cameraEntity)->cascades;
}
directionalLightIndex++;
Expand Down Expand Up @@ -375,6 +378,7 @@
perLight.shadowMapSize = slot->size;
perLight.shadowBias = caster.value().baseSettings.bias;
perLight.shadowBlurRadius = caster.value().baseSettings.blurRadius;
perLight.normalOffsetScale = caster.value().baseSettings.normalOffsetScale;

Check warning on line 381 in engine/src/render/deferred_shading/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/render/deferred_shading/plugin.cpp#L381

Added line #L381 was not covered by tests
}
else
{
Expand Down
1 change: 1 addition & 0 deletions engine/src/render/shadows/caster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
return core::ecs::TypeBuilder<ShadowCaster>("cubos::engine::ShadowCaster")
.withField("bias", &ShadowCaster::bias)
.withField("blurRadius", &ShadowCaster::blurRadius)
.withField("normalOffsetScale", &ShadowCaster::normalOffsetScale)

Check warning on line 12 in engine/src/render/shadows/caster.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/render/shadows/caster.cpp#L12

Added line #L12 was not covered by tests
.build();
}
Loading