Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

PCSS Shadow Implementation Attempt

Discussion in 'Works In Progress - Archive' started by macdude2, Sep 19, 2016.

  1. macdude2

    macdude2

    Joined:
    Sep 22, 2010
    Posts:
    686
    For some reason, I had PCSS stuck in my mind for the past few days and couldn't find any code for it so I decided to try and implement it based on NVDIA's paper. Patched together code all over the internet for the shadow depth test/PCF and then implemented my own PCSS on top of it. It still needs a fair bit of work, but I can definitely post the code if people would be interested in seeing how it works! (Or have any interest in making it look a bit better!)

    Screen Shot 2016-09-19 at 12.38.17 PM.png
     
    TheMasonX, StaffanEk and Mauri like this.
  2. Manul

    Manul

    Joined:
    Nov 30, 2012
    Posts:
    18
    Hi macdude2 - I would be interested to look at your PCSS - working on a spotlight-reimplementation I plan to walk throughin a Unity Usergroup Talk - PCSS would be a nice addition. How did you integrate it with the rest of Unity Lighting ?
     
  3. macdude2

    macdude2

    Joined:
    Sep 22, 2010
    Posts:
    686
    That was the hardest part for sure, fortunately I found some code online that pretty much implemented it for directional lights. I was originally aiming to make the effect work for spotlights too - but I don't think I found any code for it online, and I wasn't really satisfied enough with the quality of the pcss here...

    Actually tho, found NVIDIA's actual shader source (which produced the output below). I directly translated it and things *almost* worked... Still suffers from aliasing. Not sure if there's any good way to fix this? Seems like NVDIA uses their custom interpolation function, maybe writing something like that would be the trick. Screen Shot 2016-09-30 at 6.06.07 PM.png
     
    TheMasonX likes this.
  4. TheMasonX

    TheMasonX

    Joined:
    Nov 9, 2012
    Posts:
    27
    Nice work! I finally got it somewhat working today using their "PCSS Integration" whitepaper. Like you said, it *almost* works, which made for a maddening time debugging to see what was throwing it. The main problem I had was that you can't read the declared shadow map's depth when it's a Texture2D and requires a sampler, unless I mucked around a fair bit with the built-in cg includes (may try another time though).

    They've got a complete version here with much more (derivative biasing, cubemaps, all sorts of cool stuff). It's actually part of a sample pack of a bunch of effects/whatever written for OpenGL ES, but it's pretty easy to translate, at least much easier than the stuff in their SDK haha.

    So I ended up using a command buffer to blit a copy in, which I've seen done a few times to get a hold of the shadowmap as a sampler2D, even in the Adam demo's smoke. I might do some extra smoothing and stuff this way too, depending on performance. But even with these somewhat kludgey methods, I still think I got it working somewhat decently so far.



    My main issue is the aliasing between different Poisson sample offsets, which I'll be working on next and would love to take with you about since you seem to have do it in the first one. You can obviously see it in the photos below, but the main thing I noticed was how much more important PCF is than blocking, at least the way I've got it set up.

    upload_2017-1-14_13-1-49.png

    I also found Nvidia's use of ordered Poisson points to be lacking, as interleaving them prevents them from aligning when using smaller sample sizes for performance reasons:

    upload_2017-1-14_13-15-21.png

    Anyways, I'll eventually be uploading this to GitHub, but I obviously have a lot of cleanup work to do first, both in visuals and code. But I think it's on the right track, and I bet I can figure out some more from that
     
    Reanimate_L and jdraper3 like this.
  5. TheMasonX

    TheMasonX

    Joined:
    Nov 9, 2012
    Posts:
    27
    Well, I improved it a bit, using the declared shadow map for the final PCF sampling, which at least smoothed out the edges. Still need to implement that "irregular sampling" to trade banding for noise, but I tried it anyways in a game I'm working on, The Universim (I'm trying to convince my boss to let me add them). Luckily, it's as easy as importing the shaders and adding the script to the light object. Here's the results outside a test environment:
    Forest Village.gif Well Girl.jpg PCSS Village 2.jpg Candid.jpg Building.jpg

    I'm super pleased with how they performed in game, and I think they really added a lot to the scene (maybe I'm just seeing what I want to see though haha). What do you guys think?
     
    Rodolfo-Rubens and jdraper3 like this.
  6. macdude2

    macdude2

    Joined:
    Sep 22, 2010
    Posts:
    686
    That looks sick! Nice job with that! How did you end up fixing the issues from the Poisson sampling? I know NVIDIA uses a special lerp algorithm to negate the affects of the sampling, but I tried using a standard one and the effects didn't really go away.

    Also, how did you manage to make edges of your shadows appear smooth? – mine look super aliased...
     
    TheMasonX likes this.
  7. TheMasonX

    TheMasonX

    Joined:
    Nov 9, 2012
    Posts:
    27
    Thanks! I'm not exactly sure what you mean. In that picture, I still have the banding (I have yet to figure out the "irregular sampling" mentioned briefly in their Advanced Shadows whitepaper but I haven't seen it in any of their implementations, so it can't be that important), but it's hidden by being in a more detailed scene, by using a slightly smaller light radius (my boss is a sucker for subtlety, so I made sure to keep it small to help convince him to let me add them), by using a large number of samples (32 each runs fine on my beast), and by using an exponential falloff (1f - (1f - x) * (1f - x)) so that the outsides blended in better (maybe not the most accurate, but it had a nice smoothing effect).

    As far as the smooth edges, I used a sampler2D that was blited in by a ComputeBuffer to get the depth for the blocker search, and the DECLARE_SHADOWMAP(tex) texture2D for the PCF Poisson sampling at the end, which is automatically filtered and soft at the edges. So not the best on texture memory, but it looks a bit nicer haha. If only the shadow map had a second SamplerState to use for depth...
     
    Last edited: Jan 17, 2017
  8. TheMasonX

    TheMasonX

    Joined:
    Nov 9, 2012
    Posts:
    27
    Oh, and a benefit of checking out their GitHub version I mentioned, was a "Depth Gradient" solution to the selfshadowing problem described in their Advanced Soft Shadows white paper. I get the dz_duv in the frag shader:
    float2 dz_duv = depthGradient(shadowCoord.xy, shadowCoord.z);

    // Derivatives of light-space depth with respect to texture2D coordinates
    float2 depthGradient(float2 uv, float z)
    {
    float2 dz_duv = float2(0.0, 0.0);

    float3 duvdist_dx = ddx(float3(uv, z));
    float3 duvdist_dy = ddy(float3(uv, z));

    dz_duv.x = duvdist_dy.y * duvdist_dx.z;
    dz_duv.x -= duvdist_dx.y * duvdist_dy.z;

    dz_duv.y = duvdist_dx.x * duvdist_dy.z;
    dz_duv.y -= duvdist_dy.x * duvdist_dx.z;

    float det = (duvdist_dx.x * duvdist_dy.y) - (duvdist_dx.y * duvdist_dy.x);
    dz_duv /= det;

    return dz_duv;
    }
    Which I pass into the PCSS, and then into both the blocker and pcfSampler, which use the eyeDepth (zReceiver), dz_duz (something about slopes and gradients), and then the uv offset (poisson * radius):
    float z = biasedZ(zReceiver, dz_duv, offset);

    float biasedZ(float z0, float2 dz_duv, float2 offset)
    {
    return z0 + dot(dz_duv, offset);
    }​
    Then you use this to test the depth/shadow sample instead of zReceiver, which helps a bit and is super cheap. EDIT: Didn't mean to pull an Nvidia on you there and release only some of what you needed haha. I wrote this after a full day of work, so I'm bound to make a mistake here and there haha
     
    Last edited: Jan 17, 2017
    zugsoft likes this.
  9. Flurgle

    Flurgle

    Joined:
    May 16, 2016
    Posts:
    389
    @macdude2 @TheMasonX Looks good, do you guys have a prototype / alpha shader we could try out (before the release)?
     
  10. macdude2

    macdude2

    Joined:
    Sep 22, 2010
    Posts:
    686
    There's actually a pcss shader on the asset store right now that is much better than anything I did!
     
  11. Flurgle

    Flurgle

    Joined:
    May 16, 2016
    Posts:
    389
    @macdude2 thanks, though a lot of us indie game jammers are looking for non commercial or FOSS solutions to muck around with :D
     
  12. macdude2

    macdude2

    Joined:
    Sep 22, 2010
    Posts:
    686
    On reddit, MasonX said he would release the source on GitHub. Tho I don't think he has yet. This is where it will show up apparently. https://github.com/TheMasonX/UnityPCSS

    I'd give you my source, but it doesn't work in Unity5 and I have yet to debug it... Not sure it would be of much use to you.
     
    Flurgle likes this.
  13. MaT227

    MaT227

    Joined:
    Jul 3, 2012
    Posts:
    628
    Hey everyone, I would have some question for the people who have worked on PCSS on Unity. I would like to know if they achieved to handle penumbra width variation as the object get far from the light source.
    Any idea about that ? @macdude2 @TheMasonX ?
     
  14. macdude2

    macdude2

    Joined:
    Sep 22, 2010
    Posts:
    686
  15. TheMasonX

    TheMasonX

    Joined:
    Nov 9, 2012
    Posts:
    27
    Sorry for the delay, but it's finally up! As @macdude2 said, it's available here: https://github.com/TheMasonX/UnityPCSS
     
    Oxanen and elias_t like this.
  16. macdude2

    macdude2

    Joined:
    Sep 22, 2010
    Posts:
    686
    Saw it on reddit yesterday! Looks very cool, will certainly have to try it out, thanks for making it public!