Write an OpenGL program in C++ to read and display a 3D mesh. 1. Use the half-ed
ID: 3754369 • Letter: W
Question
Write an OpenGL program in C++ to read and display a 3D mesh.
1. Use the half-edge data structure to read an OBJ file and store the elements into a vertex list and face list and also compute bounding box.
2. Compute the normal of each face, save them in a property array so that they are indexed and reused correctly later.
3. Compute the normal of each vertex, by linearly interpolating its one-ring neighboring faces’ normal vectors, weighted by incident angles. Save vertex normal in a property array.
4. Use the normal information to produce better shading effects (apply glNormal() before glVertex()). Press a key to switch between face normal (‘f’) and vertex normal (‘v’).
5. Compute the Gaussian curvature Kg on every vertex. Render a red sphere on each vertex that is a local maximum within its 2-ring neighboring vertices; and render a blue sphere on each vertex that is a local minimum within its 2-ring neighboring vertices. Use the keyboard control whether or not to render these spheres: pressing ‘k’ to switch on and off.
6. Detection of “sharp edges”. On each edge, calculate the dot product of normal vectors from this edge’s two adjacent faces. If the dot product value is smaller than 0.5, render this edge in blue. Use the keyboard control whether or not to render these edges: pressing ‘s’ to switch on and off.
Explanation / Answer
#include <iostream>
#include <fstream>
#include <OpenGL/OpenGL.h>
#include <GLUT/glut.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <cmath>
struct Vertex
{
double x, y, z;
};
std::vector<Vertex> vertexList;
std::vector<Vertex> faceList;
Vertex boxCenter;
double minX,minY,minZ,maxX,maxY,maxZ,diagLength;
char keyControl;
int mouseButton;
/* Some variables to measure mouse movement */
int mousePositionX0 = 0, mousePositionY0 = 0;
float obj1_angle_x = 0.0f;
float obj1_angle_y = 0.0f;
float obj1_trans[2] = { 0.0f, 0.0f };
float camera_zoom = 0.0f;
bool ReadOBJFile(const char filename[]){
std::ifstream file(filename);
std::vector<std::string> fileContents;
//check file existance
if(!file)
{
std::cout << "Failure opening file at "" << filename <<"".";
return false;
}
//file is located
std::string buffer;
while(std:: getline(file, buffer))
{
// Add the buffer contents to our fileContents vector if it's not a comment
// (Doing the check now reduces memory usage :D
if(buffer[0] != '#' || buffer[0] != ' ')
{
fileContents.push_back(buffer);
}
}
if(fileContents.size() == 0)
{
std::cout << "File "" << filename << "" Was empty... Failure to load ";
return false;
}
//If the whole file wasn't all comments ...
//initialize min and max values
if(fileContents[0].c_str()[0] == 'v' && fileContents[0].c_str()[1] == ' ')
{
sscanf(fileContents[0].c_str(), "v %lf %lf %lf" ,&minX,&minY,&minZ);
maxX = minX;
maxY = minY;
maxZ = minZ;
}
//save the vertices and faces in the structure
for(unsigned int n = 0; n < fileContents.size(); n++){
if(fileContents[n].c_str()[0] == 'v' && fileContents[n].c_str()[1] == ' ')
{
//std::cout << "Vertex ";
double tmpx, tmpy, tmpz;
sscanf(fileContents[n].c_str(), "v %lf %lf %lf" ,&tmpx,&tmpy,&tmpz);
Vertex tmpVert = {tmpx, tmpy, tmpz};
//checking for min values
if(tmpx < minX)minX = tmpx;
if(tmpy < minY)minY = tmpy;
if(tmpz < minZ)minZ = tmpz;
//checking for max values
if(tmpx > maxX)maxX = tmpx;
if(tmpy > maxY)maxY = tmpy;
if(tmpz > maxZ)maxZ = tmpz;
vertexList.push_back(tmpVert);
}
else if(fileContents[n].c_str()[0] == 'f' && fileContents[n].c_str()[1] == ' '){
// std::cout << "Face ";
double tmpx, tmpy, tmpz;
sscanf(fileContents[n].c_str(), "f %lf %lf %lf" ,&tmpx,&tmpy,&tmpz);
Vertex tmpFace = {tmpx, tmpy, tmpz};
faceList.push_back(tmpFace);
}
}
diagLength = sqrt(pow((minX - maxX), 2) + pow((minY - maxY), 2) + pow((minZ - maxZ), 2));
boxCenter = {(minX+maxX)/2,(minY+maxY)/2, (minZ+maxZ)/2};
//std::cout<<vertexList[1].x;std::cout<<" ";
//std::cout<<vertexList[1].y;std::cout<<" ";
//std::cout<<vertexList[1].z;std::cout<<" ";
//std::cout<<"-------------- ";
//std::cout<<faceList[1].x;std::cout<<" ";
//std::cout<<faceList[1].y;std::cout<<" ";
//std::cout<<faceList[1].z;std::cout<<" ";
return true;
}
void computeBoundingBox(){
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
glPushMatrix();
glColor3f (0.0, 0.0, 0.0);
glBegin(GL_QUADS);
//FRONT
glVertex3f(minX,minY,minZ);
glVertex3f(maxX,minY,minZ);
glVertex3f(maxX,maxY,minZ);
glVertex3f(minX,maxY,minZ);
//RIGHT
glVertex3f(maxX,minY,minZ);
glVertex3f(maxX,minY,maxZ);
glVertex3f(maxX,maxY,maxZ);
glVertex3f(maxX,maxY,minZ);
//BACK
glVertex3f(maxX,maxY,maxZ);
glVertex3f(minX,maxY,maxZ);
glColor3f(1.0,0.0,0.0);
glVertex3f(minX,minY,maxZ);
glVertex3f(maxX,minY,maxZ);
glColor3f(0.0,0.0,0.0);
//LEFT
glColor3f (0.0, 0.0, 1.0);
glVertex3f(minX,minY,minZ);
glVertex3f(minX,minY,maxZ);
glColor3f (0.0, 0.0, 0.0);
glVertex3f(minX,maxY,maxZ);
glVertex3f(minX,maxY,minZ);
//TOP
glVertex3f(minX,maxY,minZ);
glVertex3f(minX,maxY,maxZ);
glVertex3f(maxX,maxY,maxZ);
glVertex3f(maxX,maxY,minZ);
//BOTTOM
glVertex3f(minX,minY,minZ);
glVertex3f(maxX,minY,minZ);
glVertex3f(maxX,minY,maxZ);
glVertex3f(minX,minY,maxZ);
glEnd();
glPopMatrix();
glPushAttrib(GL_CURRENT_BIT);
glLineWidth(3);
glColor3f (0.0, 0.0, 1.0);
glBegin(GL_LINES);
glVertex3f(minX,minY,minZ);
glVertex3f(minX,minY,maxZ);
glEnd();
glPopAttrib();
glLineWidth(1);
glPushAttrib(GL_CURRENT_BIT);
glLineWidth(3);
glColor3f (1.0, 0.0, 0.0);
glBegin(GL_LINES);
glVertex3f(minX,minY,maxZ);
glVertex3f(maxX,minY,maxZ);
glEnd();
glPopAttrib();
glLineWidth(1);
glPushAttrib(GL_CURRENT_BIT);
glLineWidth(3);
glColor3f (0.0, 1.0, 0.0);
glBegin(GL_LINES);
glVertex3f(minX,minY,maxZ);
glVertex3f(minX,maxY,maxZ);
glEnd();
glPopAttrib();
glLineWidth(1);
}
void Render_Mesh(){
glPushMatrix();
glTranslatef(obj1_trans[0], obj1_trans[1], 0);
glRotatef(obj1_angle_x, 1.0f, 0.0f, 0.0f);
glRotatef(obj1_angle_y, 0.0f, 1.0f, 0.0f);
glColor3f(1.0, 1.0, 0.0);
glBegin(GL_TRIANGLES);
for(unsigned int i = 0; i < faceList.size() -1; i++){
long firstIndex =faceList[i].x;
long secondIndex = faceList[i].y;
long thirdIndex = faceList[i].z;
//std::cout<<vertexList[firstIndex].x;std::cout<<" ";
//std::cout<<vertexList[firstIndex].y;std::cout<<" ";
//std::cout<<vertexList[firstIndex].z;std::cout<<" ";
glVertex3f(vertexList[firstIndex].x, vertexList[firstIndex].y, vertexList[firstIndex].z);
glVertex3f(vertexList[secondIndex].x, vertexList[secondIndex].y, vertexList[secondIndex].z);
glVertex3f(vertexList[thirdIndex].x, vertexList[thirdIndex].y, vertexList[thirdIndex].z);
}
glEnd();
glColor3f(0.0, 0.0, 0.0);
glPopMatrix();
glutSwapBuffers();
}
//Initializes 3D rendering
void initRendering() {
glEnable(GL_DEPTH_TEST);
glClearColor(0.7f, 0.9f, 1.0f, 1.0f); //Change the background to sky blue
keyControl = 0;
}
void drawScene(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glShadeModel(GL_FLAT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt((GLdouble)boxCenter.x, (GLdouble)boxCenter.y, (GLdouble)boxCenter.z +1.5 * diagLength, (GLdouble)boxCenter.x, (GLdouble)boxCenter.y, (GLdouble)boxCenter.z, 0, 1, 0);
glTranslatef(0.0f, 0.0f, camera_zoom);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, 1, 0.2, 6);
glMatrixMode(GL_MODELVIEW);
computeBoundingBox();
Render_Mesh();
}
//Called when a key is pressed
void handleKeypress(unsigned char key, int x, int y) {
switch (key) {
case 'r':
keyControl = 'r';
break;
case 't':
keyControl = 't';
break;
case 'z':
keyControl = 'z';
break;
case 27: //Escape key
exit(0);
}
}
void mouseClick(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
mouseButton = GLUT_LEFT_BUTTON;
else if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN)
mouseButton = GLUT_MIDDLE_BUTTON;
else if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
mouseButton = GLUT_RIGHT_BUTTON;
mousePositionX0 = x;
mousePositionY0 = y;
return;
}
void mouseMove(int x, int y)
{
float frictionFactor = 0.02f; // just a scaling factor to make the mouse moving not too sensitive
/* rotation*/
if (mouseButton == GLUT_LEFT_BUTTON)
{//Rotation
if (keyControl == 'r'){
int delta_x = x - mousePositionX0;
int delta_y = y - mousePositionY0;
obj1_angle_y += delta_x;
obj1_angle_x += delta_y;
}
else if (keyControl == 't'){
obj1_trans[0] += frictionFactor * (x - mousePositionX0);
obj1_trans[1] += frictionFactor * (mousePositionY0 - y);
}
else if (keyControl == 'z'){
camera_zoom += frictionFactor * (y - mousePositionY0);
// std::cout<<camera_zoom;
}
}
if (mouseButton == GLUT_MIDDLE_BUTTON)
{
////////////do something ////////////////
}
/* zoom in and out */
if (mouseButton == GLUT_RIGHT_BUTTON)
{
////
}
mousePositionX0 = x;
mousePositionY0 = y;
glutPostRedisplay();
}
void update(int value) {
glutPostRedisplay();
glutTimerFunc(25, update, 0);
}
int main(int argc, char** argv) {
//Initialize GLUT
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
//Create the window
glutCreateWindow("Homework 1 - Simron Thapa");
//Read object file
if(ReadOBJFile("camel.obj")){
initRendering();
glutDisplayFunc(drawScene);
glutKeyboardFunc(handleKeypress);
// glutReshapeFunc(handleResize);
glutMouseFunc(mouseClick);
glutMotionFunc(mouseMove);
glutTimerFunc(25, update, 0); //Add a timer
glutMainLoop();
}
return 0;
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.