Getting started with openGL drawing and importing external files
This paper mainly introduces the data type and basic drawing framework of the general drawing software openGL. In addition, it also provides the method of importing obj external files. The provided code can be used with a little modification. I hope it can be convenient for beginners to get started quickly.
Data type of openGL
Program structure of openGL
Basic drawing framework of openGL
#include <GL/glut.h> #include <cstdlib> void main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // When creating a window, specify the type of its display mode(Includes color modes and buffer types) ,set up GLUT_DEPTH To display 3 D graphical glutInitWindowPosition(50, 100); // Sets the initial position of the window display glutInitWindowSize(400, 300); // Sets the width and height of the window glutCreateWindow("The name of the window"); // create a window init(); // Execute your own initialization function glutDisplayFunc(myDisplay); // Callback function, display image, parameters are your own display function glutMainLoop(); // Displays and waits for subsequent commands } void init(void)//Initialization settings { glClearColor(1.0, 1.0, 1.0, 0.0); // Specifies the clear value of the color buffer and sets the background color of the window //The transformation of projection is also often written reshape Inside, init You don't have to //Draw a two-dimensional image glMatrixMode(GL_PROJECTION); // Set matrix mode //Draw a two-dimensional image with two-dimensional orthographic projection gluOrtho2D(0.0, 200.0, 0.0, 150.0); //Draw a three-dimensional image, set the visual vertebral body, and open the depth test //To display 3 D Graphics, need to be enabled GLUT Depth buffer of window program( GLUT_DEPTH),Depth test occlusion culling( GL_DEPTH_TEST),And set the viewing clipping space glFrustum(-2.5, 2.5, -2.5, 2.5, mynear, myfar); glEnable(GL_DEPTH_TEST); } void myDisplay(void)//Display function { //Set color, R,G,B Between 0 and 1 glColor3f(0.0, 0.4, 0.2); //Call the function that performs drawing operation in the display function myGraphy(); //Flush current buffer glFlush(); } void myGraphy() { //Draw points. You can't use them directly glVertex2i,This should only be a positioning function and will not be displayed glBegin(GL_POINTS); glVertex2i(xCoord, yCoord); glEnd(); //Draw a line and set the position of the two endpoints glBegin(GL_LINES); glVertex2i(180, 15); glVertex2i(10, 145); glEnd(); } //To prevent deformation, you can use reshape Function to set init Some initialization settings are moved to reshape Inside, in main In function init()Call after glutReshapeFunc(myReshape); void myReshape(int w, int h) { winWidth = w; winHeight = h; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-5.0, 5.0, -5.0, 5.0, mynear, myfar); viewxform_z = -5.0; glMatrixMode(GL_MODELVIEW); }
Import external files
First, introduce the format of OBJ file
OBJ is a 3D model file, so it does not contain animation, mapping path, dynamics and other information, and mainly supports models drawn from polygonal patches. The OBJ file does not contain face color and material definition information, and the material library information is stored in a separate file with ". mtl" suffix.
The import of obj file is divided into two stages. First, analyze the file, that is, save the corresponding parameters according to the file format, and then draw polygon patches according to these parameters, which are spliced into 3D models.
1.OBJ file parsing: the principle is to read the relevant data of polygon patches in the file and store it in the array for easy use when drawing the model. Vertices in the file are identified by "v" in the format of "v x y z". Where x, y and z respectively represent the coordinate values of the three dimensions. The face image is marked by "f" and can be composed of triangles or quadrangles. The parsing code is as follows:
ObjLoader::ObjLoader(string filename) { string line; fstream f; f.open(filename, ios::in); if (!f.is_open()) { cout << "Something Went Wrong When Opening Objfiles" << endl; } while (!f.eof()) { getline(f, line);//Get obj A line in the file as a string vector<string>parameters; string tailMark = " "; string ans = ""; line = line.append(tailMark); for (int i = 0; i < line.length(); i++) { char ch = line[i]; if (ch != ' ') { ans += ch; } else { parameters.push_back(ans); //Take out the elements in the string and divide them with spaces ans = ""; } } //cout << parameters.size() << endl; if (parameters.size() != 4 && parameters.size() != 5) { cout << "the size is not correct" << endl; } else { if (parameters[0] == "v") { //If it's a vertex vector<GLfloat>Point; for (int i = 1; i < 4; i++) { //Starting from 1, set the vertex's xyz Put the three coordinates into the vertex vector GLfloat xyz = atof(parameters[i].c_str()); Point.push_back(xyz); } vSets.push_back(Point); } else if (parameters[0] == "f") { //If it is a face, the index of three vertices is stored vector<GLint>vIndexSets; if (parameters.size() == 5) { for (int i = 1; i <= 4; i++) { string x = parameters[i]; string ans = ""; for (int j = 0; j < x.length(); j++) { //skip'/' char ch = x[j]; if (ch != '/') { ans += ch; } else { break; } } GLint index = atof(ans.c_str()); index = index--;//Because the vertex index is obj The file starts with 1, and we store vertices vector It starts from 0, so subtract 1 vIndexSets.push_back(index); } fSets.push_back(vIndexSets); } else { for (int i = 1; i < 4; i++) { string x = parameters[i]; string ans = ""; for (int j = 0; j < x.length(); j++) { //skip'/' char ch = x[j]; if (ch != '/') { ans += ch; } else { break; } } GLint index = atof(ans.c_str()); index = index--;//Because the vertex index is obj The file starts with 1, and we store vertices vector It starts from 0, so subtract 1 vIndexSets.push_back(index); } fSets.push_back(vIndexSets); } } } } f.close(); }
2. Polygon patch drawing: some source codes on the Internet default all statements marked with "f" to contain only three parameters, resulting in only triangular patches and unable to present a complete model. In fact, it can have three or four parameters, which are drawn with triangular or quadrilateral patches. After modifying the code, the complete model is drawn.
void ObjLoader::Draw() { for (int i = 0; i < fSets.size(); i++) { GLfloat VN[3]; //Three vertices GLfloat SV1[4]; GLfloat SV2[4]; GLfloat SV3[4]; GLfloat SV4[4]; if ((fSets[i]).size() != 4&& (fSets[i]).size() != 3) { cout << "the fSetsets_Size is not correct" << endl; } else { if ((fSets[i]).size() == 3) { glBegin(GL_TRIANGLES);//Start drawing triangles glColor3f(0.255, 0.215, 0); GLint firstVertexIndex = (fSets[i])[0];//Extract vertex index GLint secondVertexIndex = (fSets[i])[1]; GLint thirdVertexIndex = (fSets[i])[2]; SV1[0] = (vSets[firstVertexIndex])[0];//First vertex SV1[1] = (vSets[firstVertexIndex])[1]; SV1[2] = (vSets[firstVertexIndex])[2]; SV2[0] = (vSets[secondVertexIndex])[0]; //Second vertex SV2[1] = (vSets[secondVertexIndex])[1]; SV2[2] = (vSets[secondVertexIndex])[2]; SV3[0] = (vSets[thirdVertexIndex])[0]; //Third vertex SV3[1] = (vSets[thirdVertexIndex])[1]; SV3[2] = (vSets[thirdVertexIndex])[2]; GLfloat vec1[3], vec2[3], vec3[3];//Calculate normal vector //(x2-x1,y2-y1,z2-z1) vec1[0] = SV1[0] - SV2[0]; vec1[1] = SV1[1] - SV2[1]; vec1[2] = SV1[2] - SV2[2]; //(x3-x2,y3-y2,z3-z2) vec2[0] = SV1[0] - SV3[0]; vec2[1] = SV1[1] - SV3[1]; vec2[2] = SV1[2] - SV3[2]; //(x3-x1,y3-y1,z3-z1) vec3[0] = vec1[1] * vec2[2] - vec1[2] * vec2[1]; vec3[1] = vec2[0] * vec1[2] - vec2[2] * vec1[0]; vec3[2] = vec2[1] * vec1[0] - vec2[0] * vec1[1]; GLfloat D = sqrt(pow(vec3[0], 2) + pow(vec3[1], 2) + pow(vec3[2], 2)); VN[0] = vec3[0] / D; VN[1] = vec3[1] / D; VN[2] = vec3[2] / D; glNormal3f(VN[0], VN[1], VN[2]);//Draw normal vector glVertex3f(SV1[0], SV1[1], SV1[2]);//Draw a triangular patch glVertex3f(SV2[0], SV2[1], SV2[2]); glVertex3f(SV3[0], SV3[1], SV3[2]); glEnd(); } else { glBegin(GL_POLYGON); glColor3f(0.5, 0.5, 0); GLint firstVertexIndex = (fSets[i])[0];//Extract vertex index GLint secondVertexIndex = (fSets[i])[1]; GLint thirdVertexIndex = (fSets[i])[2]; GLint fourthVertexIndex = (fSets[i])[3]; SV1[0] = (vSets[firstVertexIndex])[0];//First vertex SV1[1] = (vSets[firstVertexIndex])[1]; SV1[2] = (vSets[firstVertexIndex])[2]; SV2[0] = (vSets[secondVertexIndex])[0]; //Second vertex SV2[1] = (vSets[secondVertexIndex])[1]; SV2[2] = (vSets[secondVertexIndex])[2]; SV3[0] = (vSets[thirdVertexIndex])[0]; //Third vertex SV3[1] = (vSets[thirdVertexIndex])[1]; SV3[2] = (vSets[thirdVertexIndex])[2]; SV4[0] = (vSets[fourthVertexIndex])[0]; //Fourth vertex SV4[1] = (vSets[fourthVertexIndex])[1]; SV4[2] = (vSets[fourthVertexIndex])[2]; glVertex3f(SV1[0], SV1[1], SV1[2]);//Draw Quad patch glVertex3f(SV2[0], SV2[1], SV2[2]); glVertex3f(SV3[0], SV3[1], SV3[2]); glVertex3f(SV4[0], SV4[1], SV4[2]); glEnd(); } } } }
Effect display:
github source code: ursulalujun/CG-openGL (github.com)
This warehouse also has the source code of geometric transformation, observation transformation, mouse, keyboard interaction and other operations. Welcome to visit!
Reference article:
https://blog.csdn.net/qq_38906523/article/details/75210105