﻿// experimental shader to animate a sphere with vertex math
// christopher rogers rogersc@fb.com 

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

Shader "Unlit/EggShader"
{
    Properties
    {
       // _MainTex ("Texture", 2D) = "white" {}
       // these need to match the number of row/cols in MakeEgg.cs
        _U("U",Range(2,140)) = 20
        _V("V",Range(2,140)) = 20
        
        // sweep less than 360 to get a pac-man shape
        _TU("pie shape",Range(-1,1)) = 0
        
        // main axis start and end 
        _TV("row start",Range(-1,1)) = 0
        _TVe("row end",Range(-1,1)) = 0
        
        // radius of sphere
        radius("radius",Range(0.1,10)) = 1
        
        
        
        // zig zag the row start for a star shape
        _star("star amount",Range(-18,18)) = 0
        
        // squeeze in uv space
        _squeeze("sqeeuze face in uv", Range(0,10)) = 0 
        
        // color speed
        _colorSpeed("color speed", Range(-2,2)) = .1 
         // mix between these 2 colors along main axis
        _col1("color1",Color) = (1,1,1,1)
        _col2("color2",Color) = (1,1,1,1)
        
        // amount of noise for all 3 channels
        _noise("noise amount",Range(0,2)) = 0.01
        
        // per channel noise freqency
        nxyz("noise freq",Vector) = (1,1,1,1)
        
        // offsets noise, doesnt do anything except be the same as _Time.y for now
        axyz("noise speed x y z w=all",Vector) = (1,1,1,1)
        
       
        
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
        Cull Off
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float4 color : COLOR;
                float4 uv : TEXCOORD0;
            //    float4 tangent : TANGENT;
               // float4 binormal : binormal;
            };

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

           // sampler2D _MainTex;
           // float4 _MainTex_ST;
            float _U;
            float _V;
            float _TU;
            float _TV, _TVe;
            float radius;
            float _noise;
            float4 nxyz;
            float4 axyz;
            float4 _col1, _col2;
            float _star;
             float _squeeze;
             float _colorSpeed;
 //https://www.shadertoy.com/view/XsX3zB
/* skew constants for 3d simplex functions */
const float F3 =  0.3333333;
const float G3 =  0.1666667;
const float M_PI = 3.1415927;
/* discontinuous pseudorandom uniformly distributed in [-0.5, +0.5]^3 */
float3 random3(float3 c) {
	float j = 4096.0*sin(dot(c,float3(17.0, 59.4, 15.0)));
	float3 r;
	r.z = frac(512.0*j);
	j *= .125;
	r.x = frac(512.0*j);
	j *= .125;
	r.y = frac(512.0*j);
	return r-0.5;
}

/* 3d simplex noise */
float simplex3d(float3 p) {
	 /* 1. find current tetrahedron T and it's four vertices */
	 /* s, s+i1, s+i2, s+1.0 - absolute skewed (integer) coordinates of T vertices */
	 /* x, x1, x2, x3 - unskewed coordinates of p relative to each of T vertices*/
	 
	 /* calculate s and x */
	 float3 s = floor(p + dot(p, float3(F3,F3,F3)));
	 float3 x = p - s + dot(s, float3(G3, G3, G3));
	 
	 /* calculate i1 and i2 */
	 float3 e = step(float3(0,0,0), x - x.yzx);
	 float3 i1 = e*(1.0 - e.zxy);
	 float3 i2 = 1.0 - e.zxy*(1.0 - e);
	 	
	 /* x1, x2, x3 */
	 float3 x1 = x - i1 + G3;
	 float3 x2 = x - i2 + 2.0*G3;
	 float3 x3 = x - 1.0 + 3.0*G3;
	 
	 /* 2. find four surflets and store them in d */
	 float4 w, d;
	 
	 /* calculate surflet weights */
	 w.x = dot(x, x);
	 w.y = dot(x1, x1);
	 w.z = dot(x2, x2);
	 w.w = dot(x3, x3);
	 
	 /* w fades from 0.6 at the center of the surflet to 0.0 at the margin */
	 w = max(0.6 - w, 0.0);
	 
	 /* calculate surflet components */
	 d.x = dot(random3(s), x);
	 d.y = dot(random3(s + i1), x1);
	 d.z = dot(random3(s + i2), x2);
	 d.w = dot(random3(s + 1.0), x3);
	 
	 /* multiply d by w^4 */
	 w *= w;
	 w *= w;
	 d *= w;
	 
	 /* 3. return the sum of the four surflets */
	 return dot(d, float4(52.0,52.,52.,52.));
}
      // given a polar coordinate convert to cartesian 
       float3 polToCart(float row, float col) {
        float3 cart = {0,0,0};
        // TODO this doesnt look right and use PI
        float u = col/_U * 6.28 * _TU;
        float v = row/_V* 3.14 * _TV;
        cart.x = radius * sin(v)*cos(u);
        cart.y = radius * sin(v)*sin(u);
        cart.z = radius * cos(v);

        return cart;
       }
       
       // doesnt get used but math is in comment at bottom
       float3 cartToPol(float3 cart) {
        float3 pol = {0,0,0};
        return pol;
       }
       
            // main vert program
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex =  (v.vertex);
                o.uv =  v.uv;
                o.color = v.color;
                UNITY_TRANSFER_FOG(o,o.vertex);
                
                // the uv coords are 0,1,2,3,4  etc
                float row = int(o.uv.x);
                float col = int(o.uv.y);
                
                // mix color along main axis
                float f = frac((_Time.y *_colorSpeed) + (o.uv.x / _U));
                 o.color  = smoothstep(_col1,_col2,f);
                 
               // min max for start/stop of rows on sphere
                row = min(row,_TV*_U);
                row = max(row,_TVe*_V);
                
                // make it jaggy
                row += (col%2) * _star;
                
                
               // f = 1 - (f*f);
               // this pushes each vert towards the center of the quad
                row += v.uv.z * (_squeeze ); // *f for pulsatiions
                col += v.uv.w  * (_squeeze  );

               o.vertex.xyz = polToCart(row ,col);
               
               // hacky animation TODO make better
               axyz.z += _Time.y;
                axyz.x += _Time.x * 0.1;
                // add noise to the position
                o.vertex.xyz +=_noise*simplex3d(axyz.xyz+(o.vertex.xyz*nxyz.xyz));
                
                // i dont understand what to do here.  Unity puts this is if i mul(MVP)
                // end goal is the object to move in space like any other object,
                // but this way its really tough/impossile to see in scene view
                // and stays the same screen size no matter how far away camera is
                o.vertex.xyz = UnityObjectToClipPos(o.vertex.xyz);
               
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = i.color;
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

/*

float radius = sqrt(@P.x*@P.x + @P.y*@P.y + @P.z*@P.z);
float u = atan2(@P.y, @P.x) + M_PI;
float v = acos(@P.z/radius);

@P.x = radius * sin(v)*cos(u);
@P.y = radius * sin(v)*sin(u);
@P.z = radius * cos(v);


// Convert object space to world space
 float4 NewCoord = mul(_Object2World, CoordToConvert);
 
 // Convert worldspace to object space
 float4 NewCoord = mul(_World2Object, CoordToConvert);
 
 
 
 quick explanation:
 c# script creates a grid of unconnected quads (they do not share a vertex) and assigns the UV to be the integer grid position, ie: UV.xy = (3.0,2.0)
 also, the script stuffs another vector into the UV.wz that is a direction from that vertex to the center of the quad, so the effect is they all shrink when applied to a vertex position
 the vertex shader uses the polarCoordinateToCartesian formula to transform this grid into a sphere.
 the row end, row start variables control the start and end of the sphere to chop the ends off, to make it a tube
 per-channel noise frequency
 should have per-channel noise animation

 
 
 
 
 
*/