Skip to content

Instantly share code, notes, and snippets.

@neildanson
Created December 2, 2017 22:10
Show Gist options
  • Save neildanson/241fad40b2650e7903650102cd96dfc2 to your computer and use it in GitHub Desktop.
Save neildanson/241fad40b2650e7903650102cd96dfc2 to your computer and use it in GitHub Desktop.
Simple Raytracer running in GLSL
#define NUM_SPHERE 6
#define NUM_LIGHT 3
struct Camera {
vec3 position;
vec3 forward;
vec3 up;
vec3 right;
};
struct Sphere {
vec3 position;
float radius;
int texture;
};
struct Ray {
vec3 position;
vec3 direction;
};
struct Intersection {
Ray ray;
float distance;
Sphere object;
};
struct Light {
vec3 position;
vec3 color;
};
Camera create_camera(vec3 position, vec3 look_at, float height) {
Camera camera;
vec3 forward = normalize(look_at - position);
vec3 down = vec3(0.0,-1.0,0.0);
vec3 right = normalize(cross(forward,down)) * 1.5 / height;
vec3 up = normalize(cross(forward,right)) * 1.5 / height;
camera.position = position;
camera.forward = forward;
camera.up = up;
camera.right = right;
return camera;
}
Sphere sphere[NUM_SPHERE];
Light lights[NUM_LIGHT];
bool intersects(Sphere sphere, Ray ray, out Intersection intersection) {
vec3 diff = sphere.position.xyz - ray.position.xyz;
float v = dot(diff, ray.direction);
if (v < 0.0) {
return false;
} else {
float distance_squared = pow(sphere.radius, 2.0) - (dot(diff, diff) - pow(v,2.0));
if (distance_squared < 0.0) {
return false;
} else {
float distance = v - sqrt(distance_squared);
intersection.ray = ray;
intersection.distance = distance;
intersection.object = sphere;
return true;
}
}
}
vec3 normal(Intersection intersection) {
return normalize(intersection.ray.position + (intersection.ray.direction * intersection.distance) - intersection.object.position);
}
float recenter_x(float x, float half_width) {
return x - half_width;
}
float recenter_y(float y, float half_height) {
return (y - half_height);
}
vec3 lookup(vec3 normal, sampler2D tex) {
float x = (normal.x / 2.0) + 0.5;
float y = (normal.y / 2.0) + 0.5;
return texture2D(tex, vec2(x, y)).xyz;
}
Ray get_ray(float x, float y, float half_width, float half_height, Camera camera) {
vec3 right = camera.right * (recenter_x(x, half_width));
vec3 up = camera.up * (recenter_y(y, half_height));
Ray ray;
ray.position = camera.position;
ray.direction = normalize(right + up + camera.forward);
return ray;
}
bool any_intersection(Ray ray) {
for (int i = 0; i < NUM_SPHERE; i++) {
Intersection intersection;
if (intersects(sphere[i], ray, intersection)) {
return true;
}
}
return false;
}
vec3 apply_light(vec3 position,
vec3 normal,
//objects: &Vec<&Sphere>,
Light light,
vec3 ray_direction,
vec3 base_color) {
vec3 light_dir = normalize(light.position - position);
Ray ray;
ray.position = position;
ray.direction = light_dir;
if (any_intersection(ray)) {
return vec3(0.0,0.0,0.0);
}
float illum = dot(light_dir, normal);
vec3 lcolor;
if (illum > 0.0) {
lcolor = light.color * illum;
}
vec3 diffuse_color = lcolor * base_color;
float d = dot(normal, ray_direction);
ray_direction = normalize(ray_direction - (normal * (2.0 * d)));
float specular = dot(light_dir, ray_direction);
vec3 specular_result;
if (specular > 0.0) {
specular_result = light.color * pow(specular, 50.0);
}
return diffuse_color + specular_result;
}
vec3 apply_lights(vec3 position,
vec3 normal,
//objects: &Vec<&Sphere>,
vec3 ray_direction,
vec3 base_color) {
vec3 color;
for (int i = 0; i < NUM_LIGHT; i++) {
color = color + apply_light(position, normal, lights[i], ray_direction, base_color);
}
return color;
}
void main() {
vec2 uv = gl_FragCoord.xy;
vec3 position = vec3(3.0 - cos(iGlobalTime),3.0,-3.0 + sin(iGlobalTime));
Camera camera = create_camera(position, vec3(0.0,0.0, 0.0), iResolution.y);
sphere[0].position = vec3(0.0,-100.0, 0.0);
sphere[0].radius = 99.0;
sphere[3].position = vec3(0.0,0.0, 1.0);
sphere[3].radius = 1.0;
sphere[4].position = vec3(2.0,0.0, 1.0);
sphere[4].radius = 1.0;
sphere[5].position = vec3(4.0,0.0, 1.0);
sphere[5].radius = 1.0;
sphere[2].position = vec3(-2.0,0.0, 1.0);
sphere[2].radius = 1.0;
sphere[1].position = vec3(-4.0,0.0, 1.0);
sphere[1].radius = 1.0;
lights[0].position = vec3(-3.0,3.0,-1.0);
lights[0].color = vec3(0.5,0.0,0.0);
lights[1].position = vec3(3.0,3.0,-1.0);
lights[1].color = vec3(0.0,0.0,0.5);
lights[2].position = vec3(0.0,1.0,-10.0);
lights[2].color = vec3(0.5,0.5,0.5);
Ray ray = get_ray(uv.x,uv.y, iResolution.x / 2.0, iResolution.y / 2.0, camera);
for (int i = 0; i < NUM_SPHERE; i++) {
Intersection intersection;
if (intersects(sphere[i], ray, intersection)) {
vec3 hit_point = intersection.ray.position + (intersection.ray.direction * intersection.distance);
vec3 n = normal(intersection);
vec3 color = lookup(n, iChannel0);
vec3 lit_color = apply_lights(hit_point, n, intersection.ray.direction, color);
gl_FragColor = vec4(lit_color.xyz,1.0);//vec4(lit_color.xyz, 1.0);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment