Advertisement
DEKTEN

SHADERTOY/SHANE/PERSPEX_WEB_LATTICE

May 4th, 2021
1,008
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //:Written By: https://www.shadertoy.com/user/Shane
  2. /*
  3.     Perspex Web Lattice
  4.     -------------------
  5.    
  6.     I felt that Shadertoy didn't have enough Voronoi examples, so I made another one. :) I'm
  7.     not exactly sure what it's supposed to be... My best guess is that an Alien race with no
  8.     common sense designed a monitor system with physics defying materials. :)
  9.  
  10.     Technically speaking, there's not much to it. It's just some raymarched 2nd order Voronoi.
  11.     The dark perspex-looking web lattice is created by manipulating the Voronoi value slightly
  12.     and giving the effected region an ID value so as to color it differently, but that's about
  13.     it. The details are contained in the "heightMap" function.
  14.  
  15.     There's also some subtle edge detection in order to give the example a slight comic look.
  16.     3D geometric edge detection doesn't really differ a great deal in concept from 2D pixel
  17.     edge detection, but it obviously involves more processing power. However, it's possible to
  18.     combine the edge detection with the normal calculation and virtually get it for free. Kali
  19.     uses it to great effect in his "Fractal Land" example. It's also possible to do a
  20.     tetrahedral version... I think Nimitz and some others may have done it already. Anyway,
  21.     you can see how it's done in the "nr" (normal) function.
  22.  
  23.     Geometric edge related examples:
  24.  
  25.     Fractal Land - Kali
  26.     https://www.shadertoy.com/view/XsBXWt
  27.  
  28.     Rotating Cubes - Shau
  29.     https://www.shadertoy.com/view/4sGSRc
  30.  
  31.     Voronoi mesh related:
  32.  
  33.     // I haven't really looked into this, but it's interesting.
  34.     Weaved Voronoi - FabriceNeyret2
  35.     https://www.shadertoy.com/view/ltsXRM
  36.  
  37. */
  38.  
  39. #define FAR 2.
  40.  
  41. int id = 0; // Object ID - Red perspex: 0; Black lattice: 1.
  42.  
  43.  
  44. // Tri-Planar blending function. Based on an old Nvidia writeup:
  45. // GPU Gems 3 - Ryan Geiss: https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch01.html
  46. vec3 tex3D( sampler2D tex, in vec3 p, in vec3 n ){
  47.    
  48.     n = max((abs(n) - .2), .001);
  49.     n /= (n.x + n.y + n.z ); // Roughly normalized.
  50.    
  51.     p = (texture(tex, p.yz)*n.x + texture(tex, p.zx)*n.y + texture(tex, p.xy)*n.z).xyz;
  52.    
  53.     // Loose sRGB to RGB conversion to counter final value gamma correction...
  54.     // in case you're wondering.
  55.     return p*p;
  56. }
  57.  
  58.  
  59. // Compact, self-contained version of IQ's 3D value noise function. I have a transparent noise
  60. // example that explains it, if you require it.
  61. float n3D(vec3 p){
  62.    
  63.     const vec3 s = vec3(7, 157, 113);
  64.     vec3 ip = floor(p); p -= ip;
  65.     vec4 h = vec4(0., s.yz, s.y + s.z) + dot(ip, s);
  66.     p = p*p*(3. - 2.*p); //p *= p*p*(p*(p * 6. - 15.) + 10.);
  67.     h = mix(fract(sin(h)*43758.5453), fract(sin(h + s.x)*43758.5453), p.x);
  68.     h.xy = mix(h.xz, h.yw, p.y);
  69.     return mix(h.x, h.y, p.z); // Range: [0, 1].
  70. }
  71.  
  72. // vec2 to vec2 hash.
  73. vec2 hash22(vec2 p) {
  74.  
  75.     // Faster, but doesn't disperse things quite as nicely. However, when framerate
  76.     // is an issue, and it often is, this is a good one to use. Basically, it's a tweaked
  77.     // amalgamation I put together, based on a couple of other random algorithms I've
  78.     // seen around... so use it with caution, because I make a tonne of mistakes. :)
  79.     float n = sin(dot(p, vec2(41, 289)));
  80.     //return fract(vec2(262144, 32768)*n);
  81.    
  82.     // Animated.
  83.     p = fract(vec2(262144, 32768)*n);
  84.     // Note the ".45," insted of ".5" that you'd expect to see. When edging, it can open
  85.     // up the cells ever so slightly for a more even spread. In fact, lower numbers work
  86.     // even better, but then the random movement would become too restricted. Zero would
  87.     // give you square cells.
  88.     return sin( p*6.2831853 + iTime )*.45 + .5;
  89.    
  90. }
  91.  
  92. // 2D 2nd-order Voronoi: Obviously, this is just a rehash of IQ's original. I've tidied
  93. // up those if-statements. Since there's less writing, it should go faster. That's how
  94. // it works, right? :)
  95. //
  96. float Voronoi(in vec2 p){
  97.    
  98.     vec2 g = floor(p), o; p -= g;
  99.    
  100.     vec3 d = vec3(1); // 1.4, etc. "d.z" holds the distance comparison value.
  101.    
  102.     for(int y = -1; y <= 1; y++){
  103.         for(int x = -1; x <= 1; x++){
  104.            
  105.             o = vec2(x, y);
  106.             o += hash22(g + o) - p;
  107.            
  108.             d.z = dot(o, o);
  109.             // More distance metrics.
  110.             //o = abs(o);
  111.             //d.z = max(o.x*.8666 + o.y*.5, o.y);//
  112.             //d.z = max(o.x, o.y);
  113.             //d.z = (o.x*.7 + o.y*.7);
  114.            
  115.             d.y = max(d.x, min(d.y, d.z));
  116.             d.x = min(d.x, d.z);
  117.                        
  118.         }
  119.     }
  120.    
  121.     return max(d.y/1.2 - d.x*1., 0.)/1.2;
  122.     //return d.y - d.x; // return 1.-d.x; // etc.
  123.    
  124. }
  125.  
  126. // The height map values. In this case, it's just a Voronoi variation. By the way, I could
  127. // optimize this a lot further, but it's not a particularly taxing distance function, so
  128. // I've left it in a more readable state.
  129. float heightMap(vec3 p){
  130.    
  131.     id =0;
  132.     float c = Voronoi(p.xy*4.); // The fiery bit.
  133.    
  134.     // For lower values, reverse the surface direction, smooth, then
  135.     // give it an ID value of one. Ie: this is the black web-like
  136.     // portion of the surface.
  137.     if (c<.07) {c = smoothstep(0.7, 1., 1.-c)*.2; id = 1; }
  138.  
  139.     return c;
  140. }
  141.  
  142. // Standard back plane height map. Put the plane at vec3(0, 0, 1), then add some height values.
  143. // Obviously, you don't want the values to be too large. The one's here account for about 10%
  144. // of the distance between the plane and the camera.
  145. float m(vec3 p){
  146.    
  147.     float h = heightMap(p); // texture(iChannel0, p.xy/2.).x; // Texture work too.
  148.    
  149.     return 1. - p.z - h*.1;
  150.    
  151. }
  152.  
  153. /*
  154. // Tetrahedral normal, to save a couple of "map" calls. Courtesy of IQ.
  155. vec3 nr(in vec3 p){
  156.  
  157.     // Note the slightly increased sampling distance, to alleviate artifacts due to hit point inaccuracies.
  158.     vec2 e = vec2(0.005, -0.005);
  159.     return normalize(e.xyy * m(p + e.xyy) + e.yyx * m(p + e.yyx) + e.yxy * m(p + e.yxy) + e.xxx * m(p + e.xxx));
  160. }
  161. */
  162.  
  163. /*
  164. // Standard normal function - for comparison with the one below.
  165. vec3 nr(in vec3 p) {
  166.     const vec2 e = vec2(0.005, 0);
  167.     return normalize(vec3(m(p + e.xyy) - m(p - e.xyy), m(p + e.yxy) - m(p - e.yxy), m(p + e.yyx) - m(p - e.yyx)));
  168. }
  169. */
  170.  
  171. // The normal function with some edge detection rolled into it.
  172. vec3 nr(vec3 p, inout float edge) {
  173.    
  174.     vec2 e = vec2(.005, 0);
  175.  
  176.     // Take some distance function measurements from either side of the hit point on all three axes.
  177.     float d1 = m(p + e.xyy), d2 = m(p - e.xyy);
  178.     float d3 = m(p + e.yxy), d4 = m(p - e.yxy);
  179.     float d5 = m(p + e.yyx), d6 = m(p - e.yyx);
  180.     float d = m(p)*2.;  // The hit point itself - Doubled to cut down on calculations. See below.
  181.      
  182.     // Edges - Take a geometry measurement from either side of the hit point. Average them, then see how
  183.     // much the value differs from the hit point itself. Do this for X, Y and Z directions. Here, the sum
  184.     // is used for the overall difference, but there are other ways. Note that it's mainly sharp surface
  185.     // curves that register a discernible difference.
  186.     edge = abs(d1 + d2 - d) + abs(d3 + d4 - d) + abs(d5 + d6 - d);
  187.     //edge = max(max(abs(d1 + d2 - d), abs(d3 + d4 - d)), abs(d5 + d6 - d)); // Etc.
  188.    
  189.     // Once you have an edge value, it needs to normalized, and smoothed if possible. How you
  190.     // do that is up to you. This is what I came up with for now, but I might tweak it later.
  191.     edge = smoothstep(0., 1., sqrt(edge/e.x*2.));
  192.    
  193.     // Return the normal.
  194.     // Standard, normalized gradient mearsurement.
  195.     return normalize(vec3(d1 - d2, d3 - d4, d5 - d6));
  196. }
  197.  
  198. /*
  199. // I keep a collection of occlusion routines... OK, that sounded really nerdy. :)
  200. // Anyway, I like this one. I'm assuming it's based on IQ's original.
  201. float cAO(in vec3 p, in vec3 n)
  202. {
  203.     float sca = 3., occ = 0.;
  204.     for(float i=0.; i<5.; i++){
  205.    
  206.         float hr = .01 + i*.5/4.;        
  207.         float dd = m(n * hr + p);
  208.         occ += (hr - dd)*sca;
  209.         sca *= 0.7;
  210.     }
  211.     return clamp(1.0 - occ, 0., 1.);    
  212. }
  213. */
  214.  
  215. /*
  216. // Standard hue rotation formula... compacted down a bit.
  217. vec3 rotHue(vec3 p, float a){
  218.  
  219.     vec2 cs = sin(vec2(1.570796, 0) + a);
  220.  
  221.     mat3 hr = mat3(0.299,  0.587,  0.114,  0.299,  0.587,  0.114,  0.299,  0.587,  0.114) +
  222.               mat3(0.701, -0.587, -0.114, -0.299,  0.413, -0.114, -0.300, -0.588,  0.886) * cs.x +
  223.               mat3(0.168,  0.330, -0.497, -0.328,  0.035,  0.292,  1.250, -1.050, -0.203) * cs.y;
  224.                              
  225.     return clamp(p*hr, 0., 1.);
  226. }
  227. */
  228.  
  229. // Simple environment mapping. Pass the reflected vector in and create some
  230. // colored noise with it. The normal is redundant here, but it can be used
  231. // to pass into a 3D texture mapping function to produce some interesting
  232. // environmental reflections.
  233. //
  234. // More sophisticated environment mapping:
  235. // UI easy to integrate - XT95    
  236. // https://www.shadertoy.com/view/ldKSDm
  237. vec3 eMap(vec3 rd, vec3 sn){
  238.    
  239.     vec3 sRd = rd; // Save rd, just for some mixing at the end.
  240.    
  241.     // Add a time component, scale, then pass into the noise function.
  242.     rd.xy -= iTime*.25;
  243.     rd *= 3.;
  244.    
  245.     //vec3 tx = tex3D(iChannel0, rd/3., sn);
  246.     //float c = dot(tx*tx, vec3(.299, .587, .114));
  247.    
  248.     float c = n3D(rd)*.57 + n3D(rd*2.)*.28 + n3D(rd*4.)*.15; // Noise value.
  249.     c = smoothstep(0.5, 1., c); // Darken and add contast for more of a spotlight look.
  250.    
  251.     //vec3 col = vec3(c, c*c, c*c*c*c).zyx; // Simple, warm coloring.
  252.     vec3 col = vec3(min(c*1.5, 1.), pow(c, 2.5), pow(c, 12.)).zyx; // More color.
  253.    
  254.     // Mix in some more red to tone it down and return.
  255.     return mix(col, col.yzx, sRd*.25+.25);
  256.    
  257. }
  258.  
  259. void mainImage(out vec4 c, vec2 u){
  260.  
  261.     // Unit direction ray, camera origin and light position.
  262.     vec3 r = normalize(vec3(u - iResolution.xy*.5, iResolution.y)),
  263.          o = vec3(0), l = o + vec3(0, 0, -1);
  264.    
  265.     // Rotate the canvas. Note that sine and cosine are kind of rolled into one.
  266.     vec2 a = sin(vec2(1.570796, 0) + iTime/8.); // Fabrice's observation.
  267.     r.xy = mat2(a, -a.y, a.x) * r.xy;
  268.  
  269.    
  270.     // Standard raymarching routine. Raymarching a slightly perturbed back plane front-on
  271.     // doesn't usually require many iterations. Unless you rely on your GPU for warmth,
  272.     // this is a good thing. :)
  273.     float d, t = 0.;
  274.    
  275.     for(int i=0; i<32;i++){
  276.        
  277.         d = m(o + r*t);
  278.         // There isn't really a far plane to go beyond, but it's there anyway.
  279.         if(abs(d)<0.001 || t>FAR) break;
  280.         t += d*.7;
  281.  
  282.     }
  283.    
  284.     t = min(t, FAR);
  285.    
  286.     // Set the initial scene color to black.
  287.     c = vec4(0);
  288.    
  289.     float edge = 0.; // Edge value - to be passed into the normal.
  290.    
  291.     if(t<FAR){
  292.    
  293.         vec3 p = o + r*t, n = nr(p, edge);
  294.  
  295.         l -= p; // Light to surface vector. Ie: Light direction vector.
  296.         d = max(length(l), 0.001); // Light to surface distance.
  297.         l /= d; // Normalizing the light direction vector.
  298.  
  299.        
  300.  
  301.         // Obtain the height map (destorted Voronoi) value, and use it to slightly
  302.         // shade the surface. Gives a more shadowy appearance.
  303.         float hm = heightMap(p);
  304.        
  305.         // Texture value at the surface. Use the heighmap value above to distort the
  306.         // texture a bit.
  307.         vec3 tx = tex3D(iChannel0, (p*2. + hm*.2), n);
  308.         //tx = floor(tx*15.999)/15.; // Quantized cartoony colors, if you get bored enough.
  309.  
  310.         c.xyz = vec3(1.)*(hm*.8 + .2); // Applying the shading to the final color.
  311.        
  312.         c.xyz *= vec3(1.5)*tx; // Multiplying by the texture value and lightening.
  313.        
  314.        
  315.         // Color the cell part with a fiery (I incorrectly spell it firey all the time)
  316.         // palette and the latticey web thing a very dark color.
  317.         //
  318.         c.x = dot(c.xyz, vec3(.299, .587, .114)); // Grayscale.
  319.         if (id==0) c.xyz *= vec3(min(c.x*1.5, 1.), pow(c.x, 5.), pow(c.x, 24.))*2.;
  320.         else c.xyz *= .1;
  321.        
  322.         // Hue rotation, for anyone who's interested.
  323.         //c.xyz = rotHue(c.xyz, mod(iTime/16., 6.283));
  324.        
  325.        
  326.         float df = max(dot(l, n), 0.); // Diffuse.
  327.         float sp = pow(max(dot(reflect(-l, n), -r), 0.), 32.); // Specular.
  328.        
  329.         if(id == 1) sp *= sp; // Increase specularity on the dark lattice.
  330.        
  331.         // Applying some diffuse and specular lighting to the surface.
  332.         c.xyz = c.xyz*(df + .75) + vec3(1, .97, .92)*sp + vec3(.5, .7, 1)*pow(sp, 32.);
  333.        
  334.         // Add the fake environmapping. Give the dark surface less reflectivity.
  335.         vec3 em = eMap(reflect(r, n), n); // Fake environment mapping.
  336.         if(id == 1) em *= .5;
  337.         c.xyz += em;
  338.        
  339.         // Edges.
  340.         //if(id == 0)c.xyz += edge*.1; // Lighter edges.
  341.         c.xyz *= 1. - edge*.8; // Darker edges.
  342.        
  343.         // Attenuation, based on light to surface distance.    
  344.         c.xyz *= 1./(1. + d*d*.125);
  345.        
  346.         // AO - The effect is probably too subtle, in this case, so we may as well
  347.         // save some cycles.
  348.         //c.xyz *= cAO(p, n);
  349.        
  350.     }
  351.    
  352.    
  353.     // Vignette.
  354.     //vec2 uv = u/iResolution.xy;
  355.     //c.xyz = mix(c.xyz, vec3(0, 0, .5), .1 -pow(16.*uv.x*uv.y*(1.-uv.x)*(1.-uv.y), 0.25)*.1);
  356.    
  357.     // Apply some statistically unlikely (but close enough) 2.0 gamma correction. :)
  358.     c = vec4(sqrt(clamp(c.xyz, 0., 1.)), 1.);
  359.    
  360.    
  361. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement