Example #1
0
// Check if the given sphere is intersected by the given ray.
// See Shirley et.al., section 10.3.1
// Returns 1 if there is an intersection (and sets the appropriate
// fields of ip), or 0 otherwise.
static int
ray_intersects_sphere(intersection_point* ip, sphere sph,
    vec3 ray_origin, vec3 ray_direction)
{
    float   A, B, C, D;
    vec3    diff;
    float   t_hit;

    A = v3_dotprod(ray_direction, ray_direction);

    diff = v3_subtract(ray_origin, sph.center);
    B = 2.0 * v3_dotprod(diff, ray_direction);
    C = v3_dotprod(diff, diff) - sph.radius * sph.radius;

    D = B*B - 4*A*C;

    if (D < 0.0)
        return 0;

    D = sqrt(D);

    // We're only interested in the first hit, i.e. the one with
    // the smallest t_hit, so we check -B-D first, followed by -B+D

    t_hit = (-B - D)/(2*A);

    if (t_hit < 0.0)
    {
        t_hit = (-B + D)/(2*A);
        if (t_hit < 0.0)
            return 0;
    }

    ip->t = t_hit;
    ip->p = v3_add(ray_origin, v3_multiply(ray_direction, t_hit));
    ip->n = v3_normalize(v3_subtract(ip->p, sph.center));
    ip->i = v3_normalize(v3_negate(ray_direction));
    ip->material = sph.material;

    return 1;
}
Example #2
0
void
ray_trace(void)
{
    vec3    forward_vector, right_vector, up_vector;
    int     i, j;
    float   image_plane_width, image_plane_height;
    vec3    color;
    char    buf[128];

    struct timeval  t0, t1;
    float           time_taken;

    fprintf(stderr, "Ray tracing ...");
    gettimeofday(&t0, NULL);

    num_rays_shot = num_shadow_rays_shot = num_triangles_tested = num_bboxes_tested = 0;

    // Compute camera coordinate system from camera position
    // and look-at point
    up_vector = v3_create(0, 0, 1);
    forward_vector = v3_normalize(v3_subtract(scene_camera_lookat, scene_camera_position));
    right_vector = v3_normalize(v3_crossprod(forward_vector, up_vector));
    up_vector = v3_crossprod(right_vector, forward_vector);

    // Compute size of image plane from the chosen field-of-view
    // and image aspect ratio. This is the size of the plane at distance
    // of one unit from the camera position.
    image_plane_height = 2.0 * tan(0.5*VFOV/180*M_PI);
    image_plane_width = image_plane_height * (1.0 * framebuffer_width / framebuffer_height);

    vec3 d, e, u, v, w, ud, vd;
    float l, r, b, t, nx, ny;
    // direction d, origin e
    // ONB u, v, w
    // image plane edges l, r, b, t
    // window size nx, ny
    e = scene_camera_position;
    u = right_vector, v = up_vector, w = v3_negate(forward_vector);
    l = -0.5 * image_plane_width, r = 0.5 * image_plane_width;
    b = 0.5 * image_plane_height, t = -0.5 * image_plane_height;
    nx = framebuffer_width, ny = framebuffer_height;

    // Loop over all pixels in the framebuffer
    for (j = 0; j < ny; j++) {
        for (i = 0; i < nx; i++) {

            ud = v3_multiply(u, (l + (r - l) * ((i + 0.5) / nx)));
            vd = v3_multiply(v, (b + (t - b) * ((j + 0.5) / ny)));
            d = v3_add(v3_add(ud, vd), v3_negate(w));
            color = ray_color(0, e, d);
            put_pixel(i, j, color.x, color.y, color.z);

        }

        sprintf(buf, "Ray-tracing ::: %.0f%% done", 100.0*j/framebuffer_height);
        glutSetWindowTitle(buf);
    }

    // Done!
    gettimeofday(&t1, NULL);

    glutSetWindowTitle("Ray-tracing ::: done");

    // Output some statistics
    time_taken = 1.0 * (t1.tv_sec - t0.tv_sec) + (t1.tv_usec - t0.tv_usec) / 1000000.0;

    fprintf(stderr, " done in %.1f seconds\n", time_taken);
    fprintf(stderr, "... %lld total rays shot, of which %d camera rays and "
            "%lld shadow rays\n", num_rays_shot,
            do_antialiasing ? 4*framebuffer_width*framebuffer_height :
                              framebuffer_width*framebuffer_height,
            num_shadow_rays_shot);
    fprintf(stderr, "... %lld triangles intersection tested "
            "(avg %.1f tri/ray)\n",
        num_triangles_tested, 1.0*num_triangles_tested/num_rays_shot);
    fprintf(stderr, "... %lld bboxes intersection tested (avg %.1f bbox/ray)\n",
        num_bboxes_tested, 1.0*num_bboxes_tested/num_rays_shot);
}
Example #3
0
static int
ray_intersects_triangle(intersection_point* ip, triangle tri,
    vec3 ray_origin, vec3 ray_direction)
{
    vec3    edge1, edge2;
    vec3    tvec, pvec, qvec;
    double  det, inv_det;
    double  t, u, v;        // u, v are barycentric coordinates
    // t is ray parameter

    num_triangles_tested++;

    edge1 = v3_subtract(scene_vertices[tri.v[1]], scene_vertices[tri.v[0]]);
    edge2 = v3_subtract(scene_vertices[tri.v[2]], scene_vertices[tri.v[0]]);

    pvec = v3_crossprod(ray_direction, edge2);

    det = v3_dotprod(edge1, pvec);

    if (det < 1.0e-6)
        return 0;

    tvec = v3_subtract(ray_origin, scene_vertices[tri.v[0]]);

    u = v3_dotprod(tvec, pvec);
    if (u < 0.0 || u > det)
        return 0;

    qvec = v3_crossprod(tvec, edge1);

    v = v3_dotprod(ray_direction, qvec);
    if (v < 0.0 || u+v > det)
        return 0;

    t = v3_dotprod(edge2, qvec);

    if (t < 0.0)
        return 0;

    inv_det = 1.0 / det;
    t *= inv_det;
    u *= inv_det;
    v *= inv_det;

    // We have a triangle intersection!
    // Return the relevant intersection values.

    // Compute the actual intersection point
    ip->t = t;
    ip->p = v3_add(ray_origin, v3_multiply(ray_direction, t));

    // Compute an interpolated normal for this intersection point, i.e.
    // we use the barycentric coordinates as weights for the vertex normals
    ip->n = v3_normalize(v3_add(
        v3_add(
            v3_multiply(tri.vn[0], 1.0-u-v),
            v3_multiply(tri.vn[1], u)
        ),
        v3_multiply(tri.vn[2], v)));

    ip->i = v3_normalize(v3_negate(ray_direction));
    ip->material = tri.material;

    return 1;
}