// Note to the user: uncomment ONE of the following // defines to generate the desired images. Be warned // that TRAIN_4 takes about 20 minutes for execution // on a P4, 2.6 GHz. The other scenes take only a few // seconds to execute. //#define MARBLES_OVER_TEXTURES //#define REFRACTION_1 //#define GLOSSY_REFLECTION #define MAGIC_BOX_4 //#define TRAIN_4 /*********************************************************************** Concordia University COMP 6761 Advanced Graphics Programming Winter 05 Prof. Mudur End of term project 2 Date due: April 14 2005, noon Date finished: April 14. Author: Louis Charbonneau, 2819538 loui_cha@cs.concordia.ca tel: 725-0252 References: This program was written largely thanks to chapter 9 of Peter Shirley`s book, where I found most of the theory of ray tracing. For textures, I have used the loader program "bitmap" written by Mr. Exel Gamboa, available on opengl.org. To save ray traced images, I used the writeTGA program available from the "OpenGL Bible" book (Sams publishing 2005). ******************************************************************** FILES IN PROJECT: bitmap.cpp, constants.cpp, geometry.cpp, main.cpp, bitmap.h, constants.h, geometry.h. DEPENDENT FILES: Textures: 3 different texture files must be present in the program directory: "satin.bmp" - used for the ground "metal.bmp" - used for the car sides "rug.bmp" - used for the benches and car floor These files were found on the Internet. I have converted the original jpeg images to bitmaps and adjusted their dimensions to 2 power n using Microsoft Photo Editor. ******************************************************************** HOW TO RUN: Compile using the Microsoft Visual Studio 6 environment. Make sure to include the three files "satin.bmp", "metal.bmp", "rug.bmp" in the project directory. Uncomment the chosen #define on top of this file to generate an image. "marbles over textures" (takes a few seconds) "refraction 1" (takes a few seconds) "magic box 4" (takes a few seconds) "train 4" (takes 20 minutes on a P4 2.6 GHz) ********************************************************************/ #include #include #include #include // exp #include #include "geometry.h" #include "constants.h" #include "bitmap.h" // from Mr. Exel Gamboa #define WIDTH 1200 #define HEIGHT 800 Canvas C(WIDTH, HEIGHT); #ifdef MARBLES_OVER_TEXTURES const int numObjects = 24; #endif #ifdef REFRACTION_1 const int numObjects = 2; #endif #ifdef GLOSSY_REFLECTION const int numObjects = 6; #endif #ifdef MAGIC_BOX_4 const int numObjects = 10; #endif #ifdef TRAIN_4 const int numObjects = 98; #endif enum projectionType {ORTHOGRAPHIC, PERSPECTIVE}; projectionType currentProjection = PERSPECTIVE; //projectionType currentProjection = ORTHOGRAPHIC; void myInit(void) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, WIDTH, 0.0, HEIGHT); glClearColor(0.0, 0.0, 0.0, 0.0); } // This function returns true if there is some hit among the scene // surfaces, along with the hitpoint, the t, the surface index and the normal. bool firstHit(Surface *list[], const int &numSurfaces, Ray &ray, Point3 &pt, const float &minT, const float &maxT, float &t, int &index, Vector3 &norm) { bool somethingWasHit = false; float newMax = maxT; for (int i = 0; i < numSurfaces; i++) { if (list[i]->Hit(ray, pt, minT, newMax, t, norm)) { // trick: we test further object hits only // if they are closer than preceding hit. newMax = t; index = i; somethingWasHit = true; } } return somethingWasHit; } // This only returns a boolean value if something is hit other than the surface // we specify with the index. This is useful to have a speedy hit calculation // for shadows. bool quickFirstHit(Surface *list[], const int &numSurfaces, Ray &ray, const float &minT, const float &maxT, const int &index) { for (int i = 0; i < numSurfaces; i++) { // as an approximation of reality, we do not consider // dielectrics as casting shadows. Some particle tracing // code should ideally go here. if ((index!= i) & (list[i]->QuickHit(ray, minT, maxT)) & !(list[i]->GetMaterial().GetDielectric())) return true; } return false; } RGBColor recursiveColor(Ray r1, Surface *list[], Light &L1, const Point3 &eyePosition, int depth) { // to do: add case where we are looking directly at the light RGBColor lightColor = L1._color; Vector3 unitLightDirection; Vector3 unitEyeDirection; Vector3 rayDirection; Vector3 transmittedDirection; RGBColor pixelColor; RGBColor mirrorBounce; RGBColor dielectric; RGBColor dielectricExit; RGBColor dielectricEnter; RGBColor dielectricReflect; Ray reflectedRay; Ray reflectedFromDielectric; Ray transmittedInDielectric; // parameters for hit point Point3 hitPoint; float t; int index = 100; Vector3 normal; Ray shadowRay; if (depth <= 0) return RGBColor(BACKGROUND_RED, BACKGROUND_GREEN, BACKGROUND_BLUE); else { if (firstHit(list, numObjects, r1, hitPoint, EPSILON, INFINITY, t, index, normal)) { // compute ambient light component in any case pixelColor = list[index]->AmbientLight(hitPoint); // check first whether the ray hits the surface from // outside and not inside, since this is the task of the // dielectric code that follows. If we have a flat object // such as a Quad or a Triangle, we flip he normal to always // "see" the object from both sides (as in GL_BACK_AND_FRONT) float dotProd = Dot(r1.GetRayDirection(), normal); // flip normal of object if it is not a sphere // NB a sphere has type = 0, a flat object has types 1 and 2. if((dotProd > 0.0) && (list[index]->GetType() != 0)) { normal = -normal; dotProd = -dotProd; } // record whether the surface is glossy bool gloss = list[index]->GetMaterial().GetGlossy(); // code for reflection ********************************************************************* // recursive call in case of a reflective surface float reflectivity = list[index]->GetMaterial().GetRefl(); if (reflectivity > 0.0) { if (dotProd < 0.0) { // compute reflection ray reflectedRay.SetRayDirection(ReflectedVector(r1.GetRayDirection(), normal, gloss)); reflectedRay.SetOrigin(hitPoint); pixelColor += recursiveColor(reflectedRay, list, L1, eyePosition, depth - 1) * reflectivity; } } // end of reflection code ****************************************************************** // code for refraction ********************************************************************* // recursive call in case of a refractive surface based // on the pseudocode from Shirley's book, page 164. if (list[index]->GetMaterial().GetDielectric()) { float c, kr, kg, kb; // compute reflected ray rayDirection = r1.GetRayDirection(); reflectedFromDielectric.SetRayDirection(ReflectedVector(rayDirection, normal, gloss)); reflectedFromDielectric.SetOrigin(hitPoint); float refr = list[index]->GetMaterial().GetRefr(); float rDotn = Dot(rayDirection, normal); if (rDotn < 0.0) // entering the object { RefractedVector(rayDirection, normal, refr, transmittedDirection); c = -rDotn; kr = 1.0; kg = 1.0; kb = 1.0; } else // exiting the object { // compute attenuation from passage of light into object kr = exp(-list[index]->GetMaterial().GetRedAtt() * t); kg = exp(-list[index]->GetMaterial().GetGreenAtt() * t); kb = exp(-list[index]->GetMaterial().GetBlueAtt() * t); Vector3 oppositeNormal = -normal; // if the angle allows exit from object, compute the quantity c, // which is if(RefractedVector(rayDirection, oppositeNormal, 1/refr, transmittedDirection)) c = Dot(transmittedDirection, normal); else { dielectricExit = recursiveColor(reflectedFromDielectric, list, L1, eyePosition, depth - 1); float r = kr * dielectricExit.GetRed(); float g = kg * dielectricExit.GetGreen(); float b = kb * dielectricExit.GetBlue(); dielectric.SetRed(r); dielectric.SetGreen(g); dielectric.SetBlue(b); pixelColor += dielectric; } } // Schlick approximation to Fresnel equations. This provides // the fraction of light reflected by the dielectric. See // Shirley's book. float R0 = ((refr - 1)*(refr - 1))/((refr + 1)*(refr + 1)); float R = R0 + (1 - R0) * pow((1 - c), 5); // compute color contribution from reflected ray dielectricReflect = recursiveColor(reflectedFromDielectric, list, L1, eyePosition, depth - 1); // compute color contribution from transmitted ray transmittedInDielectric.SetRayDirection(transmittedDirection); transmittedInDielectric.SetOrigin(hitPoint); dielectricEnter = recursiveColor(transmittedInDielectric, list, L1, eyePosition, depth - 1); float r = kr * R * dielectricReflect.GetRed() + (1 - R) * dielectricEnter.GetRed(); float g = kg * R * dielectricReflect.GetGreen() + (1 - R) * dielectricEnter.GetGreen(); float b = kb * R * dielectricReflect.GetBlue() + (1 - R) * dielectricEnter.GetBlue(); dielectric.SetRed(r); dielectric.SetGreen(g); dielectric.SetBlue(b); pixelColor += dielectric; } // end of code for refraction **************************************************** // code for shadowing ************************************************************ // TO DO: one limitation of this code is that shadow rays passing // through a dielectric are not refracted as should be. This should make for // more realistic illumination effects. // compute unit eye direction unitEyeDirection.SetX(eyePosition.GetX() - hitPoint.GetX()); unitEyeDirection.SetY(eyePosition.GetY() - hitPoint.GetY()); unitEyeDirection.SetZ(eyePosition.GetZ() - hitPoint.GetZ()); unitEyeDirection.Normalize(); // compute shadow ray L1.UnitVector(hitPoint, unitLightDirection); shadowRay.SetOrigin(hitPoint); shadowRay.SetRayDirection(unitLightDirection); // the following test removes from view the points // that are shadowed by self (applies only to solids). bool shadowFromOwnSurface = (Dot(normal, unitLightDirection) < 0.0); // if the object is a flat surface, it is never shadowed by self // NB type = 0 means a sphere, type = 1 or 2 is flat if(list[index]->GetType() != 0) shadowFromOwnSurface = false; // this computes non-ambient components of lighting if there is no // self-obstruction and if no object hides the light direction. The // minimum t is EPSILON, which guarantees that the surface from which // the ray originates will not be reported as a hit. if ( (!shadowFromOwnSurface) & !(quickFirstHit(list, numObjects, shadowRay, EPSILON, INFINITY, index))) { // compute diffuse and specular lighting pixelColor +=list[index]->DiffuseLight(normal, unitLightDirection, lightColor, unitEyeDirection, hitPoint); pixelColor +=list[index]->SpecularLight(normal, unitLightDirection, lightColor, unitEyeDirection, hitPoint); } // is an object is a dielectric, then it does not shadows from self // (this is where particle tracing should be performed for a more // realistic effect) if (list[index]->GetMaterial().GetDielectric()) { // compute diffuse and specular lighting pixelColor +=list[index]->DiffuseLight(normal, unitLightDirection, lightColor, unitEyeDirection, hitPoint); pixelColor +=list[index]->SpecularLight(normal, unitLightDirection, lightColor, unitEyeDirection, hitPoint); } } } return (pixelColor); } void DisplayScene() { #ifdef MARBLES_OVER_TEXTURES // Marbles over Texture Scene definition ******************************************* // radius of all the spheres float r = 80.0; // sphere definitions Material mat1(1.0, 0.0, 0.1, 0.5, 0.5, 0.5, 1.0, 1.0, 1.3, 0.01, 0.02, 0.03, false, true, false, 0); Point3 center1(200.0, 100.0, -100.0); Sphere s1(center1, r, mat1); Material mat2(1.0, 0.6, 0.0, 0.3, 0.5, 0.5, 2.0, 1.0, 1.3, 0.01, 0.02, 0.03, false, false, false, 0); Point3 center2(400.0, 100.0, -100.0); Sphere s2(center2, r, mat2); Material mat3(0.0, 1.0, 1.0, 0.3, 0.5, 0.5, 4.0, 1.0, 1.3, 0.01, 0.02, 0.03, true, false, false, 0); Point3 center3(600.0, 100.0, -100.0); Sphere s3(center3, r, mat3); Material mat4(1.0, 0.0, 1.0, 0.3, 0.5, 0.5, 8.0, 1.0, 1.3, 0.0, 0.0, 0.0, true, true, false, 0); Point3 center4(800.0, 100.0, -100.0); Sphere s4(center4, r, mat4); Material mat5(1.0, 0.3, 0.0, 0.3, 0.5, 0.5, 1.0, 1.3, 1.3, 0.01, 0.02, 0.03, false, true, false, 0); Point3 center5(1000.0, 100.0, -100.0); Sphere s5(center5, r, mat5); Material mat6(0.0, 1.0, 0.0, 0.3, 0.5, 0.5, 2.0, 1.0, 1.3, 0.01, 0.02, 0.03, false, false, false, 0); Point3 center6(100.0, 300.0, -100.0); Sphere s6(center6, r, mat6); Material mat7(0.0, 0.0, 1.0, 0.3, 0.5, 0.5, 4.0, 1.0, 1.3, 0.01, 0.02, 0.03, true, false, false, 0); Point3 center7(300.0, 300.0, -100.0); Sphere s7(center7, r, mat7); Material mat8(1.0, 0.5, 0.0, 0.3, 0.5, 0.5, 8.0, 1.0, 1.3, 0.0, 0.0, 0.0, true, true, false, 0); Point3 center8(500.0, 300.0, -100.0); Sphere s8(center8, r, mat8); Material mat9(1.0, 0.0, 0.5, 0.3, 0.5, 0.5, 1.0, 1.0, 1.3, 0.01, 0.02, 0.03, false, true, false, 0); Point3 center9(700.0, 300.0, -100.0); Sphere s9(center9, r, mat9); Material mat10(0.5, 1.0, 0.0, 0.3, 0.5, 0.5, 2.0, 1.0, 1.3, 0.01, 0.02, 0.03, false, false, false, 0); Point3 center10(900.0, 300.0, -100.0); Sphere s10(center10, r, mat10); Material mat11(1.0, 1.0, 0.5, 0.3, 0.5, 0.5, 4.0, 1.0, 1.3, 0.01, 0.02, 0.03, true, false, false, 0); Point3 center11(1100.0,300.0, -100.0); Sphere s11(center11, r, mat11); Material mat12(0.5, 0.0, 1.0, 0.3, 0.5, 0.5, 8.0, 1.0, 1.3, 0.0, 0.0, 0.0, true, true, false, 0); Point3 center12(200.0, 500.0, -100.0); Sphere s12(center12, r, mat12); Material mat13(0.0, 0.2, 1.0, 0.3, 0.5, 0.5, 1.0, 1.0, 1.3, 0.01, 0.02, 0.03, false, true, false, 0); Point3 center13(400.0, 500.0, -100.0); Sphere s13(center13, r, mat13); Material mat14(1.0, 0.3, 0.3, 0.3, 0.5, 0.5, 2.0, 1.0, 1.3, 0.01, 0.02, 0.03, false, false, false, 0); Point3 center14(600.0, 500.0, -100.0); Sphere s14(center14, r, mat14); Material mat15(0.0, 1.0, 0.3, 0.3, 0.5, 0.5, 4.0, 1.0, 1.3, 0.01, 0.02, 0.03, true, false, false, 0); Point3 center15(800.0, 500.0, -100.0); Sphere s15(center15, r, mat15); Material mat16(0.8, 0.5, 1.0, 0.3, 0.5, 0.5, 8.0, 1.0, 1.3, 0.0, 0.0, 0.0, true, true, false, 0); Point3 center16(1000.0,500.0, -100.0); Sphere s16(center16, r, mat16); Material mat17(1.0, 0.2, 0.5, 0.3, 0.5, 0.5, 1.0, 1.0, 1.3, 0.01, 0.02, 0.03, false, true, false, 0); Point3 center17(100.0, 700.0, -100.0); Sphere s17(center17, r, mat17); Material mat18(1.0, 0.5, 1.0, 0.3, 0.5, 0.5, 2.0, 1.0, 1.3, 0.01, 0.02, 0.03, false, false, false, 0); Point3 center18(300.0, 700.0, -100.0); Sphere s18(center18, r, mat18); Material mat19(0.5, 0.7, 0.2, 0.3, 0.5, 0.5, 4.0, 1.0, 1.3, 0.01, 0.02, 0.03, true, false, false, 0); Point3 center19(500.0, 700.0, -100.0); Sphere s19(center19, r, mat19); Material mat20(0.3, 0.5, 1.0, 0.3, 0.5, 0.5, 8.0, 1.0, 1.3, 0.0, 0.0, 0.0, true, true, false, 0); Point3 center20(700.0, 700.0, -100.0); Sphere s20(center20, r, mat20); Material mat21(1.0, 0.1, 0.0, 0.3, 0.5, 0.5, 1.0, 1.0, 1.3, 0.01, 0.02, 0.03, false, true, false, 0); Point3 center21(900.0, 700.0, -100.0); Sphere s21(center21, r, mat21); Material mat22(0.4, 0.7, 0.2, 0.3, 0.5, 0.5, 2.0, 1.0, 1.3, 0.01, 0.02, 0.03, false, false, false, 0); Point3 center22(1100.0, 700.0, -100.0); Sphere s22(center22, r, mat22); // these two triangles in mirror material are in the background Material mat23(1.0, 1.0, 1.0, 0.6, 0.7, 0.8, 8.0, 1.0, 1.6, 0.01, 0.02, 0.03, true, false, false, 1); Point3 p1(0.0, 0.0, -300.0); Point3 p2(0.0, 1000.0, -300.0); Point3 p3(1100.0, 0.0, -300.0); Triangle t1(p1, p3, p2, mat23); Material mat24(1.0, 0.0, 1.0, 0.6, 0.7, 0.8, 8.0, 1.0, 1.6, 0.01, 0.01, 0.02, true, false, false, 2); Point3 p4(1300.0, 0.0, -300.0); Point3 p5(1300.0, 1000.0, -300.0); Point3 p6(100.0, 1000.0, -300.0); Triangle t2(p4, p5, p6, mat24); // surface list definition Surface *list[numObjects] = {&s1, &s2, &s3, &s4, &s5, &s6, &s7, &s8, &s9, &s10, &s11, &s12, &s13, &s14, &s15, &s16, &s17, &s18, &s19, &s20, &s21, &s22, &t1, &t2}; // scene light // uncomment to get a point light and comment the // three following lines // Point3 lightPosition(700.0, 500.0, 0.0); // RGBColor lightColor(1.0, 1.0, 1.0); // Light L1(lightPosition, lightColor, 1); // point light Point3 lightPosition(0.0, 0.0, 1.0); RGBColor lightColor(1.0, 1.0, 1.0); Light L1(lightPosition, lightColor, 0); // directional light // End of marbles over texture scene definition ******************************************* #endif #ifdef REFRACTION_1 // refraction 1 scene definition *************************************************** // background textured triangle Material mat1(1.0, 1.0, 1.0, 0.6, 0.7, 0.8, 20.0, 0.0, 1.6, 0.01, 0.02, 0.03, false, false, false, 3); Point3 p1(200.0, 100.0, -300.0); Point3 p2(1000.0, 100.0, -300.0); Point3 p3(600.0, 700.0, -300.0); Triangle t1(p1, p2, p3, mat1); // refractive sphere over corner of triangle Material mat2(0.0, 0.0, 0.0, 0.6, 0.7, 0.8, 21.0, 0.0, 1.2, 10000.0, 0.0, 10000.0, false, false, true, 0); Point3 center1(700.0, 250.0, -100.0); float radius = 140; Sphere s1(center1, radius, mat2); // surface list definition Surface *list[numObjects] = {&t1, &s1}; // scene light Point3 lightPosition(600.0, 500.0, 0.0); RGBColor lightColor(1.0, 1.0, 1.0); Light L1(lightPosition, lightColor, 1); // point light // end of refraction 1 scene definition ******************************************* #endif #ifdef MAGIC_BOX_4 // magic box 4 scene definition ********************************************************* // back side of box Material mat1(1.0, 0.0, 1.0, 0.6, 0.7, 0.8, 20.0, 1.0, 1.6, 0.01, 0.02, 0.03, false, false, false, 1); Point3 p1(100.0, 100.0, -400.0); Point3 p2(1100.0, 100.0, -400.0); Point3 p3(1100.0, 800.0, -400.0); Point3 p4(100.0, 800.0, -400.0); Quad q1(p1, p2, p3, p4, mat1); // bottom side of box Material mat2(1.0, 1.0, 1.0, 0.6, 0.7, 0.8, 20.0, 0.0, 1.6, 0.01, 0.02, 0.03, false, false, false, 2); Point3 p5(100.0, 100.0, 100.0); Point3 p6(1100.0, 100.0, 100.0); Point3 p7(1100.0, 100.0, -400.0); Point3 p8(100.0, 100.0, -400.0); Quad q2(p5, p6, p7, p8, mat2); // left side of box Material mat3(1.0, 0.0, 1.0, 0.6, 0.7, 0.8, 60.0, 1.0, 1.2, 0.01, 0.02, 0.03, false, false, false, 0); Point3 p9(100.0, 100.0, 100.0); Point3 p10(100.0, 100.0, -400.0); Point3 p11(100.0, 800.0, -400.0); Point3 p12(100.0, 800.0, 100.0); Quad q3(p9, p10, p11, p12, mat3); // right side of box Material mat4(1.0, 0.0, 1.0, 0.6, 0.7, 0.8, 60.0, 1.0, 1.2, 0.01, 0.02, 0.03, false, false, false, 0); Point3 p13(1100.0, 100.0, -400.0); Point3 p14(1100.0, 100.0, 100.0); Point3 p15(1100.0, 800.0, 100.0); Point3 p16(1100.0, 800.0, -400.0); Quad q4(p13, p14, p15, p16, mat4); // sphere definition Material mat5(1.0, 0.0, 0.0, 0.6, 0.7, 0.8, 21.0, 0.0, 1.2, 10000.0, 0.0, 10000.0, true, false, false, 0); Point3 center1(900.0, 250.0, -200.0); float radius1 = 100; Sphere s1(center1, radius1, mat5); // sphere definition Material mat6(0.0, 1.0, 0.0, 0.6, 0.7, 0.8, 21.0, 0.0, 1.2, 10000.0, 0.0, 10000.0, true, false, false, 0); Point3 center2(700.0, 250.0, -100.0); float radius2 = 100; Sphere s2(center2, radius2, mat6); // sphere definition Material mat7(0.0, 0.0, 1.0, 0.6, 0.7, 0.8, 21.0, 1.0, 1.3, 10000.0, 0.0, 10000.0, true, false, false, 0); Point3 center3(500.0, 250.0, -100.0); float radius3 = 100; Sphere s3(center3, radius3, mat7); // sphere definition Material mat8(1.0, 0.0, 1.0, 0.6, 0.7, 0.8, 21.0, 1.0, 1.3, 10000.0, 0.0, 10000.0, true, false, false, 0); Point3 center4(300.0, 250.0, -200.0); float radius4 = 100; Sphere s4(center4, radius4, mat8); // sphere definition Material mat9(0.0, 1.0, 1.0, 0.6, 0.7, 0.8, 21.0, 1.0, 1.3, 10000.0, 0.0, 10000.0, true, false, false, 0); Point3 center5(500.0, 550.0, -300.0); float radius5 = 100; Sphere s5(center5, radius5, mat9); // sphere definition Material mat10(0.0, 0.0, 1.0, 0.6, 0.7, 0.8, 21.0, 1.0, 1.3, 10000.0, 0.0, 10000.0, true, false, false, 0); Point3 center6(300.0, 550.0, -300.0); float radius6 = 100; Sphere s6(center6, radius6, mat10); // surface list definition Surface *list[numObjects] = {&q1, &q2, &q3, &q4, &s1, &s2, &s3, &s4, &s5, &s6}; // scene light Point3 lightPosition(0.0, 2.0, 1.0); RGBColor lightColor(1.0, 1.0, 1.0); Light L1(lightPosition, lightColor, 0); // directional light // end of magic box 4 definition ************************************************* #endif #ifdef GLOSSY_REFLECTION // glossy reflection scene definition ********************************************** // back side of box Material mat1(1.0, 1.0, 1.0, 0.6, 0.7, 0.8, 20.0, 1.0, 1.6, 0.01, 0.02, 0.03, false, false, false, 3); Point3 p1(100.0, 100.0, -400.0); Point3 p2(1100.0, 100.0, -400.0); Point3 p3(1100.0, 800.0, -400.0); Point3 p4(100.0, 800.0, -400.0); Quad q1(p1, p2, p3, p4, mat1); // bottom side of box Material mat2(1.0, 1.0, 1.0, 0.6, 0.7, 0.8, 20.0, 1.0, 1.6, 0.01, 0.02, 0.03, false, true, false, 0); Point3 p5(100.0, 100.0, 100.0); Point3 p6(1100.0, 100.0, 100.0); Point3 p7(1100.0, 100.0, -400.0); Point3 p8(100.0, 100.0, -400.0); Quad q2(p5, p6, p7, p8, mat2); // left side of box Material mat3(0.0, 0.0, 0.0, 0.6, 0.7, 0.8, 60.0, 1.0, 1.2, 0.01, 0.02, 0.03, false, true, false, 0); Point3 p9(100.0, 100.0, 100.0); Point3 p10(100.0, 100.0, -400.0); Point3 p11(100.0, 800.0, -400.0); Point3 p12(100.0, 800.0, 100.0); Quad q3(p9, p10, p11, p12, mat3); // right side of box Material mat4(0.0, 0.0, 0.0, 0.6, 0.7, 0.8, 60.0, 1.0, 1.2, 0.01, 0.02, 0.03, false, true, false, 0); Point3 p13(1100.0, 100.0, -400.0); Point3 p14(1100.0, 100.0, 100.0); Point3 p15(1100.0, 800.0, 100.0); Point3 p16(1100.0, 800.0, -400.0); Quad q4(p13, p14, p15, p16, mat4); // sphere definition Material mat5(1.0, 0.0, 0.0, 0.6, 0.7, 0.8, 21.0, 0.0, 1.2, 10000.0, 0.0, 10000.0, true, false, false, 0); Point3 center1(800.0, 250.0, -200.0); float radius1 = 150; Sphere s1(center1, radius1, mat5); // sphere definition Material mat6(0.0, 1.0, 0.0, 0.6, 0.7, 0.8, 21.0, 0.0, 1.2, 10000.0, 0.0, 10000.0, true, false, false, 0); Point3 center2(400.0, 250.0, -200.0); float radius2 = 150; Sphere s2(center2, radius2, mat6); Surface *list[numObjects] = {&q1, &q2, &q3, &q4, &s1, &s2}; // scene light Point3 lightPosition(0.0, 2.0, 1.0); RGBColor lightColor(1.0, 1.0, 1.0); Light L1(lightPosition, lightColor, 0); // directional light // end of glossy reflection scene definition ************************************ #endif #ifdef TRAIN_4 // Start of train 4 scene definition ********************************************* // compartment definition (there are 5 to form a car) **************************** // outside panels of compartment have a metal texture Material mat1(1.0, 0.0, 0.0, 0.6, 0.7, 0.8, 20.0, 0.0, 1.6, 0.01, 0.02, 0.03, true, false, false, 3); // left front panel Point3 lf0(-5.0, -5.0, 0.0); Point3 lf1(-4.0, -5.0, 0.0); Point3 lf2(-4.0, -5.0, 8.0); Point3 lf3(-5.0, -5.0, 8.0); Quad q0(lf0, lf1, lf2, lf3, mat1); // left front // right front panel Point3 rf0(4.0, -5.0, 0.0); Point3 rf1(5.0, -5.0, 0.0); Point3 rf2(5.0, -5.0, 8.0); Point3 rf3(4.0, -5.0, 8.0); Quad q1(rf0, rf1, rf2, rf3, mat1); // right front // top front panel Point3 tf0(-4.0, -5.0, 6.0); Point3 tf1(4.0, -5.0, 6.0); Point3 tf2(4.0, -5.0, 8.0); Point3 tf3(-4.0, -5.0, 8.0); Quad q2(tf0, tf1, tf2, tf3, mat1); // top front // bottom front panel Point3 bf0(-4.0, -5.0, 0.0); Point3 bf1(4.0, -5.0, 0.0); Point3 bf2(4.0, -5.0, 4.0); Point3 bf3(-4.0, -5.0, 4.0); Quad q3(bf0, bf1, bf2, bf3, mat1); // bottom front // left back panel Point3 lb0(-2.0, 5.0, 0.0); Point3 lb1(-5.0, 5.0, 0.0); Point3 lb2(-5.0, 5.0, 8.0); Point3 lb3(-2.0, 5.0, 8.0); Quad q4(lb0, lb1, lb2, lb3, mat1); // left back // right back panel Point3 rb0(5.0, 5.0, 0.0); Point3 rb1(2.0, 5.0, 0.0); Point3 rb2(2.0, 5.0, 8.0); Point3 rb3(5.0, 5.0, 8.0); Quad q5(rb0, rb1, rb2, rb3, mat1); // right back // top back panel Point3 tb0(2.0, 5.0, 7.0); Point3 tb1(-2.0, 5.0, 7.0); Point3 tb2(-2.0, 5.0, 8.0); Point3 tb3(2.0, 5.0, 8.0); Quad q6(tb0, tb1, tb2, tb3, mat1); // top back // bottom back panel Point3 bb0(2.0, 5.0, 0.0); Point3 bb1(-2.0, 5.0, 0.0); Point3 bb2(-2.0, 5.0, 3.0); Point3 bb3(2.0, 5.0, 3.0); Quad q7(bb0, bb1, bb2, bb3, mat1); // bottom back // compartment edges Point3 e0(-5.0, -5.0, 0.0); Point3 e1(5.0, -5.0, 0.0); Point3 e2(5.0, -5.0, 8.0); Point3 e3(-5.0, -5.0, 8.0); Point3 e4(-5.0, 5.0, 0.0); Point3 e5(5.0, 5.0, 0.0); Point3 e6(5.0, 5.0, 8.0); Point3 e7(-5.0, 5.0, 8.0); // draw compartment floor, textured as rug Material mat2(0.0, 0.0, 0.0, 0.6, 0.7, 0.8, 20.0, 0.0, 1.6, 0.01, 0.02, 0.03, false, false, false, 2); Quad q8(e0, e1, e5, e4, mat2); // inside compartment walls are not textured Material mat3(1.0, 0.0, 1.0, 0.6, 0.7, 0.8, 20.0, 0.0, 1.6, 0.01, 0.02, 0.03, false, false, false, 0); // right door Point3 rd0(5.0, -5.0, 0.0); Point3 rd1(5.0, -5.0, 8.0); Point3 rd2(5.0, -1.0, 8.0); Point3 rd3(5.0, -1.0, 0.0); Quad q9(rd2, rd3, e5, e6, mat3); // right door // top of train, not textured Point3 top0(-5.0, -5.0, 8.0); Point3 top1(5.0, -5.0, 8.0); Point3 top2(5.0, -3.0, 9.0); Point3 top3(-5.0, -3.0, 9.0); Point3 top4(5.0, 3.0, 9.0); Point3 top5(-5.0, 3.0, 9.0); Point3 top6(5.0, 5.0, 8.0); Point3 top7(-5.0, 5.0, 8.0); Point3 top8(5.0, -3.0, 8.0); Point3 top9(5.0, 3.0, 8.0); Quad q10(top0, top1, top2, top3, mat3); // front slant Quad q11(top3, top2, top4, top5, mat3); // middle of roof Quad q12(top6, top7, top5, top4, mat3); // back slant Quad q13(top8, top9, top4, top2, mat3); // right roof center Triangle q14(top1, top8, top2, mat3); // left triangle Triangle q15(top9, top6, top4, mat3); // right triangle // inside separation walls (cabin from alley) // insideLeftWall Point3 ilw0(-5.0, -1.0, 8.0); Point3 ilw1(-5.0, -1.0, 0.0); Point3 ilw2(-1.5, -1.0, 0.0); Point3 ilw3(-1.5, -1.0, 8.0); Quad q16(ilw1, ilw2, ilw3, ilw0, mat3); // inside left wall // insideRightWall Point3 irw0(5.0, -1.0, 0.0); Point3 irw1(5.0, -1.0, 8.0); Point3 irw2(1.5, -1.0, 8.0); Point3 irw3(1.5, -1.0, 0.0); Quad q17(irw3, irw0, irw1, irw2, mat3); // inside right wall // insideDoorTop Point3 idt0(-1.5, -1.0, 7.0); Point3 idt1(1.5, -1.0, 7.0); Point3 idt2(1.5, -1.0, 8.0); Point3 idt3(-1.5, -1.0, 8.0); Quad q18(idt0, idt1, idt2, idt3, mat3); //inside door top // right bench Point3 rben0(2.5, -1.0, 2.0); Point3 rben1(5.0, -1.0, 2.0); Point3 rben2(5.0, 5.0, 2.0); Point3 rben3(2.5, 5.0, 2.0); Quad q19(rben0, rben1, rben2, rben3, mat2); // benches, textured as rugs // leftBench Point3 lben0(-5.0, -1.0, 2.0); Point3 lben1(-2.5, -1.0, 2.0); Point3 lben2(-2.5, 5.0, 2.0); Point3 lben3(-5.0, 5.0, 2.0); Quad q20(lben0, lben1, lben2, lben3, mat2); // end of compartment definition // The second compartment (initially a copy of the first) Quad q21(q0); Quad q22(q1); Quad q23(q2); Quad q24(q3); Quad q25(q4); Quad q26(q5); Quad q27(q6); Quad q28(q7); Quad q29(q8); Quad q30(q9); Quad q31(q10); Quad q32(q11); Quad q33(q12); Quad q34(q16); Quad q35(q17); Quad q36(q18); Quad q37(q19); Quad q38(q20); // The third compartment (initially a copy of the first) Quad q39(q0); Quad q40(q1); Quad q41(q2); Quad q42(q3); Quad q43(q4); Quad q44(q5); Quad q45(q6); Quad q46(q7); Quad q47(q8); Quad q48(q9); Quad q49(q10); Quad q50(q11); Quad q51(q12); Quad q52(q16); Quad q53(q17); Quad q54(q18); Quad q55(q19); Quad q56(q20); // The fourth compartment (initially a copy of the first) Quad q57(q0); Quad q58(q1); Quad q59(q2); Quad q60(q3); Quad q61(q4); Quad q62(q5); Quad q63(q6); Quad q64(q7); Quad q65(q8); Quad q66(q9); Quad q67(q10); Quad q68(q11); Quad q69(q12); Quad q70(q16); Quad q71(q17); Quad q72(q18); Quad q73(q19); Quad q74(q20); // The fifth compartment (initially a copy of the first) Quad q75(q0); Quad q76(q1); Quad q77(q2); Quad q78(q3); Quad q79(q4); Quad q80(q5); Quad q81(q6); Quad q82(q7); Quad q83(q8); Quad q84(q9); Quad q85(q10); Quad q86(q11); Quad q87(q12); Quad q88(q16); Quad q89(q17); Quad q90(q18); Quad q91(q19); Quad q92(q20); // put compartments over viewing plane q0.TrainTransform(); q1.TrainTransform(); q2.TrainTransform(); q3.TrainTransform(); q4.TrainTransform(); q5.TrainTransform(); q6.TrainTransform(); q7.TrainTransform(); q8.TrainTransform(); q9.TrainTransform(); q10.TrainTransform(); q11.TrainTransform(); q12.TrainTransform(); q13.TrainTransform();q14.TrainTransform();q15.TrainTransform(); q16.TrainTransform(); q17.TrainTransform(); q18.TrainTransform(); q19.TrainTransform(); q20.TrainTransform(); q21.TrainTransform(); q22.TrainTransform(); q23.TrainTransform(); q24.TrainTransform(); q25.TrainTransform(); q26.TrainTransform(); q27.TrainTransform(); q28.TrainTransform(); q29.TrainTransform(); q30.TrainTransform(); q31.TrainTransform(); q32.TrainTransform(); q33.TrainTransform(); q37.TrainTransform(); q38.TrainTransform(); q39.TrainTransform(); q40.TrainTransform(); q41.TrainTransform(); q42.TrainTransform(); q43.TrainTransform(); q44.TrainTransform(); q45.TrainTransform(); q46.TrainTransform(); q47.TrainTransform(); q48.TrainTransform(); q49.TrainTransform(); q50.TrainTransform(); q51.TrainTransform(); q52.TrainTransform(); q53.TrainTransform(); q54.TrainTransform(); q55.TrainTransform(); q56.TrainTransform(); q57.TrainTransform(); q58.TrainTransform(); q59.TrainTransform(); q60.TrainTransform(); q61.TrainTransform(); q62.TrainTransform(); q63.TrainTransform(); q64.TrainTransform(); q65.TrainTransform(); q66.TrainTransform(); q67.TrainTransform(); q68.TrainTransform(); q69.TrainTransform(); q70.TrainTransform(); q71.TrainTransform(); q72.TrainTransform(); q73.TrainTransform(); q74.TrainTransform(); q75.TrainTransform(); q76.TrainTransform(); q77.TrainTransform(); q78.TrainTransform(); q79.TrainTransform(); q80.TrainTransform(); q81.TrainTransform(); q82.TrainTransform(); q83.TrainTransform(); q84.TrainTransform(); q85.TrainTransform(); q86.TrainTransform(); q87.TrainTransform(); q88.TrainTransform(); q89.TrainTransform(); q90.TrainTransform(); q91.TrainTransform(); q92.TrainTransform(); // translate first compartment in place float X = 800.0; q0.Translate(X, 0.0, 0.0); q1.Translate(X, 0.0, 0.0); q2.Translate(X, 0.0, 0.0); q3.Translate(X, 0.0, 0.0); q4.Translate(X, 0.0, 0.0); q5.Translate(X, 0.0, 0.0); q6.Translate(X, 0.0, 0.0); q7.Translate(X, 0.0, 0.0); q8.Translate(X, 0.0, 0.0); q9.Translate(X, 0.0, 0.0); q10.Translate(X, 0.0, 0.0); q11.Translate(X, 0.0, 0.0); q12.Translate(X, 0.0, 0.0); q13.Translate(X, 0.0, 0.0); q14.Translate(X, 0.0, 0.0); q15.Translate(X, 0.0, 0.0); q16.Translate(X, 0.0, 0.0); q17.Translate(X, 0.0, 0.0); q18.Translate(X, 0.0, 0.0); q19.Translate(X, 0.0, 0.0); q20.Translate(X, 0.0, 0.0); // translate second compartment in place X = 600.0; q21.Translate(X, 0.0, 0.0); q22.Translate(X, 0.0, 0.0); q23.Translate(X, 0.0, 0.0); q24.Translate(X, 0.0, 0.0); q25.Translate(X, 0.0, 0.0); q26.Translate(X, 0.0, 0.0); q27.Translate(X, 0.0, 0.0); q28.Translate(X, 0.0, 0.0); q29.Translate(X, 0.0, 0.0); q30.Translate(X, 0.0, 0.0); q31.Translate(X, 0.0, 0.0); q32.Translate(X, 0.0, 0.0); q33.Translate(X, 0.0, 0.0); q34.Translate(X, 0.0, 0.0); q35.Translate(X, 0.0, 0.0); q36.Translate(X, 0.0, 0.0); q37.Translate(X, 0.0, 0.0); q38.Translate(X, 0.0, 0.0); // translate third compartment in place X = 400.0; q39.Translate(X, 0.0, 0.0); q40.Translate(X, 0.0, 0.0); q41.Translate(X, 0.0, 0.0); q42.Translate(X, 0.0, 0.0); q43.Translate(X, 0.0, 0.0); q44.Translate(X, 0.0, 0.0); q45.Translate(X, 0.0, 0.0); q46.Translate(X, 0.0, 0.0); q47.Translate(X, 0.0, 0.0); q48.Translate(X, 0.0, 0.0); q49.Translate(X, 0.0, 0.0); q50.Translate(X, 0.0, 0.0); q51.Translate(X, 0.0, 0.0); q52.Translate(X, 0.0, 0.0); q53.Translate(X, 0.0, 0.0); q54.Translate(X, 0.0, 0.0); q55.Translate(X, 0.0, 0.0); q56.Translate(X, 0.0, 0.0); // translate fourth compartment in place X = 200.0; q57.Translate(X, 0.0, 0.0); q58.Translate(X, 0.0, 0.0); q59.Translate(X, 0.0, 0.0); q60.Translate(X, 0.0, 0.0); q61.Translate(X, 0.0, 0.0); q62.Translate(X, 0.0, 0.0); q63.Translate(X, 0.0, 0.0); q64.Translate(X, 0.0, 0.0); q65.Translate(X, 0.0, 0.0); q66.Translate(X, 0.0, 0.0); q67.Translate(X, 0.0, 0.0); q68.Translate(X, 0.0, 0.0); q69.Translate(X, 0.0, 0.0); q70.Translate(X, 0.0, 0.0); q71.Translate(X, 0.0, 0.0); q72.Translate(X, 0.0, 0.0); q73.Translate(X, 0.0, 0.0); q74.Translate(X, 0.0, 0.0); // rotate all with respect to Y axis, theta = -1.0 q0.RotateY(-0.7); q1.RotateY(-0.7); q2.RotateY(-0.7); q3.RotateY(-0.7); q4.RotateY(-0.7); q5.RotateY(-0.7); q6.RotateY(-0.7); q7.RotateY(-0.7); q8.RotateY(-0.7); q9.RotateY(-0.7); q10.RotateY(-0.7); q11.RotateY(-0.7); q12.RotateY(-0.7); q13.RotateY(-0.7); q14.RotateY(-0.7); q15.RotateY(-0.7); q16.RotateY(-0.7); q17.RotateY(-0.7); q18.RotateY(-0.7); q19.RotateY(-0.7); q20.RotateY(-0.7); q21.RotateY(-0.7); q22.RotateY(-0.7); q23.RotateY(-0.7); q24.RotateY(-0.7); q25.RotateY(-0.7); q26.RotateY(-0.7); q27.RotateY(-0.7); q28.RotateY(-0.7); q29.RotateY(-0.7); q30.RotateY(-0.7); q31.RotateY(-0.7); q32.RotateY(-0.7); q33.RotateY(-0.7); q34.RotateY(-0.7); q35.RotateY(-0.7); q36.RotateY(-0.7); q37.RotateY(-0.7); q38.RotateY(-0.7); q39.RotateY(-0.7); q40.RotateY(-0.7); q41.RotateY(-0.7); q42.RotateY(-0.7); q43.RotateY(-0.7); q44.RotateY(-0.7); q45.RotateY(-0.7); q46.RotateY(-0.7); q47.RotateY(-0.7); q48.RotateY(-0.7); q49.RotateY(-0.7); q50.RotateY(-0.7); q51.RotateY(-0.7); q52.RotateY(-0.7); q53.RotateY(-0.7); q54.RotateY(-0.7); q55.RotateY(-0.7); q56.RotateY(-0.7); q57.RotateY(-0.7); q58.RotateY(-0.7); q59.RotateY(-0.7); q60.RotateY(-0.7); q61.RotateY(-0.7); q62.RotateY(-0.7); q63.RotateY(-0.7); q64.RotateY(-0.7); q65.RotateY(-0.7); q66.RotateY(-0.7); q67.RotateY(-0.7); q68.RotateY(-0.7); q69.RotateY(-0.7); q70.RotateY(-0.7); q71.RotateY(-0.7); q72.RotateY(-0.7); q73.RotateY(-0.7); q74.RotateY(-0.7); q75.RotateY(-0.7); q76.RotateY(-0.7); q77.RotateY(-0.7); q78.RotateY(-0.7); q79.RotateY(-0.7); q80.RotateY(-0.7); q81.RotateY(-0.7); q82.RotateY(-0.7); q83.RotateY(-0.7); q84.RotateY(-0.7); q85.RotateY(-0.7); q86.RotateY(-0.7); q87.RotateY(-0.7); q88.RotateY(-0.7); q89.RotateY(-0.7); q90.RotateY(-0.7); q91.RotateY(-0.7); q92.RotateY(-0.7); // floor (not transformed), textured as satin Material mat4(1.0, 0.0, 1.0, 0.6, 0.7, 0.8, 20.0, 0.0, 1.6, 0.01, 0.02, 0.03, false, false, false, 1); Point3 p1(100.0, 50.0, 100.0); Point3 p2(1100.0, 50.0, 100.0); Point3 p3(1100.0, 50.0, -700.0); Point3 p4(100.0, 50.0, -700.0); Quad q93(p1, p2, p3, p4, mat4); // reflective left box wall Material mat5(0.0, 0.0, 0.0, 0.6, 0.7, 0.8, 20.0, 1.0, 1.6, 0.01, 0.02, 0.03, false, false, false, 0); Point3 p5(100.0, 50.0, 100.0); Point3 p6(100.0, 50.0, -700.0); Point3 p7(100.0, 800.0, -700.0); Point3 p8(100.0, 800.0, 100.0); Quad q94(p5, p6, p7, p8, mat5); // back box wall Material mat6(0.0, 0.0, 0.0, 0.6, 0.7, 0.8, 20.0, 1.0, 1.6, 0.01, 0.02, 0.03, false, false, false, 2); Point3 p9(100.0, 50.0, -700.0); Point3 p10(1100.0, 50.0, -700.0); Point3 p11(1100.0, 800.0, -700.0); Point3 p12(100.0, 800.0, -700.0); Quad q95(p9, p10, p11, p12, mat6); // a reflective sphere for fun Material mat10(0.0, 0.0, 1.0, 0.6, 0.7, 0.8, 21.0, 1.0, 1.3, 10000.0, 0.0, 10000.0, false, false, false, 0); Point3 center1(800.0, 400.0, -500.0); float radius1 = 200; Sphere s1(center1, radius1, mat10); // a dielectric sphere for even more fun Material mat11(0.0, 0.0, 0.0, 0.6, 0.7, 0.8, 42.0, 1.0, 1.3, 10000.0, 0.0, 10000.0, false, false, true, 0); Point3 center2(400.0, 200.0, -150.0); float radius2 = 75; Sphere s2(center2, radius2, mat11); // surface list definition Surface *list[numObjects] = {&q0, &q1, &q2, &q3, &q4, &q5, &q6, &q7, &q8, &q9, &q10, &q11, &q12, &q13, &q14, &q15, &q16, &q17, &q18, &q19, &q20, &q21, &q22, &q23, &q24, &q25, &q26, &q27, &q28, &q29, &q30, &q31, &q32, &q33, &q34, &q35, &q36, &q37, &q38, &q39, &q40, &q41, &q42, &q43, &q44, &q45, &q46, &q47, &q48, &q49, &q50, &q51, &q52, &q53, &q54, &q55, &q56, &q57, &q58, &q59, &q60, &q61, &q62, &q63, &q64, &q65, &q66, &q67, &q68, &q69, &q70, &q71, &q72, &q73, &q74, &q75, &q76, &q77, &q78, &q79, &q80, &q81, &q82, &q83, &q84, &q85, &q86, &q87, &q88, &q89, &q90, &q91, &q92, &q93, &q94, &q95, &s1, &s2}; // scene light Point3 lightPosition(1.0, 1.0, -0.5); // Point3 lightPosition(0.0, 0.0, 1.0); RGBColor lightColor(1.0, 1.0, 1.0); Light L1(lightPosition, lightColor, 0); // directional light // end of train 4 scene definition ******************************************************* #endif /* // this code is only for debugging purposes *********************************** Material mat1(1.0, 0.0, 1.0, 0.6, 0.7, 0.8, 20.0, 1.0, 1.6, 0.01, 0.02, 0.03, false, false, false, 3); Point3 p1(100.0, 100.0, -400.0); Point3 p2(600.0, 100.0, -400.0); Point3 p3(600.0, 800.0, -400.0); Point3 p4(100.0, 800.0, -400.0); Quad q1(p2, p1, p4, p3, mat1); Material mat2(1.0, 1.0, 1.0, 0.6, 0.7, 0.8, 20.0, 0.0, 1.6, 0.01, 0.02, 0.03, false, false, false, 3); Point3 p5(603.0, 100.0, -400.0); Point3 p6(1100.0, 100.0, -400.0); Point3 p7(1100.0, 800.0, -400.0); Point3 p8(603.0, 800.0, -400.0); Quad q2(p5, p6, p7, p8, mat2); Surface *list[numObjects] = {&q1, &q2}; // scene light // Point3 lightPosition(0.0, 1.0, 1.0); Point3 lightPosition(0.0, 0.0, 1.0); RGBColor lightColor(1.0, 1.0, 1.0); Light L1(lightPosition, lightColor, 0); // directional light */ // Drawing code starts here **************************************************** // this is the loop variable that records // the color of the pixel we look at. RGBColor pixel; // this is the hard-working ray that does all the drawing! Ray r1; // Viewer parameters Vector3 rayDirection; Point3 rayOrigin; Point3 eyePosition; // perspective projection parameters: the invariant is // the ray origin, always at the eye position, so we set // it here before the loop starts. The ray direction will // be changed at each loop iteration. if (currentProjection == PERSPECTIVE) { // look from center of scene from a // comfortable distance rayOrigin.SetX(600.0); rayOrigin.SetY(400.0); rayOrigin.SetZ(800.0); r1.SetOrigin(rayOrigin); eyePosition.SetX(600.0); eyePosition.SetY(400.0); eyePosition.SetZ(800.0); } // orthographic projection parameters: the invariant is // the ray direction, always looking towards (0, 0, -1), // so we set it before the loop starts. The ray origin // will be changed at each loop iteration if (currentProjection == ORTHOGRAPHIC) { // always look in the same direction rayDirection.SetX( 0.0); rayDirection.SetY( 0.0); rayDirection.SetZ(-1.0); r1.SetRayDirection(rayDirection); eyePosition.SetX(0.0); eyePosition.SetY(0.0); eyePosition.SetZ(1.0); } // main drawing loop. We draw the canvas pixel by pixel. for (int i = 0; i < WIDTH; i++) { C.flushCanvas(); for (int j = 0; j < HEIGHT; j++) { // orthographic projection: we set the // ray origin to (i, j, 0) if (currentProjection == ORTHOGRAPHIC) { rayOrigin.SetX(float(i)); rayOrigin.SetY(float(j)); r1.SetOrigin(rayOrigin); } // perspective projection: we set the ray direction // to ( (i, j, 0) - eyePosition) if (currentProjection == PERSPECTIVE) { rayDirection.SetX(i - rayOrigin.GetX()); rayDirection.SetY(j - rayOrigin.GetY()); rayDirection.SetZ(0.0 - rayOrigin.GetZ()); rayDirection.Normalize(); r1.SetRayDirection(rayDirection); } pixel.SetRed(BACKGROUND_RED); pixel.SetGreen(BACKGROUND_GREEN); pixel.SetBlue(BACKGROUND_BLUE); pixel = recursiveColor(r1, list, L1, eyePosition, MAX_RECURSION_DEPTH); C.drawPixel(i, j, pixel); } } C.flushCanvas(); /* // This remaining code is used only for debugging purposes int i = 450; int j = 420; // orthographic projection: we set the // ray origin to (i, j, 0) if (currentProjection == ORTHOGRAPHIC) { rayOrigin.SetX(float(i)); rayOrigin.SetY(float(j)); r1.SetOrigin(rayOrigin); } // perspective projection: we set the ray direction // to ( (i, j, 0) - eyePosition) if (currentProjection == PERSPECTIVE) { rayDirection.SetX(i - rayOrigin.GetX()); rayDirection.SetY(j - rayOrigin.GetY()); rayDirection.SetZ(0.0 - rayOrigin.GetZ()); rayDirection.Normalize(); r1.SetRayDirection(rayDirection); } pixel = recursiveColor(r1, list, L1, eyePosition, MAX_RECURSION_DEPTH); */ } // main void myDisplay(void) { DisplayScene(); C.flushCanvas(); gltWriteTGA("refraction1.tga"); } int main(int argc, char** argv) { //OpenGL initialization glutInit(&argc, argv); glutInitWindowSize(WIDTH, HEIGHT); glutInitWindowPosition(10, 10); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutCreateWindow("Louis Charbonneau 2819538"); myInit(); glutDisplayFunc(myDisplay); glutMainLoop(); return 0; }