Converting Custom shader into URP compatible shader

Hi, I am using a custom shader “Barrel distortion.shader” from github Repo :jondyne / ARcore mobileVRHeadset, working perfectly in Legacy Rendering Pipeline.

Now I am using URP. Started learning shader programming from yesterday. I am trying to rewrite it in HLSL to make it compatible with URP.

Here’s the custom shader I am using in Legacy rendering pipeline:

Shader "Yaturu/Barrel Distortion"
{
    Properties{
        _MainTex("", 2D) = "white" {}

        _FOV("FOV", Range(1, 2)) = 1.0
        _Alpha("Alpha", Float) = 1.0
    }

    SubShader{
        ZWrite Off

        Pass{
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct v2f {
                float4 pos : POSITION;
                float2 uv : TEXCOORD0;
            };

            // Default Vertex Shader
            v2f vert(appdata_img v) {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = MultiplyUV(UNITY_MATRIX_TEXTURE0, v.texcoord.xy);
                return o;
            }

            // Parameters
            sampler2D _MainTex;
            float _FOV;

            // Alpha is the ratio of pixel density: width to height
            float _Alpha;

            uniform float4x4 _UnityDisplayTransform;

            // Fragment Shader: Remap the texture coordinates to combine
            // barrel distortion and disparity video display
            fixed4 frag(v2f i) : COLOR {
                float2 uv1, uv2, uv3;
                float t1, t2;
                float offset;

                // uv1 is the remap of left and right screen to a full screen
                uv1 = i.uv - 0.5;
                uv1.x = uv1.x * 2 - 0.5 + step(i.uv.x, 0.5);

                t1 = sqrt(1.0 - uv1.x * uv1.x - uv1.y * uv1.y);
                t2 = 1.0 / (t1 * tan(_FOV * 0.5));

                // uv2 is the remap of side screen with barrel distortion
                uv2 = uv1 * t2 + 0.5;

                // black color for out-of-range pixels
                if (uv2.x >= 1.5 || uv2.y >= 1.0 || uv2.x <= -0.5 || uv2.y <= 0.0) {
                    return fixed4(0, 0, 0, 1);
                } else {
                    offset = 0.5 - _Alpha * 0.5;
                    // uv3 is the remap of image texture
                    uv3 = uv2;
                    uv3.x = uv2.x * _Alpha + offset;

                    return tex2D(_MainTex, uv3);
                }
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

This is the rewritten shader in HLSL with my one day shader programming learning knowledge with the help of available online documentation:

Shader "Custom/StereoURP"
{
    Properties{
        _MainTex("", 2D) = "white" {}

        _FOV("FOV", Range(1, 2)) = 1.0
        _Alpha("Alpha", Float) = 1.0
    }

    SubShader{
        ZWrite Off

        // SubShader Tags define when and under which conditions a SubShader block or
        // a pass is executed.
        Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalRenderPipeline" }

        Pass{
            // The HLSL code block. Unity SRP uses the HLSL language.
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

         
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"
            #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl"
         


            struct v2f {
                float4 pos : POSITION;
                float2 uv : TEXCOORD0;
            };


            struct appdata_img {
                float4 vertex : POSITION;
                half2 texcoord : TEXCOORD0;
            };

            float4 ObjectToClipPos(float3 pos)
            {
                return mul(UNITY_MATRIX_VP, mul(UNITY_MATRIX_M, float4 (pos, 1)));
            }

            float2 MultiplyUV(float4x4 mat, float2 inUV) {
                float4 temp = float4 (inUV.x, inUV.y, 0, 0);
                temp = mul(mat, temp);
                return temp.xy;
            }
         

            // Default Vertex Shader
            v2f vert(appdata_img v) {
                v2f o;
                o.pos = TransformWorldToHClip(v.vertex);
                //o.pos = mul(UNITY_MATRIX_MVP, v.vertex );
                o.uv = MultiplyUV(float4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1), v.texcoord.xy);
                return o;
            }

            // Parameters
            sampler2D _MainTex;
            float _FOV;

            // Alpha is the ratio of pixel density: width to height
            float _Alpha;

            uniform float4x4 _UnityDisplayTransform;

            // Fragment Shader: Remap the texture coordinates to combine
            // barrel distortion and disparity video display
            fixed4 frag(v2f i) : COLOR {
                float2 uv1, uv2, uv3;
                float t1, t2;
                float offset;

                // uv1 is the remap of left and right screen to a full screen
                uv1 = i.uv - 0.5;
                uv1.x = uv1.x * 2 - 0.5 + step(i.uv.x, 0.5);

                t1 = sqrt(1.0 - uv1.x * uv1.x - uv1.y * uv1.y);
                t2 = 1.0 / (t1 * tan(_FOV * 0.5));

                // uv2 is the remap of side screen with barrel distortion
                uv2 = uv1 * t2 + 0.5;

                // black color for out-of-range pixels
                if (uv2.x >= 1.5 || uv2.y >= 1.0 || uv2.x <= -0.5 || uv2.y <= 0.0) {
                    return fixed4(0, 0, 0, 1);

                } else {
                    offset = 0.5 - _Alpha * 0.5;
                    // uv3 is the remap of image texture
                    uv3 = uv2;
                    uv3.x = uv2.x * _Alpha + offset;

                    return tex2D(_MainTex, uv3);
                }
            }
                ENDHLSL
        }
    }
    FallBack "Diffuse"
}

Showing 2 Errors :

  1. unrecognized identifier ‘fixed4’ at line 73
  2. ‘TransformWorldToHClip’: implicit truncation of vector type at line 56

I appreciate any tips or pointer to make changes in code for fixing errors and making it compatible with URP.

Thanks in advance.

1 Like

For the first, you can try to change it to float4 or half4, but I am not sure if it will help. Also, change COLOR to SV_TARGET

For the second you have to specify which variables you will use.
Change it to v.vertex.xyz

2 Likes

Thanks a lot Ragueel, By changing the shader as you mentioned, it worked. Disparity video and Barrel distortion are now applied to the screen.

I found a new issue after applying the shader, the output is inverted horizontally. I observed it when I changed the cube position, from 0 meters to 0.5f in X-axis, cube moved to left side in game view. What changes do I need to make output appear correct.

I flipped the output horizontally using “uv.x = 1.0 - uv.x;” before returning the texture in the shader.