Search Unity

Internal-DeferredShading.shader -> Adding my self generated diffuse light

Discussion in 'Shaders' started by Quatum1000, Jul 22, 2021.

  1. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    889
    Hi,
    I wrote a easy solution to add pre-rendered diffuse light as image effect to the world scene.

    I thought to use it in Internal-DeferredShading.shader and I need (_WorldSpaceCameraPos, wpos.xz, data.normalWorld) variables to get it to work.

    Code (CSharp):
    1. half4 CalculateLight (unity_v2f_deferred i)
    2. {
    3.     float3 wpos;
    4.     float2 uv;
    5.     float atten, fadeDist;
    6.     UnityLight light;
    7.     UNITY_INITIALIZE_OUTPUT(UnityLight, light);
    8.     UnityDeferredCalculateLightParams (i, wpos, uv, light.dir, atten, fadeDist);
    9.  
    10.     light.color = _LightColor.rgb * atten;
    11.  
    12.     // unpack Gbuffer
    13.     half4 gbuffer0 = tex2D (_CameraGBufferTexture0, uv);
    14.     half4 gbuffer1 = tex2D (_CameraGBufferTexture1, uv);
    15.     half4 gbuffer2 = tex2D (_CameraGBufferTexture2, uv);
    16.     UnityStandardData data = UnityStandardDataFromGbuffer(gbuffer0, gbuffer1, gbuffer2);
    17.  
    18.     float3 eyeVec = normalize(wpos-_WorldSpaceCameraPos);
    19.     half oneMinusReflectivity = 1 - SpecularStrength(data.specularColor.rgb);
    20.  
    21.     UnityIndirect ind;
    22.     UNITY_INITIALIZE_OUTPUT(UnityIndirect, ind);
    23.     ind.diffuse = 0;
    24.     ind.specular = 0;
    25.  
    26.     half4 res = UNITY_BRDF_PBS (data.diffuseColor, data.specularColor, oneMinusReflectivity,
    27.     data.smoothness, data.normalWorld, -eyeVec, light, ind);
    28.  
    29. /////// My Insert -  works only if directional light intensity is > 0.0 ////////////////
    30. #if defined (DIRECTIONAL) || defined (DIRECTIONAL_COOKIE)
    31.  
    32.            // ... Result CalculateIndirect() = 0=unlit to 1.0=full light.
    33.            res += CalculateIndirect(_WorldSpaceCameraPos, wpos.xz, data.normalWorld);
    34.  
    35.            // ... * has no effect
    36.            //       res *= CalculateIndirect(_WorldSpaceCameraPos, wpos.xz, data.normalWorld);
    37. #endif
    38.  
    39.     return res;
    40. }
    41.  
    res += CalculateIndirect(_WorldSpaceCameraPos, wpos.xz, data.normalWorld);
    Adds a ugly washed out light, like the photoshop screen effect to the scene.

    Untitled-1.jpg

    res *= CalculateIndirect(_WorldSpaceCameraPos, wpos.xz, data.normalWorld);
    Does nothing to the scene.

    Untitled-2.jpg

    I think I must get grab unlit albedo from the scene and calculate in, but can't get from anywhere. I can not enlighten pixels that are already black for sure.

    Where I can add the calculation as multiplication to the scene and receiving (_WorldSpaceCameraPos, wpos.xz, data.normalWorld) as well ?

    Thanks a lot.
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    You already have it. That’s what
    data.diffuseColor
    is.
     
    Quatum1000 likes this.
  3. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    889
    Thanks.. completely overseen this..

    Can you help me with a small vector thing in shader plz.
    I want to take the pixel vector worldNormal.xyz and extend the direction by any meters, to get the blue x,y,z world position.

    Untitled-1.jpg

    How can I do this in shader? Thank you.
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    To answer your question exactly as you asked it:
    surface world position + normalized direction * distance = new world position

    But I suspect that's not actually what you were trying to ask. Do you want the world position that's represented by the camera depth texture at the same pixel position as an arbitrary world position?

    Well, assuming the position is actually on screen, it's really just a matter of transforming the world position offset from the surface back into screen space to get the screen space UV, and using the camera to world position ray to reconstruct a world position from the depth.

    A lot of this mimics how the
    UnityDeferredCalculateLightParams
    function calculates the world position it outputs.
    Code (csharp):
    1. float3 offsetWorldPos = worldPos + worldNormal * distance;
    2.  
    3. float4 offsetClipPos = UnityWorldToClipPos(offsetWorldPos);
    4. float4 offsetScreenPos = ComputeScreenPos(offsetClipPos);
    5. float2 offsetUV = offsetScreenPos.xy / offsetScreenPos.w;
    6.  
    7. float3 offsetViewPos = UnityWorldToViewPos(offsetWorldPos);
    8. float3 offsetRay = offsetViewPos / (_ProjectionParams.z * offsetViewPos.z);
    9.  
    10. float offsetDepth = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, offsetUV));
    11. float4 newViewPos = float4(offsetRay * offsetDepth, 1.0);
    12. float3 newWorldPos = mul(unity_CameraToWorld, newViewPos).xyz;
     
  5. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    889
    That's a good question! But currently didn't know exactly what the best decision is, from where an how I get the required data. Atm I'm calculating the diffuse light in pure world-space based on the cam position.

    The goals is to get realtime diffuse lighting from static lights.

    Tomorrow I will try to get neighbor lights by float3 offsetWorldPos = worldPos + worldNormal * distance; This concept is a bit sophisticated and versatile.

    On 1 light you get this in Unity.
    Untitled-1.jpg

    With enabled realtime diffuse lighting, any objects can move through, rotate etc.Further it doesn't matter how many lights are in the scene, runs below 0.2ms.
    Untitled-2.jpg