CMPS-3480 Computer Graphics
Lab-10
Overview:
1. Log into Odin 2. Change to your /3480/a folder. Copy these files now... cp ../9/lab9.cpp lab10.cpp cp ../9/Makefile . We will start by programming together. goal #1 Perlin noise with turbulence Multiple octaves goal #2 Marble texture
new code for turbulence and marble ----------------------------------
2D noise on a disc |
3D marble on a sphere |
Rendered in lab10.cpp
a triangle - code is below 3480 version of Ken Perlin's vase. It needs marble texture, handles, and Phong shading. This can be a project for one or two students. new code for triangle rendering ------------------------------- in enum ------- OBJ_TYPE_TRI in Object class --------------- Vec tri[3]; a new function -------------- void getTriangleNormal(Vec tri[3], Vec &norm) { Vec v0,v1; v0.diff(tri[1], tri[0]); v1.diff(tri[2], tri[0]); norm.crossProduct(v0, v1); norm.normalize(); } in check_keys to define a triangle ---------------------------------- obj[nobjects].type = OBJ_TYPE_TRI; obj[nobjects].tri[0].make(-90.0, 0.0, 180.0); obj[nobjects].tri[1].make( 0.0, 0.0, 200.0); obj[nobjects].tri[2].make(-45.0, 120.0, 180.0); getTriangleNormal(obj[nobjects].tri, obj[nobjects].normal); obj[nobjects].color[0] = 50; obj[nobjects].color[1] = 250; obj[nobjects].color[2] = 100; ++nobjects; a new function -------------- int rayPlaneIntersect(Vec center, Vec normal, Ray *ray, Hit *hit) { Vec v0; v0.diff(ray->o, center); Flt dot1 = v0.dotProduct(normal); if (dot1 == 0.0) return 0; Flt dot2 = ray->d.dotProduct(normal); if (dot2 == 0.0) return 0; hit->t = -dot1 / dot2; if (hit->t < 0.0) return 0; hit->p.x = ray->o.x + hit->t * ray->d.x; hit->p.y = ray->o.y + hit->t * ray->d.y; hit->p.z = ray->o.z + hit->t * ray->d.z; return 1; } a new function -------------- bool pointInTriangle(Vec tri[3], Vec p, Flt *u, Flt *v) { //source: http://blogs.msdn.com/b/rezanour/archive/2011/08/07/ // //This function determines if point p is inside triangle tri. // step 1: 3D half-space tests // step 2: find barycentric coordinates // Vec cross0, cross1, cross2; Vec ba, ca, pa; ba.diff(tri[1], tri[0]); ca.diff(tri[2], tri[0]); pa.diff(p, tri[0]); //This is a half-space test cross1.crossProduct(ca, pa); cross0.crossProduct(ca, ba); if (cross0.dotProduct(cross1) < 0.0) return false; //This is a half-space test cross2.crossProduct(ba,pa); cross0.crossProduct(ba,ca); if (cross0.dotProduct(cross2) < 0.0) return false; //Point is within 2 half-spaces //Get area proportions //Area is actually length/2, but we just care about the relationship. Flt areaABC = cross0.len(); Flt areaV = cross1.len(); Flt areaU = cross2.len(); *u = areaU / areaABC; *v = areaV / areaABC; //return true if valid barycentric coordinates. return (*u >= 0.0 && *v >= 0.0 && *u + *v <= 1.0); } a new function -------------- int rayTriangleIntersect(Object *o, Ray *ray, Hit *hit) { if (rayPlaneIntersect(o->tri[0], o->normal, ray, hit)) { Flt u,v; if (pointInTriangle(o->tri, hit->p, &u, &v)) { //Flt w = 1.0 - u - v; //if (o->surface == SURF_BARY) { // o->color[0] = u; // o->color[1] = v; // o->color[2] = w; //} return 1; } } return 0; } in the trace function --------------------- case OBJ_TYPE_TRI: if (rayTriangleIntersect(&obj[k], ray, &hit)) { if (hit.t < closehit.t) { closehit.t = hit.t; closehit.p.copy(hit.p); closehit.color.copy(obj[k].color); closehit.norm.copy(obj[k].normal); g.hit_idx = k; idx = k; } } break;
Sketch your design on paper. The vase is made out of triangles only. Cylinders are stacked up with different radii. Here is the code... Add this macro to your program. #define rnd() ((Flt)rand() / (Flt)RAND_MAX) Add this variable to Global, to turn specular highlights on/off. int hspecular; Case #8 in check_keys case XK_8: //floor nobjects = 0; obj[nobjects].type = OBJ_TYPE_DISC; obj[nobjects].pos.make(0.0, 0.0, 0.0); obj[nobjects].normal.make(0.0, 1.0, 0.0); obj[nobjects].normal.normalize(); obj[nobjects].radius = 2000.0; obj[nobjects].checker = 0; obj[nobjects].color[0] = 250; obj[nobjects].color[1] = 250; obj[nobjects].color[2] = 250; obj[nobjects].stexture = 0; obj[nobjects].specular = 1; obj[nobjects].checker = 1; obj[nobjects].checker_size = 127.0; obj[nobjects].checker_tex[0] = -1; obj[nobjects].checker_tex[1] = -1; obj[nobjects].checker_color[0].make(.2, .2, .7); obj[nobjects].checker_color[1].make(.2, .2, .4); ++nobjects; // //stars for (int i=0; i<100; i++) { obj[nobjects].type = OBJ_TYPE_DISC; obj[nobjects].pos.make( rnd()*2000.0-1000.0, rnd()*1500.0, -2000); obj[nobjects].normal.make(0.0, 0.0, 1.0); obj[nobjects].normal.normalize(); obj[nobjects].radius = rnd() * 3.0 + 0.5; obj[nobjects].checker = 0; obj[nobjects].color[0] = rnd() * 50.0 + 200.0; obj[nobjects].color[1] = rnd() * 50.0 + 200.0; obj[nobjects].color[2] = rnd() * 50.0 + 200.0; obj[nobjects].stexture = 0; obj[nobjects].specular = 0; obj[nobjects].checker = 0; ++nobjects; } // //build perlin vase { //points on a circle int n = 27; Flt angle = 0.0; Flt inc = (PI * 2.0) / (Flt)n; Flt radii[13] = { 3,3,1,1,3,4.5,5,5, 2, 1.5, 2, 3, 3 }; Flt height[13] = { 0,1,2,3,5,7, 9,11,12,13.5,15,16,17 }; Vec pts[40]; for (int i=0; i<n; i++) { pts[i].x = cos(angle); pts[i].y = 0.0; pts[i].z = sin(angle); angle += inc; } //13 levels //13 levels Flt vsize = 20.0; for (int i=0; i<12; i++) { for (int j=0; j<n; j++) { int k = (j+1) % n; obj[nobjects].type = OBJ_TYPE_TRI; //across 2 then up obj[nobjects].tri[0].copy(pts[j]); obj[nobjects].tri[2].copy(pts[k]); obj[nobjects].tri[1].copy(pts[k]); // obj[nobjects].tri[0].scale(radii[i]*vsize); obj[nobjects].tri[2].scale(radii[i]*vsize); obj[nobjects].tri[1].scale(radii[i+1]*vsize); obj[nobjects].tri[0].y = height[i]*vsize; obj[nobjects].tri[2].y = height[i]*vsize; obj[nobjects].tri[1].y = height[i+1]*vsize; // getTriangleNormal(obj[nobjects].tri, obj[nobjects].normal); obj[nobjects].color[0] = 30; obj[nobjects].color[1] = 110; obj[nobjects].color[2] = 40; obj[nobjects].specular = 1; obj[nobjects].hspecular = 0; obj[nobjects].stexture = 0; ++nobjects; //up diagonal then back obj[nobjects].type = OBJ_TYPE_TRI; obj[nobjects].tri[0].copy(pts[j]); obj[nobjects].tri[2].copy(pts[k]); obj[nobjects].tri[1].copy(pts[j]); // obj[nobjects].tri[0].scale(radii[i]*vsize); obj[nobjects].tri[2].scale(radii[i+1]*vsize); obj[nobjects].tri[1].scale(radii[i+1]*vsize); obj[nobjects].tri[0].y = height[i]*vsize; obj[nobjects].tri[2].y = height[i+1]*vsize; obj[nobjects].tri[1].y = height[i+1]*vsize; // getTriangleNormal(obj[nobjects].tri, obj[nobjects].normal); obj[nobjects].color[0] = 30; obj[nobjects].color[1] = 110; obj[nobjects].color[2] = 40; obj[nobjects].specular = 1; obj[nobjects].hspecular = 0; obj[nobjects].stexture = 0; ++nobjects; } } } // g.light_pos.make(-200, 500, 600); g.ambient.make(.4, .4, .4); g.diffuse.make(.7, .7, .7); g.background_black = 1; // cam.pos.make(-30.0, 100.0, 900.0); cam.at.make(0.0, 180.0, 0.0); cam.up.make(0.0, 1.0, 0.0); cam.ang = 40.0; break;
Your instructor will find your work out on Odin!