Skip to content

Instantly share code, notes, and snippets.

Created December 29, 2012 18:13
Show Gist options
  • Save anonymous/4408478 to your computer and use it in GitHub Desktop.
Save anonymous/4408478 to your computer and use it in GitHub Desktop.
glsl ray tracing
#ifdef GL_ES
precision highp float;
#endif
uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
struct Ray {
vec3 o;
vec3 d; //should always be normalized
};
struct Sphere {
vec3 pos;
float rad;
vec4 col;
};
float rrad = 1.35;
float rspeed = 1.0;
vec4 specularColor = vec4(1.0);
Sphere sphere1 = Sphere(vec3(rrad*cos(rspeed*time), 1.0+0.5*sin(rspeed*time), rrad*sin(rspeed*time)),
1.0, vec4(1.0, 0.5, 0.5, 1.0));
Sphere sphere2 = Sphere(vec3(-rrad*cos(rspeed*time), 1.0-0.5*sin(rspeed*time), -rrad*sin(rspeed*time)),
1.0, vec4(1.0, 1.0, 0.5, 1.0));
vec3 lightPos = vec3(10.0, 10.0, 10.0);
vec3 cameraPos = vec3(mouse.x-0.5, mouse.y, 4.0);
vec4 amb = vec4(0.1, 0.2, 0.4, 1.0);
float intersectSphere(in Ray ray, in Sphere sphere)
{
vec3 oc = ray.o - sphere.pos;
float b = 2.0 * dot(ray.d, oc);
float c = dot(oc, oc) - sphere.rad*sphere.rad;
float disc = b * b - 4.0 * c;
if (disc < 0.0)
return -1.0;
// compute q as described above
float q;
if (b < 0.0)
q = (-b - sqrt(disc))/2.0;
else
q = (-b + sqrt(disc))/2.0;
float t0 = q;
float t1 = c / q;
// make sure t0 is smaller than t1
if (t0 > t1) {
// if t0 is bigger than t1 swap them around
float temp = t0;
t0 = t1;
t1 = temp;
}
// if t1 is less than zero, the object is in the ray's negative direction
// and consequently the ray misses the sphere
if (t1 < 0.0)
return -1.0;
// if t0 is less than zero, the intersection point is at t1
if (t0 < 0.0) {
return t1;
} else {
return t0;
}
}
float intersectPlane(in Ray ray)
{
return -ray.o.y/ray.d.y;
}
vec3 sphereNormal(in vec3 pos, in Sphere sphere)
{
return (pos - sphere.pos)/sphere.rad;
}
float diffuseFactor(in vec3 surfaceNormal, in vec3 lightDir) {
return clamp(dot(surfaceNormal, lightDir), 0.0, 1.0);
}
float specularFactor(in vec3 surfaceNormal, in vec3 lightDir)
{
vec3 viewDirection = normalize(cameraPos);
vec3 halfAngle = normalize(lightDir + viewDirection);
float ks = dot(surfaceNormal, halfAngle);
ks = clamp(ks, 0.0, 1.0);
ks = pow(ks, 50.0);
return ks;
}
int worldIntersect(in Ray ray, float maxlen, inout float t)
{
t = maxlen;
int id = 0;
float ts1 = intersectSphere(ray, sphere1);
float ts2 = intersectSphere(ray, sphere2);
float tp = intersectPlane(ray);
if (ts1 > 0.0) {
t = ts1;
id = 1;
}
if (ts2 > 0.0 && ts2 < t) {
t = ts2;
id = 2;
}
if ( tp > 0.0 && tp < t) {
t = tp;
id = 3;
}
return id;
}
float worldShadow(in Ray ray, in float maxlen, in int id)
{
float ts1 = intersectSphere(ray, sphere1);
float ts2 = intersectSphere(ray, sphere2);
if(ts1 > 0.0 && id != 1)
return 0.0;
if(ts2 > 0.0 && id != 2)
return 0.0;
return 1.0;
}
void applyFog(in float t, inout vec4 col)
{
col = mix(col, amb, clamp(sqrt(t*t)/10.0, 0.0, 1.0));
}
void main( void ) {
//pixels from 0 to 1
vec2 uv = gl_FragCoord.xy/resolution.xy;
vec3 d = vec3(-1.0 + 2.0*uv, -1.0);
d.x *= resolution.x/resolution.y;
Ray ray = Ray(cameraPos, normalize(d));
vec4 col = vec4(0.0,0.0,0.0,1.0);
float t = 0.0;
int id = worldIntersect(ray, 1000.0, t);
vec3 pos = ray.o + t*ray.d;
vec3 lightDir = normalize(lightPos-pos);
if (id == 1) {
vec3 surfaceNormal = sphereNormal(pos, sphere1);
float dif = diffuseFactor(surfaceNormal, lightDir);
float spec = specularFactor(surfaceNormal, lightDir);
col = dif*sphere1.col+spec*specularColor;
} else if (id == 2) {
vec3 surfaceNormal = sphereNormal(pos, sphere2);
float dif = diffuseFactor(surfaceNormal, lightDir);
float spec = specularFactor(surfaceNormal, lightDir);
col = dif*sphere2.col+spec*specularColor;
} else if (id == 3) {
col = vec4(0.7, 0.7, 0.7, 1.0);
}
col *= worldShadow(Ray(vec3(pos), lightDir), 100.0, id);
col = col + 0.2*amb;
//col = sqrt(col);
applyFog(t, col);
gl_FragColor = col;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment