Search Unity

Deferred Decals to Forward Decals

Discussion in 'General Graphics' started by Kalidor, Sep 26, 2017.

  1. Kalidor

    Kalidor

    Joined:
    Sep 13, 2017
    Posts:
    14
    Hi!

    I'am using a deferred decal system. I want to have the possibility to switch to forward rendering.

    I tried it with using Graphics.DrawMesh only. It works, but with undesired shown decals (without _NormasCopy). I don't know how to convert the _NormalsCopy part to forward rendering.

    Thank you!

    Shader Code:
    Code (CSharp):
    1. sampler2D _MainTex;
    2. sampler2D _NormalMap;
    3. float _Alpha;
    4. sampler2D_float _CameraDepthTexture;
    5. sampler2D _NormalsCopy;
    6.  
    7. void frag(v2f i, out half4 outDiffuse : COLOR0, out half4 outNormal : COLOR1)
    8. {
    9.     i.ray = i.ray * (_ProjectionParams.z / i.ray.z);
    10.     float2 uv = i.screenUV.xy / i.screenUV.w;
    11.     float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
    12.     depth = Linear01Depth (depth);
    13.     float4 vpos = float4(i.ray * depth,1);
    14.     float3 wpos = mul (unity_CameraToWorld, vpos).xyz;
    15.     float3 opos = mul (unity_WorldToObject, float4(wpos, 1)).xyz;
    16.  
    17.     clip (float3(0.5, 0.5, 0.5) - abs(opos.xyz));
    18.  
    19.     i.uv = opos.xz + 0.5;
    20.  
    21.     half3 normal = tex2D(_NormalsCopy, uv).rgb;
    22.     fixed3 wnormal = normal.rgb * 2.0 - 1.0;
    23.     clip (dot(wnormal, i.orientation) - 0.3);
    24.  
    25.     fixed4 col = tex2D (_MainTex, i.uv);
    26.     col.a *= _Alpha;
    27.     outDiffuse = col;
    28.  
    29.     fixed3 nor = UnpackNormal(tex2D(_NormalMap, i.uv));
    30.     half3x3 norMat = half3x3(i.orientationX, i.orientationZ, i.orientation);
    31.     nor = mul (nor, norMat);
    32.     outNormal = fixed4(nor * 0.5 + 0.5, col.a);
    33. }
    Render Code:

    Code (CSharp):
    1. Camera camera = Camera.current;
    2.  
    3. if (!camera)
    4. {
    5.     return;
    6. }
    7.  
    8. CommandBuffer buffer = null;
    9.  
    10. if (cameras.ContainsKey(camera))
    11. {
    12.     buffer = cameras[camera];
    13.     buffer.Clear();
    14. }
    15.  
    16. else
    17. {
    18.     buffer = new CommandBuffer();
    19.     cameras[camera] = buffer;
    20.     camera.AddCommandBuffer(CameraEvent.BeforeLighting, buffer);
    21. }
    22.  
    23. var normalsID = Shader.PropertyToID("_NormalsCopy");
    24. buffer.GetTemporaryRT(normalsID, -1, -1);
    25. buffer.Blit(BuiltinRenderTextureType.GBuffer2, normalsID);
    26.  
    27. RenderTargetIdentifier[] mrt = { BuiltinRenderTextureType.GBuffer0, BuiltinRenderTextureType.GBuffer2 };
    28. buffer.SetRenderTarget(mrt, BuiltinRenderTextureType.CameraTarget);
    29.  
    30. foreach (Decal decal in DecalManager.Instance.decals)
    31. {
    32.     if (decal)
    33.     {
    34.         buffer.DrawMesh(mesh, decal.transform.localToWorldMatrix, decal.material);
    35.     }
    36. }
    37.  
    38. buffer.ReleaseTemporaryRT(normalsID);
     
  2. brianasu

    brianasu

    Joined:
    Mar 9, 2010
    Posts:
    369
    I think Gbuffer2 target is only for deferred rendering. Forward rendering does not render a gbuffer. You have to manually set the camera.depthmode != DepthTextureMode.DepthNormals. This will make the camera render a depth + normals global texture called _CameraDepthNormals

    https://docs.unity3d.com/Manual/SL-CameraDepthTexture.html
     
  3. Kalidor

    Kalidor

    Joined:
    Sep 13, 2017
    Posts:
    14
    Thank you, i got it working with the DepthNormal texture!
     
  4. DanielDickinson

    DanielDickinson

    Joined:
    Aug 4, 2013
    Posts:
    278
    @Kalidor - I've written what you're currently writing now (essentially screen-space decals). If you're interested I thought I would jump in and share the 2 biggest problems, and solutions I had. Who knows, you or someone else might come up with better solutions and return the favor.

    1. Banding - The depth you get from depthNormals texture is only 16bit, and the normals only 8bit. This can lead to "banding", especially in the scene view, which has a very large far clipping plane. (depth is a stored as an exponential value between these planes, so as the distance between these planes grows, you lose accuracy, which causes banding). If you render both depth and depthNormals you can use the high precision depth from the depth texture and the low precision normals from the normal texture and ignore the normal artifacts, which are usually pretty hard to notice. Or you could roll your own multi-pass shader replacement solution that uses ARGB2101010 to get 10bit normals.

    2. - Edge artifacts - This article actually sums it up quite nicely (http://aras-p.info/blog/2010/01/07/screenspace-vs-mip-mapping/) I dropped mipmapping when sampling just the occlusion of my decals. It's not ideal but supported everywhere.
     
  5. brianasu

    brianasu

    Joined:
    Mar 9, 2010
    Posts:
    369
    Your Dynamic decals look impressive. Have you looked at http://www.humus.name/index.php?page=3D&start=8 he uses decals to render roads and mentions issue #2.

    He also has a demo of 3d texture decals that might be a cool feature you could add. I think you have something similar with a omni decal.