Created
December 2, 2017 22:10
-
-
Save neildanson/241fad40b2650e7903650102cd96dfc2 to your computer and use it in GitHub Desktop.
Simple Raytracer running in GLSL
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
#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