# [Solved] Curved horizon with sprites

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

1. ### 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

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. }

unityunity