top of page

INSTANT RADIOSITY:

A COMPUTER GRAPHICS PROJECT

//Returns reflected ray when intersecting with a triangle in the scene. Otherwise, returns same ray.
struct ray castRay(struct ray r)    
{
       int i, t, f, useTri0 = 0, useTri1 = 0;
        struct point tuv0, tuv1, V, endPt;
        struct mat3 M;    
        struct ray newRay;    
        struct triangle tri0, tri1;
    struct vec4 newPt;
    struct mat4 transf =        //Transformation matrix for the teapot. Since teapot geometry is transformed when rendering, check with those same transformations for intersections.
    {
        {teaScale, 0.0, 0.0, 0.0},
        {0.0, teaScale, 0.0, 0.0},
        {0.0, 0.0, teaScale, 0.0},
        {0.0, 0.0, 0.0, 1.0}
    };

    transf = multMat4ByMat4( getTranslMat(teaTrans), transf);
    transf = multMat4ByMat4( getRotateZMat(teaRotateZ), transf );
    transf = multMat4ByMat4( getRotateXMat(teaRotateX), transf );
    transf = multMat4ByMat4( getRotateYMat(teaRotateY), transf );    

    //ray: startPt*(1-t) + dir*t | t>=0 (if t=1 then at dir)
    //triangle: (1-u-v)*v0 + u*v1 + v*v2 | u,v >= 0 && u,v <= 1
      for (i=0; i < (numFaces*2 +12); i+=2)
       {            
            //Check teapot intersection first before walls.    
        if (i >= (numFaces*2))
        {
            t = i - (numFaces*2);
            tri0 = boxTris[t];
            tri0 = boxTris[t];
            tri1 = boxTris[t+1];
        }
            //Split each teapot quad {v0,v1,v2,v3} into two triangles: {v0,v1,v2,n}, {v0,v2,v3,n}
        else    
        {
              f = i/2;
        // First tri from quad: {v0,v1,v2,n}        
            newPt.x = vertices[faceVerts[f*4]];
            newPt.y = vertices[faceVerts[f*4] +1];
            newPt.z = vertices[faceVerts[f*4] +2];
            newPt.w = 1.0;    
            newPt = multMat4ByVec4(transf, newPt);        //Need 4D vector (with homogeneous coord) to transform.
            tri0.v0.x = newPt.x;                //Keep the 3D info to use in the triangle.
            tri0.v0.y = newPt.y;
            tri0.v0.z = newPt.z;
        
            newPt.x = vertices[faceVerts[f*4 +1]];
            newPt.y = vertices[faceVerts[f*4 +1] +1];
            newPt.z = vertices[faceVerts[f*4 +1] +2];
            newPt.w = 1.0;    
            newPt = multMat4ByVec4(transf, newPt);    
            tri0.v1.x = newPt.x;
            tri0.v1.y = newPt.y;
            tri0.v1.z = newPt.z;
            
            newPt.x = vertices[faceVerts[f*4 +2]];
            newPt.y = vertices[faceVerts[f*4 +2] +1];
            newPt.z = vertices[faceVerts[f*4 +2] +2];
            newPt.w = 1.0;    
            newPt = multMat4ByVec4(transf, newPt);    
            tri0.v2.x = newPt.x;
            tri0.v2.y = newPt.y;
            tri0.v2.z = newPt.z;
                        //Calculate normal coming out of v1, orthogonal to v0-v1 and v2-v1.
            tri0.n = normalize(crossProduct( addVecs(tri0.v0, scaleVec(tri0.v1, -1)), addVecs(tri0.v2, scaleVec(tri0.v1, -1)) ));
            
        // 2nd tri from quad: {v0,v2,v3,n}        
            tri1.v0 = tri0.v0;                //Two vertices are shared with the first triangle.
            tri1.v1 = tri0.v2;    
            newPt.x = vertices[faceVerts[f*4 +3]];
            newPt.y = vertices[faceVerts[f*4 +3] +1];
            newPt.z = vertices[faceVerts[f*4 +3] +2];
            newPt.w = 1.0;    
            newPt = multMat4ByVec4(transf, newPt);    
            tri1.v2.x = newPt.x;
            tri1.v2.y = newPt.y;
            tri1.v2.z = newPt.z;
            tri1.n = tri0.n;
        }    
           
        endPt = addVecs(r.startPt, r.dir);    //Actual end point (dp) is along start (startPt) in direction (dir) (start + dir).
        
    //Calculate t,u,v for intersection with tri0.    
        M.vec0 = addVecs(r.startPt, scaleVec(endPt, -1));        //sp - dp
        M.vec1 = addVecs(tri0.v1, scaleVec(tri0.v0, -1));        //tri vert1 - tri vert0
        M.vec2 = addVecs(tri0.v2, scaleVec(tri0.v0, -1));        //tri vert2 - tri vert0
        M = inverseTranspose(M);
        tuv0 = multMat3ByVec( M, addVecs(r.startPt, scaleVec(tri0.v0, -1)) );    //M * (startPt - tri vert0)

    //Calculate t,u,v for intersection with tri1.    
        M.vec0 = addVecs(r.startPt, scaleVec(endPt, -1));        //sp - dp
        M.vec1 = addVecs(tri1.v1, scaleVec(tri1.v0, -1));        //tri vert1 - tri vert0
        M.vec2 = addVecs(tri1.v2, scaleVec(tri1.v0, -1));        //tri vert2 - tri vert0
        M = inverseTranspose(M);
        tuv1 = multMat3ByVec( M, addVecs(r.startPt, scaleVec(tri1.v0, -1)) );    //M * (startPt - tri vert0)

    //t should be 0 or positive. u,v >= 0 and u+v <= 1.
        if ( (tuv0.x >= 0) && (tuv0.y >= 0) && (tuv0.z >= 0) && (tuv0.y + tuv0.z <= 1))
        { useTri0 = 1; }
        else if ( (tuv1.x >= 0) && (tuv1.y >= 0) && (tuv1.z >= 0) && (tuv1.y + tuv1.z <= 1))
        { useTri1 = 1; }
        
        if ((useTri0) || (useTri1))
        {
            V = scaleVec(r.dir, -1);                //When calculating reflection, starts at same point as normal.    
    
            if (i<(numFaces*2))
            { printf("teapot tri\n"); }    
            else    
            { printf("box tri\n"); }    
            
            if (useTri0)    
            {
                newRay.startPt = addVecs( scaleVec(r.startPt, 1-tuv0.x), scaleVec(endPt, tuv0.x) );        //sp*(1-t) + dir*t (t defines point of intersection from start along direction)
                                                                //Has same result as (1-u-v)*v0 + u*v1 + v*v2.
                newRay.dir = scaleVec(tri0.n, 2*dotProduct(V, tri0.n));                     //2(V dot N)N    
            }
            else    
            {
                newRay.startPt = addVecs( scaleVec(r.startPt, 1-tuv1.x), scaleVec(endPt, tuv1.x) );    
                newRay.dir = scaleVec(tri1.n, 2*dotProduct(V, tri1.n));             
            }
            
            
            newRay.dir = normalize(addVecs( scaleVec(V, -1.0), newRay.dir ));
            
            
            if (i > numFaces*2)        //If box face, get color of wall to set as light diffuse and specular colors.
            {
                lightDiffuse = normalize(componentMult(lightDiffuse, boxColors[(i-numFaces*2)/2]));    //i-numFaces*2 = tri index. i/2 gives face index.
                lightSpecular = lightDiffuse;        
            }
              else                //Else, get color from teapot.
            {
                lightDiffuse = normalize(componentMult(lightDiffuse, teapotMaterials[1]));    
                lightSpecular = lightDiffuse;    
            }
    
            return newRay;    
        }    
    
       }    //end triangle loop
    
    return r;    
}    


 

PROJECT PAGE

Language:  C (using OpenGL)

Date:  Spring 2017

Class:  Computer Graphics (Graduate)

This project is a real-time implementation of Alexander Keller’s 1999 SIGGRAPH paper as a means to achieve global illumination, mimicking light bouncing off of surfaces (for example, capturing the color-bleeding effect of the purple and teal from the left and right walls reflecting onto the other off-white walls).  The project is written in C using OpenGL and GLSL.  I implemented sampling using the Halton-sequence, ray-casting,  and collision detection, along with OBJ and MTL file parsing.  I also created a normal map using Substance Painter and read and use it in my lighting calculations.

Click on image to expand.

bottom of page