top of page

RAYCASTING AND LIGHTING:

A COMPUTER GRAPHICS PROJECT

struct colorRGB hit(struct point3 origin, struct vector3 d, int rayLength, struct sphere* origSpheres, int lenSpheres)
{
    //struct sphere* spheres;
    struct colorRGB color;
    float a, b, c, discr, t1, t2, t;
    struct vector3 v;
    float red, green, blue;
    struct vector3 norm, light, halfway;
    struct point3 lightSrc, pOfT;
    struct sphere sph;

// Constants for Blinn shading (light, ambience, diffuse, and specular)
    float Ia = .2;
    float ka = .2;
    float I = 1;
    float rkd = .75;
    float gkd = .75;
    float bkd = .75;
    float rks = .5;
    float gks = .5;
    float bks = .5;
    int p = 50;
    float amb, diffuse, specular;

    lightSrc.x = 30;
    lightSrc.y = 30;
    lightSrc.z = 10;

// Default dark color when sphere not hit.
    color.r = 30;
    color.g = 0;
    color.b = 30;

    //spheres = reorderSpheres(origSpheres, lenSpheres);
    reorderSpheres(origSpheres, lenSpheres);

    for (int i=0; i<lenSpheres; i++)
    {
        sph = origSpheres[i];

        v.x = origin.x - sph.center.x;
        v.y = origin.y - sph.center.y;
        v.z = origin.z - sph.center.z;

        a = dot(d, d);
        b = 2 * dot(d, v);
        c = dot(v, v) - (sph.radius*sph.radius);
        discr = (b*b) - (4*a*c);

        if (discr >= 0)
        {
            t1 = (-b - std::sqrt(discr)) / (2*a);
            t2 = (-b + std::sqrt(discr)) / (2*a);

            if (std::abs(t1) <= std::abs(t2))                // Pick which point is closer to view. (Should always be t2.)
            { t = t1; }
            else
            { t = t2; }

            if (t > 0 and t <= rayLength)
            {
                pOfT.x = origin.x + (t*d.x);
                pOfT.y = origin.y + (t*d.y);
                pOfT.z = origin.z + (t*d.z);

                // Normal from sphere center to a point on the sphere's surface.
                norm.x = pOfT.x - sph.center.x;
                norm.y = pOfT.y - sph.center.y;
                norm.z = pOfT.z - sph.center.z;
                normalize(&norm);
                // light vector from surface TO the light source.
                light.x = lightSrc.x - pOfT.x;
                light.y = lightSrc.y - pOfT.y;
                light.z = lightSrc.z - pOfT.z;
                normalize(&light);
                // halfway vector for calculating specularity
                normalize(&v);
                halfway = addVectors(v, light);
                normalize(&halfway);

                amb = ka * Ia;
                diffuse = max(0, dot(norm, light));
                specular = pow(max(0, dot(norm, halfway)), p);

                red = amb + (I * rkd * diffuse) + (I * rks * specular);
                green = amb + (I * gkd * diffuse) + (I * gks * specular);
                blue = amb + (I * bkd * diffuse) + (I * bks * specular);

                if (red > 1) {red = 1;}
                if (green > 1) {green = 1;}
                if (blue > 1) {blue = 1;}

                color.r = (int) (red*sph.color.r);
                color.g = (int) (green*sph.color.g);
                color.b = (int) (blue*sph.color.b);
            }
        }
    }
    return color;
}


/*
width: Width of 2d image to draw to. (x-axis)
height: Height 2d image to draw to. (y-axis)
length: Far distance of ray, what t should not exceed. (z-axis)
origin: The viewing point.
spheres: An array of sphere structs.
*/
GLubyte* raycaster(int bpp, int width, int height, int rayLength, struct point3 origin, struct sphere* spheres, int lenSpheres)
{
    GLubyte * buffer = (unsigned char*) malloc(bpp*width*height);
    struct point3 p_viewingPlane;
    struct vector3 ray;
    struct colorRGB shadedColor;
    float zn, vFovAngle, vFovAngleRadians, side;

    zn = origin.z - 1;
    vFovAngle = 90;                            // our vertical field of view is typically 100 degrees
    vFovAngleRadians = vFovAngle*(PI/180);
    side = -2 * tan(vFovAngleRadians/2);

    for (int x=0; x<width; x++)
    {
        for (int y=0; y<height; y++)
        {
            p_viewingPlane.x = zn * (((x*1.0)/width)-0.5) * ((side * width)/height);        // Normalized values already
            p_viewingPlane.y = zn * -(((y*1.0)/height)-0.5) * side;
            p_viewingPlane.z = zn;

            ray.x = p_viewingPlane.x - origin.x;
            ray.y = p_viewingPlane.y - origin.y;
            ray.z = p_viewingPlane.z - origin.z;
            normalize(&ray);

            shadedColor = hit(origin, ray, rayLength, spheres, lenSpheres);
            drawPixel(buffer, bpp, width, height, x, y, shadedColor);
        }
    }
    return buffer;
}

 

PROJECT PAGE

I'm a paragraph. Click here to add your own text and edit me. It’s easy. Just click “Edit Text” or double click me to add your own content and make changes to the font. I’m a great place for you to tell a story and let your users know a little more about you.

Language:  C (using OpenGL)

Date:  Spring 2016

Class:  Computer Graphics

 

In this CG project, I rendered images of spheres from 3D space to 2D pixels by using raycasting.  Rays were "projected" from some viewing point through pixel coordinates on the near clipping plane and were tested for intersections with any of the spheres.  If there was an intersection, I calculated the lighting for that particular fragment of the sphere using the Blinn-Phong shading model.

 

The code snippet on the left contains the two main functions used in this project, raycaster() and hit().

Click on image to expand.

bottom of page