top of page

360 Image Planet Shader Tutorial.

Updated: Oct 9, 2022

So recently I came across a task, which was to make a planet Shader for my buddy. What he wanted was to turn a panorama 360 texture into a something that looks like the image shown below.


Before going down the article. I want to you to know that I assume you know the basics of Shader programming and is familiar with most of the elementary math concepts. That said. Lets start with a simple Shader applied on a quad with standard UV coordinates. Were the X-axis is shown in red and Y-axis in green.

so here the coordinate begin from the bottom-left corner and spans to a value of 1 at the top-right corner. For to achieve the effect we are going for we need to turn this into polar-coordinated were the positions are represented in terms of Thera and radius.

For that we need to represent our UV coordinated in reference to the center of the quad. For that we need to scale the UV to half the size as quad so that the UV spans to one at the edges of the quad. Then we need to offset it by half the length so that now the origin is in the center of the quad.

The fun part comes here!. We now convert the UV coordinate to polar coordinate. As mentioned earlier polar coordinate represent a position in terms of the distance from the center and angle relative to the x-axis. Lets calculate the the r or distance by getting square root of the UV coordinate.

To find the x equivalent parameter called theta we need to find the tan invers of the UV coordinate position. which get you the theta between a range of -PI to PI. which is approximately -3.14 to 3.14.

To convert it between a range of 0 to 1. Divide the theta with IP then multiply with 0.5 and add the product with 0.5 to offset it.

So you get something like this.

Now you have both the components of a polar coordinate so lets replace the UV part in the image sampling function with the newly obtained polar coordinate.


fixed4 col = tex2D(_MainTex, fixed2(theta, r));


This is how the result looks like. We are some where close but not quiet.

The issue here is that the r is on a linear scale so the value spans uniformly outward. But to achieve our desired look we need to make it negative exponential. So that the value scales us which means a smaller scale while it scales out towards to the edges of the circle.

the easiest was to achieve this is to power the r value by value in the range of 0 - 0.9.


r = pow(r, _value)


and that will result in following.

So here we have it. I hope you manage to get it working, if not and I case if you are too busy. Here is the code to my Shader. Hope it helped.


Shader "Unlit/PolarPlanetShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _CutRadious("Cut Range", range(0, 2)) = 1
        _Zoom("Zoom", range(0, 2)) = 1
        _angle("Angle", range(0, 6.28)) = 1
        _DeLinearize("De-Linearize", range(0, 1)) = 1
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed _CutRadious, _Zoom, _angle, _DeLinearize;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {

                fixed2 newUV = (i.uv * 2) - 1;
                
                fixed newX = newUV.x * cos(_angle) - newUV.y * sin(_angle);
                fixed newY = newUV.x * sin(_angle) + newUV.y * cos(_angle);

                newUV = fixed2(newX, newY);

                fixed rawL = length(newUV);

                fixed theta = (atan2(newUV.y, newUV.x) / 3.14) * 0.5 + 0.5;
                
                fixed l = pow(saturate(rawL), _DeLinearize);
                               
                fixed4 col = tex2D(_MainTex, fixed2(theta, l * _Zoom));
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);

                clip(_CutRadious - rawL);

                return col;
            }
            ENDCG
        }
    }
}




References :



22 views0 comments
bottom of page