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