Skip to content

Instantly share code, notes, and snippets.

@vxf
Last active August 3, 2020 00:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vxf/86192c2f9453850862a705630cf70687 to your computer and use it in GitHub Desktop.
Save vxf/86192c2f9453850862a705630cf70687 to your computer and use it in GitHub Desktop.
// 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