1#version 120
2// Compatibility #ifdefs needed for parameters
3#ifdef GL_ES
4#define COMPAT_PRECISION mediump
5#else
6#define COMPAT_PRECISION
7#endif
8
9// Parameter lines go here:
10#pragma parameter RETRO_PIXEL_SIZE "Retro Pixel Size" 0.84 0.0 1.0 0.01
11#ifdef PARAMETER_UNIFORM
12// All parameter floats need to have COMPAT_PRECISION in front of them
13uniform COMPAT_PRECISION float RETRO_PIXEL_SIZE;
14#else
15#define RETRO_PIXEL_SIZE 0.84
16#endif
17
18#if defined(VERTEX)
19
20#if __VERSION__ >= 130
21#define COMPAT_VARYING out
22#define COMPAT_ATTRIBUTE in
23#define COMPAT_TEXTURE texture
24#else
25#define COMPAT_VARYING varying
26#define COMPAT_ATTRIBUTE attribute
27#define COMPAT_TEXTURE texture2D
28#endif
29
30#ifdef GL_ES
31#define COMPAT_PRECISION mediump
32#else
33#define COMPAT_PRECISION
34#endif
35
36COMPAT_ATTRIBUTE vec4 VertexCoord;
37COMPAT_ATTRIBUTE vec4 COLOR;
38COMPAT_ATTRIBUTE vec4 TexCoord;
39COMPAT_VARYING vec4 COL0;
40COMPAT_VARYING vec4 TEX0;
41// out variables go here as COMPAT_VARYING whatever
42
43vec4 _oPosition1;
44uniform mat4 MVPMatrix;
45uniform COMPAT_PRECISION int FrameDirection;
46uniform COMPAT_PRECISION int FrameCount;
47uniform COMPAT_PRECISION vec2 OutputSize;
48uniform COMPAT_PRECISION vec2 TextureSize;
49uniform COMPAT_PRECISION vec2 InputSize;
50
51// compatibility #defines
52#define vTexCoord TEX0.xy
53#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
54#define OutSize vec4(OutputSize, 1.0 / OutputSize)
55
56void main()
57{
58    gl_Position = MVPMatrix * VertexCoord;
59    TEX0.xy = VertexCoord.xy;
60// Paste vertex contents here:
61}
62
63#elif defined(FRAGMENT)
64
65#if __VERSION__ >= 130
66#define COMPAT_VARYING in
67#define COMPAT_TEXTURE texture
68out vec4 FragColor;
69#else
70#define COMPAT_VARYING varying
71#define FragColor gl_FragColor
72#define COMPAT_TEXTURE texture2D
73#endif
74
75#ifdef GL_ES
76#ifdef GL_FRAGMENT_PRECISION_HIGH
77precision highp float;
78#else
79precision mediump float;
80#endif
81#define COMPAT_PRECISION mediump
82#else
83#define COMPAT_PRECISION
84#endif
85
86uniform COMPAT_PRECISION int FrameDirection;
87uniform COMPAT_PRECISION int FrameCount;
88uniform COMPAT_PRECISION vec2 OutputSize;
89uniform COMPAT_PRECISION vec2 TextureSize;
90uniform COMPAT_PRECISION vec2 InputSize;
91uniform sampler2D Texture;
92COMPAT_VARYING vec4 TEX0;
93// in variables go here as COMPAT_VARYING whatever
94
95// compatibility #defines
96#define Source Texture
97#define vTexCoord TEX0.xy
98
99#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
100#define OutSize vec4(OutputSize, 1.0 / OutputSize)
101
102// delete all 'params.' or 'registers.' or whatever in the fragment
103float iGlobalTime = float(FrameCount)*0.025;
104vec2 iResolution = OutputSize.xy;
105
106// Luminescence by Martijn Steinrucken aka BigWings - 2017
107// countfrolic@gmail.com
108// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
109
110// My entry for the monthly challenge (May 2017) on r/proceduralgeneration
111// Use the mouse to look around. Uncomment the SINGLE define to see one specimen by itself.
112// Code is a bit of a mess, too lazy to clean up. Hope you like it!
113
114// Music by Klaus Lunde
115// https://soundcloud.com/klauslunde/zebra-tribute
116
117// YouTube: The Art of Code -> https://www.youtube.com/channel/UCcAlTqd9zID6aNX3TzwxJXg
118// Twitter: @Steinrucken
119
120#define INVERTMOUSE -1.
121
122#define MAX_STEPS 100.
123#define VOLUME_STEPS 8.
124//#define SINGLE
125#define MIN_DISTANCE 0.1
126#define MAX_DISTANCE 100.
127#define HIT_DISTANCE .01
128
129#define S(x,y,z) smoothstep(x,y,z)
130#define B(x,y,z,w) S(x-z, x+z, w)*S(y+z, y-z, w)
131#define sat(x) clamp(x,0.,1.)
132#define SIN(x) sin(x)*.5+.5
133
134const vec3 lf=vec3(1., 0., 0.);
135const vec3 up=vec3(0., 1., 0.);
136const vec3 fw=vec3(0., 0., 1.);
137
138const float halfpi = 1.570796326794896619;
139const float pi = 3.141592653589793238;
140const float twopi = 6.283185307179586;
141
142
143vec3 accentColor1 = vec3(1., .1, .5);
144vec3 secondColor1 = vec3(.1, .5, 1.);
145
146vec3 accentColor2 = vec3(1., .5, .1);
147vec3 secondColor2 = vec3(.1, .5, .6);
148
149vec3 bg;	 	// global background color
150vec3 accent;	// color of the phosphorecence
151
152float N1( float x ) { return fract(sin(x)*5346.1764); }
153float N2(float x, float y) { return N1(x + y*23414.324); }
154
155float N3(vec3 p) {
156    p  = fract( p*0.3183099+.1 );
157	p *= 17.0;
158    return fract( p.x*p.y*p.z*(p.x+p.y+p.z) );
159}
160
161struct ray {
162    vec3 o;
163    vec3 d;
164};
165
166struct camera {
167    vec3 p;			// the position of the camera
168    vec3 forward;	// the camera forward vector
169    vec3 left;		// the camera left vector
170    vec3 up;		// the camera up vector
171
172    vec3 center;	// the center of the screen, in world coords
173    vec3 i;			// where the current ray intersects the screen, in world coords
174    ray ray;		// the current ray: from cam pos, through current uv projected on screen
175    vec3 lookAt;	// the lookat point
176    float zoom;		// the zoom factor
177};
178
179struct de {
180    // data type used to pass the various bits of information used to shade a de object
181	float d;	// final distance to field
182    float m; 	// material
183    vec3 uv;
184    float pump;
185
186    vec3 id;
187    vec3 pos;		// the world-space coordinate of the fragment
188};
189
190struct rc {
191    // data type used to handle a repeated coordinate
192	vec3 id;	// holds the floor'ed coordinate of each cell. Used to identify the cell.
193    vec3 h;		// half of the size of the cell
194    vec3 p;		// the repeated coordinate
195    //vec3 c;		// the center of the cell, world coordinates
196};
197
198rc Repeat(vec3 pos, vec3 size) {
199	rc o;
200    o.h = size*.5;
201    o.id = floor(pos/size);			// used to give a unique id to each cell
202    o.p = mod(pos, size)-o.h;
203    //o.c = o.id*size+o.h;
204
205    return o;
206}
207
208camera cam;
209
210
211void CameraSetup(vec2 uv, vec3 position, vec3 lookAt, float zoom) {
212
213    cam.p = position;
214    cam.lookAt = lookAt;
215    cam.forward = normalize(cam.lookAt-cam.p);
216    cam.left = cross(up, cam.forward);
217    cam.up = cross(cam.forward, cam.left);
218    cam.zoom = zoom;
219
220    cam.center = cam.p+cam.forward*cam.zoom;
221    cam.i = cam.center+cam.left*uv.x+cam.up*uv.y;
222
223    cam.ray.o = cam.p;						// ray origin = camera position
224    cam.ray.d = normalize(cam.i-cam.p);	// ray direction is the vector from the cam pos through the point on the imaginary screen
225}
226
227
228// ============== Functions I borrowed ;)
229
230//  3 out, 1 in... DAVE HOSKINS
231vec3 N31(float p) {
232   vec3 p3 = fract(vec3(p) * vec3(.1031,.11369,.13787));
233   p3 += dot(p3, p3.yzx + 19.19);
234   return fract(vec3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));
235}
236
237// DE functions from IQ
238float smin( float a, float b, float k )
239{
240    float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );
241    return mix( b, a, h ) - k*h*(1.0-h);
242}
243
244float smax( float a, float b, float k )
245{
246	float h = clamp( 0.5 + 0.5*(b-a)/k, 0.0, 1.0 );
247	return mix( a, b, h ) + k*h*(1.0-h);
248}
249
250float sdSphere( vec3 p, vec3 pos, float s ) { return (length(p-pos)-s); }
251
252// From http://mercury.sexy/hg_sdf
253vec2 pModPolar(inout vec2 p, float repetitions, float fix) {
254	float angle = twopi/repetitions;
255	float a = atan(p.y, p.x) + angle/2.;
256	float r = length(p);
257	float c = floor(a/angle);
258	a = mod(a,angle) - (angle/2.)*fix;
259	p = vec2(cos(a), sin(a))*r;
260
261	return p;
262}
263
264// -------------------------
265
266
267float Dist( vec2 P,  vec2 P0, vec2 P1 ) {
268    //2d point-line distance
269
270	vec2 v = P1 - P0;
271    vec2 w = P - P0;
272
273    float c1 = dot(w, v);
274    float c2 = dot(v, v);
275
276    if (c1 <= 0. )  // before P0
277    	return length(P-P0);
278
279    float b = c1 / c2;
280    vec2 Pb = P0 + b*v;
281    return length(P-Pb);
282}
283
284vec3 ClosestPoint(vec3 ro, vec3 rd, vec3 p) {
285    // returns the closest point on ray r to point p
286    return ro + max(0., dot(p-ro, rd))*rd;
287}
288
289vec2 RayRayTs(vec3 ro1, vec3 rd1, vec3 ro2, vec3 rd2) {
290	// returns the two t's for the closest point between two rays
291    // ro+rd*t1 = ro2+rd2*t2
292
293    vec3 dO = ro2-ro1;
294    vec3 cD = cross(rd1, rd2);
295    float v = dot(cD, cD);
296
297    float t1 = dot(cross(dO, rd2), cD)/v;
298    float t2 = dot(cross(dO, rd1), cD)/v;
299    return vec2(t1, t2);
300}
301
302float DistRaySegment(vec3 ro, vec3 rd, vec3 p1, vec3 p2) {
303	// returns the distance from ray r to line segment p1-p2
304    vec3 rd2 = p2-p1;
305    vec2 t = RayRayTs(ro, rd, p1, rd2);
306
307    t.x = max(t.x, 0.);
308    t.y = clamp(t.y, 0., length(rd2));
309
310    vec3 rp = ro+rd*t.x;
311    vec3 sp = p1+rd2*t.y;
312
313    return length(rp-sp);
314}
315
316vec2 sph(vec3 ro, vec3 rd, vec3 pos, float radius) {
317	// does a ray sphere intersection
318    // returns a vec2 with distance to both intersections
319    // if both a and b are MAX_DISTANCE then there is no intersection
320
321    vec3 oc = pos - ro;
322    float l = dot(rd, oc);
323    float det = l*l - dot(oc, oc) + radius*radius;
324    if (det < 0.0) return vec2(MAX_DISTANCE);
325
326    float d = sqrt(det);
327    float a = l - d;
328    float b = l + d;
329
330    return vec2(a, b);
331}
332
333
334vec3 background(vec3 r) {
335
336    float x = atan(r.x, r.z);		// from -pi to pi
337	float y = pi*0.5-acos(r.y);  		// from -1/2pi to 1/2pi
338
339    vec3 col = bg*(1.+y);
340
341	float t = iGlobalTime;				// add god rays
342
343    float a = sin(r.x);
344
345    float beam = sat(sin(10.*x+a*y*5.+t));
346    beam *= sat(sin(7.*x+a*y*3.5-t));
347
348    float beam2 = sat(sin(42.*x+a*y*21.-t));
349    beam2 *= sat(sin(34.*x+a*y*17.+t));
350
351    beam += beam2;
352    col *= 1.+beam*.05;
353
354    return col;
355}
356
357
358
359
360float remap(float a, float b, float c, float d, float t) {
361	return ((t-a)/(b-a))*(d-c)+c;
362}
363
364
365
366de map( vec3 p, vec3 id ) {
367
368    float t = iGlobalTime*2.;
369
370    float N = N3(id);
371
372    de o;
373    o.m = 0.;
374
375    float x = (p.y+N*twopi)*1.+t;
376    float r = 1.;
377
378    float pump = cos(x+cos(x))+sin(2.*x)*.2+sin(4.*x)*.02;
379
380    x = t + N*twopi;
381    p.y -= (cos(x+cos(x))+sin(2.*x)*.2)*.6;
382    p.xz *= 1. + pump*.2;
383
384    float d1 = sdSphere(p, vec3(0., 0., 0.), r);
385    float d2 = sdSphere(p, vec3(0., -.5, 0.), r);
386
387    o.d = smax(d1, -d2, .1);
388    o.m = 1.;
389
390    if(p.y<.5) {
391        float sway = sin(t+p.y+N*twopi)*S(.5, -3., p.y)*N*.3;
392        p.x += sway*N;	// add some sway to the tentacles
393        p.z += sway*(1.-N);
394
395        vec3 mp = p;
396    	mp.xz = pModPolar(mp.xz, 6., 0.);
397
398        float d3 = length(mp.xz-vec2(.2, .1))-remap(.5, -3.5, .1, .01, mp.y);
399    	if(d3<o.d) o.m=2.;
400        d3 += (sin(mp.y*10.)+sin(mp.y*23.))*.03;
401
402        float d32 = length(mp.xz-vec2(.2, .1))-remap(.5, -3.5, .1, .04, mp.y)*.5;
403        d3 = min(d3, d32);
404        o.d = smin(o.d, d3, .5);
405
406        if( p.y<.2) {
407             vec3 op = p;
408    		op.xz = pModPolar(op.xz, 13., 1.);
409
410        	float d4 = length(op.xz-vec2(.85, .0))-remap(.5, -3., .04, .0, op.y);
411    		if(d4<o.d) o.m=3.;
412            o.d = smin(o.d, d4, .15);
413        }
414    }
415    o.pump = pump;
416    o.uv = p;
417
418    o.d *= .8;
419    return o;
420}
421
422vec3 calcNormal( de o ) {
423	vec3 eps = vec3( 0.01, 0.0, 0.0 );
424	vec3 nor = vec3(
425	    map(o.pos+eps.xyy, o.id).d - map(o.pos-eps.xyy, o.id).d,
426	    map(o.pos+eps.yxy, o.id).d - map(o.pos-eps.yxy, o.id).d,
427	    map(o.pos+eps.yyx, o.id).d - map(o.pos-eps.yyx, o.id).d );
428	return normalize(nor);
429}
430
431de CastRay(ray r) {
432    float d = 0.;
433    float dS = MAX_DISTANCE;
434
435    vec3 pos = vec3(0., 0., 0.);
436    vec3 n = vec3(0.);
437    de o, s;
438
439    float dC = MAX_DISTANCE;
440    vec3 p;
441    rc q;
442    float t = iGlobalTime;
443    vec3 grid = vec3(6., 30., 6.);
444
445    for(float i=0.; i<MAX_STEPS; i++) {
446        p = r.o + r.d*d;
447
448        #ifdef SINGLE
449        s = map(p, vec3(0.));
450        #else
451        p.y -= t;  // make the move up
452        p.x += t;  // make cam fly forward
453
454        q = Repeat(p, grid);
455
456        vec3 rC = ((2.*step(0., r.d)-1.)*q.h-q.p)/r.d;	// ray to cell boundary
457        dC = min(min(rC.x, rC.y), rC.z)+.01;		// distance to cell just past boundary
458
459        float N = N3(q.id);
460        q.p += (N31(N)-.5)*grid*vec3(.5, .7, .5);
461
462		if(Dist(q.p.xz, r.d.xz, vec2(0.))<1.1)
463        //if(DistRaySegment(q.p, r.d, vec3(0., -6., 0.), vec3(0., -3.3, 0)) <1.1)
464        	s = map(q.p, q.id);
465        else
466            s.d = dC;
467
468
469        #endif
470
471        if(s.d<HIT_DISTANCE || d>MAX_DISTANCE) break;
472        d+=min(s.d, dC);	// move to distance to next cell or surface, whichever is closest
473    }
474
475    if(s.d<HIT_DISTANCE) {
476        o.m = s.m;
477        o.d = d;
478        o.id = q.id;
479        o.uv = s.uv;
480        o.pump = s.pump;
481
482        #ifdef SINGLE
483        o.pos = p;
484        #else
485        o.pos = q.p;
486        #endif
487    }
488
489    return o;
490}
491
492float VolTex(vec3 uv, vec3 p, float scale, float pump) {
493    // uv = the surface pos
494    // p = the volume shell pos
495
496	p.y *= scale;
497
498    float s2 = 5.*p.x/twopi;
499    float id = floor(s2);
500    s2 = fract(s2);
501    vec2 ep = vec2(s2-.5, p.y-.6);
502    float ed = length(ep);
503    float e = B(.35, .45, .05, ed);
504
505   	float s = SIN(s2*twopi*15. );
506	s = s*s; s = s*s;
507    s *= S(1.4, -.3, uv.y-cos(s2*twopi)*.2+.3)*S(-.6, -.3, uv.y);
508
509    float t = iGlobalTime*5.;
510    float mask = SIN(p.x*twopi*2. + t);
511    s *= mask*mask*2.;
512
513    return s+e*pump*2.;
514}
515
516vec4 JellyTex(vec3 p) {
517    vec3 s = vec3(atan(p.x, p.z), length(p.xz), p.y);
518
519    float b = .75+sin(s.x*6.)*.25;
520    b = mix(1., b, s.y*s.y);
521
522    p.x += sin(s.z*10.)*.1;
523    float b2 = cos(s.x*26.) - s.z-.7;
524
525    b2 = S(.1, .6, b2);
526    return vec4(b+b2);
527}
528
529vec3 render( vec2 uv, ray camRay, float depth ) {
530    // outputs a color
531
532    bg = background(cam.ray.d);
533
534    vec3 col = bg;
535    de o = CastRay(camRay);
536
537    float t = iGlobalTime;
538    vec3 L = up;
539
540
541    if(o.m>0.) {
542        vec3 n = calcNormal(o);
543        float lambert = sat(dot(n, L));
544        vec3 R = reflect(camRay.d, n);
545        float fresnel = sat(1.+dot(camRay.d, n));
546        float trans = (1.-fresnel)*.5;
547        vec3 ref = background(R);
548        float fade = 0.;
549
550        if(o.m==1.) {	// hood color
551            float density = 0.;
552            for(float i=0.; i<VOLUME_STEPS; i++) {
553                float sd = sph(o.uv, camRay.d, vec3(0.), .8+i*.015).x;
554                if(sd!=MAX_DISTANCE) {
555                    vec2 intersect = o.uv.xz+camRay.d.xz*sd;
556
557                    vec3 uv = vec3(atan(intersect.x, intersect.y), length(intersect.xy), o.uv.z);
558                    density += VolTex(o.uv, uv, 1.4+i*.03, o.pump);
559                }
560            }
561            vec4 volTex = vec4(accent, density/VOLUME_STEPS);
562
563
564            vec3 dif = JellyTex(o.uv).rgb;
565            dif *= max(.2, lambert);
566
567            col = mix(col, volTex.rgb, volTex.a);
568            col = mix(col, vec3(dif), .25);
569
570            col += fresnel*ref*sat(dot(up, n));
571
572            //fade
573            fade = max(fade, S(.0, 1., fresnel));
574        } else if(o.m==2.) {						// inside tentacles
575            vec3 dif = accent;
576    		col = mix(bg, dif, fresnel);
577
578            col *= mix(.6, 1., S(0., -1.5, o.uv.y));
579
580            float prop = o.pump+.25;
581            prop *= prop*prop;
582            col += pow(1.-fresnel, 20.)*dif*prop;
583
584
585            fade = fresnel;
586        } else if(o.m==3.) {						// outside tentacles
587        	vec3 dif = accent;
588            float d = S(100., 13., o.d);
589    		col = mix(bg, dif, pow(1.-fresnel, 5.)*d);
590        }
591
592        fade = max(fade, S(0., 100., o.d));
593        col = mix(col, bg, fade);
594
595        if(o.m==4.)
596            col = vec3(1., 0., 0.);
597    }
598     else
599        col = bg;
600
601    return col;
602}
603
604void mainImage( out vec4 fragColor, in vec2 fragCoord )
605{
606	float t = iGlobalTime*.04;
607
608    vec2 uv = (fragCoord.xy / iResolution.xy);
609    uv -= .5;
610    uv.y *= iResolution.y/iResolution.x;
611
612#ifdef MOUSE
613    vec2 mouse = iMouse.xy/iResolution.xy;
614    if(m.x<0.05 || m.x>.95) {				// move cam automatically when mouse is not used
615    	mouse = vec2(t*.25, SIN(t*pi)*.5+.5);
616    }
617#else
618    vec2 mouse = vec2(t*.25, SIN(t*pi)*.5+.5);
619#endif
620
621    accent = mix(accentColor1, accentColor2, SIN(t*15.456));
622    bg = mix(secondColor1, secondColor2, SIN(t*7.345231));
623
624    float turn = (.1-mouse.x)*twopi;
625    float s = sin(turn);
626    float c = cos(turn);
627    mat3 rotX = mat3(c,  0., s, 0., 1., 0., s,  0., -c);
628
629    #ifdef SINGLE
630    float camDist = -10.;
631    #else
632    float camDist = -.1;
633    #endif
634
635    vec3 lookAt = vec3(0., -1., 0.);
636
637    vec3 camPos = vec3(0., INVERTMOUSE*camDist*cos((mouse.y)*pi), camDist)*rotX;
638
639    CameraSetup(uv, camPos+lookAt, lookAt, 1.);
640
641    vec3 col = render(uv, cam.ray, 0.);
642
643    col = pow(col, vec3(mix(1.5, 2.6, SIN(t+pi))));		// post-processing
644    float d = 1.-dot(uv, uv);		// vignette
645    col *= (d*d*d)+.1;
646
647    fragColor = vec4(col, 1.);
648}
649
650 void main(void)
651{
652  //just some shit to wrap shadertoy's stuff
653  vec2 FragCoord = vTexCoord.xy*OutputSize.xy;
654  mainImage(FragColor,FragCoord);
655}
656#endif
657