Search Unity

[Solved] Curved horizon with sprites

Discussion in 'Shaders' started by ElKrullo, Aug 11, 2015.

  1. ElKrullo

    ElKrullo

    Joined:
    Feb 24, 2013
    Posts:
    17
    Hey guys!

    I am trying to modify Unitys default sprite shader to achieve a curved effect. Basically, I want to decrease the Y-position of vertices by the square distance from the camera along the X-axis.

    I found this curved world shader that helped me get started. Here is the main part of the functionality in that shader, slightly modified so that it curves based on the X-axis rather than Z:
    Code (CSharp):
    1. // This is where the curvature is applied
    2. void vert( inout appdata_full v)
    3. {
    4.     // Transform the vertex coordinates from model space into world space
    5.     float4 vv = mul( _Object2World, v.vertex );
    6.     // Now adjust the coordinates to be relative to the camera position
    7.     vv.xyz -= _WorldSpaceCameraPos.xyz;
    8.     // Reduce the y coordinate (i.e. lower the "height") of each vertex based
    9.     // on the square of the distance from the camera in the z axis, multiplied
    10.     // by the chosen curvature factor
    11.     vv = float4( 0.0f, (vv.x * vv.x) * - _Curvature, 0.0f, 0.0f );
    12.     // Now apply the offset back to the vertices in model space
    13.     v.vertex += mul(_World2Object, vv);
    14. }
    So in the sprite shader I a have tried this:
    Code (CSharp):
    1. v2f vert(appdata_full IN)
    2.     {
    3.     v2f OUT;
    4.     float4 vv = mul(UNITY_MATRIX_MVP, IN.vertex);
    5.     vv.xyz -= _WorldSpaceCameraPos.xyz;
    6.     vv = float4( 0.0f, (vv.x * vv.x) * - _Curvature, 0.0f, 0.0f );
    7.     vv += mul(_World2Object, vv);
    8.     OUT.vertex = vv;
    9.     OUT.texcoord = IN.texcoord;
    10.     OUT.color = IN.color * _Color;
    11.     #ifdef PIXELSNAP_ON
    12.     OUT.vertex = UnityPixelSnap (OUT.vertex);
    13.     #endif
    14.  
    15.     return OUT;
    16. }
    I am very new to this, and I don't really understand what UNITY_MATRIX_MVP is. I have tried to replace it with _Object2World but that didn't help. Obviously I am doing something very wrong, because the sprite disappears.

    If someone could point me in the right direction I would really appreciate it! I guess I need a better understanding of the math involved here.

    Full modified sprite shader below.


    Code (CSharp):
    1. Shader "Sprites/Curved"
    2. {
    3.     Properties
    4.     {
    5.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    6.         _Color ("Tint", Color) = (1,1,1,1)
    7.         [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
    8.         _Curvature ("Curvature", Float) = 0.001
    9.     }
    10.  
    11.     SubShader
    12.     {
    13.         Tags
    14.         {
    15.             "Queue"="Transparent"
    16.             "IgnoreProjector"="True"
    17.             "RenderType"="Transparent"
    18.             "PreviewType"="Plane"
    19.             "CanUseSpriteAtlas"="True"
    20.         }
    21.  
    22.         Cull Off
    23.         Lighting Off
    24.         ZWrite Off
    25.         Blend One OneMinusSrcAlpha
    26.  
    27.         Pass
    28.         {
    29.         CGPROGRAM
    30.             #pragma vertex vert
    31.             #pragma fragment frag
    32.             #pragma multi_compile _ PIXELSNAP_ON
    33.             #include "UnityCG.cginc"
    34.          
    35.             struct appdata_t
    36.             {
    37.                 float4 vertex   : POSITION;
    38.                 float4 color    : COLOR;
    39.                 float2 texcoord : TEXCOORD0;
    40.             };
    41.  
    42.             struct v2f
    43.             {
    44.                 float4 vertex   : SV_POSITION;
    45.                 fixed4 color    : COLOR;
    46.                 half2 texcoord  : TEXCOORD0;
    47.             };
    48.          
    49.             fixed4 _Color;
    50.             uniform float _Curvature;
    51.  
    52.             v2f vert(appdata_full IN)
    53.             {
    54.                 v2f OUT;
    55.                 float4 vv = mul(UNITY_MATRIX_MVP, IN.vertex);
    56.                 vv.xyz -= _WorldSpaceCameraPos.xyz;
    57.                 vv = float4( 0.0f, (vv.x * vv.x) * - _Curvature, 0.0f, 0.0f );
    58.                 vv += mul(_World2Object, vv);
    59.                 OUT.vertex = vv;
    60.                 OUT.texcoord = IN.texcoord;
    61.                 OUT.color = IN.color * _Color;
    62.                 #ifdef PIXELSNAP_ON
    63.                 OUT.vertex = UnityPixelSnap (OUT.vertex);
    64.                 #endif
    65.  
    66.                 return OUT;
    67.             }
    68.  
    69.             sampler2D _MainTex;
    70.  
    71.             fixed4 frag(v2f IN) : SV_Target
    72.             {
    73.                 fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color;
    74.                 c.rgb *= c.a;
    75.                 return c;
    76.             }
    77.         ENDCG
    78.         }
    79.     }
    80. }
     
    Last edited: Aug 11, 2015
  2. ElKrullo

    ElKrullo

    Joined:
    Feb 24, 2013
    Posts:
    17
    Yay, I managed to fix it myself!

    It's not perfect. Some sprites behave a little strange close to the edge of the screen. It's like the new vertex positions disappear sometimes. But still, I'm very happy to have made it this far!

    So if anyone else would like to use or improve on it, feel free. And please share the results!

    Code (CSharp):
    1. Shader "Sprites/Curved"
    2. {
    3.     Properties
    4.     {
    5.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    6.         _Color ("Tint", Color) = (1,1,1,1)
    7.         [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
    8.         _Curvature ("Curvature", Float) = 0.001
    9.     }
    10.  
    11.     SubShader
    12.     {
    13.         Tags
    14.         {
    15.             "Queue"="Transparent"
    16.             "IgnoreProjector"="True"
    17.             "RenderType"="Transparent"
    18.             "PreviewType"="Plane"
    19.             "CanUseSpriteAtlas"="True"
    20.         }
    21.  
    22.         Cull Off
    23.         Lighting Off
    24.         ZWrite Off
    25.         Blend One OneMinusSrcAlpha
    26.  
    27.         Pass
    28.         {
    29.         CGPROGRAM
    30.             #pragma vertex vert
    31.             #pragma fragment frag
    32.             #pragma multi_compile _ PIXELSNAP_ON
    33.             #include "UnityCG.cginc"
    34.            
    35.             struct appdata_t
    36.             {
    37.                 float4 vertex   : POSITION;
    38.                 float4 color    : COLOR;
    39.                 float2 texcoord : TEXCOORD0;
    40.             };
    41.  
    42.             struct v2f
    43.             {
    44.                 float4 vertex   : SV_POSITION;
    45.                 fixed4 color    : COLOR;
    46.                 half2 texcoord  : TEXCOORD0;
    47.             };
    48.            
    49.             fixed4 _Color;
    50.             uniform float _Curvature;
    51.  
    52.             v2f vert(appdata_t IN)
    53.             {
    54.                 v2f OUT;
    55.                 float4 vv = mul( _Object2World, IN.vertex );
    56.                 vv.xyz -= _WorldSpaceCameraPos.xyz;
    57.                
    58.                 //Curvature and taper effects are calculated here
    59.                 vv = float4( vv.x * (vv.y * _Curvature), (vv.x * vv.x) * - _Curvature, 0.0f, 0.0f );
    60.                
    61.                 //Use this instead if you don't want the taper effect
    62.                 //vv = float4( 0.0f, (vv.x * vv.x) * - _Curvature, 0.0f, 0.0f );
    63.                
    64.                 OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex) + mul(_World2Object, vv);
    65.                 OUT.texcoord = IN.texcoord;
    66.                 OUT.color = IN.color * _Color;
    67.                 #ifdef PIXELSNAP_ON
    68.                 OUT.vertex = UnityPixelSnap (OUT.vertex);
    69.                 #endif
    70.  
    71.                 return OUT;
    72.             }
    73.  
    74.             sampler2D _MainTex;
    75.  
    76.             fixed4 frag(v2f IN) : SV_Target
    77.             {
    78.                 fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color;
    79.                 c.rgb *= c.a;
    80.                 return c;
    81.             }
    82.         ENDCG
    83.         }
    84.     }
    85. }