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 (in .obj format). 1

ID: 3743346 • Letter: W

Question

Write an OpenGL program in C++ to read and display a 3D mesh (in .obj format).

1. Write a function, “bool ReadOBJFile(const char filename[])”, to read in an obj file and store the elements into a vertex list and face list.

2. Implement a “ComputeBoundingBox()” function, to compute the bounding box of the object, its diagonal axis length, and its center, then put the camera at:

x_cam = x_BCenter;
y_cam = y_BCenter;
z_cam = z_BCenter + 1.5 * BoundingBoxDiagonalAxisLength;
and look towards the bounding box center.

3. Implement the “Render_Mesh()” function to finish the OpenGL rendering.

4. Control the rendered mesh using keyboard+mouse-controlled rotations (R, mouse left button), panning (T, mouse left button), and zooming (Z, mouse left button) functions.

You only need to consider the simplest OBJ format. It contains a list of vertices (each row starts with a keyword “v”, e.g., v x y z), and a list of faces (each row starts with a keyword “f”, e.g., f vInd1 vInd2 vInd3). Note that the vertex index vInd starts at 1. So, if you have store vertex positions in an array, the first vertex is at position 0, and each vertex’s location is vInd-1.

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