Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

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;
}

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote