Search Unity

Getting Cameras View Direction in Custom Post Process Shader

Discussion in 'High Definition Render Pipeline' started by plehmann1991, Nov 13, 2020.

  1. plehmann1991

    plehmann1991

    Joined:
    Jul 6, 2019
    Posts:
    1
    Hello,

    this issue has already cost me several days, so I hope someone here can get me on the right track. I'm currently trying to follow a YouTube series from the wonderful Sebastian Lague on creating a universe with gravity, generated planets including atmosphere. He seems to have done it with the built-in renderer, for several reasons I'm trying to follow the tutorial in HDRP.

    I'm stuck creating atmospheres in a custom Post Process, making use of a raySphere function provided by Sebastian. You can see the bit I'm currently working on in his video up until 2:40:


    I was able to implement the atmosphere functionality with the following shader (most parts obviously copied from Sebastians GitHub repo):

    Code (CSharp):
    1. Shader "Hidden/Shader/Atmosphere"
    2. {
    3.     HLSLINCLUDE
    4.  
    5.     #pragma target 4.5
    6.     #pragma only_renderers d3d11 playstation xboxone vulkan metal switch
    7.  
    8.     #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
    9.     #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
    10.     #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
    11.     #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/FXAA.hlsl"
    12.     #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/RTUpscale.hlsl"
    13.    
    14.     float3 _WorldSpaceCameraMainPos;
    15.     matrix _InvCamProjMatrix;
    16.  
    17.     struct Attributes
    18.     {
    19.         uint vertexID : SV_VertexID;
    20.         float2 uv : TEXCOORD0;
    21.         UNITY_VERTEX_INPUT_INSTANCE_ID
    22.     };
    23.  
    24.     struct Varyings
    25.     {
    26.         float4 positionCS : SV_POSITION;
    27.         float2 texcoord   : TEXCOORD0;
    28.         float3 viewVector : TEXCOORD1;
    29.         float2 uv   : TEXCOORD2;  
    30.     };
    31.  
    32.     Varyings Vert(Attributes input)
    33.     {
    34.         Varyings output;
    35.         UNITY_SETUP_INSTANCE_ID(input);
    36.         UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
    37.         output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID);
    38.         output.texcoord = GetFullScreenTriangleTexCoord(input.vertexID);
    39.         output.uv = input.uv;
    40.         output.viewVector = mul( _InvProjMatrix, float4(input.uv * 2 - 1, 0, -1));
    41.         output.viewVector = mul(UNITY_MATRIX_M, float4(output.viewVector,0));
    42.         return output;
    43.     }
    44.  
    45.     float LinearEyeDepth(float z)
    46.                 {
    47.                     return 1.0 / (_ZBufferParams.z * z + _ZBufferParams.w);
    48.                 }
    49.  
    50.     static const float maxFloat = 0;//3.402823466e+38;
    51.    
    52.  
    53.     // Returns vector (dstToSphere, dstThroughSphere)
    54.     // If ray origin is inside sphere, dstToSphere = 0
    55.     // If ray misses sphere, dstToSphere = maxValue; dstThroughSphere = 0
    56.     float2 raySphere(float3 sphereCentre, float sphereRadius, float3 rayOrigin, float3 rayDir) {
    57.         float3 offset = rayOrigin - sphereCentre;
    58.         float a = dot(rayDir, rayDir);// if rayDir might not be normalized
    59.         float b = 2 * dot(offset, rayDir);
    60.         float c = dot(offset, offset) - sphereRadius * sphereRadius;
    61.         float d = (b * b) - (4 * a * c); // Discriminant from quadratic formula
    62.  
    63.         // Number of intersections: 0 when d < 0; 1 when d = 0; 2 when d > 0
    64.         if (d > 0) {
    65.             float s = sqrt(d);
    66.             float dstToSphereNear = -b - s;
    67.             float dstToSphereFar = -b + s;
    68.  
    69.             // Ignore intersections that occur behind the ray
    70.             if (dstToSphereFar < 0) {
    71.                 dstToSphereFar = -1;
    72.             }
    73.  
    74.             if (dstToSphereNear < 0) {
    75.                 dstToSphereNear = -1;  
    76.             }
    77.  
    78.             dstToSphereNear = dstToSphereNear / (2 * a);
    79.             dstToSphereFar = dstToSphereFar / (2 * a);
    80.  
    81.             return float2(dstToSphereNear, dstToSphereFar - dstToSphereNear);
    82.  
    83.         }
    84.         // Ray did not intersect sphere
    85.         return float2(-1, 0);
    86.     }
    87.  
    88.     // List of properties to control your post process effect
    89.     float _Intensity;
    90.     TEXTURE2D_X(_InputTexture);
    91.  
    92.     float3 planetCentre;
    93.     float atmosphereRadius;
    94.     float planetRadius;
    95.  
    96.     float4 CustomPostProcess(Varyings input) : SV_Target
    97.     {
    98.         // scenedepth
    99.         float sceneDepthNonLinear = SampleCameraDepth(input.uv);
    100.         float sceneDepth = LinearEyeDepth(sceneDepthNonLinear) * length(input.viewVector);
    101.  
    102.         // viewdirection
    103.         PositionInputs posInput = GetPositionInput(input.positionCS.xy, _ScreenSize.zw, sceneDepth, UNITY_MATRIX_I_VP, UNITY_MATRIX_V);
    104.         float3 viewDirection = GetWorldSpaceNormalizeViewDir(posInput.positionWS);//posInput.positionWS);
    105.        
    106.         // rayorigin
    107.         uint2 positionSS = input.texcoord * _ScreenSize.xy;
    108.         float  deviceDepth = LoadCameraDepth(positionSS);
    109.         float2 positionNDC = positionSS * _ScreenSize.zw + (0.5 * _ScreenSize.zw);
    110.         float3 positionWS = ComputeWorldSpacePosition(positionNDC, deviceDepth, UNITY_MATRIX_I_VP);
    111.        
    112.         // raysphere                                  
    113.         float3 rayOrigin = GetAbsolutePositionWS(positionWS);
    114.         float3 rayDir = normalize(viewDirection);
    115.  
    116.         float2 hitInfo = raySphere(planetCentre, atmosphereRadius, rayOrigin, rayDir);
    117.         float dstToAtmosphere = hitInfo.x;
    118.         float dstThroughAtmosphere = min(hitInfo.y, sceneDepth - dstToAtmosphere);
    119.              
    120.         // add to color
    121.         float4 outColor = LOAD_TEXTURE2D_X(_InputTexture, positionSS);                    
    122.         return outColor + (dstThroughAtmosphere / (atmosphereRadius * 2));
    123.     }
    124.    
    125.  
    126.     ENDHLSL
    127.  
    128.     SubShader
    129.     {
    130.         Pass
    131.         {
    132.             Name "Atmosphere"
    133.  
    134.             ZWrite Off
    135.             ZTest Always
    136.             Blend Off
    137.             Cull Off
    138.  
    139.             HLSLPROGRAM
    140.                 #pragma fragment CustomPostProcess
    141.                 #pragma vertex Vert
    142.                
    143.             ENDHLSL
    144.         }
    145.     }
    146.     Fallback Off
    147. }
    which renders the correct output, looking directly at the planet:

    Bildschirmfoto 2020-11-13 um 08.05.26.png
    This is wonderful and exactly what I want (and Sebastian does in his video). Strange things start to happen when I turn the camera exactly 180 degrees, having the planet in my back. The effect still renders:

    Bildschirmfoto 2020-11-13 um 08.05.51.png
    Also, when returning to scene view, the effect generates strange artifacts:
    Bildschirmfoto 2020-11-13 um 08.06.19.png
    It seems like the outgoing ray goes forwards and backwards, therefore rendering the effect even when looking away from the planet. I can't wrap my head around the problem in the scene. I tweaked several parts of the shader code, but was not able to track the error down. Does somebody have an idea?

    This is on Unity 2020.1.11f1, HDRP, HLSL.
     
  2. Olmi

    Olmi

    Joined:
    Nov 29, 2012
    Posts:
    1,553
    Do you have a minimal Custom Post Process script for the shader, if anyone wants to take a look at this?
     
  3. Erathor

    Erathor

    Joined:
    Jan 11, 2014
    Posts:
    18
    What if you check through your post processing script, if the viewing direction is correct. The same as with tracking UI elements on an object for example. I think it is the z axis on the view direction.
     
  4. RavenflashCom

    RavenflashCom

    Joined:
    May 17, 2019
    Posts:
    1
    Yup, Erathor is right.
    I've fixed a similar issue in the water shader by Sebastian Lague mixed with plehmann1991's HDRP version by diverting the ray direction vector.

    Works great!