Last active
August 3, 2020 00:50
-
-
Save vxf/86192c2f9453850862a705630cf70687 to your computer and use it in GitHub Desktop.
This file contains 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
// raytracer for shadertoy https://www.shadertoy.com/view/wtsBz7 | |
// reference: | |
// https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection | |
#define MOVING | |
const float MAXFLOAT = 3.402823e+38; | |
const float EPSILON = 0.001; | |
const int MAX_BOUNCE = 4; | |
vec3 camera = vec3(0.0, 0.0, 0.0); | |
vec3 center = vec3(0.0, 0.0, 2.0); | |
vec3 light = vec3(-10.0, 10.0, -10.0); | |
float radius = 1.0; | |
float radius2 = 1.0; // squared | |
vec3 color_white = vec3(1.0, 1.0, 1.0); | |
vec3 color_black = vec3(0.0, 0.0, 0.0); | |
const vec3 sphere_color = vec3(1.0, 0.0, 0.0); | |
vec4[5] scene = vec4[]( | |
vec4(0.0, 0.0, 4.0, 0.9), | |
vec4(-2.0, 0.6, 4.0, 0.9), | |
vec4(2.0, 0.6, 4.0, 0.9), | |
vec4(-0.5, -0.5, 2.0, 0.3), | |
vec4(0.5, -0.5, 2.0, 0.3) | |
); | |
void sphere_normal(vec3 i, out vec3 normal) | |
{ | |
normal = normalize(i - center); | |
} | |
bool sphere_intersect(in vec4 sphere, in vec3 origin, in vec3 dir, out float x0, out float x1) | |
{ | |
vec3 center = sphere.xyz; | |
float radius2 = sphere.w*sphere.w; | |
vec3 L = origin - center; | |
float a = dot(dir, dir); | |
float b = 2.0 * dot(dir, L); | |
float c = dot(L, L) - radius2; | |
float discr = b * b - 4.0 * a * c; | |
if (discr < 0.0) | |
return false; | |
if (discr == 0.0) | |
{ | |
x0 = x1 = -0.5 * b / a; | |
return true; | |
} | |
float q = (b > 0.0) ? -0.5 * (b + sqrt(discr)) : -0.5 * (b - sqrt(discr)); | |
x0 = q / a; | |
x1 = c / q; | |
if (x0 > x1) | |
{ | |
float t = x0; | |
x0 = x1; | |
x1 = t; | |
} | |
if (x0 < 0.0) | |
{ | |
x0 = x1; | |
if (x0 < EPSILON) // avoid self colisions roughly | |
return false; | |
} | |
return true; | |
} | |
void phong(in vec3 l, in vec3 v, in vec3 n, out vec3 color) | |
{ | |
vec3 h = normalize(l + v); | |
vec3 diffuse = sphere_color * max(dot(n, l), 0.0); | |
vec3 specular = color_white * max(pow(dot(n, h), 200.0), 0.0); | |
color = (specular * 0.3) + (diffuse * 0.5) + color_white * 0.2; | |
//color = diffuse; | |
//color = specular; | |
} | |
bool nearest_intersection(in vec3 origin, in vec3 dir, out vec3 center, out float t) | |
{ | |
t = MAXFLOAT; | |
float t0, t1; | |
bool hit = false; | |
#ifdef MOVING | |
vec4 sphere; | |
for (int i = 0; i < 3; i++) | |
{ | |
if(sphere_intersect(scene[i], origin, dir, t0, t1)) | |
{ | |
if(t0 < t) | |
{ | |
t = t0; | |
center = scene[i].xyz; | |
} | |
hit = true; | |
} | |
} | |
for (int i = 0; i < 8; i++) | |
{ | |
//sphere = scene[0]; | |
float ts = iTime + float(i) * 3.14/4.0; | |
sphere = vec4(cos(ts)*1.5, -0.6, sin(ts)*1.5+4.0, 0.5); | |
if(sphere_intersect(sphere, origin, dir, t0, t1)) | |
{ | |
if(t0 < t) | |
{ | |
t = t0; | |
center = sphere.xyz; | |
} | |
hit = true; | |
} | |
} | |
#else | |
for (int i = 0; i < 5; i++) | |
{ | |
if(sphere_intersect(scene[i], origin, dir, t0, t1)) | |
{ | |
if(t0 < t) | |
{ | |
t = t0; | |
center = scene[i].xyz; | |
} | |
hit = true; | |
} | |
} | |
#endif | |
return hit; | |
} | |
void reflectv2(in vec3 origin, in vec3 dir, out vec3 color) | |
{ | |
vec3 center; | |
float t; | |
bool hit = true; | |
color = color_white; | |
vec3 o = origin; | |
vec3 d = dir; | |
for (int n = 0; n < MAX_BOUNCE; n++) | |
{ | |
if(!nearest_intersection(o, d, center, t)) | |
break; | |
vec3 pcolor; | |
vec3 intersection = o + (d * t); | |
vec3 normal = normalize(intersection - center); | |
phong( | |
normalize(light - intersection), // light | |
normalize(o - intersection), // view | |
normalize(intersection - center), // normal | |
pcolor); | |
vec3 rcolor; | |
vec3 r = reflect(d, normal); | |
color = (color + pcolor) / 2.0; | |
o = intersection; | |
d = r; | |
} | |
} | |
void mainImage( out vec4 fragColor, in vec2 fragCoord ) | |
{ | |
// Normalized pixel coordinates (from 0 to 1) | |
//vec2 uv = fragCoord/iResolution.xy; | |
float aspect = iResolution.x / iResolution.y; | |
vec2 uv = vec2(fragCoord.x / iResolution.x * aspect, fragCoord.y / iResolution.y); | |
// primary rays | |
vec3 dir = normalize(vec3(uv.x - aspect / 2.0, uv.y-0.5, 1.0)); | |
float t = MAXFLOAT; | |
vec3 center; | |
if(nearest_intersection(camera, dir, center, t)) | |
{ | |
vec3 color; | |
vec3 intersection = camera + (dir * t); | |
vec3 normal = normalize(intersection - center); | |
phong( | |
normalize(light - intersection), // light | |
normalize(camera - intersection), // view | |
normalize(intersection - center), // normal | |
color); | |
vec3 rcolor; | |
vec3 r = reflect(dir, normal); | |
reflectv2(intersection, r, rcolor); | |
color = (color + rcolor) / 2.0; | |
//color = rcolor; | |
// fragColor = vec4(color_black, 1.0); | |
fragColor = vec4(color, 1.0); | |
} | |
else | |
fragColor = vec4(color_white, 1.0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment