Week 10 Assignment

Matt Parker

 

Problem 1.Add the OpenGL lighting code to your project. This code may be placed in the init() function or in the displayFunc(), if you want to move or change the light.


void displayFunc(void) {
	
	glColor3f(1, 1, 1);
	
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	Mesh myMesh(20,20,5);
	myMesh.makeSphere();
	
	if ( whichProblem==1 ){
		myMesh.drawSolid1();
	} else if ( whichProblem==2 ){
		myMesh.drawSolid2();
	} else if ( whichProblem==3 ){
		myMesh = Mesh(100,100,5);
		Circle3d circ1 = Circle3d(300,100,Vec3d(0,0,0));
		Circle3d circ2 = Circle3d(100,100,Vec3d(0,0,0));
		
		myMesh.makeExtrusionOnPath(circ1.getVecs(), circ2.getVecs());
	} else if ( whichProblem==5 ){
		center = velocity(center);
		glRectf(center.x-5, center.y-5, center.x+5, center.y+5);
	} else if ( whichProblem==4 ){
		Circle3d circ1 = Circle3d(300,20,Vec3d(0,0,0));
		Circle3d circ2 = Circle3d(100,20,Vec3d(0,0,0));
		
		float scale[20] = 
				{0.1, 0.2, 0.3, 0.4, 0.5,
				0.6, 0.7, 0.8, 0.9, 1.0,
				1.1, 1.2, 1.3, 1.4, 1.5,
				1.6, 1.7, 1.8, 1.9, 2.0};
		
		myMesh.makeScaledExtrusionOnPath(circ1.getVecs(), circ2.getVecs(), scale);

	} else if ( whichProblem==5 ){
//			pts
	Vec3d point1(-100, -100, 0);
	Vec3d point2(100, 100, 0);
	Vec3d point3(100, 100, mouseX);
	
//			vecs
	Vec3d vec1 = point2 - point1;
	Vec3d vec2 = point3 - point1;
	Vec3d normal = vec1.crossProduct(vec2);
	
	normal.normalize();
	
	Vec3d light(0,-1, 0);
	
//			computer shading
	float shade = light.dotProduct(normal);
	
	glColor3f(shade, shade, shade);
	glBegin(GL_TRIANGLES);

	drawVertex(point1);
	drawVertex(point2);
	drawVertex(point3);
	
	glEnd();
	
	}
	
	if(cameraX >= 300)
		incr = -0.1;
	else if (cameraX < 0)
		incr = 0.1;
	
	cameraX += incr;
	
	glutPostRedisplay();
	glutSwapBuffers();
}


void init ( GLvoid )
{
glShadeModel( GL_SMOOTH );
glClearColor( 0.0, 0.0, 0.0, 0.0 );
glEnable ( GL_COLOR_MATERIAL );
glEnable( GL_BLEND );
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);

//turn on gl lighting
glEnable( GL_LIGHTING);

//turn on first light
glEnable( GL_LIGHT0);

//set up lighting parameters
float ambientLight[4] = {0.0, 0.2, 0.2, 1.0};
float diffuseLight[4] = {0.8, 0.8, 0.0, 1.0};
float specularLight[4] = {0.8, 0.8, 0.8, 1.0};
float lightPosition[4] = {-500, -500, 500, 1.0};

glLightfv( GL_LIGHT0, GL_AMBIENT, ambientLight);
glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuseLight);
glLightfv( GL_LIGHT0, GL_SPECULAR, specularLight);
glLightfv( GL_LIGHT0, GL_POSITION, lightPosition);

// enable glColor3f to affect material color
glEnable( GL_COLOR_MATERIAL );
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
}
 

 

Problem 2. Add a function called calculateNormal() to the Mesh class that calculates and stores a normal vector for every point in the mesh. This normal vector should be based upon the normal vectors of the faces surrounding the point.



void Mesh::calcNormals(){

	for(int x = 0; x < width - 1; x++){
		for(int y = 0; y < height - 1; y++){
			
			GridPoint pt1 = grid[x][y];
			GridPoint pt2 = grid[x + 1][y];
			GridPoint pt3 = grid[x][y + 1];
			
			Vec3d vec1 = pt2.point - pt1.point;
			Vec3d vec2 = pt3.point - pt1.point;
			
			Vec3d normal = vec1.crossProduct(vec2);
			normal.normalize();
			
			pt1.normal = pt1.normal + normal;
			pt2.normal = pt2.normal + normal;
			pt3.normal = pt3.normal + normal;
			
			pt1.normal.normalize();
			pt2.normal.normalize();
			pt3.normal.normalize();
			
			grid[x][y]     = pt1;
			grid[x + 1][y] = pt2;
			grid[x][y + 1] = pt3;
			
		}
	}
				
 

 

Problem 3. Add a function called drawShadedSolid2 that draws the mesh as a solid form and utilizes the per-point normal vectors. This function does not need to calculate the shading, since that is now done by the OpenGL lighting system.

void Mesh::drawSolid2(){

	calcNormals();
	
	Vec3d light(0, 0, 1000);
	light.normalize();
	
	for(int x = 0; x < width - 1; x++){
		for(int y = 0; y < height - 1; y++){
			
			Vec3d vec1 = grid[x + 1][y].point - grid[x][y].point;
			Vec3d vec2 = grid[x][y + 1].point - grid[x][y].point;
			
			Vec3d normal = vec1.crossProduct(vec2);
			normal.normalize();
			
			glBegin(GL_TRIANGLE_STRIP);
			grid[x][y].normal.setNormal();
			grid[x][y].point.drawVertex();
			grid[x + 1][y].normal.setNormal();
			grid[x + 1][y].point.drawVertex();
			grid[x][y + 1].normal.setNormal();
			grid[x][y + 1].point.drawVertex();
			glEnd();
			
			vec1 = grid[x][y + 1].point - grid[x + 1][y + 1].point;
			vec2 = grid[x + 1][y].point - grid[x + 1][y + 1].point;
			
			normal = vec1.crossProduct(vec2);
			normal.normalize();
			
			glBegin(GL_TRIANGLE_STRIP);
			grid[x + 1][y + 1].normal.setNormal();
			grid[x + 1][y + 1].point.drawVertex();
			grid[x][y + 1].normal.setNormal();
			grid[x][y + 1].point.drawVertex();
			grid[x + 1][y].normal.setNormal();
			grid[x + 1][y].point.drawVertex();
			glEnd();
		}
	}
}
				
 

 

Problem 4. Add a function called makeExtrusionOnPath. This function should take as inputs an array of points that define the extrusion shape and an array of points that define the extrusion path. For this to work correctly, the number of point in the extrusion shape should equal width of the Mesh. Likewise, the number of points in the extrusion path should equal the height of the Mesh.


void Mesh::makeExtrusionOnPath(Vec3d* path, Vec3d* shape) {
	Vec3d upVec = Vec3d(0,1,0);
	Vec3d rightVec = Vec3d(1,0,0);
	
	Vec3d vec;
	Vec3d vec1;
	Vec3d vec2;
	
	for (int x = 0; x < width; x++) {
		if(x == 0){
			vec =  path[x];
			vec1 = path[x];
			vec2 = path[x + 1];
		} else if(x == (width - 1)){
			vec =  path[x];
			vec1 = path[x - 1];
			vec2 = path[x];
		} else {
			vec =  path[x];
			vec1 = path[x - 1];
			vec2 = path[x + 1];
		}
	
		Vec3d para = vec1 - vec2;
		
		Vec3d normal;
		
		if(para.dotProduct(rightVec) > 0)
			normal = para.crossProduct(upVec);
		else
			normal = upVec.crossProduct(para);
		
		normal.normalize();
		Vec3d side = normal.crossProduct(para);
		side.normalize();
		
		for (int y = 0; y < height; y++) {
			grid[x][y].point = path[x] + (side * shape[y].x) + (normal * shape[y].y);
		}
	}

	drawSolid2();
}
				
 

 

Problem 5. Add a function called makeScaledExtrusionOnPath. This function should be identical to the makeExtrusionOnPath function, but should also take as an input an array of scaling parameters. The array should have as many scaling parameters as the extrusion path (which is also equal to the height of the Mesh.) Each scaling parameter should be used to scale the extruded shape at each point along the path.

void Mesh::makeExtrusionOnPath(Vec3d* path, Vec3d* shape) {
	Vec3d upVec = Vec3d(0,1,0);
	Vec3d rightVec = Vec3d(1,0,0);
	
	Vec3d vec;
	Vec3d vec1;
	Vec3d vec2;
	
	for (int x = 0; x < width; x++) {
		if(x == 0){
			vec =  path[x];
			vec1 = path[x];
			vec2 = path[x + 1];
		} else if(x == (width - 1)){
			vec =  path[x];
			vec1 = path[x - 1];
			vec2 = path[x];
		} else {
			vec =  path[x];
			vec1 = path[x - 1];
			vec2 = path[x + 1];
		}
	
		Vec3d para = vec1 - vec2;
		
		Vec3d normal;
		
		if(para.dotProduct(rightVec) > 0)
			normal = para.crossProduct(upVec);
		else
			normal = upVec.crossProduct(para);
		
		normal.normalize();
		Vec3d side = normal.crossProduct(para);
		side.normalize();
		
		for (int y = 0; y < height; y++) {
			grid[x][y].point = path[x] + (side * shape[y].x) + (normal * shape[y].y);
		}
	}

	drawSolid2();
}
				
 

 

Problem 6. Utilizing the makeScaledExtrusionOnPath function, create a cornucopia.


void Mesh::makeScaledExtrusionOnPath(Vec3d* path, Vec3d* shape, float* scale) {
	Vec3d upVec = Vec3d(0,1,0);
	Vec3d rightVec = Vec3d(1,0,0);
	
	Vec3d vec;
	Vec3d vec1;
	Vec3d vec2;
	
	for (int x = 0; x < width; x++) {
		if(x == 0){
			vec =  path[x];
			vec1 = path[x];
			vec2 = path[x + 1];
		} else if(x == (width - 1)){
			vec =  path[x];
			vec1 = path[x - 1];
			vec2 = path[x];
		} else {
			vec =  path[x];
			vec1 = path[x - 1];
			vec2 = path[x + 1];
		}
	
		Vec3d para = vec1 - vec2;
		
		Vec3d normal;
		
		if(para.dotProduct(rightVec) > 0)
			normal = para.crossProduct(upVec);
		else
			normal = upVec.crossProduct(para);
		
		normal.normalize();
		
		//normal = normal * scale[x];
		Vec3d side = normal.crossProduct(para);
		side.normalize();
		
		for (int y = 0; y < height; y++) {
			grid[x][y].point = path[x] + (side * shape[y].x * scale[x]) + (normal * shape[y].y * scale[x]);
		}
	}

	drawSolid2();
}