CMPS-3480 Computer Graphics
Lab-10

Overview:

Start:

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
Above the trace function... --------------------------- Flt my_noise2(Vec vec) { extern float noise2(float vec[2]); float v[2] = { (float)vec.x, (float)vec.y }; return (Flt)noise2(v); } Flt my_noise3(Vec vec) { extern float noise3(float vec[3]); float v[3] = { (float)vec.x, (float)vec.y, (float)vec.z }; return (Flt)noise3(v); } Inside trace function... ------------------------ if (o->perlin3) { float sz = 200.0f; float size = sz; Vec col; while (size >= 1.0f) { Vec vec(closehit.p); vec.add(4000.0); //octave vec.scale(1.0/size); Flt mag = my_noise3(vec); //we have the magnitude mag = mag + 0.6; mag = mag / 1.2; mag = mag * size; col.add(mag); size = size / 2.0f; } col.scale(1.0f/sz); if (o->marble3) { col.x = fabs(sin(col.x * PI)); col.y = fabs(sin(col.y * PI)); col.z = fabs(sin(col.z * PI)); } closehit.color.copy(col); } if (o->perlin2) { float size = 200.0f; Vec col; while (size >= 1.0f) { Vec vec(closehit.p); vec.add(10000.0); vec.scale(1.0/size); Flt mag = my_noise2(vec); //we have the magnitude mag = mag + 0.6; mag = mag / 1.2; mag = mag * size; col.add(mag); size = size / 2.0f; } col.scale(1.0f/300.0f); if (o->marble2) { col.x = fabs(sin(col.x * PI)); col.y = fabs(sin(col.y * PI)); col.z = fabs(sin(col.z * PI)); } closehit.color.copy(col); } Inside the Object class... -------------------------- New object variables for 2D and 3D perlin noise. //flags int perlin2, perlin3; int marble2, marble3; In the Vec class... ------------------- void add(Flt a) { x = x + a; y = y + a; z = z + a; }

Triangles

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;

Perlin Vase Object
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;



What to turn in...
Your instructor will find your work out on Odin!