code snippets, stubs and sketches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

#### 325 lines 9.2 KiB Raw Permalink Blame History

 `// ray marching code from ` `// http://jamie-wong.com/2016/07/15/ray-marching-signed-distance-functions/` `// https://www.shadertoy.com/view/Xtd3z7` ``` ``` `// SDF shapes from ` `// https://iquilezles.org/www/articles/distfunctions/distfunctions.htm` ``` ``` `#ifdef GL_ES` `precision mediump float;` `#endif` ``` ``` `#define PI 3.1415926535897932384626433832795` `#define TWO_PI 6.2831853071795864769252867665590` ``` ``` `uniform vec2 u_resolution;` `uniform float u_time;` `uniform sampler2D u_tex0;` ``` ``` `// hash based 3d value noise` `// function taken from https://www.shadertoy.com/view/XslGRr` `// Created by inigo quilez - iq/2013` `// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.` ``` ``` `float vnhash( float n )` `{` ` return fract(sin(n)*43758.5453);` `}` ``` ``` `float vnoise( vec3 x )` `{` ` // The noise function returns a value in the range -1.0f -> 1.0f` ``` ``` ` vec3 p = floor(x);` ` vec3 f = fract(x);` ``` ``` ` f = f*f*(3.0-2.0*f);` ` float n = p.x + p.y*57.0 + 113.0*p.z;` ``` ``` ` return mix(mix(mix( vnhash(n+0.0), vnhash(n+1.0),f.x),` ` mix( vnhash(n+57.0), vnhash(n+58.0),f.x),f.y),` ` mix(mix( vnhash(n+113.0), vnhash(n+114.0),f.x),` ` mix( vnhash(n+170.0), vnhash(n+171.0),f.x),f.y),f.z);` `}` ``` ``` ``` ``` `//` `// Description : GLSL 2D simplex noise function` `// Author : Ian McEwan, Ashima Arts` `// Maintainer : ijm` `// Lastmod : 20110822 (ijm)` `// License :` `// Copyright (C) 2011 Ashima Arts. All rights reserved.` `// Distributed under the MIT License. See LICENSE file.` `// https://github.com/ashima/webgl-noise` `//` ``` ``` `// Some useful functions` `vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }` `vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }` `vec3 permute(vec3 x) { return mod289(((x*34.0)+1.0)*x); }` ``` ``` `float noise(vec2 v) {` ``` ``` ` // Precompute values for skewed triangular grid` ` const vec4 C = vec4(0.211324865405187,` ` // (3.0-sqrt(3.0))/6.0` ` 0.366025403784439,` ` // 0.5*(sqrt(3.0)-1.0)` ` -0.577350269189626,` ` // -1.0 + 2.0 * C.x` ` 0.024390243902439);` ` // 1.0 / 41.0` ``` ``` ` // First corner (x0)` ` vec2 i = floor(v + dot(v, C.yy));` ` vec2 x0 = v - i + dot(i, C.xx);` ``` ``` ` // Other two corners (x1, x2)` ` vec2 i1 = vec2(0.0);` ` i1 = (x0.x > x0.y)? vec2(1.0, 0.0):vec2(0.0, 1.0);` ` vec2 x1 = x0.xy + C.xx - i1;` ` vec2 x2 = x0.xy + C.zz;` ``` ``` ` // Do some permutations to avoid` ` // truncation effects in permutation` ` i = mod289(i);` ` vec3 p = permute(` ` permute( i.y + vec3(0.0, i1.y, 1.0))` ` + i.x + vec3(0.0, i1.x, 1.0 ));` ``` ``` ` vec3 m = max(0.5 - vec3(` ` dot(x0,x0),` ` dot(x1,x1),` ` dot(x2,x2)` ` ), 0.0);` ``` ``` ` m = m*m ;` ` m = m*m ;` ``` ``` ` // Gradients:` ` // 41 pts uniformly over a line, mapped onto a diamond` ` // The ring size 17*17 = 289 is close to a multiple` ` // of 41 (41*7 = 287)` ``` ``` ` vec3 x = 2.0 * fract(p * C.www) - 1.0;` ` vec3 h = abs(x) - 0.5;` ` vec3 ox = floor(x + 0.5);` ` vec3 a0 = x - ox;` ``` ``` ` // Normalise gradients implicitly by scaling m` ` // Approximation of: m *= inversesqrt(a0*a0 + h*h);` ` m *= 1.79284291400159 - 0.85373472095314 * (a0*a0+h*h);` ``` ``` ` // Compute final noise value at P` ` vec3 g = vec3(0.0);` ` g.x = a0.x * x0.x + h.x * x0.y;` ` g.yz = a0.yz * vec2(x1.x,x2.x) + h.yz * vec2(x1.y,x2.y);` ` return 130.0 * dot(m, g);` `}` ``` ``` ``` ``` `// code ported from alex-charlton.com/posts/Dithering_on_the_GPU/` `// adapted for running on GLSL ES 2 ----` `const mat4 dither_matrix = mat4( ` ` vec4( 0, 8, 2, 10), ` ` vec4( 12, 4, 14, 6), ` ` vec4( 3, 11, 1, 9), ` ` vec4( 15, 7, 13, 5)` `);` `float dither_4x4( float x, vec2 coord ){` ` int ix = int(mod(coord.x, 4.0));` ` int iy = int(mod(coord.y, 4.0));` ` float d = dither_matrix[iy][ix] / 16.0;` ` ` ` float closest = step( x, 0.5 );` ` float distance = abs(closest - x);` ` float branch = step( distance, d );` ``` ``` ` return 2.0*branch*closest + 1.0 - closest - branch;` `}` `// -------------------------------------` ``` ``` ``` ``` `// -------------- RAYMARCHING BOILERPLATE ---------------------------------------` ``` ``` `const int MAX_MARCHING_STEPS = 255;` `const float MIN_DIST = 0.0;` `const float MAX_DIST = 100.0;` `const float EPSILON = 0.0001;` ``` ``` `float sphereSDF(vec3 p) {` ` return length(p) - 1.0;` `}` ``` ``` `float sceneSDF(vec3 samplePoint);` ``` ``` `float shortestDistanceToSurface(vec3 eye, vec3 marchingDirection, float start, float end) {` ` float depth = start;` ` for (int i = 0; i < MAX_MARCHING_STEPS; i++) {` ` float dist = sceneSDF(eye + depth * marchingDirection);` ` if (dist < EPSILON) {` ` return depth;` ` }` ` depth += dist;` ` if (depth >= end) {` ` return end;` ` }` ` }` ` return end;` `}` ` ` `vec3 rayDirection(float fieldOfView, vec2 size, vec2 fragCoord) {` ` vec2 xy = fragCoord - size / 2.0;` ` float z = size.y / tan(radians(fieldOfView) / 2.0);` ` return normalize(vec3(xy, -z));` `}` ``` ``` `vec3 estimateNormal(vec3 p) {` ` return normalize(vec3(` ` sceneSDF(vec3(p.x + EPSILON, p.y, p.z)) - sceneSDF(vec3(p.x - EPSILON, p.y, p.z)),` ` sceneSDF(vec3(p.x, p.y + EPSILON, p.z)) - sceneSDF(vec3(p.x, p.y - EPSILON, p.z)),` ` sceneSDF(vec3(p.x, p.y, p.z + EPSILON)) - sceneSDF(vec3(p.x, p.y, p.z - EPSILON))` ` ));` `}` ``` ``` ``` ``` `float phongContribForLight(float k_d, vec3 p, vec3 eye, vec3 lightPos) {` ` vec3 N = estimateNormal(p);` ` vec3 L = normalize(lightPos - p);` ` vec3 V = normalize(eye - p);` ` vec3 R = normalize(reflect(-L, N));` ` ` ` float dotLN = dot(L, N);` ` float dotRV = dot(R, V);` ``` ``` ` // Light not visible from this point on the surface` ` if (dotLN < 0.0) { ` ` return 0.0;` ` } ` ` // Light reflection in opposite direction as viewer, ` ` // apply only diffuse component` ` if (dotRV < 0.0) { ` ` return (k_d * dotLN);` ` }` ` return (k_d * dotLN );` `}` ``` ``` `mat4 viewMatrix(vec3 eye, vec3 center, vec3 up) {` ` // Based on gluLookAt man page` ` vec3 f = normalize(center - eye);` ` vec3 s = normalize(cross(f, up));` ` vec3 u = cross(s, f);` ` return mat4(` ` vec4(s, 0.0),` ` vec4(u, 0.0),` ` vec4(-f, 0.0),` ` vec4(0.0, 0.0, 0.0, 1)` ` );` `}` ``` ``` `// ------------------- FUNCTIONS -------------------------------` `float lfo_ramp( in float speed ){ return fract(u_time*speed); }` `float lfo_tri( in float speed ){ return abs( (fract(u_time*speed) * 2.0) - 1.0 ); }` `float lfo_sin( in float speed ){ return (sin(u_time*speed*TWO_PI)*0.5 + 0.5); }` `// ------------------- 3D SDFs ---------------------------------` ``` ``` `float sdBox( vec3 p, vec3 b ){` ` vec3 q = abs(p) - b;` ` return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0);` `}` ``` ``` `float sdEllipsoid( vec3 p, vec3 r ){` ` float k0 = length(p/r);` ` float k1 = length(p/(r*r));` ` return k0*(k0-1.0)/k1;` `}` ``` ``` `mat4 rotateY(float theta) {` ` float c = cos(theta);` ` float s = sin(theta);` ``` ``` ` return mat4(` ` vec4(c, 0.0, s, 0.0),` ` vec4(0.0, 1.0, 0.0, 0.0),` ` vec4(-s, 0.0, c, 0.0),` ` vec4(0.0, 0.0, 0.0, 1.0)` ` );` `}` ``` ``` `// ------------------- SHADER ----------------------------------` ``` ``` `void main(){` ` // ------ raymarching parameters ------` ` float distance = 70.0;` ` float K_a = 0.05; // ambient gradient` ` float K_d = 0.9; // light gradient` ` vec3 light_pos = vec3(2.0, 4.0, 4.0 );` ``` ``` ` float clok = u_time * 0.2;` ` float theta = lfo_ramp( 0.03 ) * TWO_PI;` ` vec3 camera = vec3( 7.0, 3.0, 0.0);` ` ` ` vec3 look_at = vec3( 0, 0, 0 );` ``` ``` ` // ------ more raymarching boilerplate ------` ` vec2 st = gl_FragCoord.xy/u_resolution;` ` vec3 viewDir = rayDirection(distance, u_resolution.xy, gl_FragCoord.xy); ` ` mat4 viewToWorld = viewMatrix(camera, look_at, vec3(0.0, 1.0, 0.0));` ` vec3 worldDir = (viewToWorld * vec4(viewDir, 0.0)).xyz;` ` float dist = shortestDistanceToSurface(camera, worldDir, MIN_DIST, MAX_DIST);` ` if (dist > MAX_DIST - EPSILON) {` ` // Didn't hit anything` ` gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);` ` return;` ` }` ` // The closest point on the surface to the eyepoint along the view ray` ` vec3 p = camera + dist * worldDir;` ` ` ` float c = K_a;` ` c += phongContribForLight(K_d, p, camera, light_pos );` ``` ``` ` gl_FragColor = vec4(vec3(c), 1.0);` ``` ``` ` // dithering ` ` c *= 1.4;` ` float a = dither_4x4( c, gl_FragCoord.xy );` ` gl_FragColor = vec4(vec3(a), 1.0);` `}` ``` ``` `#define FPS 8.0 ` `// 8 sec for a complete rotation` ``` ``` `float sceneSDF(vec3 samplePoint) {` ` float theta_step = TWO_PI / 64.0;` ``` ``` ` float sdf = 0.0f;` ` ` ` float stepping = floor(-u_time*FPS) * theta_step;` ` vec4 rotated = rotateY(stepping) * vec4(samplePoint.xyz, 1.0);` ` float o0 = sdBox( rotated.xyz, vec3( 0.05, 1.8, 0.5) ); ` ``` ``` ` float displace = abs( fract( u_time*0.125 + 0.5 )*2.0 -1.0) * 0.25;` ``` ``` ` ` ` float oadd = o0 + noise( vec2(rotated.z*2.0, rotated.y*3.5 + stepping ) ) * displace;` ` sdf = min( o0, oadd );` ` ` ` float offset = 1.8;` ``` ``` ` stepping = floor(8.0 + u_time*FPS) * theta_step;` ``` ``` ` for ( int i=0; i<8; ++i ){` ` float r = stepping + float(i) * TWO_PI*0.125;` ` float r2 = stepping + float(i) * TWO_PI*0.5;` ` rotated = rotateY( r ) * vec4(samplePoint.xyz, 1.0);` ``` ``` ` vec3 p0 = rotated.xyz + vec3(0.0, 0.0, offset);` ` rotated.y += sin( r*2.0 + r2 ) * 0.2;` ` float b = sdEllipsoid( rotated.xyz + vec3(0.0, 0.0, -offset), vec3(0.2, 0.08, 0.08 ) );` ` sdf = min( b, sdf );` ` }` ` ` ` return sdf; ` `}` ``` ``` ``` ```