Fix normal bias for spotlights.
The normal bias is now computed correctly, this requires to compute the z in lightspace in the shader. Note that this would not work as well if we used LISPSM, but we'll cross that bridge when we get there.
This commit is contained in:
committed by
Mathias Agopian
parent
21db695e79
commit
f9aaf5c42e
@@ -427,8 +427,11 @@ void ShadowMap::updateSpot(const FScene::LightSoa& lightData, size_t index,
|
||||
// Project receivers, casters and view onto near plane,
|
||||
// compute intersection of that which gives the l,r,t,b planes
|
||||
|
||||
// FIXME: texelSizeWorldSpace doesn't work for spotlights
|
||||
mTexelSizeWs = 0; //texelSizeWorldSpace(Mp, mat4f(MbMt));
|
||||
// For spotlights, we store the texel size at 1 world unit
|
||||
// The size of a texel in world unit is given by: (near/dimension) / lightspace.z,
|
||||
// when computing the required bias we need a half-texel size, so we multiply by 0.5 here.
|
||||
// Note: this would not work with LISPSM, which warps the texture space.
|
||||
mTexelSizeWs = 0.5f * nearPlane / float(mShadowMapInfo.shadowDimension);
|
||||
|
||||
if (!mShadowMapInfo.vsm) {
|
||||
mLightSpace = St;
|
||||
|
||||
@@ -8,18 +8,37 @@
|
||||
* The returned point may contain a bias to attempt to eliminate common
|
||||
* shadowing artifacts such as "acne". To achieve this, the world space
|
||||
* normal at the point must also be passed to this function.
|
||||
* Normal bias is not used for VSM.
|
||||
*/
|
||||
highp vec4 computeLightSpacePosition(const highp vec3 p, const highp vec3 n, const highp vec3 l,
|
||||
const float b, const highp mat4 lightFromWorldMatrix) {
|
||||
|
||||
#if defined(HAS_VSM)
|
||||
// VSM don't apply the shadow bias
|
||||
highp vec4 lightSpacePosition = mulMat4x4Float3(lightFromWorldMatrix, p);
|
||||
#else
|
||||
float NoL = saturate(dot(n, l));
|
||||
float sinTheta = sqrt(1.0 - NoL * NoL);
|
||||
highp vec3 offsetPosition = p + n * (sinTheta * b);
|
||||
highp vec4 lightSpacePosition = mulMat4x4Float3(lightFromWorldMatrix, offsetPosition);
|
||||
#endif
|
||||
return lightSpacePosition;
|
||||
#if defined(HAS_DIRECTIONAL_LIGHTING)
|
||||
highp vec4 computeLightSpacePositionDirectional(const highp vec3 p, const highp vec3 n,
|
||||
const highp vec3 l, const float b, const highp mat4 lightFromWorldMatrix) {
|
||||
return mulMat4x4Float3(lightFromWorldMatrix, p);
|
||||
}
|
||||
#endif
|
||||
#endif // HAS_DIRECTIONAL_LIGHTING
|
||||
#if defined(HAS_DYNAMIC_LIGHTING)
|
||||
highp vec4 computeLightSpacePositionSpot(const highp vec3 p, const highp vec3 n,
|
||||
const highp vec3 l, const float b, const highp mat4 lightFromWorldMatrix) {
|
||||
return mulMat4x4Float3(lightFromWorldMatrix, p);
|
||||
}
|
||||
#endif // HAS_DYNAMIC_LIGHTING
|
||||
#else // HAS_VSM
|
||||
highp vec4 computeLightSpacePositionDirectional(const highp vec3 p, const highp vec3 n,
|
||||
const highp vec3 l, const float b, const highp mat4 lightFromWorldMatrix) {
|
||||
float NoL = saturate(dot(n, l));
|
||||
highp float sinTheta = sqrt(1.0 - NoL * NoL);
|
||||
highp vec3 offsetPosition = p + n * (sinTheta * b);
|
||||
return mulMat4x4Float3(lightFromWorldMatrix, offsetPosition);
|
||||
}
|
||||
#if defined(HAS_DYNAMIC_LIGHTING)
|
||||
highp vec4 computeLightSpacePositionSpot(const highp vec3 p, const highp vec3 n,
|
||||
const highp vec3 l, const float b, const highp mat4 lightFromWorldMatrix) {
|
||||
highp vec4 positionLs = mulMat4x4Float3(lightFromWorldMatrix, p);
|
||||
highp float oneOverZ = positionLs.w / positionLs.z;
|
||||
return computeLightSpacePositionDirectional(p, n, l, b * oneOverZ, lightFromWorldMatrix);
|
||||
}
|
||||
#endif // HAS_DIRECTIONAL_LIGHTING
|
||||
#endif // HAS_VSM
|
||||
#endif // HAS_SHADOWING
|
||||
|
||||
@@ -102,7 +102,7 @@ highp vec3 getNormalizedViewportCoord2() {
|
||||
highp vec4 getSpotLightSpacePosition(uint index) {
|
||||
highp vec3 dir = shadowUniforms.shadows[index].direction;
|
||||
float bias = shadowUniforms.shadows[index].normalBias;
|
||||
return computeLightSpacePosition(vertex_worldPosition.xyz,
|
||||
return computeLightSpacePositionSpot(vertex_worldPosition.xyz,
|
||||
vertex_worldNormal, dir, bias, shadowUniforms.shadows[index].lightFromWorldMatrix);
|
||||
}
|
||||
#endif
|
||||
@@ -128,13 +128,13 @@ uint getShadowCascade() {
|
||||
highp vec4 getCascadeLightSpacePosition(uint cascade) {
|
||||
// For the first cascade, return the interpolated light space position.
|
||||
// This branch will be coherent (mostly) for neighboring fragments, and it's worth avoiding
|
||||
// the matrix multiply inside computeLightSpacePosition.
|
||||
// the matrix multiply inside computeLightSpacePositionDirectional.
|
||||
if (cascade == 0u) {
|
||||
// Note: this branch may cause issues with derivatives
|
||||
return vertex_lightSpacePosition;
|
||||
}
|
||||
|
||||
return computeLightSpacePosition(getWorldPosition(), getWorldNormalVector(),
|
||||
return computeLightSpacePositionDirectional(getWorldPosition(), getWorldNormalVector(),
|
||||
frameUniforms.lightDirection, frameUniforms.shadowBias.y,
|
||||
frameUniforms.lightFromWorldMatrix[cascade]);
|
||||
}
|
||||
|
||||
+2
-1
@@ -89,7 +89,8 @@ void main() {
|
||||
#endif
|
||||
|
||||
#if defined(HAS_SHADOWING) && defined(HAS_DIRECTIONAL_LIGHTING)
|
||||
vertex_lightSpacePosition = computeLightSpacePosition(vertex_worldPosition.xyz, vertex_worldNormal,
|
||||
vertex_lightSpacePosition = computeLightSpacePositionDirectional(
|
||||
vertex_worldPosition.xyz, vertex_worldNormal,
|
||||
frameUniforms.lightDirection, frameUniforms.shadowBias.y, getLightFromWorldMatrix());
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user