void main()
 {
     vPosition = uMVMatrix * vec4(aVertexPosition, 1.0f);
     gl_Position = uPMatrix * vPosition;
     vTextureCoord = aTextureCoord;
     vTransformedNormal = uNMatrix * aVertexNormal;
 }
        int func(vec3 pos, float stepshift)
        {
            vec3 v2 = abs(fract(pos) - vec3(0.5f, 0.5f, 0.5f)) / 2.0f;
            float r = 0.0769f * sin(t * -0.0708f);
            float blowup = BLOWUP / pow(2.0f, stepshift + 8.0f);

            if (sum(v2) - 0.1445 + r < blowup) return 1;
            v2 = vec3(0.25f, 0.25f, 0.25f) - v2;
            if (sum(v2) - 0.1445 - r < blowup) return 2;

            int hue;
            float width;
            if (abs(sum(v2) - 3.0f * r - 0.375f) < 0.03846f)
            {
                width = 0.1445f;
                hue = 4;
            }
            else
            {
                width = 0.0676f;
                hue = 3;
            }

            if (sum(abs(v2.zxy - v2.xyz)) - width < blowup) return hue;

            return 0;

        }
 void main()
 {
     gl_Position = prMatrix * mvMatrix * vec4(scale * aPos, 1.0f);
     vec4 rotNorm = mvMatrix * vec4(aPos, .0f);
     float i = max(0.0f, dot(rotNorm, dirDif));
     col = i * color;
     i = pow(max(0.0f, dot(rotNorm, dirHalf)), 30.0f);
     col += vec3(i, i, i);
 }
        vec3 v_Normal;         		// This will be passed into the fragment shader.

        // The entry point for our vertex shader.  
        void main()
        {
            // Transform the vertex into eye space.
            v_Position = vec3(u_MVMatrix * a_Position);
            // Pass through the color.
            v_Color = a_Color;
            // Transform the normal's orientation into eye space.
            v_Normal = vec3(u_MVMatrix * vec4(a_Normal, 0.0f));
            // gl_Position is a special variable used to store the final position.
            // Multiply the vertex by the matrix to get the final point in normalized screen coordinates.
            gl_Position = u_MVPMatrix * a_Position;
        }
        bool intersectWorld(vec3 lStart, vec3 lDir, ref vec3 pos,
                            ref vec3 normal, ref vec3 color)
        {
            float d1, d2, d3;
            bool h1, h2, h3;

            h1 = intersectSphere(sphere1Center, lStart, lDir, out d1);
            h2 = intersectSphere(sphere2Center, lStart, lDir, out d2);
            h3 = intersectSphere(sphere3Center, lStart, lDir, out d3);

            if (h1 && d1 < d2 && d1 < d3)
            {
                pos = lStart + d1 * lDir;
                normal = pos - sphere1Center;
                color = vec3(0.0f, 0.0f, 0.9f);
            }
            else if (h2 && d2 < d3)
            {
                pos = lStart + d2 * lDir;
                normal = pos - sphere2Center;
                color = vec3(0.9f, 0.0f, 0.0f);
            }
            else if (h3)
            {
                pos = lStart + d3 * lDir;
                normal = pos - sphere3Center;
                color = vec3(0.0f, 0.9f, 0.0f);
            }
            else if (lDir.y < -0.01)
            {
                pos = lStart + ((lStart.y + 2.7f) / -lDir.y) * lDir;
                if (pos.x * pos.x + pos.z * pos.z > 30.0)
                {
                    return false;
                }
                normal = vec3(0.0f, 1.0f, 0.0f);
                if (fract(pos.x / 5.0f) > 0.5f == fract(pos.z / 5.0f) > 0.5f)
                {
                    color = vec3(1.0f);
                }
                else
                {
                    color = vec3(0.0f);
                }
            }
            else
            {
                return false;
            }

            return true;
        }
        vec3 lightAt(vec3 N, vec3 V, vec3 color)
        {
            vec3 L = lightDir;
            vec3 R = reflect(-L, N);

            float c = 0.3f + 0.4f * pow(max(dot(R, V), 0.0f), 30.0f) + 0.7f * dot(L, N);

            if (c > 1.0)
            {
                return mix(color, vec3(1.6f, 1.6f, 1.6f), c - 1.0f);
            }

            return c * color;
        }
        void main()
        {

            vec3 uAmbientColor = vec3(0.2f, 0.2f, 0.2f);
            vec3 uDirectionalColor = vec3(0.8f, 0.8f, 0.8f);
            vec3 uLightingDirection = vec3(0f, 1f, 0f);

            gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0f);
            gl_PointSize = 2.0f;
            //vLightWeighting = vec3(1.0, 1.0, 1.0);
            vec4 transformedNormal = uNMatrix * vec4(aVertexNormal.xyz, 1.0f);
            float directionalLightWeighting = max(dot(transformedNormal.xyz, uLightingDirection), 0.0f);
            vLightWeighting = uAmbientColor + uDirectionalColor * directionalLightWeighting;
            vColor = aVertexColor;
        }
        void main()
        {
            gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0f);
            vTextureCoord = aTextureCoord;

            if (!uUseLighting)
            {
                vLightWeighting = vec3(1.0f, 1.0f, 1.0f);
            }
            else
            {
                vec3 transformedNormal = uNMatrix * aVertexNormal;
                float directionalLightWeighting = max(dot(transformedNormal, uLightingDirection), 0.0f);
                vLightWeighting = uAmbientColor + uDirectionalColor * directionalLightWeighting;
            }
        }
        void main()
        {
            vec4 mvPosition = uMVMatrix * vec4(aVertexPosition, 1.0f);
            gl_Position = uPMatrix * mvPosition;
            vTextureCoord = aTextureCoord;

            if (!uUseLighting)
            {
                vLightWeighting = vec3(1.0f, 1.0f, 1.0f);
            }
            else
            {
                vec3 lightDirection = normalize(uPointLightingLocation - mvPosition.xyz);

                vec3 transformedNormal = uNMatrix * aVertexNormal;
                float directionalLightWeighting = max(dot(transformedNormal, lightDirection), 0.0f);
                vLightWeighting = uAmbientColor + uPointLightingColor * directionalLightWeighting;
            }
        }
        void main()
        {

            vec4 mPosition = objectMatrix * vec4(position, 1.0f);
            vec4 mvPosition = modelViewMatrix * vec4(position, 1.0f);
            vec3 nWorld = normalize(
                mat3(
                    objectMatrix[0].xyz, 
                    objectMatrix[1].xyz, 
                    objectMatrix[2].xyz
                ) * normal);

            vNormal = normalize(normalMatrix * normal);

            vec3 I = mPosition.xyz - cameraPosition;
            vRefract = refract(normalize(I), nWorld, 1.02f);

            gl_Position = projectionMatrix * mvPosition;

        }
        bool intersectSphere(vec3 center, vec3 lStart, vec3 lDir,
                             out float dist)
        {
            vec3 c = center - lStart;
            float b = dot(lDir, c);
            float d = b * b - dot(c, c) + 1.0f;
            if (d < 0.0)
            {
                dist = 10000.0f;
                return false;
            }

            dist = b - sqrt(d);
            if (dist < 0.0)
            {
                dist = 10000.0f;
                return false;
            }

            return true;
        }
 abstract protected int func(vec3 pos, float stepshift);
 static protected vec4 vec4(vec3 x, float y)
 {
     throw new NotImplementedException();
 }
 static protected vec3 vec3(vec3 v)
 {
     throw new NotImplementedException();
 }
		//------------------------------------------------------------------------
		// Camera
		//
		// Move the camera. In this case it's using time and the mouse position
		// to orbitate the camera around the origin of the world (0,0,0), where
		// the yellow sphere is.
		//------------------------------------------------------------------------
		void doCamera(out vec3 camPos, out vec3 camTar, float time, float mouseX)
		{
			float an = 0.3f * iGlobalTime + 10.0f * mouseX;
			camPos = vec3(3.5f * sin(an) + sin(iGlobalTime * 0.1f) * 15.0f, 1.1f + sin(iGlobalTime * 0.25f), 3.5f * cos(an));
			camTar = vec3(0.0f, 0.0f, 0.0f);
		}
		float sdBox(vec3 p, vec3 b)
		{
			vec3 d = abs(p) - b;
			return min(max(d.x, max(d.y, d.z)), 0.0f) +
				   length(max(d, 0.0f));
		}
		mat3 calcLookAtMatrix(vec3 ro, vec3 ta, float roll)
		{
			vec3 ww = normalize(ta - ro);
			vec3 uu = normalize(cross(ww, vec3(sin(roll), cos(roll), 0.0f)));
			vec3 vv = normalize(cross(uu, ww));
			return mat3(uu, vv, ww);
		}
		vec3 calcNormal(vec3 pos)
		{
			const float eps = 0.002f;			  // precision of the normal computation

			var v1 = vec3(1.0f, -1.0f, -1.0f);
			var v2 = vec3(-1.0f, -1.0f, 1.0f);
			var v3 = vec3(-1.0f, 1.0f, -1.0f);
			var v4 = vec3(1.0f, 1.0f, 1.0f);

			return normalize(v1 * doModel(pos + v1 * eps) +
							  v2 * doModel(pos + v2 * eps) +
							  v3 * doModel(pos + v3 * eps) +
							  v4 * doModel(pos + v4 * eps));
		}
		//------------------------------------------------------------------------
		// Lighting
		//------------------------------------------------------------------------
		//float calcSoftshadow( in vec3 ro, in vec3 rd);

		vec3 doLighting(vec3 pos, vec3 nor, vec3 rd, float dis, vec3 mal)
		{
			vec3 lin = vec3(0.0f);

			// key light
			//-----------------------------
			vec3 lig = normalize(vec3(1.0f, 0.7f, 0.9f));
			float dif = max(dot(nor, lig), 0.0f);
			float sha = 0.0f; if (dif > 0.01) sha = calcSoftshadow(pos + 0.01f * nor, lig);
			lin += dif * vec3(4.00f, 4.00f, 4.00f) * sha;

			// ambient light
			//-----------------------------
			lin += vec3(0.50f, 0.50f, 0.50f);


			// surface-light interacion
			//-----------------------------
			vec3 col = mal * lin;


			return col;
		}
 abstract protected float sum(vec3 v);
 void main()
 {
     gl_Position = vec4(aVertexPosition, 1.0f, 1.0f);
     vPosition = aPlotPosition;
 }
		//------------------------------------------------------------------------
		// Material 
		//
		// Defines the material (colors, shading, pattern, texturing) of the model
		// at every point based on its position and normal. In this case, it simply
		// returns a constant yellow color.
		//------------------------------------------------------------------------
		vec3 doMaterial(vec3 pos, vec3 nor) => vec3(0.15f, 0.2f, 0.23f);
			float surface3( vec3 coord ) {

				float n = 0.0f;

				n += 1.0f * abs( snoise( coord ) );
				n += 0.5f * abs( snoise( coord * 2.0f ) );
				n += 0.25f * abs( snoise( coord * 4.0f ) );
				n += 0.125f * abs( snoise( coord * 8.0f ) );

				return n;

			}
		float calcIntersection(vec3 ro, vec3 rd)
		{
			const float maxd = 20.0f;			// max trace distance
			const float precis = 0.001f;		// precission of the intersection
			float h = precis * 2.0f;
			float t = 0.0f;
			float res = -1.0f;
			for (int i = 0; i < 90; i++)		  // max number of raymarching iterations is 90
			{
				if (h < precis || t > maxd) break;
				h = doModel(ro + rd * t);
				t += h;
			}

			if (t < maxd) res = t;
			return res;
		}
			float snoise( vec3 v ) {

				/* const*/ vec2 C = vec2( 1.0f / 6.0f, 1.0f / 3.0f );
				/* const*/ vec4 D = vec4( 0.0f, 0.5f, 1.0f, 2.0f );

				// First corner

				vec3 i  = floor( v + dot( v, C.yyy ) );
				vec3 x0 = v - i + dot( i, C.xxx );

				// Other corners

				vec3 g = step( x0.yzx, x0.xyz );
				vec3 l = 1.0f - g;
				vec3 i1 = min( g.xyz, l.zxy );
				vec3 i2 = max( g.xyz, l.zxy );

				vec3 x1 = x0 - i1 + 1.0f * C.xxx;
				vec3 x2 = x0 - i2 + 2.0f * C.xxx;
				vec3 x3 = x0 - 1.0f + 3.0f * C.xxx;

				// Permutations

				i = mod( i, 289.0f );
				vec4 p = permute( permute( permute(
						 i.z + vec4( 0.0f, i1.z, i2.z, 1.0f ) )
					   + i.y + vec4( 0.0f, i1.y, i2.y, 1.0f ) )
					   + i.x + vec4( 0.0f, i1.x, i2.x, 1.0f ) );

				// Gradients
				// ( N*N points uniformly over a square, mapped onto an octahedron.)

				float n_ = 1.0f / 7.0f; // N=7

				vec3 ns = n_ * D.wyz - D.xzx;

				vec4 j = p - 49.0f * floor( p * ns.z *ns.z );  //  mod(p,N*N)

				vec4 x_ = floor( j * ns.z );
				vec4 y_ = floor( j - 7.0f * x_ );    // mod(j,N)

				vec4 x = x_ *ns.x + ns.yyyy;
				vec4 y = y_ *ns.x + ns.yyyy;
				vec4 h = 1.0f - abs( x ) - abs( y );

				vec4 b0 = vec4( x.xy, y.xy );
				vec4 b1 = vec4( x.zw, y.zw );


				vec4 s0 = floor( b0 ) * 2.0f + 1.0f;
				vec4 s1 = floor( b1 ) * 2.0f + 1.0f;
				vec4 sh = -step( h, vec4( 0.0f ) );

				vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
				vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;

				vec3 p0 = vec3( a0.xy, h.x );
				vec3 p1 = vec3( a0.zw, h.y );
				vec3 p2 = vec3( a1.xy, h.z );
				vec3 p3 = vec3( a1.zw, h.w );

				// Normalise gradients

				vec4 norm = taylorInvSqrt( vec4( dot( p0, p0 ), dot( p1, p1 ), dot( p2, p2 ), dot( p3, p3 ) ) );
				p0 *= norm.x;
				p1 *= norm.y;
				p2 *= norm.z;
				p3 *= norm.w;

				// Mix final noise value

				vec4 m = max( 0.6f - vec4( dot( x0, x0 ), dot( x1, x1 ), dot( x2, x2 ), dot( x3, x3 ) ), 0.0f );
				m = m * m;
				return 42.0f * dot( m*m, vec4( dot( p0, x0 ), dot( p1, x1 ),
											  dot( p2, x2 ), dot( p3, x3 ) ) );

			}
		float calcSoftshadow(vec3 ro, vec3 rd)
		{
			float res = 1.0f;
			float t = 0.0005f;				   // selfintersection avoidance distance
			float h = 1.0f;
			for (int i = 0; i < 40; i++)		 // 40 is the max numnber of raymarching steps
			{
				h = doModel(ro + rd * t);
				res = min(res, 48.0f * h / t);	 // 64 is the hardness of the shadows
				t += clamp(h, 0.02f, 2.0f);	  // limit the max and min stepping distances
			}
			return clamp(res, 0.0f, 1.0f);
		}
 protected vec4 texture2DProjLod(sampler2D sampler, vec3 coord, float lod) { throw new NotImplementedException(); }
		float udBox(vec3 p, vec3 b) => length(max(abs(p) - b, 0.0f));
 protected vec4 textureCubeLod(samplerCube sampler, vec3 coord, float lod) { throw new NotImplementedException(); }
		// n must be normalized
		float sdPlane(vec3 p, vec4 n) => dot(p, n.xyz) + n.w;
 float sum(vec3 v)
 {
     return v.x + v.y + v.z;
 }
		//------------------------------------------------------------------------
		// Modelling 
		//
		// Defines the shapes (a sphere in this case) through a distance field, in
		// this case it's a sphere of radius 1.
		//------------------------------------------------------------------------
		float doModel(vec3 p)
		{
			vec3 idx = vec3(floor(abs(p.xz - 0.5f)), 0.5f);
			p.xz = mod(p.xz + 0.5f, 1.0f) - 0.5f;
			float h = sin(length(idx.xy * 0.5f) + iGlobalTime * 1.5f) * 0.6f;
			float d = sdBox(p, vec3(0.05f, h, 0.05f));

			d = smin(d, sdPlane(p, normalize(vec4(0, 1, 0, 0))), 0.035f);

			return d;
		}
 static protected mat3 mat3(vec3 x, vec3 y, vec3 z)
 {
     throw new NotImplementedException();
 }