Search Unity

Question [SOLVED] URP: Screen effects for Single Pass VR (Sobel, Blur, ...)

Discussion in 'Shaders' started by cocapasteque, Jul 28, 2020.

  1. cocapasteque

    cocapasteque

    Joined:
    Sep 30, 2016
    Posts:
    20
    Hey there,

    I'm trying to get some shaders I wrote to work with Single Pass VR with URP. It works in Multi-Pass already and I'm happy with the result. I just can't make it work with Single Pass...

    I guess the problem I'm having here is that I cannot sample the UV correctly, I've tried a couple of things but it just won't render in Single Pass on my Oculus Quest.

    Code (CSharp):
    1. Shader "Unlit/SobelFilter"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Base (RGB)", 2D) = "white" {}
    6.     }
    7.     SubShader
    8.     {
    9.         Tags { "RenderPipeline" = "UniversalPipeline" "RenderType"="Opaque" }
    10.         LOD 200
    11.        
    12.         Pass
    13.         {
    14.             HLSLPROGRAM
    15.             #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl"
    16.             #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
    17.              
    18.             TEXTURE2D(_MainTex);
    19.             SAMPLER(sampler_MainTex);
    20.            
    21.             CBUFFER_START(UnityPerMaterial)
    22.             half4 _MainTex_ST;
    23.             float2 _MainTex_TexelSize;
    24.             CBUFFER_END;
    25.            
    26.             float _Intensity;
    27.             float _Weight;
    28.             float _Blend;
    29.             half4 _OutlineColor;
    30.             half4 _BackgroundColor;
    31.             float _Threshold;
    32.             float _SobelValue;
    33.             float _ShowGrayscale;
    34.            
    35.             struct Attributes
    36.             {
    37.                 float4 positionOS       : POSITION;
    38.                 float2 uv               : TEXCOORD0;
    39.             };
    40.  
    41.             struct Varyings
    42.             {
    43.                 float2 uv        : TEXCOORD0;
    44.                 float4 vertex : SV_POSITION;
    45.                 UNITY_VERTEX_OUTPUT_STEREO
    46.             };
    47.            
    48.             float2 UnityStereoScreenSpaceUVAdjust(float2 uv, float4 scaleAndOffset)
    49.             {
    50.                 return uv.xy * scaleAndOffset.xy + scaleAndOffset.zw;
    51.             }
    52.            
    53.             float intensity(float4 color){
    54.                 return sqrt((color.x*color.x)+(color.y*color.y)+(color.z*color.z));
    55.             }
    56.            
    57.             float sobel(float stepx, float stepy, float2 uv)
    58.             {
    59.                 float tleft = intensity(SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(-stepx, stepy)));
    60.                 float left = intensity(SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(-stepx, 0)));
    61.                 float bleft = intensity(SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(-stepx, -stepy)));
    62.                 float top = intensity(SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(0, stepy)));
    63.                 float bottom = intensity(SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(0, -stepy)));
    64.                 float tright = intensity(SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(stepx, stepy)));
    65.                 float right = intensity(SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(stepx, 0)));
    66.                 float bright = intensity(SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + float2(stepx, -stepy)));
    67.                
    68.                 float x = (_SobelValue/2 * tleft) + (_SobelValue * left) + (_SobelValue/2 * bleft) - (_SobelValue/2 * tright) - (_SobelValue * right) - (_SobelValue/2 * bright);
    69.                 float y = -(_SobelValue/2 * tleft) - (_SobelValue * top) - (_SobelValue/2 * tright) + (_SobelValue/2 * bleft) + (_SobelValue * bottom) + (_SobelValue/2 * bright);
    70.                
    71.                 float xlum = dot(x, float3(0.2126729, 0.7151522, 0.0721750));
    72.                 float ylum = dot(y, float3(0.2126729, 0.7151522, 0.0721750));
    73.                
    74.                 float color = sqrt((xlum*xlum) + (ylum*ylum));
    75.                
    76.                 if(_ShowGrayscale == 1){
    77.                     return color;
    78.                 }
    79.                
    80.                 // Replacing all values bellow threshold to black and white above (greyscale to b&w)
    81.                 if( color <= _Threshold ) { color = 0; }
    82.                 else { color = 1; }
    83.                
    84.                 return color;
    85.             }
    86.            
    87.             half4 applyColors(half4 s) {
    88.                 // Replacing blacks with background color and whites with outline color
    89.                 if (s.r == 0) {
    90.                     s = _BackgroundColor;
    91.                 } else if (s.r == 1) {
    92.                     s = lerp(_BackgroundColor, _OutlineColor, _Intensity);
    93.                 }
    94.                 return s;
    95.             }
    96.            
    97.             Varyings vert(Attributes input)
    98.             {
    99.                 Varyings output = (Varyings)0;
    100.                 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
    101.  
    102.                 VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
    103.                 output.vertex = vertexInput.positionCS;
    104.                 output.uv = input.uv;
    105.                
    106.                 return output;
    107.             }
    108.             half4 frag (Varyings input) : SV_Target
    109.             {
    110.                 UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
    111.                
    112.                 // Apply Sobel Filter
    113.                 half4 s = sobel(_MainTex_TexelSize.x, _MainTex_TexelSize.y, UnityStereoScreenSpaceUVAdjust(input.uv, _MainTex_ST));
    114.                 half4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoScreenSpaceUVAdjust(input.uv, _MainTex_ST));
    115.                
    116.                 // Apply outline and background color
    117.                 half4 r = applyColors(s);  
    118.                
    119.                 if(_ShowGrayscale == 1){
    120.                     return s;
    121.                 }
    122.                    
    123.                 // blending with normal texture and weight
    124.                 r = lerp(r, r * color, _Blend);
    125.                 r = lerp(color, r, _Weight);      
    126.                 return r;
    127.                    
    128.             }
    129.            
    130.             #pragma vertex vert
    131.             #pragma fragment frag
    132.            
    133.             ENDHLSL
    134.         }
    135.     }
    136.     FallBack "Diffuse"
    137. }
    138.  
     
  2. cocapasteque

    cocapasteque

    Joined:
    Sep 30, 2016
    Posts:
    20
    Solved : The solution is actually really straightforward and I think Unity should spend some time actually documenting the URP Shader macros a bit more, I found the solution on a forum post. There's nothing about it anywhere on the internet.

    The trick is to use TEXTURE2D_X and SAMPLE_TEXTURE2D_X instead of TEXTURE2D and SAMPLE_TEXTURE2D. I also replaced my method
    UnityStereoScreenSpaceUVAdjust(uv, _MainTex_ST) 
    with
    UnityStereoTransformScreenSpaceTex(uv).


    These macros with the X as prefix are specifically designed for single pass VR
     
    mddsvr, KingOfSnake and morepixels like this.
  3. monky822

    monky822

    Joined:
    Feb 1, 2016
    Posts:
    3
    Can you offer some guidance on my blur shader?

    I'm running in to the same issue with the Built in Renderer. The blur works in multi-pass but not in single-pass. I'm running a blur filter for each individual eye. When applied the left eye is gray and the right eye is black. Here's my shader code:

    Code (CSharp):
    1.  
    2. Shader "Hidden/BlurEffectConeTap" {
    3.     Properties { _MainTex ("", any) = "" {} }
    4.     CGINCLUDE
    5.     #include "UnityCG.cginc"
    6.     struct v2f {
    7.         float4 pos : SV_POSITION;
    8.         half2 uv : TEXCOORD0;
    9.         half2 taps[4] : TEXCOORD1;
    10.     };
    11.     sampler2D _MainTex;
    12.     half4 _MainTex_TexelSize;
    13.     half4 _MainTex_ST;
    14.     half4 _BlurOffsets;
    15.     v2f vert( appdata_img v ) {
    16.         v2f o;
    17.         o.pos = UnityObjectToClipPos(v.vertex);
    18.  
    19.         o.uv = v.texcoord - _BlurOffsets.xy * _MainTex_TexelSize.xy;
    20. #ifdef UNITY_SINGLE_PASS_STEREO
    21.         // we need to keep texel size correct after the uv adjustment.
    22.         o.taps[0] = UnityStereoScreenSpaceUVAdjust(o.uv + _MainTex_TexelSize * _BlurOffsets.xy * (1.0f / _MainTex_ST.xy), _MainTex_ST), _MainTex_ST);
    23.         o.taps[1] = UnityStereoScreenSpaceUVAdjust(o.uv - _MainTex_TexelSize * _BlurOffsets.xy * (1.0f / _MainTex_ST.xy), _MainTex_ST), _MainTex_ST);
    24.         o.taps[2] = UnityStereoScreenSpaceUVAdjust(o.uv + _MainTex_TexelSize * _BlurOffsets.xy * half2(1, -1) * (1.0f / _MainTex_ST.xy), _MainTex_ST);
    25.         o.taps[3] = UnityStereoScreenSpaceUVAdjust(o.uv - _MainTex_TexelSize * _BlurOffsets.xy * half2(1, -1) * (1.0f / _MainTex_ST.xy), _MainTex_ST);
    26. #else
    27.         o.taps[0] = o.uv + _MainTex_TexelSize * _BlurOffsets.xy;
    28.         o.taps[1] = o.uv - _MainTex_TexelSize * _BlurOffsets.xy;
    29.         o.taps[2] = o.uv + _MainTex_TexelSize * _BlurOffsets.xy * half2(1,-1);
    30.         o.taps[3] = o.uv - _MainTex_TexelSize * _BlurOffsets.xy * half2(1,-1);
    31. #endif
    32.         return o;
    33.     }
    34.     half4 frag(v2f i) : SV_Target {
    35.         half4 color = tex2D(_MainTex, i.taps[0]);
    36.         color += tex2D(_MainTex, i.taps[1]);
    37.         color += tex2D(_MainTex, i.taps[2]);
    38.         color += tex2D(_MainTex, i.taps[3]);
    39.         return color * 0.25;
    40.     }
    41.     ENDCG
    42.     SubShader {
    43.          Pass {
    44.               ZTest Always Cull Off ZWrite Off
    45.  
    46.               CGPROGRAM
    47.               #pragma vertex vert
    48.               #pragma fragment frag
    49.               ENDCG
    50.           }
    51.     }
    52.     Fallback off
    53. }
    54.