am trying to implement the Percentage-closer Soft Shadows (PCSS) from NVidia inside Unity but I am facing some issue and I don't know where they come from and then, I do not know how to solve them...
Here is my current setup.
I using an orthographic camera to calculate my shadowmap here are the different steps and some pseudo-code.
// Setup camera
_shadowCamera.clearFlags = CameraClearFlags.Depth;
_shadowCamera.orthographic= true;
// Setup a render texture to output the shadowmap from the camera
RenderTexture _shadowTexture = new RenderTexture((int)_shadowMapSize, _shadowMapSize, 16, RenderTextureFormat.Shadowmap, RenderTextureReadWrite.Linear);
// Render scene using a replacement shader. This is only used to output
_shadowCamera.SetReplacementShader(_shadowMapShader, "RenderType");
_shadowCamera.Render();
// Set the camera positions and matrix
_radius = _bounds;
Vector3 targetPos = _target.transform.position;
Vector3 lightDir = _light.transform.forward;
Quaternion lightRot = _light.transform.rotation;
_shadowCamera.transform.position = targetPos - lightDir * _radius;
_shadowCamera.transform.rotation = lightRot;
_shadowCamera.orthographicSize = _radius;
_shadowCamera.farClipPlane = _radius * 2.0f;
Matrix4x4 shadowViewMatrix = _shadowCamera.worldToCameraMatrix;
Matrix4x4 shadowProjectionMatrix = GL.GetGPUProjectionMatrix(_shadowCamera.projectionMatrix, false);
Matrix4x4 shadowBiasMatrix = Matrix4x4.identity;
shadowBiasMatrix.SetRow(0, new Vector4(0.5f, 0.0f, 0.0f, 0.5f));
shadowBiasMatrix.SetRow(1, new Vector4(0.0f, 0.5f, 0.0f, 0.5f));
shadowBiasMatrix.SetRow(2, new Vector4(0.0f, 0.0f, 1.0f, 0.0f));
shadowBiasMatrix.SetRow(3, new Vector4(0.0f, 0.0f, 0.0f, 1.0f));
_shadowMatrix = shadowBiasMatrix * shadowProjectionMatrix * shadowViewMatrix;
// Transfering data to shader
_material.SetMatrix("_ShadowMatrix", _shadowMatrix);
_material.SetTexture("_ShadowTexture", _shadowTexture);
_material.SetTexture("u_PointSampler", _pointSampler);
_material.SetFloat("u_NearPlane", _shadowCamera.nearClipPlane);
_material.SetFloat("u_LightWorldSize", _lightWorldSize);
_material.SetFloat("u_LightFrustrumWidth", _lightFrustrumWidth);
In my shader, I am simply doing the blocker search part and here is also some pseudo-code.
Nothing really different from nvidia code.
#define BLOCKER_SEARCH_NUM_SAMPLES 16
#define NEAR_PLANE u_NearPlane
#define LIGHT_WORLD_SIZE u_LightWorldSize
#define LIGHT_FRUSTUM_WIDTH u_LightFrustrumWidth
#define LIGHT_SIZE_UV (LIGHT_WORLD_SIZE / LIGHT_FRUSTUM_WIDTH)
uniform Texture2D _ShadowTexture;
uniform SamplerComparisonState sampler_ShadowTexture;
uniform Texture2D u_PointSampler;
uniform SamplerState sampleru_PointSampler;
half4 coords = mul(_ShadowMatrix, float4(worldPos.xyz, 1.f));
float2 uv = coords.xy;
float zReceiver = coords.z;
float searchWidth = LIGHT_SIZE_UV * (zReceiver - NEAR_PLANE) / zReceiver;
float blockerSum = u_PointSampler.Sample(sampleru_PointSampler, float2(0, 0)).a;
float numBlockers = 0;
for (int i = 0; i < BLOCKER_SEARCH_NUM_SAMPLES; ++i)
{
float shadowMapDepth = _ShadowTexture.Sample(sampleru_PointSampler, uv.xy + poissonDisk[i] * searchWidth).r;
if (shadowMapDepth < zReceiver)
{
blockerSum += shadowMapDepth;
numBlockers++;
}
}
float avgBlockerDepth = blockerSum / numBlockers;
return avgBlockerDepth;
Here is an example of my issue. As you can see on the right the shadowing seems correct but if you move the cylinder, you can see on the left, the penumbra is not computed correctly.
As I said I don't know what I am doing wrong, I suppose that this comes from the matrix or maybe the depth but there might be some other problems.
Any help is welcome, Thanks !