ACADEMIC RESEARCH AND PUBLICATIONS
during Graduate and Undergraduate Studies
ACADEMIC RESEARCH AND PUBLICATIONS
during Graduate and Undergraduate Studies
Doctoral Candidate in Computer Science
Visual Computing Division, Digital Production Arts
Clemson University | School of Computing
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.