Search Unity

Equirectangular Mapping Shader

Discussion in 'AR/VR (XR) Discussion' started by kemkriszt11, Aug 17, 2016.

  1. kemkriszt11

    kemkriszt11

    Joined:
    Sep 20, 2013
    Posts:
    1
    Hi, I have found this shader on this forum:

    Code (CSharp):
    1. Shader "Custom/Equirectangular" {
    2.     Properties {
    3.         _Color ("Main Color", Color) = (1,1,1,1)
    4.         _MainTex ("Diffuse (RGB) Alpha (A)", 2D) = "gray" {}
    5.     }
    6.     SubShader{
    7.         Pass {
    8.             Tags {"LightMode" = "Always"}
    9.             Cull front //Added by me
    10.             CGPROGRAM
    11.                 #pragma vertex vert
    12.                 #pragma fragment frag
    13.                 #pragma fragmentoption ARB_precision_hint_fastest
    14.                 #pragma glsl
    15.                 #pragma target 3.0
    16.                 #include "UnityCG.cginc"
    17.                 struct appdata {
    18.                    float4 vertex : POSITION;
    19.                    float3 normal : NORMAL;
    20.                 };
    21.                 struct v2f
    22.                 {
    23.                     float4    pos : SV_POSITION;
    24.                     float3    normal : TEXCOORD0;
    25.                 };
    26.                 v2f vert (appdata v)
    27.                 {
    28.                     v2f o;
    29.                     o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    30.                     o.normal = v.normal;
    31.                     return o;
    32.                 }
    33.                 sampler2D _MainTex;
    34.                 #define PI 3.141592653589793
    35.                 inline float2 RadialCoords(float3 a_coords)
    36.                 {
    37.                     float3 a_coords_n = normalize(a_coords);
    38.                     float lon = atan2(a_coords_n.z, a_coords_n.x);
    39.                     float lat = acos(a_coords_n.y);
    40.                     float2 sphereCoords = float2(lon, lat) * (1.0 / PI);
    41.                     return float2(sphereCoords.x * 0.5 + 0.5, 1 - sphereCoords.y);
    42.                 }
    43.                 float4 frag(v2f IN) : COLOR
    44.                 {
    45.                     float2 equiUV = RadialCoords(IN.normal);
    46.                     return tex2D(_MainTex, equiUV);
    47.                 }
    48.             ENDCG
    49.         }
    50.     }
    51.     FallBack "VertexLit"
    52. }
    and it works fine. The only problem is that I want to put the texture inside the sphere. I started modifying it based on an other Shader I found (which is not working good enough but at least inverts the texture) but there is so much difference and I know almost nothing about shaders so I couldn't do anything except changing the face culling.

    An other problem with that shader is that it draw a brown line at the seem of the image. Can you please help me figuring out what the problem is?

    Thanks.
     
  2. fullace

    fullace

    Joined:
    Aug 18, 2016
    Posts:
    2
  3. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    Or just invert the normals for the uv determination:
    Code (csharp):
    1.  
    2. float2 equiUV = RadialCoords(-IN.normal);
    3.  
    The seam is probably at the top/bottom, because the texture is set to repeat/tile instead of clamp. In a perfect world, you want the U address to be tiling and the V address to be clamped. But fully clamped is better than fully tiling.
     
  4. gaelleBe

    gaelleBe

    Joined:
    Nov 6, 2020
    Posts:
    8
    I need to adapt the shader to a Full screen custom pass in HDRP, has it been done before?
     
  5. mikerz1985

    mikerz1985

    Joined:
    Oct 23, 2014
    Posts:
    79
    You'll want to sample the texture with a mipmap bias in order to eliminate the seam; this will also net you a clearer image toward the poles of the image.

    https://makc3d.wordpress.com/2017/01/19/sampling-equirectangular-textures/

    If you want to render from the inside of the sphere, either create a 3d model of a sphere which is inverted, or set culling to either Off or Front.

    I haven't used HDRP, but adapting the concept to a full screen shader is definitely doable, but would take some significant shader work.
     
  6. gaelleBe

    gaelleBe

    Joined:
    Nov 6, 2020
    Posts:
    8
    thanks for your reply.
    My project doesnt mapp the texture, i want to display the distorted texture (outpuiting to a projection system mapped onto a physical 'real ' sphere). Here is my attempt of porting to HDRP so far, somehow seems mixed with the current display (see images below), what am I missing?

    Code (Boo):
    1. Shader "FullScreen/NewFullScreenCustomPass"
    2. {
    3.  
    4. Properties{
    5.  
    6.         _Color("Color", Color) = (1,1,1,1)
    7.  
    8.  
    9.     }
    10.  
    11.  
    12.     HLSLINCLUDE
    13.  
    14.     #pragma vertex Vert
    15.     //#pragma vertex vert
    16.  
    17.     #pragma target 4.5
    18.     #pragma only_renderers d3d11 ps4 xboxone vulkan metal switch
    19.  
    20.     #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
    21.     #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
    22.     #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonLighting.hlsl"
    23. #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
    24.  
    25.     #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassCommon.hlsl"
    26.  
    27.  
    28.     // The PositionInputs struct allow you to retrieve a lot of useful information for your fullScreenShader:
    29.     // struct PositionInputs
    30.      //{
    31.     //     float3 positionWS;  // World space position (could be camera-relative)
    32.     //    float2 positionNDC; // Normalized screen coordinates within the viewport    : [0, 1) (with the half-pixel offset)
    33.     //     uint2  positionSS;  // Screen space pixel coordinates                       : [0, NumPixels)
    34.     //     uint2  tileCoord;   // Screen tile coordinates                              : [0, NumTiles)
    35.     //     float  deviceDepth; // Depth from the depth buffer                          : [0, 1] (typically reversed)
    36.     //     float  linearDepth; // View space Z coordinate                              : [Near, Far]
    37.     // };
    38.  
    39.     // To sample custom buffers, you have access to these functions:
    40.     // But be careful, on most platforms you can't sample to the bound color buffer. It means that you
    41.     // can't use the SampleCustomColor when the pass color buffer is set to custom (and same for camera the buffer).
    42.     // float4 SampleCustomColor(float2 uv);
    43.     // float4 LoadCustomColor(uint2 pixelCoords);
    44.     // float LoadCustomDepth(uint2 pixelCoords);
    45.     // float SampleCustomDepth(float2 uv);
    46.  
    47.     // There are also a lot of utility function you can use inside Common.hlsl and Color.hlsl,
    48.     // you can check them out in the source code of the core SRP package.
    49.  
    50.     float4 _Color;
    51.     float M_PI = 3.141592654f;
    52.     // sampler2D _MainTex;
    53.     // TEXTURE2D(_MainTex);
    54.     SAMPLER(sampler_MainTex);
    55.             float4 _MainTex_ST;
    56.  
    57.     float4 FullScreenPass(Varyings varyings) : SV_Target
    58.    // fixed4 FullScreenPass(Varyings varyings) : SV_Target
    59.     {
    60.    
    61.         UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(varyings);
    62.  
    63.         float depth = LoadCameraDepth(varyings.positionCS.xy);
    64.         PositionInputs posInput = GetPositionInput(varyings.positionCS.xy, _ScreenSize.zw, depth, UNITY_MATRIX_I_VP, UNITY_MATRIX_V);
    65.      
    66.                float2 uv =  posInput.positionNDC.xy * _RTHandleScale.xy;
    67.  
    68.                 float theta = (uv.x*2 + 1) * 3.141592654;
    69.                 //float theta = (varyings.positionCS.x*2 + 1) * 3.141592654;
    70.                float phi = (-(uv.y * 2 - 1) * 3.141592654) / 2;
    71.                // float phi = (-(varyings.positionCS.y * 2 - 1) * 3.141592654) / 2;
    72.                 float x = cos(phi) * sin(theta);
    73.                 float y = sin(phi);
    74.                 float z = cos(phi) * cos(theta);
    75.                 float scale;
    76.                 float2 px;
    77.                 float2 offset;
    78.  
    79.        // float3 viewDirection = GetWorldSpaceNormalizeViewDir(posInput.positionWS);
    80.         float4 colortest =  float4(posInput.positionNDC.x, posInput.positionNDC.y, posInput.positionNDC.x, 0.9);
    81.         float c = float4(0,0,0,1);
    82.         // Load the camera color buffer at the mip 0 if we're not at the before rendering injection point
    83.      //   if (_CustomPassInjectionPoint != CUSTOMPASSINJECTIONPOINT_BEFORE_RENDERING)
    84.        //   float4  color = float4(CustomPassLoadCameraColor(varyings.positionCS.xy, 0), 1);
    85.  
    86.  
    87.          // Pull from each of the 6 textures based on the phi/theta pair
    88.                 if (abs(x) >= abs(y) && abs(x) >= abs(z))
    89.                 {    
    90.                     if (x < 0)
    91.                     {
    92.                         scale = -1.0 / x;
    93.                         px.x = (z * scale + 1.0) / 2.0f;
    94.                         px.y = (y * scale + 1.0) / 2.0f;
    95.                         // Left
    96.                       //  colortest = float4 ( 0.9, 0.0, 0.9 ,0.0);
    97.                        // return float4 ( 0.8, 0.5, 0.9 ,1.0);
    98.                        // return tex2D(_MainTex, float2(px.x / 4, 1 - ((px.y + 1) / 3 )));
    99.                        //  float4 c = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, float2(px.x / 4, 1 - ((px.y + 1) / 3 )));
    100.                         // colortest = c;
    101.                         //  return float4(c.rgb, 0.5);
    102.                          c = tex2Dlod (sampler_MainTex, float4(px.x / 4, 1 - ((px.y + 1) / 3 ), 0,1));
    103.                        return c;
    104.                         //return Texture2D(_MainTex, float2(px.x / 4, 1 - ((px.y + 1) / 3 )));
    105.                     }
    106.  
    107.                  else
    108.                     {
    109.                         scale = 1.0 / x;
    110.                         px.x = (-z * scale + 1.0) / 2.0f;
    111.                         px.y = (y * scale + 1.0) / 2.0f;
    112.                         offset.x = 2;
    113.                         offset.y = 1;
    114.                         // Right            
    115.                         colortest =  float4 ( 0.5, 0.5, 0.5 ,0.5);
    116.                         c =  tex2Dlod (sampler_MainTex, float4(px.x / 4 + .5f, 1 - ((px.y + 1) / 3), 0, 1));
    117.                     return c;
    118.                        // return tex2D(_MainTex, float2(px.x / 4 + .5f, 1 - ((px.y + 1) / 3)));
    119.                     }
    120.                 }
    121.                 else if (abs(y) >= abs(z))
    122.                 {
    123.                     if (y < 0)
    124.                     {
    125.                         scale = -1.0f / y;
    126.                         px.x = (x * scale + 1.0) / 2.0f;
    127.                         px.y = (z * scale + 1.0) / 2.0f;
    128.                         // Top
    129.                        colortest =  float4 ( 0.0, 0.9, 0.0 ,0.5);
    130.                        c = tex2Dlod (sampler_MainTex, float4(px.x / 4 + .25f, 1 - (px.y / 3), 0,1));
    131.                        return c;
    132.                 // return tex2D(_MainTex, float2(px.x / 4 + .25f, 1 - (px.y / 3)));
    133.                     }
    134.                     else
    135.                     {
    136.                         scale = 1.0 / y;
    137.                         px.x = (x * scale + 1.0) / 2.0f;
    138.                         px.y =1 - (-z * scale + 1.0) / 2.0f;
    139.            
    140.                         // Bottom
    141.                                             colortest =  float4 ( 0.9, 0.2, 0.2 ,0.5);
    142.                     c = tex2Dlod (sampler_MainTex, float4(px.x / 4 + .25f, (px.y / 3), 0,1));
    143.                     return c;
    144.                      //  return tex2D(_MainTex, float2(px.x / 4 + .25f, px.y / 3));
    145.            
    146.                     }
    147.                 }
    148.                 else
    149.                 {
    150.                     if (z < 0)
    151.                     {
    152.                         scale = -1.0 / z;
    153.                         px.x = (-x * scale + 1.0) / 2.0f;
    154.                         px.y = (y * scale + 1.0) / 2.0f;
    155.                         // Back
    156.                          colortest = float4 ( 0.5, 0.8, 0.5 ,0.5);
    157.                             c = tex2Dlod (sampler_MainTex, float4(px.x / 4 + .75f, 1 - ((px.y + 1) / 3 ), 0, 1));
    158.  
    159.                              c=  float4
    160.                         return c;
    161.                         //return tex2D(_MainTex, float2(px.x / 4 + .75f, 1 - ((px.y + 1) / 3 )));
    162.                     }
    163.                     else
    164.                     {
    165.                         scale = 1.0 / z;
    166.                         px.x = (x * scale + 1.0) / 2.0f;
    167.                         px.y = (y * scale + 1.0) / 2.0f;
    168.                         // Front
    169.                         colortest =  float4 ( 0.2, 0.0, 0.5 ,0.5);
    170.                         c = tex2Dlod (sampler_MainTex, float4(px.x / 4 + .25f, 1 - ((px.y + 1) / 3), 0, 1));
    171.                         return c;
    172.                        // return tex2D(_MainTex, float2(px.x / 4 + .25f, 1 - ((px.y + 1) / 3)));
    173.                     }
    174.                 }
    175.                 // Should never come here
    176.         // Fade value allow you to increase the strength of the effect while the camera gets closer to the custom pass volume
    177.  
    178.       return float4 ( colortest.rgb ,_Color.a);
    179.  
    180.     }
    181.  
    182.     ENDHLSL
    183.  
    184.  
    185.     SubShader
    186.     {
    187.  
    188.         Pass
    189.         {
    190.             Name "Custom Pass 0"
    191.  
    192.             ZWrite Off
    193.             ZTest LEqual//Always
    194.             Blend SrcAlpha OneMinusSrcAlpha
    195.             Cull Off //Front
    196.  
    197.             HLSLPROGRAM
    198.                 #pragma fragment FullScreenPass
    199.    
    200.             ENDHLSL
    201.  
    202.  
    203.  
    204.  
    205.         }
    206.     }
    207.     Fallback Off
    208. }
    209.  

     

    Attached Files:

    Last edited: Jan 13, 2021
  7. thunderwiring

    thunderwiring

    Joined:
    Aug 28, 2021
    Posts:
    5
    Got few questions about the projection, appreciate if you can help me understand:
    1. the TEXCOORD0 coord got a Z component, is it always 1 (or a const across all texture pixels)?
    2. How the coords returned by RadialCoords are in the 2D space, how does it map to a 3D point on the sphere?
     
  8. MyUserName8

    MyUserName8

    Joined:
    Sep 7, 2023
    Posts:
    1
    I had the same problem and the solution to remove the brown line is to set minFilter and magFilter to LinearFilter in your texture definition.