1// Compatibility #ifdefs needed for parameters
2#ifdef GL_ES
3#define COMPAT_PRECISION mediump
4#else
5#define COMPAT_PRECISION
6#endif
7
8// Parameter lines go here:
9#pragma parameter RETRO_PIXEL_SIZE "Retro Pixel Size" 0.84 0.0 1.0 0.01
10#ifdef PARAMETER_UNIFORM
11// All parameter floats need to have COMPAT_PRECISION in front of them
12uniform COMPAT_PRECISION float RETRO_PIXEL_SIZE;
13#else
14#define RETRO_PIXEL_SIZE 0.84
15#endif
16
17#if defined(VERTEX)
18
19#if __VERSION__ >= 130
20#define COMPAT_VARYING out
21#define COMPAT_ATTRIBUTE in
22#define COMPAT_TEXTURE texture
23#else
24#define COMPAT_VARYING varying
25#define COMPAT_ATTRIBUTE attribute
26#define COMPAT_TEXTURE texture2D
27#endif
28
29#ifdef GL_ES
30#define COMPAT_PRECISION mediump
31#else
32#define COMPAT_PRECISION
33#endif
34
35COMPAT_ATTRIBUTE vec4 VertexCoord;
36COMPAT_ATTRIBUTE vec4 COLOR;
37COMPAT_ATTRIBUTE vec4 TexCoord;
38COMPAT_VARYING vec4 COL0;
39COMPAT_VARYING vec4 TEX0;
40// out variables go here as COMPAT_VARYING whatever
41
42vec4 _oPosition1;
43uniform mat4 MVPMatrix;
44uniform COMPAT_PRECISION int FrameDirection;
45uniform COMPAT_PRECISION int FrameCount;
46uniform COMPAT_PRECISION vec2 OutputSize;
47uniform COMPAT_PRECISION vec2 TextureSize;
48uniform COMPAT_PRECISION vec2 InputSize;
49
50// compatibility #defines
51#define vTexCoord TEX0.xy
52#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
53#define OutSize vec4(OutputSize, 1.0 / OutputSize)
54
55void main()
56{
57    gl_Position = MVPMatrix * VertexCoord;
58    TEX0.xy = VertexCoord.xy;
59// Paste vertex contents here:
60}
61
62#elif defined(FRAGMENT)
63
64#if __VERSION__ >= 130
65#define COMPAT_VARYING in
66#define COMPAT_TEXTURE texture
67out vec4 FragColor;
68#else
69#define COMPAT_VARYING varying
70#define FragColor gl_FragColor
71#define COMPAT_TEXTURE texture2D
72#endif
73
74#ifdef GL_ES
75#ifdef GL_FRAGMENT_PRECISION_HIGH
76precision highp float;
77#else
78precision mediump float;
79#endif
80#define COMPAT_PRECISION mediump
81#else
82#define COMPAT_PRECISION
83#endif
84
85uniform COMPAT_PRECISION int FrameDirection;
86uniform COMPAT_PRECISION int FrameCount;
87uniform COMPAT_PRECISION vec2 OutputSize;
88uniform COMPAT_PRECISION vec2 TextureSize;
89uniform COMPAT_PRECISION vec2 InputSize;
90uniform sampler2D Texture;
91COMPAT_VARYING vec4 TEX0;
92// in variables go here as COMPAT_VARYING whatever
93
94// compatibility #defines
95#define Source Texture
96#define vTexCoord TEX0.xy
97
98#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
99#define OutSize vec4(OutputSize, 1.0 / OutputSize)
100
101// delete all 'params.' or 'registers.' or whatever in the fragment
102float iGlobalTime = float(FrameCount)*0.025;
103vec2 iResolution = OutputSize.xy;
104
105/*--------------------------------------------------------------------------------------
106License CC0 - http://creativecommons.org/publicdomain/zero/1.0/
107To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
108----------------------------------------------------------------------------------------
109-Otavio Good
110*/
111
112// The noise function in this was inspired by IQ's "Terrain Tubes" shader. I never really figured out
113// his function completely, so I'm not sure of the exact similarities. It's nice though because it
114// works the same on all computers (I think). It's not based on a hash that changes from computer to
115// computer. That means I can finally rely on the terrain being the same and make a camera path. :)
116// It's also a much faster noise function, although it can look a bit repetitive.
117
118#define MOTION_BLUR
119#define MOVING_SUN
120
121float Hash2d(vec2 uv)
122{
123    float f = uv.x + uv.y * 47.0;
124    return fract(cos(f*3.333)*100003.9);
125}
126float Hash3d(vec3 uv)
127{
128    float f = uv.x + uv.y * 37.0 + uv.z * 521.0;
129    return fract(cos(f*3.333)*100003.9);
130}
131
132float PI=3.14159265;
133
134vec3 saturate(vec3 a) { return clamp(a, 0.0, 1.0); }
135vec2 saturate(vec2 a) { return clamp(a, 0.0, 1.0); }
136float saturate(float a) { return clamp(a, 0.0, 1.0); }
137
138vec3 RotateX(vec3 v, float rad)
139{
140  float cos = cos(rad);
141  float sin = sin(rad);
142  //if (RIGHT_HANDED_COORD)
143  return vec3(v.x, cos * v.y + sin * v.z, -sin * v.y + cos * v.z);
144  //else return new float3(x, cos * y - sin * z, sin * y + cos * z);
145}
146vec3 RotateY(vec3 v, float rad)
147{
148  float cos = cos(rad);
149  float sin = sin(rad);
150  //if (RIGHT_HANDED_COORD)
151  return vec3(cos * v.x - sin * v.z, v.y, sin * v.x + cos * v.z);
152  //else return new float3(cos * x + sin * z, y, -sin * x + cos * z);
153}
154vec3 RotateZ(vec3 v, float rad)
155{
156  float cos = cos(rad);
157  float sin = sin(rad);
158  //if (RIGHT_HANDED_COORD)
159  return vec3(cos * v.x + sin * v.y, -sin * v.x + cos * v.y, v.z);
160}
161
162
163// This function basically is a procedural environment map that makes the sun
164vec3 sunCol = vec3(258.0, 208.0, 100.0) / 4255.0;//unfortunately, i seem to have 2 different sun colors. :(
165vec3 GetSunColorReflection(vec3 rayDir, vec3 sunDir)
166{
167	vec3 localRay = normalize(rayDir);
168	float dist = 1.0 - (dot(localRay, sunDir) * 0.5 + 0.5);
169	float sunIntensity = 0.015 / dist;
170	sunIntensity = pow(sunIntensity, 0.3)*100.0;
171
172    sunIntensity += exp(-dist*12.0)*300.0;
173	sunIntensity = min(sunIntensity, 40000.0);
174	return sunCol * sunIntensity*0.0425;
175}
176vec3 GetSunColorSmall(vec3 rayDir, vec3 sunDir)
177{
178	vec3 localRay = normalize(rayDir);
179	float dist = 1.0 - (dot(localRay, sunDir) * 0.5 + 0.5);
180	float sunIntensity = 0.05 / dist;
181    sunIntensity += exp(-dist*12.0)*300.0;
182	sunIntensity = min(sunIntensity, 40000.0);
183	return sunCol * sunIntensity*0.025;
184}
185
186// This is a spline used for the camera path
187vec4 CatmullRom(vec4 p0, vec4 p1, vec4 p2, vec4 p3, float t)
188{
189    float t2 = t*t;
190    float t3 = t*t*t;
191    return 0.5 *((2.0 * p1) +
192                 (-p0 + p2) * t +
193    			 (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 +
194    			 (-p0 + 3.0 * p1- 3.0 * p2 + p3) * t3);
195}
196
197// This spiral noise works by successively adding and rotating sin waves while increasing frequency.
198// It should work the same on all computers since it's not based on a hash function like some other noises.
199// It can be much faster than other noise functions if you're ok with some repetition.
200const float nudge = 0.739513;	// size of perpendicular vector
201float normalizer = 1.0 / sqrt(1.0 + nudge*nudge);	// pythagorean theorem on that perpendicular to maintain scale
202float SpiralNoiseC(vec3 p)
203{
204    float n = 0.0;	// noise amount
205    float iter = 1.0;
206    for (int i = 0; i < 8; i++)
207    {
208        // add sin and cos scaled inverse with the frequency
209        n += -abs(sin(p.y*iter) + cos(p.x*iter)) / iter;	// abs for a ridged look
210        // rotate by adding perpendicular and scaling down
211        p.xy += vec2(p.y, -p.x) * nudge;
212        p.xy *= normalizer;
213        // rotate on other axis
214        p.xz += vec2(p.z, -p.x) * nudge;
215        p.xz *= normalizer;
216        // increase the frequency
217        iter *= 1.733733;
218    }
219    return n;
220}
221float SpiralNoiseD(vec3 p)
222{
223    float n = 0.0;
224    float iter = 1.0;
225    for (int i = 0; i < 6; i++)
226    {
227        n += abs(sin(p.y*iter) + cos(p.x*iter)) / iter;	// abs for a ridged look
228        p.xy += vec2(p.y, -p.x) * nudge;
229        p.xy *= normalizer;
230        p.xz += vec2(p.z, -p.x) * nudge;
231        p.xz *= normalizer;
232        iter *= 1.733733;
233    }
234    return n;
235}
236float SpiralNoise3D(vec3 p)
237{
238    float n = 0.0;
239    float iter = 1.0;
240    for (int i = 0; i < 5; i++)
241    {
242        n += (sin(p.y*iter) + cos(p.x*iter)) / iter;
243        //p.xy += vec2(p.y, -p.x) * nudge;
244        //p.xy *= normalizer;
245        p.xz += vec2(p.z, -p.x) * nudge;
246        p.xz *= normalizer;
247        iter *= 1.33733;
248    }
249    return n;
250}
251
252// These are the xyz camera positions and a left/right facing angle relative to the path line
253// I think webgl glsl can only access arrays using a constant, so I'm writing all these out.
254// Someone please tell me if I'm wrong.
255vec4 c00 = vec4(3.5, 2.0, 13.1, 0.0);	// start point
256vec4 c01 = vec4(12.5, 2.2, 17.0, 0.0);	// run up to canyon 2 before hole in large rock face
257vec4 c02 = vec4(21.5, 4.0, 8.1, 0.0);	// canyon 2 before hole in large rock face
258vec4 c03 = vec4(21.0, 5.0, 1.1, -0.5);	// before hole in large rock face
259vec4 c04 = vec4(17.8, 5.4, -0.2, 0.0);	// hole in large rock face
260vec4 c05 = vec4(14.7, 2.5, 1.4, 0.0);	// after hole in large rock face
261vec4 c06 = vec4(7.9, 2.3, -2.1, 0.0);
262vec4 c07 = vec4(0.5, -0.7, -3.5, 1.0);
263vec4 c08 = vec4(-3.0, -1.0, -3.5, 1.3);
264vec4 c09 = vec4(-3.5, -1.0, 4.0, 1.3);
265vec4 c10 = vec4(3.0, -0.7, 3.3, 0.8);
266vec4 c11 = vec4(3.5, -1.0, -4.75, 0.0);
267vec4 c12 = vec4(-6.0, -0.2, 1.0, 3.14);
268vec4 c13 = vec4(-6.0, -1.0, 5.5, 0.0);
269
270vec4 cXX = vec4(0.0, 3.0, 0.0, 0.0);
271
272float camPathOffset = 0.0;	// where to start on the camera path - parametric t var for catmull-rom spline
273vec3 camPos = vec3(0.0), camFacing;
274vec3 camLookat=vec3(0,0.0,0);
275float waterLevel = 1.5;
276// from a time t, this finds where in the camera path you are.
277// It uses Catmull-Rom splines
278vec4 CamPos(float t)
279{
280    t = mod(t, 14.0);	// repeat after 14 time units
281    float bigTime = floor(t);
282    float smallTime = fract(t);
283    // Can't do arrays right, so write this all out.
284    if (bigTime == 0.0) return CatmullRom(c00, c01, c02, c03, smallTime);
285    if (bigTime == 1.0) return CatmullRom(c01, c02, c03, c04, smallTime);
286    if (bigTime == 2.0) return CatmullRom(c02, c03, c04, c05, smallTime);
287    if (bigTime == 3.0) return CatmullRom(c03, c04, c05, c06, smallTime);
288    if (bigTime == 4.0) return CatmullRom(c04, c05, c06, c07, smallTime);
289    if (bigTime == 5.0) return CatmullRom(c05, c06, c07, c08, smallTime);
290    if (bigTime == 6.0) return CatmullRom(c06, c07, c08, c09, smallTime);
291
292    if (bigTime == 7.0) return CatmullRom(c07, c08, c09, c10, smallTime);
293    if (bigTime == 8.0) return CatmullRom(c08, c09, c10, c11, smallTime);
294    if (bigTime == 9.0) return CatmullRom(c09, c10, c11, c12, smallTime);
295    if (bigTime == 10.0) return CatmullRom(c10, c11, c12, c13, smallTime);
296    if (bigTime == 11.0) return CatmullRom(c11, c12, c13, c00, smallTime);
297    if (bigTime == 12.0) return CatmullRom(c12, c13, c00, c01, smallTime);
298    if (bigTime == 13.0) return CatmullRom(c13, c00, c01, c02, smallTime);
299    return vec4(0.0);
300}
301
302float DistanceToObject(vec3 p)
303{
304	float final = p.y + 4.5;
305    final -= SpiralNoiseC(p.xyz);	// mid-range noise
306    final += SpiralNoiseC(p.zxy*0.123+100.0)*3.0;	// large scale terrain features
307    final -= SpiralNoise3D(p);	// more large scale features, but 3d, so not just a height map.
308    final -= SpiralNoise3D(p*49.0)*0.0625*0.125;	// small scale noise for variation
309	final = min(final, length(p) - 1.99);	// sphere in center
310    final = min(final, p.y + waterLevel);	// water
311	//final = min(final, length(p-camLookat) - 0.3);
312    return final;
313}
314
315void mainImage( out vec4 fragColor, in vec2 fragCoord )
316{
317	// ---------------- First, set up the camera rays for ray marching ----------------
318	vec2 uv = fragCoord.xy/iResolution.xy * 2.0 - 1.0;
319
320	// Camera up vector.
321	vec3 camUp=vec3(0,1,0); // vuv
322
323	// Camera lookat.
324	camLookat=vec3(0,0.0,0);	// vrp
325
326/*    if (iGlobalTime == 0.0)	// for debugging with manual camera
327    {
328        camPos = cXX.xyz;
329        camLookat = vec3(0.0)*cXX.xyz;
330    }*/
331
332    // debugging camera
333#ifdef MOUSE
334    float mx=iMouse.x/iResolution.x*PI*2.0;// + iGlobalTime * 0.1;
335	float my=-iMouse.y/iResolution.y*10.0;// + sin(iGlobalTime * 0.3)*0.2+0.2;//*PI/2.01;
336#else
337    float mx=0.0/iResolution.x*PI*2.0;// + iGlobalTime * 0.1;
338	float my=-0.0/iResolution.y*10.0;// + sin(iGlobalTime * 0.3)*0.2+0.2;//*PI/2.01;
339#endif
340	camPos += vec3(cos(my)*cos(mx),sin(my),cos(my)*sin(mx))*(5.2); 	// prp
341
342    // set time for moving camera along path
343    float timeLine = iGlobalTime*0.2 + camPathOffset;
344    camFacing = camLookat + camPos;
345    // without this if condition, the mac doesn't work. mysterious. :(
346    if (iGlobalTime != -1.0)
347    {
348        vec4 catmullA = CamPos(timeLine);
349        // get a smoother derivative even though the spline is not C2 continuous.
350        // Also look ahead a bit so the camera leads the motion
351        vec4 catmullB = CamPos(timeLine + 0.3);
352#ifdef MOTION_BLUR
353        vec4 catmullC = CamPos(timeLine + 0.004);	// adjust for camera motion blur
354        vec4 catmullBlur = mix(catmullA, catmullC, Hash2d(uv));	// motion blur along camera path
355        camPos = catmullBlur.xyz;
356        // face camera along derivate of motion path
357        camFacing = normalize(catmullB.xyz - catmullA.xyz);
358        // rotate camera based on w component of camera path vectors
359        camFacing = RotateY(camFacing, -catmullBlur.w);
360#else
361        camPos = catmullA.xyz;
362        // face camera along derivate of motion path
363        camFacing = normalize(catmullB.xyz - catmullA.xyz);
364        // rotate camera based on w component of camera path vectors
365        camFacing = RotateY(camFacing, -catmullA.w);
366#endif
367        camFacing = RotateY(camFacing, -mx);
368    	camLookat = camPos + camFacing;
369    }
370
371
372    // add randomness to camera for depth-of-field look close up.
373    //camPos += vec3(Hash2d(uv)*0.91, Hash2d(uv+37.0), Hash2d(uv+47.0))*0.01;
374
375	// Camera setup.
376	vec3 camVec=normalize(camLookat - camPos);//vpn
377	vec3 sideNorm=normalize(cross(camUp, camVec));	// u
378	vec3 upNorm=cross(camVec, sideNorm);//v
379	vec3 worldFacing=(camPos + camVec);//vcv
380	vec3 worldPix = worldFacing + uv.x * sideNorm * (iResolution.x/iResolution.y) + uv.y * upNorm;//scrCoord
381	vec3 relVec = normalize(worldPix - camPos);//scp
382
383	// --------------------------------------------------------------------------------
384	float dist = 0.05;
385	float t = 0.0;
386	float inc = 0.02;
387	float maxDepth = 110.0;
388	vec3 pos = vec3(0,0,0);
389	// ray marching time
390    for (int i = 0; i < 200; i++)	// This is the count of the max times the ray actually marches.
391    {
392        if ((t > maxDepth) || (abs(dist) < 0.0075)) break;
393        pos = camPos + relVec * t;
394        // *******************************************************
395        // This is _the_ function that defines the "distance field".
396        // It's really what makes the scene geometry.
397        // *******************************************************
398        dist = DistanceToObject(pos);
399        t += dist * 0.25;	// because deformations mess up distance function.
400    }
401
402	// --------------------------------------------------------------------------------
403	// Now that we have done our ray marching, let's put some color on this geometry.
404
405#ifdef MOVING_SUN
406	vec3 sunDir = normalize(vec3(sin(iGlobalTime*0.047-1.5), cos(iGlobalTime*0.047-1.5), -0.5));
407#else
408	vec3 sunDir = normalize(vec3(0.93, 1.0, -1.5));
409#endif
410    // This makes the sky fade at sunset
411    float skyMultiplier = saturate(sunDir.y+0.7);
412	vec3 finalColor = vec3(0.0);
413
414	// If a ray actually hit the object, let's light it.
415	if (abs(dist) < 0.75)
416    //if (t <= maxDepth)
417	{
418        // calculate the normal from the distance field. The distance field is a volume, so if you
419        // sample the current point and neighboring points, you can use the difference to get
420        // the normal.
421        vec3 smallVec = vec3(0.005, 0, 0);
422        vec3 normal = vec3(dist - DistanceToObject(pos - smallVec.xyy),
423                           dist - DistanceToObject(pos - smallVec.yxy),
424                           dist - DistanceToObject(pos - smallVec.yyx));
425
426        /*if (pos.y <= waterLevel-2.995)	// water waves?
427        {
428            normal += SpiralNoise3D(pos*32.0+vec3(iGlobalTime*8.0,0.0,0.0))*0.0001;
429            normal += SpiralNoise3D(pos*27.0+vec3(0.0,0.0, iGlobalTime* 10.333))*0.0001;
430            normal += SpiralNoiseD(pos*37.0+vec3(0.0,iGlobalTime* 14.333,0.0))*0.0002;
431        }*/
432        normal = normalize(normal);
433
434        // calculate 2 ambient occlusion values. One for global stuff and one
435        // for local stuff - so the green sphere light source can also have ambient.
436        float ambientS = 1.0;
437        //ambient *= saturate(DistanceToObject(pos + normal * 0.1)*10.0);
438        ambientS *= saturate(DistanceToObject(pos + normal * 0.2)*5.0);
439        ambientS *= saturate(DistanceToObject(pos + normal * 0.4)*2.5);
440        ambientS *= saturate(DistanceToObject(pos + normal * 0.8)*1.25);
441        float ambient = ambientS * saturate(DistanceToObject(pos + normal * 1.6)*1.25*0.5);
442        ambient *= saturate(DistanceToObject(pos + normal * 3.2)*1.25*0.25);
443        ambient *= saturate(DistanceToObject(pos + normal * 6.4)*1.25*0.125);
444        //ambient = max(0.05, pow(ambient, 0.3));	// tone down ambient with a pow and min clamp it.
445        ambient = saturate(ambient);
446
447        // Trace a ray toward the sun for sun shadows
448        float sunShadow = 1.0;
449        float iter = 0.2;
450		for (int i = 0; i < 10; i++)
451        {
452            float tempDist = DistanceToObject(pos + sunDir * iter);
453	        sunShadow *= saturate(tempDist*10.0);
454            if (tempDist <= 0.0) break;
455            iter *= 1.5;	// constant is more reliable than distance-based
456            //iter += max(0.2, tempDist)*1.2;
457        }
458        float sunSet = saturate(sunDir.y*4.0); // sunset dims the sun
459        sunShadow = saturate(sunShadow) * sunSet;
460
461        // calculate the reflection vector for highlights
462        vec3 ref = reflect(relVec, normal);
463
464        // pulse the ball light source
465        vec3 ballGlow = vec3(0.1, 0.97, 0.1) * abs(SpiralNoise3D(vec3(iGlobalTime*1.3)));
466
467        // ------ Calculate texture color of the rock ------
468        // basic orange and white blended together with noise
469        vec3 texColor = mix(vec3(0.95, 1.0, 1.0),  vec3(0.9, 0.7, 0.5), pow(abs(SpiralNoise3D(pos*1.0)-1.0), 0.6) );
470        // make the undersides darker greenish
471        texColor = mix(vec3(0.2, 0.2, 0.1), texColor, saturate(normal.y));
472        // fade to reddish/orange closer to the water level
473        texColor = mix(texColor, vec3(0.64, 0.2, 0.1) , saturate(-0.4-pos.y));
474        // some more variation to the color vertically
475        texColor = mix(texColor, vec3(0.2, 0.13, 0.02) , pow(saturate(pos.y*0.125+0.5), 2.0));
476        // give the rock a stratified, layered look
477        float rockLayers = abs(cos(pos.y*1.5+ SpiralNoiseD(pos*vec3(1.0, 2.0, 1.0)*4.0)*0.2 ));
478        texColor += vec3(0.7, 0.4, 0.3)*(1.0-pow(rockLayers, 0.3));
479
480        // make the water orange. I'm trying for that "nickel tailings" look.
481        texColor = mix(texColor, vec3(1.4, 0.15, 0.05) + SpiralNoise3D(pos)*0.025, saturate((-pos.y-1.45)*17.0));
482        // make the sphere white
483        if (length(pos) <= 2.01) texColor = vec3(1.0);
484        // don't let it get too saturated or dark
485        texColor = max(texColor, 0.05);
486
487        // ------ Calculate lighting color ------
488        // Start with sun color, standard lighting equation, and shadow
489        vec3 lightColor = vec3(1.0, 0.75, 0.75) * saturate(dot(sunDir, normal)) * sunShadow*1.5;
490        // sky color, hemisphere light equation approximation, anbient occlusion, sunset multiplier
491        lightColor += vec3(1.0,0.3,0.6) * ( dot(sunDir, normal) * 0.5 + 0.5 ) * ambient * 0.25 * skyMultiplier;
492        // Make the ball cast light. Distance to the 4th light falloff looked best. Use local ambient occlusion.
493        float lp = length(pos) - 1.0;
494        lightColor += ambientS*(ballGlow*1.2 * saturate(dot(normal, -pos)*0.5+0.5) / (lp*lp*lp*lp));
495
496        // finally, apply the light to the texture.
497        finalColor = texColor * lightColor;
498
499        // Make the water reflect the sun (leaving out sky reflection for no good reason)
500        vec3 refColor = GetSunColorReflection(ref, sunDir)*0.68;
501        finalColor += refColor * sunShadow * saturate(normal.y*normal.y) * saturate(-(pos.y+1.35)*16.0);
502
503        // make the ball itself glow
504        finalColor += pow(saturate(1.0 - length(pos)*0.4925), 0.65) * ballGlow*6.1;
505        // fog that fades to reddish plus the sun color so that fog is brightest towards sun
506        finalColor = mix(vec3(1.0, 0.41, 0.41)*skyMultiplier + min(vec3(0.25),GetSunColorSmall(relVec, sunDir))*2.0*sunSet, finalColor, exp(-t*0.03));
507	}
508    else
509    {
510        // Our ray trace hit nothing, so draw sky.
511        // fade the sky color, multiply sunset dimming
512        finalColor = mix(vec3(1.0, 0.5, 0.5), vec3(0.40, 0.25, 0.91), saturate(relVec.y))*skyMultiplier;
513        // add the sun
514        finalColor += GetSunColorSmall(relVec, sunDir);// + vec3(0.1, 0.1, 0.1);
515    }
516
517    //finalColor = vec3(Hash2d(uv)*0.91,  Hash2d(uv+47.0)*0.91, 0.0);
518    // vignette?
519    finalColor *= vec3(1.0) * saturate(1.0 - length(uv/2.5));
520    finalColor *= 1.3;
521
522	// output the final color with sqrt for "gamma correction"
523	fragColor = vec4(sqrt(clamp(finalColor, 0.0, 1.0)),1.0);
524}
525
526void main(void)
527{
528  //just some shit to wrap shadertoy's stuff
529  vec2 FragCoord = vTexCoord.xy*OutputSize.xy;
530  mainImage(FragColor,FragCoord);
531}
532#endif
533