Animal Crossing Curved World Shader

Continuing the theme of my last post, I thought I’d write another shader – this time to mimic the cylindrical rolloff effect of distant objects seen in, amongst others, the “Animal Crossing” series. Rather than appearing on a flat plane, the world surface gently rolls towards you as if projected onto a cylindrical surface, as shown below:

http://images2.wikia.nocookie.net/__cb20080722232245/animalcrossing/images/6/66/CF_ss001.jpg

The following code reproduces this effect – the comments are fairly explicit as to how it works. Note that rather than being a generic HLSL/Cg pixel-fragment shader, it’s a surface shader, which means it’ll only work in Unity. The advantage, however, is that it’ll automatically calculate lighting and shadow calculations without me having to write any nasty dot products of surface normals compared to light direction etc….

Shader "Custom/CurvedWorld" {
    Properties {
        // Diffuse texture
        _MainTex ("Base (RGB)", 2D) = "white" {}
        // Degree of curvature
        _Curvature ("Curvature", Float) = 0.001
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200
       
        CGPROGRAM
        // Surface shader function is called surf, and vertex preprocessor function is called vert
        #pragma surface surf Lambert vertex:vert

        // Access the shaderlab properties
        uniform sampler2D _MainTex;
        uniform float _Curvature;

        // Basic input structure to the shader function
        // requires only a single set of UV texture mapping coordinates
        struct Input {
            float2 uv_MainTex;
        };

        // This is where the curvature is applied
        void vert( inout appdata_full v)
        {
            // Transform the vertex coordinates from model space into world space
            float4 vv = mul( _Object2World, v.vertex );

            // Now adjust the coordinates to be relative to the camera position
            vv.xyz -= _WorldSpaceCameraPos.xyz;

            // Reduce the y coordinate (i.e. lower the "height") of each vertex based
            // on the square of the distance from the camera in the z axis, multiplied
            // by the chosen curvature factor
            vv = float4( 0.0f, (vv.z * vv.z) * - _Curvature, 0.0f, 0.0f );

            // Now apply the offset back to the vertices in model space
            v.vertex += mul(_World2Object, vv);
        }

        // This is just a default surface shader
        void surf (Input IN, inout SurfaceOutput o) {
            half4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
    // FallBack "Diffuse"
}

 

The preceding code assumes that the camera faces forward along the z-axis (as is default in Unity), which gives an effect as follows (these objects are all placed on a flat, level plane – the curvature is applied solely in the shader):

image

 

The effect is perhaps more satisfying when animated:

 

Note that, if you want the world to have a spherical rolloff – i.e. to rolloff in both the x and z axes, then adjust the line in the vertex modifier function to be as follows:

vv = float4( 0.0f, ((vv.z * vv.z) + (vv.x * vv.x)) * - _Curvature, 0.0f, 0.0f )

About these ads
This entry was posted in Game Dev and tagged , , , . Bookmark the permalink.

One Response to Animal Crossing Curved World Shader

  1. Hey there- I’ve just been playing with this, and I’ve noticed sometimes it culls objects before they’ve actually disappeared. Is there a solution to this?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s