Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Is there a way to fetch albedo/specular/smoothness/occlusion and normals in a deferred frag. shader?

Discussion in 'Shaders' started by bac9-flcl, Sep 6, 2015.

  1. bac9-flcl

    bac9-flcl

    Joined:
    Dec 5, 2012
    Posts:
    829
    The title pretty much covers it.

    I want to create an opaque per-pixel fragment shader that:
    • Will be rendered after all normal opaque surfaces but before all transparent surfaces
    • Will have albedo, specular, smoothness, occlusion values and normals fetched from the deferred render targets (for each given pixel)
    • Will output those fetched RT values
    Basically, this will make the shader completely invisible, as it will just write back the content of deferred render targets. This is the base I need to create proper UE4-like normal decals and some other stuff, but those are the easy part. What I need to figure out right now is how can I get that content from RTs. I'm unable to find anything about this in the documentation, but this should be possible - after all, Unity already offers a way to fetch values like linear eye depth, so asking to fetch something like smoothness is not exactly an exotic thing.

    Can anyone help me out?
     
  2. bac9-flcl

    bac9-flcl

    Joined:
    Dec 5, 2012
    Posts:
    829
    Update: figured the fetching part out. Now, is there any info on outputting the spec/normals/emissive back from the fragment correctly? Currently I'm using this:
    Code (csharp):
    1.  
    2.     void frag
    3.     (
    4.         v2f i,
    5.         out half4 outDiffuse : COLOR0,            // RT0: diffuse color (rgb), --unused-- (a)
    6.         out half4 outSpecRoughness : COLOR1,           // RT1: spec color (rgb), roughness (a)
    7.         out half4 outNormal : COLOR2,            // RT2: normal (rgb), --unused-- (a)
    8.         out half4 outEmission : COLOR3            // RT3: emission (rgb), --unused-- (a)
    9.     )
    10.     {
    11.         float2 uv = i.screenUV.xy / i.screenUV.w;
    12.         float4 gbuffer0 = tex2D (_CameraGBufferTexture0, uv);
    13.         float4 gbuffer1 = tex2D (_CameraGBufferTexture1, uv);
    14.         float4 gbuffer2 = tex2D (_CameraGBufferTexture2, uv);
    15.  
    16.         outDiffuse = gbuffer0;
    17.         outSpecRoughness = gbuffer1;
    18.         outNormal = gbuffer2;
    19.         outEmission = gbuffer3;
    20.     }
    21.  
    And that obviously results in just diffuse being rendered properly, because that's not a surface shader which will get shading out of the box. Nothing is lit, smoothness and normals have no influence.



    How can I make the shading replicate the standard PBR setup? Do I have to cram this horrifying set of operations right into my shader to get seamless shading with Standard surfaces on background? Or is there, maybe, some helpful inline I can just plug those outputs into?

    I have tried to use the same samplers in a surface shader to leverage auto shading there (with #pragma surface surf Standard and inout SurfaceOutputStandard o of course), but unfortunately I'm getting very weird artifacts with such a shader. It works only in a tiny set of object positions, as you can see here:

     
    Last edited: Sep 6, 2015