Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

My broken SSR port...

Discussion in 'Shaders' started by Ravel, Oct 4, 2018.

  1. Ravel

    Ravel

    Joined:
    Nov 21, 2010
    Posts:
    605
    Hello, I recently got into screen space shaders and I must say, they are quite difficult to master.
    They seem simple and the theory behind them is also very simple, pixel A goes to pixel B etc.
    But when I tried to follow a tutorial, on how to do Screen Space Reflections, it al seems like it works and it probably does. But some variable is incorrect or with the wrong sign...

    I've tried finding the issue myself, but without luck. Infact when breaking the code to pieces I noticed that this code can actually show reflections without these popular SSR artefacts. I was able to get the reflections visible at a cost of mis matched origin, but the reflections were actually picture clear like a cubemap!

    Here's the code:

    Code (CSharp):
    1.  
    2. Shader "Hidden/SSR Virtex"
    3. {
    4.     Properties
    5.     {
    6.         _MainTex("Base (RGB)", 2D) = "" {}
    7.     }
    8.     SubShader
    9.     {
    10.  
    11.         Blend Off
    12.         ZTest Always
    13.         ZWrite Off
    14.         Cull Off
    15.  
    16.         CGINCLUDE
    17.  
    18.         #include "UnityCG.cginc"
    19.         #pragma glsl
    20.  
    21.         typedef vector <float, 4> vec4;
    22.         typedef vector <float, 3> vec3;
    23.         typedef vector <float, 2> vec2;
    24.         typedef vector <fixed, 3> col3;
    25.  
    26.         #define width _ScreenParams.x
    27.         #define height _ScreenParams.y
    28.         #define HalfPixel 1
    29.  
    30.         sampler2D _MainTex;
    31.         half2 _MainTex_TexelSize;
    32.         sampler2D _CameraDepthTexture;
    33.         sampler2D _CameraDepthMipmap;
    34.         sampler2D _CameraGBufferTexture0; // rgb: diffuse,  a: occlusion
    35.         sampler2D _CameraGBufferTexture1; // rgb: specular, a: smoothness
    36.         sampler2D _CameraGBufferTexture2; // rgb: normal,   a: unused
    37.         sampler2D _CameraGBufferTexture3; // rgb: emission, a: unused ///// somethings wrong, this is the smoothnes??
    38.  
    39.         inline float4 GetAlbedo(float2 uv) { return tex2D(_CameraGBufferTexture0, uv); }
    40.         inline float4 GetOcculusion(float2 uv) { return tex2D(_CameraGBufferTexture0, uv).w; }
    41.         inline float3 GetSpecular(float2 uv) { return tex2D(_CameraGBufferTexture1, uv).xyz; }
    42.         inline float3 GetSmoothness(float2 uv) { return tex2D(_CameraGBufferTexture1, uv).w; }
    43.         inline float3 GetNormal(float2 uv) { return tex2D(_CameraGBufferTexture2, uv).xyz * 2.0 - 1.0; }
    44.         inline float3 GetEmission(float2 uv) { return tex2D(_CameraGBufferTexture3, uv).xyz; }
    45.         inline float GetDepth(float2 uv) { return SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv); }
    46.  
    47.         float4x4 _InvViewProj;
    48.         float4x4 _ViewProj;
    49.         float4x4 _NormalMatrix;
    50.  
    51.         int _ViewMode;
    52.  
    53.         struct appdata
    54.         {
    55.             float4 vertex : POSITION;
    56.             float2 uv : TEXCOORD0;
    57.         };
    58.  
    59.         struct v2f
    60.         {
    61.             float4 vertex : SV_POSITION;
    62.             float2 uv : TEXCOORD0;
    63.             float4 rayDirVS : TEXCOORD1;
    64.         };
    65.  
    66.         float noise(float2 seed)
    67.         {
    68.             return frac(sin(dot(seed.xy, float2(12.9898, 78.233))) * 43758.5453);
    69.         }
    70.  
    71.         float4 ray; // temporary
    72.         v2f vert(appdata v)
    73.         {
    74.             v2f o;
    75.             o.vertex = UnityObjectToClipPos(v.vertex);
    76.             o.uv = v.uv;
    77.             o.rayDirVS = mul(unity_CameraInvProjection, float4((float2(v.uv.x, v.uv.y) - 0.5) * 2, 1, 1));
    78.             ray = o.rayDirVS; // temp
    79.             return o;
    80.         }
    81.  
    82.         float3 PosToUV(float3 vpos)
    83.         {
    84.             float4 proj_pos = mul(unity_CameraProjection, float4(vpos ,1));
    85.             float3 screenPos = proj_pos.xyz / proj_pos.w;
    86.             float z = tex2D(_CameraDepthTexture, float2(screenPos.x, screenPos.y));
    87.             return float3(float2(screenPos.x, screenPos.y), z);
    88.         }
    89.  
    90.         float sqr(float x)
    91.         {
    92.             return x*x;
    93.         }
    94.  
    95.         vec3 GetWorldPosition(vec2 input)
    96.         {
    97.             return mul(unity_ObjectToWorld, input);
    98.         }
    99.  
    100.         vec3 GetObjectPosition(vec2 input)
    101.         {
    102.             return mul(unity_WorldToObject, input);
    103.         }
    104.  
    105.         struct RayTraceOutput
    106.         {
    107.             bool Hit;
    108.             float2 UV;
    109.         };
    110.  
    111.         // The first part we’ll look at is the outer loop.
    112.         // This is what steps along the ray march check if it’s hit anything yet.
    113.         RayTraceOutput TraceRay(float2 coord)
    114.         {
    115.  
    116.             RayTraceOutput output;
    117.             output.Hit = false;
    118.             output.UV = 0;
    119.             // For each UV screen coordinate, we would need to find the 3D World Position
    120.             // (reconstructed from the Depth Map and the Camera’s InverseViewMatrix). We also
    121.             // need to get the Normal of what ever surface is at this position from the Normal Map.
    122.  
    123.  
    124.             // View
    125.             float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, coord);
    126.             depth = Linear01Depth(depth);
    127.             float3 view_pos = ray.xyz / ray.w * depth;
    128.             //float3 reflPosition = GetWorldPosition(uv);
    129.  
    130.             // Get the Normal Data
    131.             float3 normal = tex2D(_CameraGBufferTexture2, coord).xyz * 2.0 - 1.0;
    132.             normal = mul((float3x3)_NormalMatrix, normal);
    133.             //float3 normalData = tex2D(NormalSampler, texCoord).xyz;
    134.             //tranform normal back into [-1,1] range
    135.             //float3 reflNormal = 2.0f * normal - 1.0f;
    136.             float3 reflNormal = normal;
    137.  
    138.             // Since we have the Normal and 3D World Position of what ever surface is at this pixel,
    139.             // we need to now find the View Directions and Reflected Vector.
    140.  
    141.             // The View Direction is simply the pixels 3D World Space Position minus the Camera’s
    142.             // World Space Position and can be thought of as the vector that the reflected light moves along to the Camera.
    143.  
    144.             // The Reflected Vector can be thought of as the direction the light was moving before it
    145.             // hit the surface and was reflected into the camera.But as we’re reversing the process,
    146.             // this is simply the reflection of the View Direction vector.
    147.  
    148.             // First, Get the View Direction
    149.             float3 CameraPos = _WorldSpaceCameraPos;
    150.             float3 vDir = normalize(view_pos - CameraPos);
    151.             float3 reflectDir = normalize(reflect(view_pos, normalize(reflNormal)));
    152.  
    153.             //float3 reflectDir = reflect(normalize(view_pos), normal);
    154.  
    155.  
    156.             // The Current Position in 3D
    157.             float3 curPos = 0;
    158.  
    159.             // The Current UV
    160.             float3 curUV = 0;
    161.  
    162.             // The Current Length
    163.             float curLength = 1;
    164.             float DepthCheckBias = 0.1;
    165.             // Our Trace Ray function will then perform a Ray march, getting the depth for each
    166.             // position in the loop and seeing if it’s close enough to the depth in the depth buffer.
    167.             for (int i = 0; i < 10; i++)
    168.             {
    169.                 // Has it hit anything yet
    170.                 if (output.Hit == false)
    171.                 {
    172.                     // The first part we’ll look at is the outer loop.
    173.                     // This is what steps along the ray march check if it’s hit anything yet.
    174.  
    175.                     // Update the Current Position of the Ray
    176.                     curPos = view_pos + reflectDir * curLength;
    177.                     // Get the UV Coordinates of the current Ray
    178.                     curUV = PosToUV(curPos);
    179.                     // The Depth of the Current Pixel
    180.                     float curDepth = GetDepth(curUV.xy);
    181.                     // The next part then enters a loop checking if the differences between the world position
    182.                     // depth and the depth buffer value is below a certain DepthBiasBuffer value.If not then
    183.                     // though, it performs a loop checking the surrounding pixels if they are
    184.                     for (int i = 0; i < 10; i++)
    185.                     {
    186.                         if (abs(curUV.z - curDepth) < DepthCheckBias)
    187.                         {
    188.                             // If it's hit something, then return the UV position
    189.                             output.Hit = true;
    190.                             output.UV = curUV.xy;
    191.                             break;
    192.                         }
    193.                         curDepth = GetDepth(curUV.xy * HalfPixel * 2);
    194.                     }
    195.  
    196.                     // Get the New Position and Vector
    197.                     float3 newPos = GetWorldPosition(curUV.xy);
    198.                     curLength = length(view_pos - newPos);
    199.                 }
    200.             }
    201.             return output;
    202.         }
    203.         float4 frag(v2f IN) : SV_Target
    204.         {
    205.             float2 uv = IN.uv;
    206.             float4 ray = IN.rayDirVS;
    207.             float4 image = tex2D(_MainTex, uv);
    208.             float3 albedo = tex2D(_CameraGBufferTexture0, uv).xyz;
    209.             float Metallic = tex2D(_CameraGBufferTexture1, uv).xyz;
    210.             float smoothness = tex2D(_CameraGBufferTexture1, uv).w;
    211.  
    212.             // Default to the source image
    213.             fixed4 col = image;
    214.  
    215.  
    216.             //trace
    217.             // Get the Amount of reflection. Only calculate reflection on
    218.             // surfaces with reflection data.
    219.             float amount = smoothness;
    220.  
    221.             if (amount > 0)
    222.             {
    223.                 RayTraceOutput ray = TraceRay(uv * HalfPixel * 2);
    224.  
    225.                 if (ray.Hit == true)
    226.                 {
    227.                     // Fade at edges
    228.                     //if (ray.UV.y < EdgeCutOff * 2) amount *= (ray.UV.y / EdgeCutOff / 2);
    229.  
    230.                     col += tex2D(_MainTex,ray.UV.xy);
    231.                 }
    232.             }
    233.  
    234.             // View
    235.             float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
    236.             depth = Linear01Depth(depth);
    237.             float3 view_pos = ray.xyz / ray.w * depth;
    238.             // Normal from G-Buffer
    239.             float3 normal = tex2D(_CameraGBufferTexture2, uv).xyz * 2.0 - 1.0;
    240.             normal = mul((float3x3)_NormalMatrix, normal);
    241.  
    242.             float3 reflectedRay = reflect(normalize(view_pos), normal);
    243.  
    244.             if (_ViewMode == 1) return float4(normal, 1);
    245.             if (_ViewMode == 2) return float4(reflectedRay, 1);
    246.             if (_ViewMode == 3) return float4(view_pos, 1);
    247.             //if (_ViewMode == 2) return float4(reflectDir, 1);
    248.             //if (_ViewMode == 4) return float4(view_pos, 1);
    249.             //if (_ViewMode == 3) return float4(1, 1, 1, 1) * calc / _MaxLoop;
    250.             //if (_ViewMode == 4) return float4(1, 1, 1, 1) * tex2Dlod(_CameraDepthMipmap, float4(uv, 0, _MaxLOD));
    251.             if (_ViewMode == 5) return float4(tex2D(_CameraGBufferTexture0, uv).xyz, 1);
    252.             if (_ViewMode == 6) return float4(tex2D(_CameraGBufferTexture1, uv).xyz, 1);
    253.             if (_ViewMode == 7) return float4(1, 1, 1, 1) * tex2D(_CameraGBufferTexture0, uv).w;
    254.             if (_ViewMode == 8) return float4(1, 1, 1, 1) * tex2D(_CameraGBufferTexture1, uv).w;
    255.             if (_ViewMode == 9) return float4(tex2D(_CameraGBufferTexture3, uv).xyz, 1);
    256.             ///////////////////
    257.  
    258.             return col;
    259.         }
    260.         ENDCG
    261.  
    262.         Pass
    263.         {
    264.             CGPROGRAM
    265.             #pragma vertex vert
    266.             #pragma fragment frag
    267.             ENDCG
    268.         }
    269.     }
    270. }
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3.  
    4. [RequireComponent(typeof(Camera))]
    5. [ExecuteInEditMode]
    6. public class ScreenSpaceLocalReflection1 : MonoBehaviour
    7. {
    8.     enum ViewMode { Original, Normal, Reflection, CalcCount, MipMap, Diffuse, Speclar, Occlusion, Smmothness, Emission }
    9.  
    10.     [SerializeField]
    11.     ViewMode viewMode = ViewMode.Original;
    12.     [SerializeField]
    13.     Shader shader;
    14.     Material material_;
    15.  
    16.     void Update()
    17.     {
    18.         if(Input.GetKeyDown(KeyCode.Space))
    19.         {
    20.             viewMode++;
    21.         }
    22.         if ((int)viewMode > 9) viewMode = 0;
    23.     }
    24.  
    25.     void OnRenderImage(RenderTexture src, RenderTexture dst)
    26.     {
    27.         if (material_ == null)
    28.         {
    29.             material_ = new Material(shader);
    30.         }
    31.  
    32.         // matrices
    33.         var camera = GetComponent<Camera>();
    34.         camera.depthTextureMode = DepthTextureMode.Depth;
    35.         var view = camera.worldToCameraMatrix;
    36.         var proj = GL.GetGPUProjectionMatrix(camera.projectionMatrix, false);
    37.         var viewProj = proj * view;
    38.         material_.SetMatrix("_ViewProj", viewProj);
    39.         material_.SetMatrix("_InvViewProj", viewProj.inverse);
    40.         material_.SetMatrix("_NormalMatrix", view);
    41.  
    42.         // triggers
    43.         material_.SetInt("_ViewMode", (int)viewMode);
    44.  
    45.      
    46.         // Render source to destination using new material
    47.         Graphics.Blit(src, dst, material_, 0);
    48.     }
    49. }
    And here is the link to the original article
    https://virtexedgedesign.com/2018/06/24/shader-series-basic-screen-space-reflections/

    Any sugestions on what I am missing out?