/* * This is a dummy main program for the * COMP238 ray tracer parser. The routines * below just print the results of the parsed * input. * * What you'll need to do is make a call to * routines that store the info in your data * structures. * * Anselmo Lastra 2000-2002 * Adapted from the rayshade model language and * parser by Craig Kolb, etc. * See * http://graphics.stanford.edu/~cek/rayshade/rayshade.html */ #include #include #include "rayParser.h" #include "Buffer.h" #include #include #include #include #include #include #include // some types for later use typedef unsigned char byte; typedef byte rgb[3]; // these are 3 byte pixels in RGB order // a few colors to use static rgb red = { 255, 0, 0 }; static rgb blue = { 0, 0, 255 }; static rgb black = {0,0,0}; double cop[3]; //The center of projection. double dov[3]; //The direction of view, lookp - eyep. double up_dir[3]; //the up-direction vector, picked up during file input. double foc; //The focal length. double background[3];//The background color. int xres = 256; int yres = 256; int supersampl = 4; double sigma = .5; //For the filtering process. int rnum = 2; //Number of reflection/refraction rays shot for bluring. struct sphere { double rad, c[3]; //Spatial properties. double amb[3], dif[3], spec[3], refl, transp, index; //Material properties. double specpow; double sigma; //A scattering property of reflections and refractions. sphere *next; Buffer *image; sphere(double r, double x,double y, double z) { rad = r; c[0] = x; c[1] = y; c[2] = z; next = NULL; } } *sphere_head; struct plane { double p[3], n[3]; //A point and normal of the plane. double amb[3], dif[3], spec[3], refl, transp, index; //Material properties. double specpow; int textured; double sigma; //A scattering property of reflections and refractions. plane *next; Buffer *image; plane(double x, double y, double z, double nx, double ny, double nz) { p[0] = x; p[1] = y; p[2] = z; n[0] = nx; n[1] = ny; n[2] = nz; next = NULL; textured = 0; } } *plane_head; struct light { double p[3]; double amb[3], dif[3], spec[3], radius; light *next; bool extended; light(double x, double y, double z) { p[0] = x; p[1] = y; p[2] = z; next = NULL; //color[0] = c[0]; color[1] = c[1]; color[2] = c[2]; } } *light_head; //Triangles. If the normal is flat shading, the parser will //need to put the single normal in n0, to save on redundant //cross products later. struct triangle { double p0[3], p1[3], p2[3], n0[3], n1[3], n2[3], u[3], v[3]; double amb[3], dif[3], spec[3], refl, transp, index, specpow; //Material properties. int flat_shaded, textured; double sigma; //A scattering property of reflections and refractions. triangle *next; Buffer *image; triangle(double e0x, double e0y, double e0z, double e1x, double e1y, double e1z, double e2x, double e2y, double e2z) { p0[0] = e0x; p0[1] = e0y; p0[2] = e0z; p1[0] = e1x; p1[1] = e1y; p1[2] = e1z; p2[0] = e2x; p2[1] = e2y; p2[2] = e2z; next = NULL; textured = 0; } } *triangle_head; //A struct to keep material properties before association with //particular objects. struct surfmat { double amb[3], dif[3], spec[3], refl, transp, index, specpow; double sigma; //A scattering property of reflections and refractions. surfmat() { int i; for (i = 0; i < 3; i++) { amb[i] = .0; dif[i] = .0; spec[i] = .0; } refl = 0.0; transp = 0.0; index = 1.0; } } *current_surf; //The surface containing data structure. std::map SurfaceMap; //We also need such a map for the image textures. std::map ImageMap; //for keeping track of the linked lists of objects during parsing. sphere *blast, *curs; plane *plast, *curp; light *llast, *curl; triangle *tlast, *curt; surfmat *asurf; Buffer *animage; int prev_obj = 0; //This represents the previous object declared. I'm //using this for texture mapping, because the texture //is declared only after the object has been. //This object is for tracking the sumpersampling struct image_vert { double x,y, r,g,b; image_vert() { x = 0.0; y = 0.0; r = 0.0; g = 0.0; b = 0.0;} }; // an object to represent the framebuffer where I draw struct FrameBuffer { int width, height; rgb *pix; double *pz; //pixel z value. FrameBuffer(int w, int h) { width=w; height=h; pix = new rgb[width*height]; pz = new double[width*height];} void Clear(const rgb p); void Test(); } *fb; // global framebuffer object for use in callbacks struct Projection { double mat[3][3]; Projection(double dov[], double foc); //Initializes the world-from-image projection matrix. void Convert(double v[]); //Applies mat to v, where v is image coords [i j 1], returning //v = mat*v, a vector in the direction of that image plane point, //such that cop + v is on the image plane. } *Pwfi; //global projection matrix. Projection::Projection(double dov[], double foc) /*** This function initializes a projection matrix for a pinhole camera model using the One True Way (see UNC's Bishop). Meters are the unit here, and the 36mm x 36mm film is modeled. ***/ { double dov_norm = sqrt(double(pow(dov[0],2)+pow(dov[1],2)+pow(dov[2],2))); double foc_v[3]; foc_v[0] = foc*dov[0]/dov_norm; foc_v[1] = foc*dov[1]/dov_norm; foc_v[2] = foc*dov[2]/dov_norm; double foc_norm = sqrt(double(pow(foc_v[0],2)+pow(foc_v[1],2)+pow(foc_v[2],2))); //Unit vector in foc_v direction. double foc_vu[3]; foc_vu[0] = foc_v[0]/foc_norm; foc_vu[1] = foc_v[1]/foc_norm; foc_vu[2] = foc_v[2]/foc_norm; double up_foc_dot = up_dir[0]*foc_vu[0]+ up_dir[1]*foc_vu[1]+ up_dir[2]*foc_vu[2]; //The b image plane vector. double b[3]; b[0] = up_dir[0]-up_foc_dot*foc_vu[0]; b[1] = up_dir[1]-up_foc_dot*foc_vu[1]; b[2] = up_dir[2]-up_foc_dot*foc_vu[2]; double b_norm = sqrt(double(pow(b[0],2)+pow(b[1],2)+pow(b[2],2))); b[0]=0.036*b[0]/b_norm; b[1]=0.036*b[1]/b_norm; b[2]=0.036*b[2]/b_norm; //The a image plane vector, the cross of foc_vu and b. double a[3]; a[0] = foc_vu[1]*b[2]-b[1]*foc_vu[2]; a[1] = b[0]*foc_vu[2]-foc_vu[0]*b[2]; a[2] = foc_vu[0]*b[1]-b[0]*foc_vu[1]; double a_norm = sqrt(double(pow(a[0],2)+pow(a[1],2)+pow(a[2],2))); a[0]=0.036*a[0]/a_norm; a[1]=0.036*a[1]/a_norm; a[2]=0.036*a[2]/a_norm; //o, a vector pointing to the lower right hand corner of the image plane. double o[3]; o[0] = foc_v[0] - 0.5*b[0] - 0.5*a[0]; o[1] = foc_v[1] - 0.5*b[1] - 0.5*a[1]; o[2] = foc_v[2] - 0.5*b[2] - 0.5*a[2]; //Resize for the resolution, and off we go... a[0] = a[0]/xres; a[1] = a[1]/xres; a[2] = a[2]/xres; b[0] = b[0]/yres; b[1] = b[1]/yres; b[2] = b[2]/yres; for (int i = 0; i < 3; i ++) { mat[i][0] = a[i]; mat[i][1] = b[i]; mat[i][2] = o[i]; } //Now, a ray going out into the world from the cop through the pixel (i,j) //in the image plane is cop + mat*(i j 1)'. } void Projection::Convert(double v[]) /*** Simply apply the projection matrix to the referenced vector v, and return the new v. ***/ { int i,j; double mat_b[3] = {0.0,0.0,0.0}; for (i = 0; i < 3; i ++) { for (j = 0; j < 3; j ++) { mat_b[i] += mat[i][j]*v[j]; } } v[0] = mat_b[0]; v[1] = mat_b[1]; v[2] = mat_b[2]; } void FrameBuffer::Clear(const rgb p) { register byte r = p[0]; register byte g = p[1]; register byte b = p[2]; register byte* p0 = pix[0]; register byte* p1 = p0 + sizeof(rgb)*width*height; while(p0 < p1) { p0[0] = r; p0[1] = g; p0[2] = b; p0 += 3; } } double Intersect_sphere(double e[], double v[], double c[], double r) //Returns the extend along v to touch the sphere. Returns negative t if there's //no real intersection, as no intersection is treated in the same way as an //imaginary intersection. { double temp1 = pow(v[0],2) + pow(v[1],2) + pow(v[2],2); double temp2 = v[0]*(e[0]-c[0]) + v[1]*(e[1]-c[1]) + v[2]*(e[2]-c[2]); temp2 *= 2.0; double temp3 = pow(e[0],2) + pow(e[1],2) + pow(e[2],2); temp3 += pow(c[0],2) + pow(c[1],2) + pow(c[2],2); temp3 = temp3 - 2.0*(e[0]*c[0] + e[1]*c[1] + e[2]*c[2]) - pow(r,2); double big = pow(temp2,2) - 4.0*temp1*temp3; if (big > 0) { big = sqrt(big)/(2.0*temp1); double opb = -temp2/(2.0*temp1); if (opb > big + 1.0e-10) {return (opb - big);} else {return (opb + big);} }else { return -1.0; } } double Intersect_plane(double e[], double v[], double p[], double n[]) //Returns the extent along v from e to touch the plane. Again, negative //return value won't be viewed anyway, to if there isn't an intersection, //negative return value. { double D = n[0]*p[0] + n[1]*p[1] + n[2]*p[2]; double numer = D - (n[0]*e[0] + n[1]*e[1] + n[2]*e[2]); double denom = n[0]*v[0] + n[1]*v[1] + n[2]*v[2]; if (fabs(denom) < 1.0e-14) { return -1.0; }else { return (numer/denom); } } double Intersect_tri(double e[], double v[], double tuv[], triangle *t) //Returns the extent along v from e to hit the triangle (negative if //non-intersect). { double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; double det,inv_det; int i; for (i = 0; i < 3; i ++) { edge1[i] = t->p1[i] - t->p0[i]; edge2[i] = t->p2[i] - t->p0[i]; } //Cross v and edge2. pvec[0] = v[1]*edge2[2] - v[2]*edge2[1]; pvec[1] = v[2]*edge2[0] - v[0]*edge2[2]; pvec[2] = v[0]*edge2[1] - v[1]*edge2[0]; //dot edge1 with the cross of v and edge2. If the dot is close to //zero, the v is in the plane of the triangle. det = edge1[0]*pvec[0] + edge1[1]*pvec[1] + edge1[2]*pvec[2]; if (fabs(det) < 1.0e-10) return -1.0; inv_det = 1.0/det; //Distance from vert0 to ray origin. tvec[0] = e[0]- t->p0[0]; tvec[1] = e[1]- t->p0[1]; tvec[2] = e[2]- t->p0[2]; //Calculate u and test bounds tuv[1] = tvec[0]*pvec[0] + tvec[1]*pvec[1] + tvec[2]*pvec[2]; tuv[1] = tuv[1]*inv_det; if ((tuv[1] < -1.0e-10)||(tuv[1] > 1.0)) return -1.0; //Prepare for v parameter. qvec[0] = tvec[1]*edge1[2] - tvec[2]*edge1[1]; qvec[1] = tvec[2]*edge1[0] - tvec[0]*edge1[2]; qvec[2] = tvec[0]*edge1[1] - tvec[1]*edge1[0]; //Calculate v and test bounds tuv[2] = v[0]*qvec[0] + v[1]*qvec[1] + v[2]*qvec[2]; tuv[2] = tuv[2]*inv_det; if ((tuv[2] < -1.0e-10)||(tuv[1] + tuv[2] > 1.0)) return -1.0; //Calculate t. tuv[0] = edge2[0]*qvec[0] + edge2[1]*qvec[1] + edge2[2]*qvec[2]; tuv[0] = tuv[0]*inv_det; //We also scale the distance t by the length of vector v, so that //this t is comparable to those returned by other functions. //tuv[0] = tuv[0]/(sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2])); return tuv[0]; } //debug //int q = 0, z = 0; double g2d(double x, double y, double cx, double cy, double sig) //Returns the value of the 2d gaussian at (x,y), centered at (cx,cy) with //sig standard deviation. { double coef = 1/(2*3.14159265*sig*sig); return coef*exp(((x - cx)*(x - cx) + (y - cy)*(y - cy))/(-2.0*sig*sig)); } void Single_Raytrace(double v[], double p[], double color[], int level, double refract) { //color[0] = 1.0; color[1] = 0.0; color[2] = 1.0; double min_t = 1.0e90, t, sum_l[3], lightv[3]; int s_p = 0, i, snp = 0, textured = 0; //-1 for sphere, 1 for plane. sphere *cl_s, *curs = sphere_head; plane *cl_p, *curp = plane_head; //plane,sphere, triangle and light pointers. light *curl = light_head; triangle *cl_t, *curt = triangle_head; double am[3], dif[3], spe[3], ex; double rind = 0, tind = 0, newrefract = 0; //reflection and transparency info. double sum_spec[3]; //I'm going to keep the specular information separate from other mat properties, //so that reflective and transparent surfaces can still have specular highlights. double tri_tuv[3], tri_mintuv[3]; //Info regarding the normal and intersection point of a ray with a triangle. double pray[3]; //Perturbed ray for different stochastic stuff. Vec3f tcol; //Textured color. //First, intersect the ray with all the spheres. while (curs != NULL) { t = Intersect_sphere(p, v, curs->c, curs->rad); if ((t < min_t)&&(t > 1.0e-10)) { min_t = t; cl_s = curs; s_p = -1; //if (q == 0) printf("%lf\n",t); //q++; } curs = curs->next; } //Now, check for a closer plane. while (curp != NULL) { t = Intersect_plane(p, v, curp->p, curp->n); if ((t < min_t)&&(t > 1.0e-10)) { min_t = t; cl_p = curp; s_p = 1; } curp = curp->next; } //Now, check for a closer triangle. while (curt != NULL) { t = Intersect_tri(p, v, tri_tuv, curt); if ((t < min_t)&&(t > 1.0e-10)) { min_t = t; tri_mintuv[0] = tri_tuv[0]; tri_mintuv[1] = tri_tuv[1]; tri_mintuv[2] = tri_tuv[2]; cl_t = curt; s_p = 2; } curt = curt->next; } //A separate case is if the ray hits a light before all of the others. light *cl_l; //10 lights max will add some specular highlight to the surface. double vmag,lmag,ldot, mindot = .01; vmag = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); while (curl != NULL) { //Use vmag as a ruler for determining how close a light is. If the light //is closer and within (arbitrary) 30 degrees, then the light will be the //color that this ray returns. This works best for lights outside of the //scene volume. //I've changed something. Now, if the light is extended, we want to see all //of it, so the arbitrary 30 degrees doesn't work. So I've changed the ldot //condition below. for (i=0;i<3;i++) { lightv[i] = curl->p[i] - p[i]; } lmag = sqrt(lightv[0]*lightv[0]+lightv[1]*lightv[1]+lightv[2]*lightv[2]); ldot = v[0]*lightv[0] + v[1]*lightv[1] + v[2]*lightv[2]; ldot = ldot/(lmag*vmag); lmag = lmag/vmag; if ((lmag < min_t)&&(lmag > 1.0e-10)&&(ldot >= .05)&&(ldot > mindot)) { //for angles between 0 and pi/6, cos varies from ~.85 to 1. mindot = ldot; cl_l = curl; snp = -121; //if (q == 0) printf("%lf\n",t); //q++; } curl = curl->next; } //Now do the light computation if there was a hit. if ((s_p == 1)||(s_p == -1)||(s_p == 2)) { sum_l[0] = 0.0; sum_l[1] = 0.0; sum_l[2] = 0.0; sum_spec[0] = 0.0; sum_spec[1] = 0.0; sum_spec[2] = 0.0; //Pick up the material properties. if (s_p == -1) { am[0] = cl_s->amb[0]; am[1] = cl_s->amb[1]; am[2] = cl_s->amb[2]; dif[0] = cl_s->dif[0]; dif[1] = cl_s->dif[1]; dif[2] = cl_s->dif[2]; spe[0] = cl_s->spec[0]; spe[1] = cl_s->spec[1]; spe[2] = cl_s->spec[2]; ex = cl_s->specpow; }else if (s_p == 1) { am[0] = cl_p->amb[0]; am[1] = cl_p->amb[1]; am[2] = cl_p->amb[2]; dif[0] = cl_p->dif[0]; dif[1] = cl_p->dif[1]; dif[2] = cl_p->dif[2]; spe[0] = cl_p->spec[0]; spe[1] = cl_p->spec[1]; spe[2] = cl_p->spec[2]; ex = cl_p->specpow; }else if (s_p == 2) { am[0] = cl_t->amb[0]; am[1] = cl_t->amb[1]; am[2] = cl_t->amb[2]; dif[0] = cl_t->dif[0]; dif[1] = cl_t->dif[1]; dif[2] = cl_t->dif[2]; spe[0] = cl_t->spec[0]; spe[1] = cl_t->spec[1]; spe[2] = cl_t->spec[2]; ex = cl_t->specpow; textured = cl_t->textured; } //Done picking up mat. props of the intersected object. double ip[3]; //Point of intersection of the ray and object. ip[0] = p[0]+min_t*v[0]; ip[1] = p[1]+min_t*v[1]; ip[2] = p[2]+min_t*v[2]; double n[3]; //Normal at the point of intersection. Additional modifications //will be needed for phong shaded triangles. if (s_p == -1) { n[0] = ip[0]-cl_s->c[0]; n[1] = ip[1]-cl_s->c[1]; n[2] = ip[2]-cl_s->c[2]; }else if (s_p == 1) { n[0] = cl_p->n[0]; n[1] = cl_p->n[1]; n[2] = cl_p->n[2]; }else if (s_p == 2) { if (!cl_t->flat_shaded) { n[0] = (1.0-tri_mintuv[1]-tri_mintuv[2])*cl_t->n0[0] + tri_mintuv[1]*cl_t->n1[0] + tri_mintuv[2]*cl_t->n2[0]; n[1] = (1.0-tri_mintuv[1]-tri_mintuv[2])*cl_t->n0[1] + tri_mintuv[1]*cl_t->n1[1] + tri_mintuv[2]*cl_t->n2[1]; n[2] = (1.0-tri_mintuv[1]-tri_mintuv[2])*cl_t->n0[2] + tri_mintuv[1]*cl_t->n1[2] + tri_mintuv[2]*cl_t->n2[2]; }else { n[0] = cl_t->n0[0]; n[1] = cl_t->n0[1]; n[2] = cl_t->n0[2]; } } double norm = sqrt(pow(n[0],2) + pow(n[1],2) + pow(n[2],2)); n[0] = n[0]/norm; n[1] = n[1]/norm; n[2] = n[2]/norm; double view[3]; //The view vector, from intersection to eye. view[0] = p[0] - ip[0]; view[1] = p[1] - ip[1]; view[2] = p[2] - ip[2]; norm = sqrt(pow(view[0],2) + pow(view[1],2) + pow(view[2],2)); view[0] = view[0]/norm; view[1] = view[1]/norm; view[2] = view[2]/norm; //More variables, for the light calculations. double l[3], l_dif[3], l_spe[3], dot1, dot2, ref[3], add_l[3]; curl = light_head; double shadind; //If occluding surface is transparent. //This is the place to test against texturing, and pick up the surface //info if it is a texture. if (textured) { if (s_p == 2) { //Use the mintuv to provide the texture coord. double q,u,v; q = 1.0 - tri_mintuv[1] - tri_mintuv[2]; u = q*cl_t->u[0] + tri_mintuv[1]*cl_t->u[1] + tri_mintuv[2]*cl_t->u[2]; v = q*cl_t->v[0] + tri_mintuv[1]*cl_t->v[1] + tri_mintuv[2]*cl_t->v[2]; u = u*cl_t->image->get_width(); v = v*cl_t->image->get_height(); /*I couldn't get this to work. //Bilinearly interpolate the texture. ll = cl_t->image->get_color(floor(u),floor(v)); ul = cl_t->image->get_color(floor(u),floor(v)+1); ur = cl_t->image->get_color(floor(u)+1,floor(v)+1); lr = cl_t->image->get_color(floor(u)+1,floor(v)); q = u - floor(u); col1.x = q*lr.x + (1-q)*ll.x; col1.y = q*lr.y + (1-q)*ll.y; col1.z = q*lr.z + (1-q)*ll.z; col2.x = q*ul.x + (1-q)*ur.x; col2.y = q*ul.y + (1-q)*ur.y; col2.z = q*ul.z + (1-q)*ur.z; q = v - floor(v); tcol.x = (q)*col2.x + (1-q)*col1.x; tcol.y = (q)*col2.y + (1-q)*col1.y; tcol.z = (q)*col2.z + (1-q)*col1.z; */ tcol = cl_t->image->get_color(floor(u),floor(v)); //If the point is textured, multiply am and dif and spec with tcol. am[0] *= tcol.x; am[1] *= tcol.y; am[2] *= tcol.z; dif[0] *= tcol.x; dif[1] *= tcol.y; dif[2] *= tcol.z; spe[0] *= tcol.x; spe[1] *= tcol.y; spe[2] *= tcol.z; } } while (curl != NULL) { //The light values serve as a filter for the material properties of //the object intersected. shadind = 1.0; for (i = 0; i < 3; i ++) { sum_l[i] += curl->amb[i]; l[i] = curl->p[i] - ip[i]; l_dif[i] = curl->dif[i]; l_spe[i] = curl->spec[i]; } norm = sqrt(l[0]*l[0] + l[1]*l[1] + l[2]*l[2]); l[0] = l[0]/norm; l[1] = l[1]/norm; l[2] = l[2]/norm; //Now, l is a unit light vector from the intersection point. //If the light is extended, we now perturb our shadow ray a bit, //proportional to the projected area of the light on ip. if (curl->extended == true) { double x = curl->radius/norm; //a silimar triangles argument says this is the limit of the //perturbation of l along the plane normal to l. pray[0] = 2.0*x*(rand()/((double) RAND_MAX)) - x; pray[1] = 2.0*x*(rand()/((double) RAND_MAX)) - x; pray[2] = 2.0*x*(rand()/((double) RAND_MAX)) - x; norm = sqrt(pray[0]*pray[0] + pray[1]*pray[1] + pray[2]*pray[2]); pray[0] = pray[0]/norm; pray[1] = pray[1]/norm; pray[2] = pray[2]/norm; // Approximate a Gaussian distribution. // http://www.algarcia.org/nummeth/Cpp/randn.cpp //this number will scale the length of the perturbed ray. double r = (x/2)*sqrt( -2.0*log(1.0 - rand()/(double)RAND_MAX) )* cos( 6.283185307 * rand()/(double)RAND_MAX ); if (r < 1.0e-10) r = -r; if (r > x) r = x; pray[0] = r*pray[0]; pray[1] = r*pray[1]; pray[2] = r*pray[2]; if (pray[0]*l[0] + pray[1]*l[1] + pray[2]*l[2] < 1.0e-10) { pray[0] = -pray[0]; pray[1] = -pray[1]; pray[2] = -pray[2]; } l[0] += pray[0]; l[1] += pray[1]; l[2] += pray[2]; norm = sqrt(l[0]*l[0] + l[1]*l[1] + l[2]*l[2]); l[0] = l[0]/norm; l[1] = l[1]/norm; l[2] = l[2]/norm; //Now l is the perturbed,unit length, shadow ray. } //First we have to check if the point is in shadow for this light. curs = sphere_head; curp = plane_head; curt = triangle_head; while (curs != NULL) { t = Intersect_sphere(ip, l, curs->c, curs->rad); if ((t < norm)&&(t > 1.0e-8)) { //if t is less than the magnitude of the vector from ip to the //light, then the sphere is closer than the light to ip. shadind = shadind*curs->transp; //if (s_p == -1) { // t = Intersect_sphere(ip, l, curs->c, curs->rad); //} } curs = curs->next; } //Now, check for a plane closer than the light. while (curp != NULL) { t = Intersect_plane(ip, l, curp->p, curp->n); if ((t < norm)&&(t > 1.0e-8)) { shadind = shadind*curp->transp; } curp = curp->next; } //Now, check for a triangle. while(curt != NULL) { t = Intersect_tri(ip, l, tri_tuv, curt); if ((t < norm)&&(t > 1.0e-8)) { shadind = shadind*curt->transp; } curt = curt->next; } add_l[0] = 0.0; add_l[1] = 0.0; add_l[2] = 0.0; dot1 = l[0]*n[0] + l[1]*n[1] + l[2]*n[2]; if (dot1 >= 0.0) { ref[0] = 2.0*dot1*n[0]-l[0]; ref[1] = 2.0*dot1*n[1]-l[1]; ref[2] = 2.0*dot1*n[2]-l[2]; dot2 = view[0]*ref[0] + view[1]*ref[1] + view[2]*ref[2]; if (dot2 < 0.0) dot2 = 0.0; add_l[0] = dot1*dif[0]*l_dif[0];// + pow(dot2,ex)*spe[0]*l_spe[0]; add_l[1] = dot1*dif[1]*l_dif[1];// + pow(dot2,ex)*spe[1]*l_spe[1]; add_l[2] = dot1*dif[2]*l_dif[2];// + pow(dot2,ex)*spe[2]*l_spe[2]; sum_spec[0] += shadind*pow(dot2,ex)*spe[0]*l_spe[0]; sum_spec[1] += shadind*pow(dot2,ex)*spe[1]*l_spe[1]; sum_spec[2] += shadind*pow(dot2,ex)*spe[2]*l_spe[2]; } //Now, update the color to be returned. color[0] += shadind*add_l[0]; color[1] += shadind*add_l[1]; color[2] += shadind*add_l[2]; curl = curl->next; //Do the same for the next light. } //Add in the ambient terms and threshold the color value. for (i=0;i<3;i++) { if (sum_l[i] > 1.0) sum_l[i] = 1.0; color[i] += am[i]*sum_l[i]; if (color[i] > 1.0) color[i] = 1.0; } //Now we can get the color from reflection and refraction rays. if (level < 10) { //color[0] = .7*color[0]; color[1] = .7*color[1]; color[2] = .7*color[2]; double ref_col[3], trans_col[3], totcol[3], nray[3]; double refl[3]; double rsigma; trans_col[0] = 0.0; trans_col[1] = 0.0; trans_col[2] = 0.0; ref_col[0] = 0.0; ref_col[1] = 0.0; ref_col[2] = 0.0; totcol[0] = 0.0; totcol[1] = 0.0; totcol[2] = 0.0; double pplane[3]; //A point on a plane normal to the refl/refr ray; double sum = 0.0, g = 0.0, qtemp[3]; //also for blurring. double rind = 0, tind = 0, newrefract = 0; if (s_p == -1) { rind = cl_s->refl; //Weightings on transparencey and reflection. tind = cl_s->transp; newrefract = cl_s->index; rsigma = cl_s->sigma; }else if (s_p == 1) { rind = cl_p->refl; tind = cl_p->transp; newrefract = cl_p->index; rsigma = cl_p->sigma; }else if (s_p == 2) { rind = cl_t->refl; tind = cl_t->transp; newrefract = cl_t->index; rsigma = cl_t->sigma; } if (rind > 0.001) { //Make the reflection ray. dot1 = view[0]*n[0] + view[1]*n[1] + view[2]*n[2]; refl[0] = -view[0]+2.0*dot1*n[0]; refl[1] = -view[1]+2.0*dot1*n[1]; refl[2] = -view[2]+2.0*dot1*n[2]; norm = sqrt(refl[0]*refl[0] + refl[1]*refl[1] + refl[2]*refl[2]); refl[0] /= norm; refl[1] /= norm; refl[2] /= norm; pplane[0] = ip[0]+refl[0]; pplane[1] = ip[1]+refl[1]; pplane[2] = ip[2]+refl[2]; //Now we will do blurred reflections. perturb the relflection //rays a little, and take a weighted average over the samples. //This is the highest weighted one, always included. Single_Raytrace(refl, ip, ref_col, level + 1, refract); g = g2d(0.0,0.0,0.0,0.0,rsigma/2); sum += g; totcol[0] = g*ref_col[0]; totcol[1] = g*ref_col[1]; totcol[2] = g*ref_col[2]; //Now, for other weighted rays, compute reflections. for (i = 0; i < rnum; i ++) { ref_col[0] = 0.0; ref_col[1] = 0.0; ref_col[2] = 0.0; nray[0] = refl[0]; nray[1] = refl[1]; nray[2] = refl[2]; //Perturb the reflection ray. //a silimar triangles argument says this is the limit of the //perturbation of nray along the plane normal to nray. pray[0] = 2.0*rsigma*(rand()/((double) RAND_MAX)) - rsigma; pray[1] = 2.0*rsigma*(rand()/((double) RAND_MAX)) - rsigma; pray[2] = 2.0*rsigma*(rand()/((double) RAND_MAX)) - rsigma; norm = sqrt(pray[0]*pray[0] + pray[1]*pray[1] + pray[2]*pray[2]); pray[0] = pray[0]/norm; pray[1] = pray[1]/norm; pray[2] = pray[2]/norm; // Approximate a Gaussian distribution. // http://www.algarcia.org/nummeth/Cpp/randn.cpp //this number will scale the length of the perturbed ray. double r = (rsigma/2)*sqrt( -2.0*log(1.0 - rand()/(double)RAND_MAX) )* cos( 6.283185307 * rand()/(double)RAND_MAX ); if (r < 1.0e-10) r = -r; if (r > rsigma) r = rsigma; pray[0] = r*pray[0]; pray[1] = r*pray[1]; pray[2] = r*pray[2]; if (pray[0]*nray[0] + pray[1]*nray[1] + pray[2]*nray[2] < 1.0e-10) { pray[0] = -pray[0]; pray[1] = -pray[1]; pray[2] = -pray[2]; } nray[0] += pray[0]; nray[1] += pray[1]; nray[2] += pray[2]; norm = sqrt(nray[0]*nray[0] + nray[1]*nray[1] + nray[2]*nray[2]); nray[0] /= norm; nray[1] /= norm; nray[2] /= norm; //Now nray is the perturbed,unit length, reflection ray. //Reuse variables to get weighting of this perturbation. r = Intersect_plane(ip, nray, pplane, refl); qtemp[0] = pplane[0]-(ip[0]+r*nray[0]); qtemp[1] = pplane[1]-(ip[1]+r*nray[1]); qtemp[2] = pplane[2]-(ip[2]+r*nray[2]); t = sqrt(qtemp[0]*qtemp[0] + qtemp[1]*qtemp[1] + qtemp[2]*qtemp[2]); //t is the planar distance to the center of the gaussian. g = g2d(t,0.0,0.0,0.0,rsigma/2); sum += g; Single_Raytrace(nray, ip, ref_col, level + 1, refract); totcol[0] += g*ref_col[0]; totcol[1] += g*ref_col[1]; totcol[2] += g*ref_col[2]; } ref_col[0] = totcol[0]/sum; ref_col[1] = totcol[1]/sum; ref_col[2] = totcol[2]/sum; } if (tind > 0.001) { double temp; sum = 0.0; g = 0.0; //Make the transparency ray. if (refract == 0 || newrefract == 0) printf ("Refraction component zero. uh-oh.\n"); dot1 = -1.0*view[0]*n[0] + -1.0*view[1]*n[1] + -1.0*view[2]*n[2]; double norm1 = sqrt(pow(view[0],2)+pow(view[1],2)+pow(view[2],2)); norm1 *= sqrt(n[0]*n[0]+ n[1]*n[1]+ n[2]*n[2]); dot1 = dot1/norm1; double sintheta, ratio; if (dot1 < 1.0e-12) { ratio = refract/newrefract; } else { ratio = newrefract/1.0; } sintheta = sqrt(1.0 - dot1*dot1); double sinthetaprim = ratio*sintheta; double costhetaprim; if (dot1 < 0.0) costhetaprim = -sqrt(1.0 - pow(sinthetaprim,2)); else costhetaprim = sqrt(1.0 - pow(sinthetaprim,2)); if (sinthetaprim > 1.0) { costhetaprim = .0; sinthetaprim = 1.0; } double b[3]; b[0] = -view[0] + dot1*n[0]; b[1] = -view[1] + dot1*n[1]; b[2] = -view[2] + dot1*n[2]; if (fabs(sintheta) > 1.0e-10) { b[0] = b[0]/sintheta; b[1] = b[1]/sintheta; b[2] = b[2]/sintheta; } double tran[3]; if ((fabs(dot1) < 1.0e-10)||(fabs(sintheta) < 1.0e-10)) { tran[0] = -view[0]; tran[1] = -view[1]; tran[2] = -view[2]; }else { tran[0] = sinthetaprim*b[0]-costhetaprim*n[0]; tran[1] = sinthetaprim*b[1]-costhetaprim*n[1]; tran[2] = sinthetaprim*b[2]-costhetaprim*n[2]; } norm = sqrt(tran[0]*tran[0] + tran[1]*tran[1] + tran[2]*tran[2]); tran[0] /= norm; tran[1] /= norm; tran[2] /= norm; pplane[0] = ip[0]+tran[0]; pplane[1] = ip[1]+tran[1]; pplane[2] = ip[2]+tran[2]; //We're now going to make a weighted average of perturbed //transparency rays, for blurred transparency. if (dot1 < 0) temp = newrefract; else temp = 1.0; Single_Raytrace(tran, ip, trans_col, level + 1, temp); g = g2d(0.0,0.0,0.0,0.0,rsigma/2); sum += g; totcol[0] = g*trans_col[0]; totcol[1] = g*trans_col[1]; totcol[2] = g*trans_col[2]; //Now we repeat the process from above for reflections. for (i = 0; i < rnum; i ++) { trans_col[0] = 0.0; trans_col[1] = 0.0; trans_col[2] = 0.0; nray[0] = tran[0]; nray[1] = tran[1]; nray[2] = tran[2]; //Perturb the transparency ray. //a silimar triangles argument says this is the limit of the //perturbation of nray along the plane normal to nray. pray[0] = 2.0*rsigma*(rand()/((double) RAND_MAX)) - rsigma; pray[1] = 2.0*rsigma*(rand()/((double) RAND_MAX)) - rsigma; pray[2] = 2.0*rsigma*(rand()/((double) RAND_MAX)) - rsigma; norm = sqrt(pray[0]*pray[0] + pray[1]*pray[1] + pray[2]*pray[2]); pray[0] = pray[0]/norm; pray[1] = pray[1]/norm; pray[2] = pray[2]/norm; // Approximate a Gaussian distribution. // http://www.algarcia.org/nummeth/Cpp/randn.cpp //this number will scale the length of the perturbed ray. double r = (rsigma/2)*sqrt( -2.0*log(1.0 - rand()/(double)RAND_MAX) )* cos( 6.283185307 * rand()/(double)RAND_MAX ); if (r < 1.0e-10) r = -r; if (r > rsigma) r = rsigma; pray[0] = r*pray[0]; pray[1] = r*pray[1]; pray[2] = r*pray[2]; if (pray[0]*nray[0] + pray[1]*nray[1] + pray[2]*nray[2] < 1.0e-10) { pray[0] = -pray[0]; pray[1] = -pray[1]; pray[2] = -pray[2]; } nray[0] += pray[0]; nray[1] += pray[1]; nray[2] += pray[2]; norm = sqrt(nray[0]*nray[0] + nray[1]*nray[1] + nray[2]*nray[2]); nray[0] /= norm; nray[1] /= norm; nray[2] /= norm; //Now nray is the perturbed,unit length, transparency ray. //Reuse variables to get weighting of this perturbation. r = Intersect_plane(ip, nray, pplane, tran); qtemp[0] = pplane[0]-(ip[0]+r*nray[0]); qtemp[1] = pplane[1]-(ip[1]+r*nray[1]); qtemp[2] = pplane[2]-(ip[2]+r*nray[2]); t = sqrt(qtemp[0]*qtemp[0] + qtemp[1]*qtemp[1] + qtemp[2]*qtemp[2]); //t is the planar distance to the center of the gaussian. g = g2d(t,0.0,0.0,0.0,rsigma/2); sum += g; Single_Raytrace(nray, ip, trans_col, level + 1, temp); totcol[0] += g*trans_col[0]; totcol[1] += g*trans_col[1]; totcol[2] += g*trans_col[2]; } trans_col[0] = totcol[0]/sum; trans_col[1] = totcol[1]/sum; trans_col[2] = totcol[2]/sum; } dot1 = 1.0 - tind - rind; color[0] = dot1*color[0] + rind*ref_col[0] + tind*trans_col[0]; color[1] = dot1*color[1] + rind*ref_col[1] + tind*trans_col[1]; color[2] = dot1*color[2] + rind*ref_col[2] + tind*trans_col[2]; /* //Now, if the object is texture mapped, find the texture color and //have it contribute to this returned color. The problem is, the specs //don't say how much to give the texture, verses the surface. I'm going //something arbitrary (no lambertian stuff if it's a texture). if (!textured) { color[0] = dot1*color[0] + rind*ref_col[0] + tind*trans_col[0]; color[1] = dot1*color[1] + rind*ref_col[1] + tind*trans_col[1]; color[2] = dot1*color[2] + rind*ref_col[2] + tind*trans_col[2]; }else { if (s_p == 2) { //Use the mintuv to provide the texture coord. double q = 1.0 - tri_mintuv[1] - tri_mintuv[2]; double u = q*cl_t->u[0] + tri_mintuv[1]*cl_t->u[1] + tri_mintuv[2]*cl_t->u[2]; double v = q*cl_t->v[0] + tri_mintuv[1]*cl_t->v[1] + tri_mintuv[2]*cl_t->v[2]; Vec3f tcol; u = u*cl_t->image->get_width(); v = v*cl_t->image->get_height(); tcol = cl_t->image->get_color(floor(u),floor(v)); printf("the texture colors %f %f %f\n", tcol.x,tcol.y,tcol.z); color[0] = dot1*tcol.x + rind*ref_col[0] + tind*trans_col[0]; color[1] = dot1*tcol.y + rind*ref_col[1] + tind*trans_col[1]; color[2] = dot1*tcol.z + rind*ref_col[2] + tind*trans_col[2]; } } */ //Now add the specular highlights in. color[0] += sum_spec[0]; color[1] += sum_spec[1]; color[2] += sum_spec[2]; } //printf("."); //color[0] = 1.0; color[1] = 1.0; color[2] = 1.0; }else { color[0] = background[0]; color[1] = background[1]; color[2] = background[2]; if (snp == -121) { //the ray got close to a light. So return part of the color of the light. //printf("the ray hit a light\n"); if (cl_l->extended == false) { double temppwr; temppwr = pow(mindot,50); color[0] += temppwr*(cl_l->amb[0]);// + cl_l->dif[0] + cl_l->spec[0])/3.0; color[1] += temppwr*(cl_l->amb[1]);// + cl_l->dif[1] + cl_l->spec[1])/3.0; color[2] += temppwr*(cl_l->amb[2]);// + cl_l->dif[2] + cl_l->spec[2])/3.0; }else { //Before, I determined the added color as per specular highlighting. Now, //I will do a real gaussian weighting. double l[3]; l[0] = p[0] - cl_l->p[0]; l[1] = p[1] - cl_l->p[1]; l[2] = p[2] - cl_l->p[2]; t = Intersect_plane(p, v, cl_l->p, l); //Reusing variables am[0] = p[0]+t*v[0]; am[1] = p[1]+t*v[1]; am[2] = p[2]+t*v[2]; lmag = sqrt((am[0]-cl_l->p[0])*(am[0]-cl_l->p[0]) + (am[1]-cl_l->p[1])*(am[1]-cl_l->p[1]) + (am[2]-cl_l->p[2])*(am[2]-cl_l->p[2])); //lmag is now the planar distance from the origin (where the origin is the light). t = g2d(lmag, 0.0, 0.0,0.0, 2.0*cl_l->radius); t /= g2d(0.0, 0.0, 0.0,0.0, 2.0*cl_l->radius); t *= cl_l->amb[0]; //this is since all the intensities are set the same. //Now t is the additional light to be added to the returned color. color[0] += t; color[1] += t; color[2] += t; } } } for(i=0;i<3;i++) if (color[i] > 1.0) color[i] = 1.0; } void FrameBuffer::Test() { ///srand( time(NULL) ); if (1.0*rand()/RAND_MAX > .5) fb->Clear(red); else fb->Clear(blue); } void myDisplay(void) { // copy the framebuffer to the screen glDrawPixels(fb->width, fb->height, GL_RGB, GL_UNSIGNED_BYTE, fb->pix); glFlush(); } void myDraw() { int i, j, sami, samj, r, s; double v[3], imp[3]; //ray, center-of-proj, direction-of-view, focal-length, point on the image plane. double color[3]; register byte *p; int z = (int) supersampl, curint; double iz = 1.0/supersampl; double sxres = z*xres, syres = z; //printf("diffuse material info, %lf %lf %lf\n", current_surf->dif[0], current_surf->dif[1], current_surf->dif[2]); Pwfi = new Projection(dov, foc); //We're going to do jittered supersampling. With grid dimensions per pixel //defined with resolution at the top of this file, we make a larger than displayed //image and filter it down to the display size. This should alleviate some //jagginess. image_vert *I = new image_vert[xres*yres]; //In the final image, coords i,j map to j*xres + i image_vert *jI = new image_vert[z*xres*z*yres]; //The magic function converting a particular jittered sample x,y,s,t //(the s,t of pixel x,y) should be just (zx+s)*z*yres + zy+t; srand( time(NULL) ); for (i = 0; i < xres; i ++) { for (j = 0; j < yres; j ++) { for (sami = 0; sami < z; sami ++) { for (samj = 0; samj < z; samj ++) { //Randomly jitter the sample (i,j).(s,t). curint = z*(z*j+samj)*xres + z*i+sami; v[0] = 1.0*i + sami*iz + (double) (rand()/(4.0*RAND_MAX)); v[1] = 1.0*j + samj*iz + (double) (rand()/(4.0*RAND_MAX)); v[2] = 1.0; jI[curint].x = v[0]; jI[curint].y = v[1]; Pwfi->Convert(v); imp[0]=cop[0]+v[0]; imp[1]=cop[1]+v[1]; imp[2]=cop[2]+v[2]; color[0] = 0.0; color[1] = 0.0; color[2] = 0.0; Single_Raytrace(v, imp, color, 1, 1.0); //Now we have a color. store it for later filtering. jI[curint].r = color[0]; jI[curint].g = color[1]; jI[curint].b = color[2]; //This does all the work with, using the global scene variables to //fill leave the correct color in color. //p = fb->pix[j*xres + i]; //p[0] = (byte) 255*color[0]; p[1] = (byte) 255*color[1]; p[2] = (byte) 255*color[2]; } } } } /* //just spit out the image for debug. for (i = 0; i < xres; i ++) { for (j = 0; j < yres; j ++) { for (sami = 0; sami < z; sami ++) { for (samj = 0; samj < z; samj ++) { curint = z*(z*j+samj)*xres + z*i+sami; p = fb->pix[curint]; p[0] = (byte) 255*jI[curint].r; p[1] = (byte) 255*jI[curint].g; p[2] = (byte) 255*jI[curint].b; if (i == xres - 1 && j == yres - 1) { p[0] = (byte) 255; p[1] = (byte) 0; p[2] = (byte) 0; } if (i == 0 && j == 0) { p[2] = (byte) 255; p[1] = (byte) 0; p[0] = (byte) 0; } if (i == xres-1 && j == 0) { p[1] = (byte) 255; p[0] = (byte) 0; p[2] = (byte) 0; } } } } } */ double sum, g; int bi, bj, ci, cj; for (i = 0; i < xres; i ++) { for (j = 0; j < yres; j ++) { I[j*xres + i].r = 0.0; I[j*xres + i].g = 0.0; I[j*xres + i].b = 0.0; sum = 0; for (bi = -1; bi <= 1; bi ++) { for (bj = -1; bj <= 1; bj ++) { for (r = 0; r < z; r ++) { for (s = 0; s < z; s ++) { ci = i + bi; cj = j + bj; if (ci >= 0 && ci < xres && cj >= 0 && cj < yres) { curint = z*(z*cj+s)*xres + z*ci+r; g = g2d(jI[curint].x, jI[curint].y, i+.5,j+.5,sigma); sum += g; I[j*xres + i].r += jI[curint].r*g; I[j*xres + i].g += jI[curint].g*g; I[j*xres + i].b += jI[curint].b*g; } } } } } I[j*xres + i].r /= sum; I[j*xres + i].g /= sum; I[j*xres + i].b /= sum; } } //Now fill out the frame buffer. for (i = 0; i < xres; i ++) { for (j = 0; j < yres; j ++) { curint = j*xres + i; p = fb->pix[curint]; p[0] = (byte) 255*I[curint].r; p[1] = (byte) 255*I[curint].g; p[2] = (byte) 255*I[curint].b; } } myDisplay(); } void myInit() { // initialize GL stuff for speed //#if 1 // this makes quite a difference on the PC with software GL glEnable(GL_DITHER); glEnable(GL_BLEND); //#endif // SGI claims some of these might produce speedups for some architectures //#if 0 glDisable(GL_ALPHA_TEST); glDisable(GL_DEPTH_TEST); glDisable(GL_FOG); glDisable(GL_LIGHTING); glDisable(GL_LOGIC_OP); glDisable(GL_STENCIL_TEST); glDisable(GL_TEXTURE_1D); glDisable(GL_TEXTURE_2D); glPixelTransferi(GL_MAP_COLOR, GL_FALSE); glPixelTransferi(GL_RED_SCALE, 1); glPixelTransferi(GL_RED_BIAS, 0); glPixelTransferi(GL_GREEN_SCALE, 1); glPixelTransferi(GL_GREEN_BIAS, 0); glPixelTransferi(GL_BLUE_SCALE, 1); glPixelTransferi(GL_BLUE_BIAS, 0); glPixelTransferi(GL_ALPHA_SCALE, 1); glPixelTransferi(GL_ALPHA_BIAS, 0); glShadeModel (GL_FLAT); //#endif } void KeyInputHandler(unsigned char Key, int x, int y) { switch(Key) { case 27: exit(0); default: myDraw(); break; }; } void yyerror(char *s){ fprintf(stderr, "Error: %s\n", s); } extern "C" { void EyePoint(double x, double y, double z) { //printf("eyep %f %f %f\n", x, y, z); cop[0] = x; cop[1] = y; cop[2] = z; } void LookAt(double x, double y, double z) { //printf("lookp %f %f %f\n", x, y, z); //printf("\tLOOKAT must be defined AFTER EyePoint\n"); dov[0] = x-cop[0]; dov[1] = y-cop[1]; dov[2] = z-cop[2]; } void UpVector(double x, double y, double z) { //printf("up %f %f %f\n", x, y, z); up_dir[0] = x; up_dir[1] = y; up_dir[2] = z; } void FieldOfView(double angle) { //printf("fov %f\n", angle); //I will now recompute this to the desired focal length. foc = .018/tan(angle*3.14159265/360); } void Background(double r, double g, double b) { //printf("background %f %f %f\n", r, g, b); background[0] = r; background[1] = g; background[2] = b; //printf("colored the background.\n"); } void PointLight(double intensity, double x, double y, double z) { int i; //printf("light %f point %f %f %f\n", intensity, x, y, z); if (light_head == NULL) { light_head = new light(x,y,z); for (i = 0; i < 3; i++) { light_head->amb[i] = intensity; light_head->dif[i] = intensity; light_head->spec[i] = intensity; } light_head->extended = false; llast = light_head; }else { curl = new light(x,y,z); for (i = 0; i < 3; i++) { curl->amb[i] = intensity; curl->dif[i] = intensity; curl->spec[i] = intensity; } curl->extended = false; llast->next = curl; llast = curl; } } void ExtendedLight(double intensity, double radius, double x, double y, double z) { int i; //printf("light %f point %f %f %f\n", intensity, x, y, z); if (light_head == NULL) { light_head = new light(x,y,z); for (i = 0; i < 3; i++) { light_head->amb[i] = intensity; light_head->dif[i] = intensity; light_head->spec[i] = intensity; } light_head->extended = true; light_head->radius = radius; llast = light_head; }else { curl = new light(x,y,z); for (i = 0; i < 3; i++) { curl->amb[i] = intensity; curl->dif[i] = intensity; curl->spec[i] = intensity; } curl->extended = true; curl->radius = radius; llast->next = curl; llast = curl; } //printf("light %f extended %f %f %f %f\n", intensity, radius, x, y, z); } void Surface(char *s) { int i; //printf("surface %s\n", s); //SurfaceMap[s] = new surfmat(); current_surf = &SurfaceMap[s]; free(s); for (i = 0; i < 3; i ++) { current_surf->amb[i] = 0.0; current_surf->dif[i] = 0.0; current_surf->spec[i] = 0.0; } current_surf->refl = .0; current_surf->specpow = 32.0; current_surf->transp = .0; current_surf->index = 1.0; current_surf->sigma = .25; } void Applysurf() { //printf("applysurf\n"); } void Ambient(double r, double g, double b) { //printf("ambient %f %f %f\n", r, g, b); current_surf->amb[0] = r; current_surf->amb[1] = g; current_surf->amb[2] = b; } void Diffuse(double r, double g, double b) { //printf("diffuse %f %f %f\n", r, g, b); current_surf->dif[0] = r; current_surf->dif[1] = g; current_surf->dif[2] = b; } void Specular(double r, double g, double b) { //printf("specular %f %f %f\n", r, g, b); current_surf->spec[0] = r; current_surf->spec[1] = g; current_surf->spec[2] = b; } void Reflective(int reflect){ //if(reflect != 0) //printf("reflect 1.0\n"); // else //printf("reflect 0.0\n"); } void Reflect(double reflect) { //printf("reflect %f\n", reflect); current_surf->refl = reflect; } void Specpow(double p) { //printf("specpow %f\n", p); current_surf->specpow = p; } void Transparent(int trans){ //if(trans != 0) //printf("transparency 1.0\n"); // else //printf("transparency 0.0\n"); } void Transp(double trans) { //printf("transp %f\n", trans); current_surf->transp = trans; } void Index(double index) { //printf("index %f\n", index); current_surf->index = index; } void Plane(double point_x, double point_y, double point_z, double normal_x, double normal_y, double normal_z) { int i; //printf("plane %f %f %f %f %f %f\n", point_x, point_y, point_z, // normal_x, normal_y, normal_z); //printf("I have supported planes without material properties as white.\n"); if (plane_head == NULL) { plane_head = new plane(point_x,point_y,point_z,normal_x,normal_y,normal_z); for (i = 0; i < 3; i ++) { plane_head->amb[i] = .2; plane_head->dif[i] = .5; plane_head->spec[i] = .4; } plane_head->specpow = 32.0; plane_head->refl = .0; plane_head->transp = .0; plane_head->index = 1.0; plane_head->sigma = .25; curp = plane_head; plast = plane_head; }else { curp = new plane(point_x,point_y,point_z,normal_x,normal_y,normal_z); for (i = 0; i < 3; i ++) { curp->amb[i] = .2; curp->dif[i] = .5; curp->spec[i] = .4; } curp->specpow = 32.0; curp->refl = .0; curp->transp = .0; curp->index = 1.0; curp->sigma = .25; plast->next = curp; plast = curp; } prev_obj = 1; } void PlaneS(char *surface, double point_x, double point_y, double point_z, double normal_x, double normal_y, double normal_z) { int i; //printf("plane %s %f %f %f %f %f %f\n", surface, point_x, point_y, point_z, // normal_x, normal_y, normal_z); //pick up the surface info. asurf = &SurfaceMap[surface]; if (plane_head == NULL) { plane_head = new plane(point_x,point_y,point_z,normal_x,normal_y,normal_z); for (i = 0; i < 3; i ++) { plane_head->amb[i] = asurf->amb[i]; plane_head->dif[i] = asurf->dif[i]; plane_head->spec[i] = asurf->spec[i]; } plane_head->specpow = asurf->specpow; plane_head->refl = asurf->refl; plane_head->transp = asurf->transp; plane_head->index = asurf->index; plane_head->sigma = asurf->sigma; curp = plane_head; plast = plane_head; }else { curp = new plane(point_x,point_y,point_z,normal_x,normal_y,normal_z); for (i = 0; i < 3; i ++) { curp->amb[i] = asurf->amb[i]; curp->dif[i] = asurf->dif[i]; curp->spec[i] = asurf->spec[i]; } curp->specpow = asurf->specpow; curp->refl = asurf->refl; curp->transp = asurf->transp; curp->index = asurf->index; curp->sigma = asurf->sigma; plast->next = curp; plast = curp; } prev_obj = 1; } void Sphere(double radius, double x, double y, double z) { int i; //printf("sphere %f %f %f %f\n", radius, x, y, z); //printf("\tSPHERES without material properties are considered white.\n"); if (sphere_head == NULL) { sphere_head = new sphere(radius,x,y,z); for (i = 0; i < 3; i ++) { sphere_head->amb[i] = .3; sphere_head->dif[i] = .5; sphere_head->spec[i] = .4; } sphere_head->specpow = 64; sphere_head->refl = .0; sphere_head->transp = .0; sphere_head->index = 1.0; sphere_head->sigma = .25; curs = sphere_head; blast = sphere_head; }else { curs = new sphere(radius,x,y,z); for (i = 0; i < 3; i ++) { curs->amb[i] = .3; curs->dif[i] = .5; curs->spec[i] = .4; } curs->specpow = 64; curs->refl = .0; curs->transp = .0; curs->index = 1.0; curs->sigma = .25; blast->next = curs; blast = curs; } prev_obj = -1; } void SphereS(char *surface, double radius, double x, double y, double z) { int i; //printf("sphere %s %f %f %f %f\n", surface, radius, x, y, z); asurf = &SurfaceMap[surface]; if (sphere_head == NULL) { sphere_head = new sphere(radius,x,y,z); for (i = 0; i < 3; i ++) { sphere_head->amb[i] = asurf->amb[i]; sphere_head->dif[i] = asurf->dif[i]; sphere_head->spec[i] = asurf->spec[i]; } sphere_head->specpow = asurf->specpow; sphere_head->refl = asurf->refl; sphere_head->transp = asurf->transp; sphere_head->index = asurf->index; sphere_head->sigma = asurf->sigma; curs = sphere_head; blast = sphere_head; }else { curs = new sphere(radius,x,y,z); for (i = 0; i < 3; i ++) { curs->amb[i] = asurf->amb[i]; curs->dif[i] = asurf->dif[i]; curs->spec[i] = asurf->spec[i]; } curs->specpow = asurf->specpow; curs->refl = asurf->refl; curs->transp = asurf->transp; curs->index = asurf->index; curs->sigma = asurf->sigma; blast->next = curs; blast = curs; } prev_obj = -1; free(surface); } void Triangle(double v1x, double v1y, double v1z, double v2x, double v2y, double v2z, double v3x, double v3y, double v3z) { int i, q = 0; double norm; //printf("triangle %f %f %f %f %f %f %f %f %f\n", // v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z); //printf("\tTRIANGLES without material properties are white.\n"); if (triangle_head == NULL) { triangle_head = new triangle(v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z); curt = triangle_head; q = 1; }else curt = new triangle(v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z); for (i = 0; i < 3; i ++) { curt->amb[i] = .3; curt->dif[i] = .5; curt->spec[i] = .4; } //Get the normal. curt->n0[0] = (v2y-v1y)*(v3z-v1z) - (v3y-v1y)*(v2z-v1z); curt->n0[1] = (v3x-v1x)*(v2z-v1z) - (v2x-v1x)*(v3z-v1z); curt->n0[2] = (v2x-v1x)*(v3y-v1y) - (v3x-v1x)*(v2y-v1y); norm = sqrt(curt->n0[0]*curt->n0[0] + curt->n0[1]*curt->n0[1] + curt->n0[2]*curt->n0[2]); curt->n0[0] = curt->n0[0]/norm; curt->n0[1] = curt->n0[1]/norm; curt->n0[2] = curt->n0[2]/norm; curt->specpow = 64; curt->refl = .0; curt->transp = .0; curt->index = 1.0; curt->flat_shaded = 1; curt->sigma = .25; if (q) tlast = curt; else { tlast->next = curt; tlast = curt; } prev_obj = 2; } void TriangleS(char *surface, double v1x, double v1y, double v1z, double v2x, double v2y, double v2z, double v3x, double v3y, double v3z) { int i, q = 0; double norm; //printf("triangle %s %f %f %f %f %f %f %f %f %f\n", surface, // v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z); asurf = &SurfaceMap[surface]; if (triangle_head == NULL) { triangle_head = new triangle(v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z); curt = triangle_head; q = 1; }else curt = new triangle(v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z); for (i = 0; i < 3; i ++) { curt->amb[i] = asurf->amb[i]; curt->dif[i] = asurf->dif[i]; curt->spec[i] = asurf->spec[i]; } //Get the normal. curt->n0[0] = (v2y-v1y)*(v3z-v1z) - (v3y-v1y)*(v2z-v1z); curt->n0[1] = (v3x-v1x)*(v2z-v1z) - (v2x-v1x)*(v3z-v1z); curt->n0[2] = (v2x-v1x)*(v3y-v1y) - (v3x-v1x)*(v2y-v1y); norm = sqrt(curt->n0[0]*curt->n0[0] + curt->n0[1]*curt->n0[1] + curt->n0[2]*curt->n0[2]); curt->n0[0] = curt->n0[0]/norm; curt->n0[1] = curt->n0[1]/norm; curt->n0[2] = curt->n0[2]/norm; curt->specpow = asurf->specpow; curt->refl = asurf->refl; curt->transp = asurf->transp; curt->index = asurf->index; curt->flat_shaded = 1; curt->sigma = asurf->sigma; if (q) tlast = curt; else { tlast->next = curt; tlast = curt; } prev_obj = 2; free(surface); } //Do this for texture mapping void TriangleUVS(char *surface, double v1x, double v1y, double v1z, double v1u, double v1v, double v2x, double v2y, double v2z, double v2u, double v2v, double v3x, double v3y, double v3z, double v3u, double v3v) { int i, q = 0; double norm; //printf("triangle %s %f %f %f %f %f %f %f %f %f\n", surface, // v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z); asurf = &SurfaceMap[surface]; if (triangle_head == NULL) { triangle_head = new triangle(v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z); curt = triangle_head; q = 1; }else curt = new triangle(v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z); for (i = 0; i < 3; i ++) { curt->amb[i] = asurf->amb[i]; curt->dif[i] = asurf->dif[i]; curt->spec[i] = asurf->spec[i]; } //Get the normal. curt->n0[0] = (v2y-v1y)*(v3z-v1z) - (v3y-v1y)*(v2z-v1z); curt->n0[1] = (v3x-v1x)*(v2z-v1z) - (v2x-v1x)*(v3z-v1z); curt->n0[2] = (v2x-v1x)*(v3y-v1y) - (v3x-v1x)*(v2y-v1y); norm = sqrt(curt->n0[0]*curt->n0[0] + curt->n0[1]*curt->n0[1] + curt->n0[2]*curt->n0[2]); curt->n0[0] = curt->n0[0]/norm; curt->n0[1] = curt->n0[1]/norm; curt->n0[2] = curt->n0[2]/norm; curt->specpow = asurf->specpow; curt->refl = asurf->refl; curt->transp = asurf->transp; curt->index = asurf->index; curt->flat_shaded = 1; curt->sigma = asurf->sigma; curt->textured = 1; if (q) tlast = curt; else { tlast->next = curt; tlast = curt; } curt->u[0] = v1u; curt->u[1] = v2u; curt->u[2] = v3u; curt->v[0] = v1v; curt->v[1] = v2v; curt->v[2] = v3v; prev_obj = 2; //printf("triangleuv %s %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n", surface, // v1x, v1y, v1z, v1u, v1v, // v2x, v2y, v2z, v2u, v2v, // v3x, v3y, v3z, v3u, v3v); free(surface); } //More texture mapping. extern void TriangleUV(double v1x, double v1y, double v1z, double v1u, double v1v, double v2x, double v2y, double v2z, double v2u, double v2v, double v3x, double v3y, double v3z, double v3u, double v3v) { int i, q = 0; double norm; //printf("triangle %f %f %f %f %f %f %f %f %f\n", // v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z); //printf("\tTRIANGLES without material properties are white.\n"); if (triangle_head == NULL) { triangle_head = new triangle(v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z); curt = triangle_head; q = 1; }else curt = new triangle(v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z); for (i = 0; i < 3; i ++) { curt->amb[i] = .3; curt->dif[i] = .6; curt->spec[i] = .4; } //Get the normal. curt->n0[0] = (v2y-v1y)*(v3z-v1z) - (v3y-v1y)*(v2z-v1z); curt->n0[1] = (v3x-v1x)*(v2z-v1z) - (v2x-v1x)*(v3z-v1z); curt->n0[2] = (v2x-v1x)*(v3y-v1y) - (v3x-v1x)*(v2y-v1y); norm = sqrt(curt->n0[0]*curt->n0[0] + curt->n0[1]*curt->n0[1] + curt->n0[2]*curt->n0[2]); curt->n0[0] = curt->n0[0]/norm; curt->n0[1] = curt->n0[1]/norm; curt->n0[2] = curt->n0[2]/norm; curt->specpow = 64; curt->refl = .0; curt->transp = .0; curt->index = 1.0; curt->flat_shaded = 1; curt->sigma = .25; curt->textured = 1; if (q) tlast = curt; else { tlast->next = curt; tlast = curt; } curt->u[0] = v1u; curt->u[1] = v2u; curt->u[2] = v3u; curt->v[0] = v1v; curt->v[1] = v2v; curt->v[2] = v3v; prev_obj = 2; //printf("triangleuv %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n", // v1x, v1y, v1z, v1u, v1v, // v2x, v2y, v2z, v2u, v2v, // v3x, v3y, v3z, v3u, v3v); } void TriangleN(double v1x, double v1y, double v1z, double n1x, double n1y, double n1z, double v2x, double v2y, double v2z, double n2x, double n2y, double n2z, double v3x, double v3y, double v3z, double n3x, double n3y, double n3z) { int i, q = 0; //printf("triangle %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n", // v1x, v1y, v1z, n1x, n1y, n1z, // v2x, v2y, v2z, n2x, n2y, n2z, // v3x, v3y, v3z, n3x, n3y, n3z); //printf("\tTRIANGLES without material properties are white.\n"); if (triangle_head == NULL) { triangle_head = new triangle(v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z); curt = triangle_head; q = 1; }else curt = new triangle(v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z); for (i = 0; i < 3; i ++) { curt->amb[i] = .3; curt->dif[i] = .5; curt->spec[i] = .4; } //Get the normals curt->n0[0] = n1x; curt->n0[1] = n1y; curt->n0[2] = n1z; curt->n1[0] = n2x; curt->n1[1] = n2y; curt->n1[2] = n2z; curt->n2[0] = n3x; curt->n2[1] = n3y; curt->n2[2] = n3z; curt->specpow = 64; curt->refl = .0; curt->transp = .0; curt->index = 1.0; curt->flat_shaded = 0; curt->sigma = .25; if (q) tlast = curt; else { tlast->next = curt; tlast = curt; } prev_obj = 2; } void TriangleNS(char *surface, double v1x, double v1y, double v1z, double n1x, double n1y, double n1z, double v2x, double v2y, double v2z, double n2x, double n2y, double n2z, double v3x, double v3y, double v3z, double n3x, double n3y, double n3z) { int i, q = 0; //printf("triangle %s %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n", surface, // v1x, v1y, v1z, n1x, n1y, n1z, // v2x, v2y, v2z, n2x, n2y, n2z, // v3x, v3y, v3z, n3x, n3y, n3z); asurf = &SurfaceMap[surface]; if (triangle_head == NULL) { triangle_head = new triangle(v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z); curt = triangle_head; q = 1; }else curt = new triangle(v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z); for (i = 0; i < 3; i ++) { curt->amb[i] = asurf->amb[i]; curt->dif[i] = asurf->dif[i]; curt->spec[i] = asurf->spec[i]; } //Get the normal. curt->n0[0] = n1x; curt->n0[1] = n1y; curt->n0[2] = n1z; curt->n1[0] = n2x; curt->n1[1] = n2y; curt->n1[2] = n2z; curt->n2[0] = n3x; curt->n2[1] = n3y; curt->n2[2] = n3z; curt->specpow = asurf->specpow; curt->refl = asurf->refl; curt->transp = asurf->transp; curt->index = asurf->index; curt->flat_shaded = 0; curt->sigma = asurf->sigma; if (q) tlast = curt; else { tlast->next = curt; tlast = curt; } prev_obj = 2; free(surface); } void Translate(double x, double y, double z) { printf("translate %f %f %f\n", x, y, z); } void Rotate(double x, double y, double z, double angle) { printf("rotate %f %f %f %f\n", x, y, z, angle); } void Scale(double x, double y, double z) { printf("scale %f %f %f\n", x, y, z); } void Name(char *s) { printf("name %s list\n", s); free(s); } void End() { printf("end\n"); } void Object(char *name) { printf("object %s\n", name); free(name); } void ObjectS(char *s, char *name) { printf("object %s %s\n", s, name); free(s); free(name); } void Screen(int x, int y) { printf("screen %d %d\n", x, y); } void Texture(char *s) { printf("texture image %s\n", s); animage = &ImageMap[s]; animage->ReadTGA(s); if (prev_obj == -1) { curs->image = animage; }else if (prev_obj == 1) { curp->image = animage; }else if (prev_obj == 2) { curt->image = animage; }else { printf("Texture provided before object.\n"); } } }; void main(int argc, char* argv[]) { ifstream fin; char *filename = new char[80]; rayParser parser("model1.txt"); fb = new FrameBuffer(xres, yres); glutInitDisplayMode(GLUT_RGB); glutInitWindowPosition(50, 50); glutInitWindowSize(xres, yres); glutCreateWindow("COMP 236 - ASSN2"); glutKeyboardFunc(KeyInputHandler); glutDisplayFunc(myDisplay); myInit(); printf("Parsing input file...\n"); parser.Parse(); printf("Type any character to compute an image.\n"); glutMainLoop(); }