<p>I am trying to implement the <a href="http://developer.download.nvidia.com/shaderlibrary/docs/shadow_PCSS.pdf" rel="nofollow noreferrer">Percentage-closer Soft Shadows</a> (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...</p>

<p>Here is my current setup.</p>

<p>I am using an orthographic camera to calculate my shadowmap. Here are the different steps and some pseudo-code.</p>

<pre><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);
</code></pre>

<p>In my shader, I am simply doing the blocker search part and here is also some pseudo-code.</p>

<pre><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 &lt; BLOCKER_SEARCH_NUM_SAMPLES; ++i)
{
    float shadowMapDepth = _ShadowTexture.Sample(sampleru_PointSampler, uv.xy + poissonDisk[i] * searchWidth).r;
    if (shadowMapDepth &lt; zReceiver)
    {
        blockerSum += shadowMapDepth;
        numBlockers++;
    }
}
float avgBlockerDepth = blockerSum / numBlockers;
return avgBlockerDepth;
</code></pre>

<p>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.</p>

<p><a href="https://i.sstatic.net/uBosM.jpg" rel="nofollow noreferrer"><img src="https://i.sstatic.net/uBosM.jpg" alt="pcss"></a></p>

<p>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.</p>

<h1>Additional information</h1>

<p>I've rebuilt my system and I better understand the whole thing and I also think that I know where the issue comes from.</p>

<p>Let's focus on the near plane value, the shadow map and the zReceiver which is the z projection coordinate.</p>

<p>The shadow map and the zReceiver are calculated within the light view space as you can see in the following screenshot.</p>

<p><a href="https://i.sstatic.net/8KSCZ.jpg" rel="nofollow noreferrer"><img src="https://i.sstatic.net/8KSCZ.jpg" alt="enter image description here"></a></p>

<p>Now let's see how the searchWidth is calculated and some screenshots with different NEAR_PLANE values.</p>

<pre><code>float searchWidth = LIGHT_SIZE_UV * (zReceiver - NEAR_PLANE) / zReceiver;
</code></pre>

<p>In those examples only the NEAR_PLANE value is changed and the camera near plane remains to 0.</p>

<p><a href="https://i.sstatic.net/pC0lH.jpg" rel="nofollow noreferrer"><img src="https://i.sstatic.net/pC0lH.jpg" alt="enter image description here"></a></p>

<p>As you can see with a NEAR_PLANE value of zero the searchWidth doesn't vary compared to other values. But I think that other values are wrong and don't behave right as I am using a directional light. Indeed, the penumbra should not be affected by the distance from the object to the light. To try fixing this, I only used the zReceiver without taking in account the NEAR_PLANE value and the results are not good.</p>

<pre><code>float searchWidth = LIGHT_SIZE_UV * zReceiver;
</code></pre>

<p>As you can see in the following screenshots, in the red circles as you move the object far according to the shadow map, the width gets bigger and it shouldn't.</p>

<p><a href="https://i.sstatic.net/HniVt.jpg" rel="nofollow noreferrer"><img src="https://i.sstatic.net/HniVt.jpg" alt="enter image description here"></a></p>

<p>The correct behaviour is that the searchWidth shouldn't be affected by the object position in the shadow map but more by its height. I think that this should makes sense.</p>

<p>I would like know how could I calculate the searchWidth as it seems that my problem comes from its calculation. Maybe the issue also comes from the shadowmap or the zReceiver but I have some doubts about it.</p>

CC BY-SA 3.0
2016-12-12T23:11:11.320Z
Are you able to share your actual code (as opposed to pseudo-code)? That way we can test it rather than just reason about it. Incidentally, that's a lot of semicolons for pseudocode - it almost looks as if it would compile...
trichoplax is on Codidact now
CC BY-SA 3.0
2016-12-13T00:20:37.173Z
Thanks for your answer @trichoplax. Concerning the screenshot it might be awkward as the whole thing is wrong because as you move the cylinder, you can notice that the penumbra doesn't behaves well.
I would be glad to share the code because I am losing all my hair trying to make true PCSS... I just need to clean the code a bit :)
MaT
CC BY-SA 3.0
2016-12-13T00:22:03.370Z
Will post some source soon. Hope somebody can help about that.
MaT
CC BY-SA 3.0
2016-12-13T09:19:24.510Z
I meant "the right seems to be correct and the left not". So, no error in the description.
MaT
CC BY-SA 3.0
2016-12-14T14:07:39.877Z
I've posted a new answer to avoid making a huuuuge question.
MaT
CC BY-SA 3.0
2016-12-14T14:40:38.620Z
Alright, I'll move it to the question.
MaT
CC BY-SA 3.0
2016-12-14T14:41:49.160Z
Incidentally, it's very well written. I was ready to upvote the answer if it had a solution at the end.
trichoplax is on Codidact now
CC BY-SA 3.0
2016-12-14T14:45:13.880Z
@trichoplax Thanks I think that it's better to give as much informations as possible especially with this kind of topics. It also might help others.
If you know somebody that might be able to help don't hesitate ;)
MaT
CC BY-SA 3.0
2016-12-15T19:28:18.150Z
Alright I think I got something by using the distance between the receiver and the blocker. Now I need to apply it correctly.
MaT
<rendering><shader><lighting><shadow><shadow-mapping>
Percentage-closer Soft Shadows implementation
MaT
# Percentage-closer Soft Shadows implementation

(Asked by: username_0 on 2016-12-12)

I am trying to implement the [Percentage-closer Soft Shadows](http://developer.download.nvidia.com/shaderlibrary/docs/shadow_PCSS.pdf) (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 am 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.

```
#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.

[![pcss](https://i.sstatic.net/uBosM.jpg)](https://i.sstatic.net/uBosM.jpg)

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.

# Additional information

I've rebuilt my system and I better understand the whole thing and I also think that I know where the issue comes from.

Let's focus on the near plane value, the shadow map and the zReceiver which is the z projection coordinate.

The shadow map and the zReceiver are calculated within the light view space as you can see in the following screenshot.

[![enter image description here](https://i.sstatic.net/8KSCZ.jpg)](https://i.sstatic.net/8KSCZ.jpg)

Now let's see how the searchWidth is calculated and some screenshots with different NEAR\_PLANE values.

```
float searchWidth = LIGHT_SIZE_UV * (zReceiver - NEAR_PLANE) / zReceiver;

```

In those examples only the NEAR\_PLANE value is changed and the camera near plane remains to 0.

[![enter image description here](https://i.sstatic.net/pC0lH.jpg)](https://i.sstatic.net/pC0lH.jpg)

As you can see with a NEAR\_PLANE value of zero the searchWidth doesn't vary compared to other values. But I think that other values are wrong and don't behave right as I am using a directional light. Indeed, the penumbra should not be affected by the distance from the object to the light. To try fixing this, I only used the zReceiver without taking in account the NEAR\_PLANE value and the results are not good.

```
float searchWidth = LIGHT_SIZE_UV * zReceiver;

```

As you can see in the following screenshots, in the red circles as you move the object far according to the shadow map, the width gets bigger and it shouldn't.

[![enter image description here](https://i.sstatic.net/HniVt.jpg)](https://i.sstatic.net/HniVt.jpg)

The correct behaviour is that the searchWidth shouldn't be affected by the object position in the shadow map but more by its height. I think that this should makes sense.

I would like know how could I calculate the searchWidth as it seems that my problem comes from its calculation. Maybe the issue also comes from the shadowmap or the zReceiver but I have some doubts about it.

**Tags:** rendering, shader, lighting, shadow, shadow-mapping

> **Comments:**
> **username_1**: Are you able to share your actual code (as opposed to pseudo-code)? That way we can test it rather than just reason about it. Incidentally, that's a lot of semicolons for pseudocode - it almost looks as if it would compile...  
> **username_0**: Thanks for your answer @username_1. Concerning the screenshot it might be awkward as the whole thing is wrong because as you move the cylinder, you can notice that the penumbra doesn't behaves well. I would be glad to share the code because I am losing all my hair trying to make true PCSS... I just need to clean the code a bit :)  
> **username_0**: Will post some source soon. Hope somebody can help about that.  
> **username_0**: I meant "the right seems to be correct and the left not". So, no error in the description.  
> **username_0**: I've posted a new answer to avoid making a huuuuge question.  
> **username_0**: Alright, I'll move it to the question.  
> **username_1**: Incidentally, it's very well written. I was ready to upvote the answer if it had a solution at the end.  
> **username_0**: @username_1 Thanks I think that it's better to give as much informations as possible especially with this kind of topics. It also might help others. If you know somebody that might be able to help don't hesitate ;)  
> **username_0**: Alright I think I got something by using the distance between the receiver and the blocker. Now I need to apply it correctly.  

---

## 0 answers

