Created
April 10, 2019 23:51
-
-
Save ShiftedClock/49bd98a3cddea9f0315855f7a69c6e04 to your computer and use it in GitHub Desktop.
Raymarching Refraction Shader from: https://www.noirbear.com/toys/marching/refraction.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #define M_PI 3.1415926535897932384626433832795 | |
| #define M_2PI 6.2831853071795864769252867665590 | |
| #define SKY_R 60.0 // inner radius of sky sphere | |
| #define TRANS_MAT 2.0 // largest material ID for transparent materials | |
| // Many, many thanks to IQ for providing the incredibly helpful sample | |
| // code for getting started with ray marching: https://www.shadertoy.com/view/Xds3zN | |
| precision mediump float; | |
| uniform float time; | |
| uniform vec2 uResolution; | |
| uniform vec2 uMouse; | |
| uniform sampler2D uFloorSampler; | |
| uniform sampler2D uSkySampler; | |
| const float maxDepth = 128.0; | |
| const int maxIterations = 256; | |
| const float epsilon = 0.001; | |
| // polynomial smooth min | |
| float smin( float a, float b, float k ) | |
| { | |
| float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 ); | |
| return mix( b, a, h ) - k*h*(1.0-h); | |
| } | |
| float length8(vec2 p) | |
| { | |
| return pow(pow(p.x,0.125) + pow(p.y,0.125), 0.125); | |
| } | |
| float plane( vec3 p ) | |
| { | |
| return p.y; | |
| } | |
| float sphere(vec3 p, float s) | |
| { | |
| return (length(p)-s); | |
| } | |
| float wigglesphere(vec3 p, float s) | |
| { | |
| return 0.02*sin(35.0*p.y + 8.*time) + 0.1*cos(5.*p.z + 2.*time) + sphere(p, s); | |
| } | |
| float wigglesphere1(vec3 p, float s) | |
| { | |
| return 0.02*sin(65.*p.z*p.x + 20.*time) + 0.01*cos(120.*p.x - 25.*time) - 0.02*sin(30.*p.z + time) + sphere(p, s); | |
| } | |
| float udRoundBox( vec3 p, vec3 b, float r ) | |
| { | |
| return length(max(abs(p)-b,0.0))-r; | |
| } | |
| float sdTorus( vec3 p, vec2 t ) | |
| { | |
| vec2 q = vec2(length(p.xy)-t.x,p.z); | |
| return length(q)-t.y; | |
| } | |
| vec2 opU(vec2 d1, vec2 d2) | |
| { | |
| return (d1.x < d2.x) ? d1 : d2; | |
| } | |
| float opBlend( float d1, float d2 ) | |
| { | |
| return smin( d1, d2, 0.1 ); | |
| } | |
| float opTwist( vec3 p ) | |
| { | |
| float c = cos(20.0*p.y); | |
| float s = sin(20.0*p.y); | |
| mat2 m = mat2(c,-s,s,c); | |
| vec3 q = vec3(m*p.xz,p.y); | |
| return sdTorus(q, vec2(0.4, 0.1)); | |
| } | |
| float opBend( vec3 p ) | |
| { | |
| float c = 0.6*cos(0.5*p.x)+0.2*sin(0.3*p.z); | |
| float s = 0.1*sin(0.08*p.z*p.x); | |
| mat2 m = mat2(c,-s,s,c); | |
| vec3 q = vec3(m*p.xy,p.y); | |
| return plane(vec3(p.x, p.y+c+s, p.z));//, vec3(0.62, 0.32, 0.5), 0.25); | |
| } | |
| vec2 map(in vec3 p) | |
| { | |
| vec2 res = opU(opU( vec2(opBend(vec3(p.x, p.y + 0.65, p.z)), 4.0), // floor plane | |
| vec2(max(sphere(vec3(p.x, p.y + 0.65, p.z), SKY_R), - sphere(vec3(p.x, p.y + 0.65, p.z), SKY_R)), 3.0)), // sky sphere | |
| vec2(opBlend(sdTorus(vec3(p.x+1.0, p.y-0.1, p.z), vec2(0.4,0.15)), udRoundBox(vec3(p.x, p.y, p.z), vec3(0.62, 0.32, 0.2), 0.3)), 1.0) | |
| //vec2(wigglesphere1(p, 0.62), 1.0) // wiggly blob | |
| ); | |
| //res = opU(res, vec2(wigglesphere1(p, 0.55), 1.0)); // for debugging | |
| return res; | |
| } | |
| vec3 calcNormal( in vec3 pos ) | |
| { | |
| vec3 eps = vec3( 0.001, 0.0, 0.0 ); | |
| vec3 nor = vec3( | |
| map(pos+eps.xyy).x - map(pos-eps.xyy).x, | |
| map(pos+eps.yxy).x - map(pos-eps.yxy).x, | |
| map(pos+eps.yyx).x - map(pos-eps.yyx).x ); | |
| return normalize(nor); | |
| } | |
| float softshadow( in vec3 ro, in vec3 rd, in float mint, in float maxt, in float k ) | |
| { | |
| float res = 1.0; | |
| float t = mint; | |
| for( int i=0; i<30; i++ ) | |
| { | |
| if( t<maxt ) | |
| { | |
| float h = map( ro + rd*t ).x; | |
| res = min( res, k*h/t ); | |
| t += 0.02; | |
| } | |
| } | |
| return clamp( res, 0.3, 1.0 ); | |
| } | |
| float calcAO( in vec3 pos, in vec3 nor ) | |
| { | |
| float total = 0.0; | |
| float sca = 1.0; | |
| for( int aoi=0; aoi<5; aoi++ ) | |
| { | |
| float hr = 0.01 + 0.05*float(aoi); | |
| vec3 aopos = nor * hr + pos; | |
| float dd = map( aopos ).x; | |
| total += -(dd-hr)*sca; | |
| sca *= 0.75; | |
| } | |
| return clamp( 1.0 - 4.0*total, 0.0, 1.0 ); | |
| } | |
| vec3 getColorAt(in vec3 pos, in float mat, in float dist, in vec3 rd) | |
| { | |
| vec3 col = vec3(0.5); | |
| if( dist < maxDepth ) // raymarch converged after dist steps | |
| { | |
| vec3 normal = calcNormal( pos ); | |
| vec3 light = normalize( vec3(-1.0, 1.5, -1.1) ); | |
| float ao = calcAO(pos, normal); | |
| if (mat > 3.0) // floor has mat == 4.0 | |
| { | |
| float amb = clamp( 0.5+0.5*normal.y - (dist / maxDepth), 0.0, 1.0 ); | |
| float diffuse = clamp(dot(normal, light), 0.0, 1.0); | |
| float bac = clamp( dot( normal, normalize(vec3(-light.x,0.0,-light.z))), 0.0, 1.0 )*clamp( 1.0-pos.y,0.0,1.0); | |
| vec3 brdf = vec3(0.0); | |
| float sh = softshadow( pos, light, 0.02, 2.0, 1.0 ); | |
| float pp = clamp( dot( reflect(rd,normal), light ), 0.0, 1.0 ); | |
| float spe = sh*pow(pp,16.0); | |
| vec3 tex = texture2D(uFloorSampler, vec2(pos.x*0.1, pos.z*0.1)).rgb; | |
| diffuse *= sh; | |
| brdf += amb*vec3(0.99215, 0.77647, 0.38431); | |
| brdf += vec3(0.4, 0.2, 0.0) * clamp(dot(normal, light), 0.0, 1.0) * (1.0 / pow(distance(pos, light),4.0))*0.2; | |
| brdf += 0.2*bac*vec3(0.15, 0.15, 0.15); | |
| brdf += 1.2*diffuse*vec3(1.0, 0.9, 0.7); | |
| col = brdf * tex * ao*ao + vec3(0.1)*spe; | |
| } | |
| else if (mat> 2.0) // sky has mat == 3.0 | |
| { | |
| vec3 np = normalize(pos); | |
| vec2 nnp = normalize(pos.xz); | |
| float arc = (atan(nnp.x, nnp.y) - atan(-1.0, -1.0) + M_2PI) * SKY_R; | |
| float tx = arc / (M_2PI * SKY_R); | |
| col = texture2D(uSkySampler, vec2(tx, -np.y-0.05)).rgb; | |
| } | |
| else if (mat > 0.0) // scene objects | |
| { | |
| float diffuse = clamp(dot(normal, light), 0.3, 1.0); | |
| //col = vec3(dif, dif, dif); | |
| col = vec3(0.2*diffuse, 0.3*diffuse, 0.8*diffuse) * (1.0 / pow(distance(pos, light),3.0)); | |
| } | |
| } | |
| return vec3( clamp(col,0.0,1.0) ); | |
| } | |
| vec3 castRay( in vec3 ro, in vec3 rd, in float maxd ) | |
| { | |
| float h=epsilon*2.0; // step size | |
| vec2 result; // result of distance check | |
| float t = 0.0; // distance travelled | |
| float m = -1.0; // material | |
| vec3 color = vec3(1.0); | |
| vec3 pos = ro+rd*t; | |
| for( int i=0; i<maxIterations; i++ ) | |
| { | |
| if( abs(h)<epsilon||t>maxd ) continue;//break; | |
| t += h; | |
| pos = ro+rd*t; | |
| result = map(pos); | |
| h = result.x; | |
| m = result.y; | |
| } | |
| if ((t < maxd) && (m < 3.0)) // hit transparent surface; march again | |
| { | |
| pos = ro+t*rd; | |
| vec3 new_ro = pos; | |
| vec3 rd_ref = refract(rd, calcNormal(pos), 0.75); | |
| color *= getColorAt(pos, m, t, rd); // color @ surface | |
| //t = 0.0; | |
| // do refractive ray | |
| h = epsilon*1000.0; | |
| for( int i=0; i<maxIterations; i++ ) | |
| { | |
| if( abs(h)<epsilon||t>maxd ) continue;//break; | |
| t += h; | |
| pos = new_ro+t*rd_ref; | |
| result = map(pos); | |
| h = result.x; | |
| m = result.y; | |
| } | |
| color += getColorAt(pos, m, t, rd_ref); // color from refracted ray | |
| // do penetrative ray | |
| h = epsilon*1000.0; | |
| for ( int i=0; i<maxIterations; i++) | |
| { | |
| if( abs(h) < epsilon||t>maxd ) continue; //break; | |
| t += h; | |
| pos = new_ro+t*rd; | |
| result = map(pos); | |
| h = result.x; | |
| m = result.y; | |
| } | |
| } | |
| return color*getColorAt(pos, m, t, rd); | |
| } | |
| vec3 render( in vec3 ro, in vec3 rd ) | |
| { | |
| return castRay(ro,rd,maxDepth); | |
| } | |
| void main(void) | |
| { | |
| vec2 q = gl_FragCoord.xy/uResolution.xy; | |
| vec2 p = -1.0+2.0*q; | |
| p.x *= uResolution.x/uResolution.y; | |
| vec2 mo = uMouse.xy/uResolution.xy; | |
| // camera | |
| vec3 rorigin = vec3(3.2*cos(6.0*mo.x), 2.0*mo.y, 3.2*sin(6.0*mo.x) ); | |
| vec3 ta = vec3( -0.5, -0.4, 0.5 ); | |
| // camera tx | |
| vec3 cw = normalize( ta-rorigin ); | |
| vec3 cp = vec3( 0.0, 1.0, 0.0 ); | |
| vec3 cu = normalize( cross(cw,cp) ); | |
| vec3 cv = normalize( cross(cu,cw) ); | |
| vec3 rdir = normalize( p.x*cu + p.y*cv + 2.5*cw ); | |
| vec3 color = render( rorigin, rdir ); | |
| gl_FragColor=vec4( color, 1.0 ); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment