October 26, 2014

Simple Ray Traced Sphere

Here is a ray traced sphere!  It has diffuse and specular lighting.  Right now it's not doing much, just hanging out in space.


CODE:
struct sphere {
    vec3 pos;
    float radius;
    vec3 col;
    int id;
};
 
vec3 light = vec3(3.0, 5.0, 8.0);
vec3 eye = vec3(0.0, 0.0, 8.0);
vec3 up = vec3(0.0, 1.0, 0.0);
sphere s1;

struct eye_coord_system  {
  vec3 n;
  vec3 u;
  vec3 v;
};

float intersection_Sphere(vec3 ray_origin, vec3 ray_direction, sphere sph) {
    vec3 d = ray_direction;
    float a = dot(d, d);
    float b = 2.0 * dot(d, ray_origin - sph.pos);
    float c = dot(ray_origin - sph.pos, ray_origin - sph.pos) - (sph.radius * sph.radius);
    float delta = b*b - 4.0*a*c;
  float t = delta < 0.0 ? -1.0 : (-b - sqrt(delta)) / (2.0*a);
    return t;
}

vec3 get_sphere_normal(vec3 pos, sphere sph ) {
    return (pos - sph.pos)/sph.radius;
}

vec3 get_color_of_point(eye_coord_system eye_coord, vec3 ray_origin, vec3 ray_direction, sphere sph, vec3 col) {
    float intersection = intersection_Sphere(ray_origin, ray_direction, sph);
  if (intersection > 0.0) {
  vec3 pos = ray_origin + intersection*ray_direction;
  vec3 nor = get_sphere_normal(pos, sph);
        vec3 reflection = normalize(reflect(ray_direction, nor));
        float diffuse = max(0.0, dot(nor, normalize(light)));
        float specular = pow(dot(reflection, eye_coord.u), 50.0);
        specular = max(specular, 0.01); // for some reason 0.0 returns crappy results
        col = vec3(diffuse + specular);
    }
    return col;
}

eye_coord_system create_coord_system(vec3 eye, vec3 center, vec3 up) {
        vec3 n = vec3(eye - center) / length(eye - center);
        vec3 u = cross(up, n) / length(cross(up, n));
        vec3 v = cross(n, u);
        eye_coord_system coord_system = eye_coord_system(n, u, v);
        return coord_system;
}

vec3 calculate_pixel_loc(vec3 eye, eye_coord_system eye_coord) {
        float i = gl_FragCoord.x; float j = gl_FragCoord.y;
        float X = iResolution.x; float Y = iResolution.y;
        float aspectRatio = iResolution.x / iResolution.y;
        float d = distance(s1.pos, eye)/2.0;
        float H = 1.5; float W = H * aspectRatio;
        vec3 C = eye - eye_coord.n * d;
        vec3 L = C - eye_coord.u * (W/2.0) - eye_coord.v * (H/2.0);
        vec3 s = L + eye_coord.u * i * (W/X) + eye_coord.v * j * (H/Y);
        return s;
}

void main(void) {
        s1 = sphere(vec3(0.0), 1.0, vec3(0.3), 1);
        eye_coord_system eye_coord = create_coord_system(eye, s1.pos, up);
        vec3 s = calculate_pixel_loc(eye, eye_coord);
        vec3 ray_direction = s - eye;
 
        vec3 col = vec3(0.3);
        col = get_color_of_point(eye_coord, eye, ray_direction, s1, col);
        gl_FragColor = vec4(col,1.0);
}

Algo in a nutshell: Thousands of tiny microscopic minions are enlisted to go out exploring in space.  If there is an object floating around out there, some of the minions will collide with that object.  The tiny minions remember where they collide and they can figure out themselves how the object should be colored at that location, because they know the shape of the object and they know where the light is.  So they take out their tiny microscopic paintbrushes and color the surface accordingly and dutifully return back to homebase where they repeat the process over and over again.  (Their lightning fast speed makes up for their miniscule proportions).
Well.. that's how I think of it anyway


I think most of the code here complies with conventional ray traced algorithms I've seen online.  Only difference might be the method calculate_pixel_loc, which fixes any perspective distortion issues which become obvious if the sphere is moved from its origin.
Perspective distortion

Used these slides on raytracing and these slides on illumination from my old rendering professor for guidance.  (My school dropped the rendering course on ray tracing so that's why I'm not learning it in class :/)