赞
踩
Obj文件的限制
① 只支持全部表面都是三角形的模型,也就是说顶点位置,纹理坐标和法向量必须全部说明,并且以这样的形式: f #/#/# #/#/# #/#/#
② 材料的标签被忽略后,纹理贴图的做法必须用第五章的方法完成
③ 只有全部是三角形网格组成的obj模型才能支持,其余复杂网格模型的obj文件不支持
④ 每一行的元素由空格分隔开
软件界面中有新手教程自带正方体,右上角“文件”->“导出”->“obj”
在obj导出弹窗,选择存储位置和存储名称,选择包括在内的内容,包括顶点,法线和三角面
然后在相应位置会生成obj文件,可以右键选择用记事本打开
查找错误得方法:通过用 print(“成功运行\n xxx语句\n”)
放在要检测的函数后面,运行,看弹出的终端窗口是否出现这句话,如果出现,说明被检测的函数可以正常运行,如果没有出现,就说明被检测函数有误,需要跳到函数定义中,逐句再查看。
通过逐一观察,发现:numObjVertices 这个值没有正常获取数值,还是0的状态,导致后面的遍历无法进行。同时,i < numObjVertices-1
应该改为 i < numObjVertices
Line.compare(0, 2, “f ”);
表示,从索引0开始的2个字符进行对比,所以f 后面一定要加一个空格,构成2个字符,一共需要 个文件,分别是:
① 220302 6.3 OBJLoader.cpp 主程序
② 6.3 ImportedModel.cpp 一个类,用于读取obj文件
③ 6.3 ImportedModel.h 类的声明
④ 5.2 Utils.cpp 一些调用函数,比如检测错误的函数
⑤ 5.2 Utils.h 调用函数声明
⑥ 5.2 vertShader.glsl 点着色器,确定3D点坐标
⑦ 5.2 fragShader.glsl 片着色器,确定每个点的颜色
⑧ 6.3 cube1.obj obj文件,这里用的是Blender软件生成的
⑨ 6.1 earth.jpg 一张图片
#include <string> #include <iostream> #include <fstream> #include <cmath> #include "glm\glm.hpp" #include "glm\gtc\type_ptr.hpp" #include "glm\gtc\matrix_transform.hpp" #include "Utils\6.3 ImportedModel.h" #include "Utils\5.2 Utils.h" using namespace std; #define numVAOs 1 #define numVBOs 3 float cameraX, cameraY, cameraZ; float pyrLocX, pyrLocY, pyrLocZ; GLuint renderingProgram; GLuint vao[numVAOs]; GLuint vbo[numVBOs]; GLuint brickTexture; // 纹理图片ID // allocate variables used in display() function, // so that they won’t need to be allocated during rendering GLuint mvLoc, projLoc; int width, height; float aspect; glm::mat4 pMat, vMat, mMat, mvMat; ImportedModel myModel("add/6.3 cube1.obj"); // in top-level declarations void setupVertices(void) { std::vector<glm::vec3> vert = myModel.getVertices(); std::vector<glm::vec2> tex = myModel.getTextureCoords(); std::vector<glm::vec3> norm = myModel.getNormals(); int numObjVertices = myModel.getNumVertices(); // 出错,这一行的值竟然是0 std::vector<float> pvalues; // vertex positions std::vector<float> tvalues; // texture coordinates std::vector<float> nvalues; // normal vectors for (int i = 0; i < numObjVertices; i++) { pvalues.push_back((vert[i]).x); pvalues.push_back((vert[i]).y); pvalues.push_back((vert[i]).z); tvalues.push_back((tex[i]).s); tvalues.push_back((tex[i]).t); nvalues.push_back((norm[i]).x); nvalues.push_back((norm[i]).y); nvalues.push_back((norm[i]).z); } glGenVertexArrays(1, vao); glBindVertexArray(vao[0]); glGenBuffers(numVBOs, vbo); // VBO for vertex locations glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); glBufferData(GL_ARRAY_BUFFER, pvalues.size() * 4, &pvalues[0], GL_STATIC_DRAW); // VBO for texture coordinates glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); glBufferData(GL_ARRAY_BUFFER, tvalues.size() * 4, &tvalues[0], GL_STATIC_DRAW); // VBO for normal vectors glBindBuffer(GL_ARRAY_BUFFER, vbo[2]); glBufferData(GL_ARRAY_BUFFER, nvalues.size() * 4, &nvalues[0], GL_STATIC_DRAW); } void init(GLFWwindow* window) { renderingProgram = createShaderProgram("add/5.2 vertShader.glsl", "add/5.2 fragShader.glsl"); cameraX = -3.0f; cameraY = 4.0f; cameraZ = 15.0f; pyrLocX = 0.0f; pyrLocY = 0.0f; pyrLocZ = 0.0f; // shift down Y to reveal perspective setupVertices(); brickTexture = loadTexture("add/6.1 earth.jpg"); // 加载纹理的图片 } void display(GLFWwindow* window, double currentTime) { glClear(GL_DEPTH_BUFFER_BIT); glUseProgram(renderingProgram); // get the uniform variables for the MV and projection matrices mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix"); projLoc = glGetUniformLocation(renderingProgram, "proj_matrix"); // build perspective matrix glfwGetFramebufferSize(window, &width, &height); aspect = (float)width / (float)height; pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f); // 1.0472 radians = 60 degrees // build view matrix, model matrix, and model-view matrix vMat = glm::translate(glm::mat4(1.0f), glm::vec3(-cameraX, -cameraY, -cameraZ)); // vbo[0] mMat = glm::translate(glm::mat4(1.0f), glm::vec3(pyrLocX, pyrLocY, pyrLocZ)); mvMat = vMat * mMat; // copy perspective and MV matrices to corresponding uniform variables glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvMat)); glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(pMat)); // associate VBO with the corresponding vertex attribute in the vertex shader glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(0); // 纹理 glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(1); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, brickTexture); // vb0[2] glBindBuffer(GL_ARRAY_BUFFER, vbo[2]); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(2); // adjust OpenGL settings and draw model glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glFrontFace(GL_CCW);// 锥体的三角形是逆时针的面认为是正方向 glDrawArrays(GL_TRIANGLES, 0, myModel.getNumVertices()); } int main(void) { // main() is unchanged from before if (!glfwInit()) { exit(EXIT_FAILURE); } glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); GLFWwindow* window = glfwCreateWindow(1200, 800, "Chapter 6 - program 2", NULL, NULL); glfwMakeContextCurrent(window); if (glewInit() != GLEW_OK) { exit(EXIT_FAILURE); } glfwSwapInterval(1); init(window); while (!glfwWindowShouldClose(window)) { display(window, glfwGetTime()); glfwSwapBuffers(window); glfwPollEvents(); } glfwDestroyWindow(window); glfwTerminate(); exit(EXIT_SUCCESS); }
#include <fstream> #include <sstream> #include <glm\glm.hpp> #include "6.3 ImportedModel.h" #include <iostream> // cout 函数需要用 using namespace std; // ------------ Imported Model class ImportedModel::ImportedModel(const char *filePath) { ModelImporter modelImporter = ModelImporter(); modelImporter.parseOBJ(filePath); // uses modelImporter to get vertex information numVertices = modelImporter.getNumVertices(); // 出错,这里的数值还是0 std::vector<float> verts = modelImporter.getVertices(); std::vector<float> tcs = modelImporter.getTextureCoordinates(); std::vector<float> normals = modelImporter.getNormals(); for (int i = 0; i < numVertices; i++) { vertices.push_back(glm::vec3(verts[i * 3], verts[i * 3 + 1], verts[i * 3 + 2])); texCoords.push_back(glm::vec2(tcs[i * 2], tcs[i * 2 + 1])); normalVecs.push_back(glm::vec3(normals[i * 3], normals[i * 3 + 1], normals[i * 3 + 2])); } } int ImportedModel::getNumVertices() { return numVertices; } // accessors // 出错,这里的数值还是0 std::vector<glm::vec3> ImportedModel::getVertices() { return vertices; } std::vector<glm::vec2> ImportedModel::getTextureCoords() { return texCoords; } std::vector<glm::vec3> ImportedModel::getNormals() { return normalVecs; } // -------------- Model Importer class ModelImporter::ModelImporter() {} void ModelImporter::parseOBJ(const char *filePath) { float x, y, z; string content; ifstream fileStream(filePath, ios::in); string line = ""; int iNum = 0;//调试 while (!fileStream.eof()) { getline(fileStream, line); if (line.compare(0, 2, "v ") == 0) { // vertex position ("v" case) stringstream ss(line.erase(0, 1)); ss >> x; ss >> y; ss >> z; // extract the vertex position values vertVals.push_back(x); vertVals.push_back(y); vertVals.push_back(z); } if (line.compare(0, 2, "vt") == 0) { // texture coordinates ("vt" case) stringstream ss(line.erase(0, 2)); ss >> x; ss >> y; // extract texture coordinate values stVals.push_back(x); stVals.push_back(y); } if (line.compare(0, 2, "vn") == 0) { // vertex normals ("vn" case) stringstream ss(line.erase(0, 2)); ss >> x; ss >> y; ss >> z; // extract the normal vector values normVals.push_back(x); normVals.push_back(y); normVals.push_back(z); } if (line.compare(0, 2, "f ") == 0) { // 注意,这里的 f 后面必须加一个空格,因为line.compare(0, 2, "f ")中表示从索引0开始的2个字符,而f不加空格只有一个字符 string oneCorner, v, t, n; stringstream ss(line.erase(0, 2)); for (int i = 0; i < 3; i++) { getline(ss, oneCorner, ' '); // extract triangle face references stringstream oneCornerSS(oneCorner); getline(oneCornerSS, v, '/'); getline(oneCornerSS, t, '/'); getline(oneCornerSS, n, '/'); int vertRef = (stoi(v) - 1) * 3; // "stoi" converts string to integer int tcRef = (stoi(t) - 1) * 2; int normRef = (stoi(n) - 1) * 3; triangleVerts.push_back(vertVals[vertRef]); // build vector of vertices triangleVerts.push_back(vertVals[vertRef + 1]); triangleVerts.push_back(vertVals[vertRef + 2]); textureCoords.push_back(stVals[tcRef]); // build vector of texture coords textureCoords.push_back(stVals[tcRef + 1]); normals.push_back(normVals[normRef]); //… and normals normals.push_back(normVals[normRef + 1]); normals.push_back(normVals[normRef + 2]); } } } } int ModelImporter::getNumVertices() { return (triangleVerts.size() / 3); } // accessors // 先注释,为了调试,等调试结束再解除注释 std::vector<float> ModelImporter::getVertices() { return triangleVerts; } std::vector<float> ModelImporter::getTextureCoordinates() { return textureCoords; } std::vector<float> ModelImporter::getNormals() { return normals; }
#pragma once #include <vector> class ImportedModel { private: int numVertices; std::vector<glm::vec3> vertices; std::vector<glm::vec2> texCoords; std::vector<glm::vec3> normalVecs; public: ImportedModel(const char *filePath); int getNumVertices(); std::vector<glm::vec3> getVertices(); std::vector<glm::vec2> getTextureCoords(); std::vector<glm::vec3> getNormals(); }; class ModelImporter { private: // values as read in from OBJ file std::vector<float> vertVals; std::vector<float> stVals; std::vector<float> normVals; // values stored for later use as vertex attributes std::vector<float> triangleVerts; std::vector<float> textureCoords; std::vector<float> normals; public: ModelImporter(); void parseOBJ(const char *filePath); int getNumVertices(); std::vector<float> getVertices(); std::vector<float> getTextureCoordinates(); std::vector<float> getNormals(); };
#include "Utils/5.2 Utils.h" #include "GL/glew.h" #include "GLFW/glfw3.h" #include "SOIL2/SOIL2.h" #include <iostream> #include <string> #include <fstream> using namespace std; GLuint createShaderProgram(const char* a_Path, const char* b_Path) { GLint vertCompiled; GLint fragCompiled; GLint linked; string vertShaderStr = readShaderSource(a_Path); // 文件在add文件夹中 string fragShaderStr = readShaderSource(b_Path); const char *vertShaderSrc = vertShaderStr.c_str(); const char *fragShaderSrc = fragShaderStr.c_str(); GLuint vShader = glCreateShader(GL_VERTEX_SHADER); GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(vShader, 1, &vertShaderSrc, NULL); glShaderSource(fShader, 1, &fragShaderSrc, NULL); // 在编译着色器时,捕捉错误 glCompileShader(vShader); checkOpenGLError(); glGetShaderiv(vShader, GL_COMPILE_STATUS, &vertCompiled); if (vertCompiled != 1) { cout << "vertex compilation failed" << endl; printShaderLog(vShader); } glCompileShader(fShader); checkOpenGLError(); glGetShaderiv(fShader, GL_COMPILE_STATUS, &fragCompiled); if (fragCompiled != 1) { cout << "fragment compilation failed" << endl; printShaderLog(fShader); } GLuint vfProgram = glCreateProgram(); glAttachShader(vfProgram, vShader); glAttachShader(vfProgram, fShader); glLinkProgram(vfProgram); checkOpenGLError(); glGetProgramiv(vfProgram, GL_LINK_STATUS, &linked); if (linked != 1) { cout << "linking failed" << endl; printProgramLog(vfProgram); } return vfProgram; } string readShaderSource(const char *filePath) { string content; ifstream fileStream(filePath, ios::in); string line = ""; while (!fileStream.eof()) { getline(fileStream, line); content.append(line + "\n"); } fileStream.close(); return content; } bool checkOpenGLError() { bool foundError = false; int glErr = glGetError(); while (glErr != GL_NO_ERROR) { cout << "glError: " << glErr << endl; foundError = true; glErr = glGetError(); } return foundError; } void printProgramLog(int prog) { int len = 0; int chWrittn = 0; char *log; glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len); if (len > 0) { log = (char *)malloc(len); glGetProgramInfoLog(prog, len, &chWrittn, log); cout << "Program Info Log: " << log << endl; free(log); } } void printShaderLog(GLuint shader) { int len = 0; int chWrittn = 0; char *log; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len); if (len > 0) { log = (char *)malloc(len); glGetShaderInfoLog(shader, len, &chWrittn, log); cout << "Shader Info Log: " << log << endl; free(log); } } GLuint loadTexture(const char *texImagePath) { GLuint textureID; textureID = SOIL_load_OGL_texture(texImagePath, SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y); if (textureID == 0) cout << "could not find texture file" << texImagePath << endl; // mipmaps glBindTexture(GL_TEXTURE_2D, textureID); 不倒置也不镜像——多选一 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 倒置+镜像——多选一 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); 仅有一个,其余颜色为红色——多选一 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); //float redColor[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; //glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, redColor); // 仅有一个,其余为图片最边缘一行一列的颜色拓展——多选一 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glGenerateMipmap(GL_TEXTURE_2D); // if also anisotropic filtering if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) { GLfloat anisoSetting = 0.0f; glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisoSetting); //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoSetting); } return textureID; }
#pragma once #ifndef UTILS_H #define UTILS_H #include <string> #include "GL\glew.h" #include "GLFW\glfw3.h" using namespace std; GLuint createShaderProgram(const char* a_Path, const char* b_Path); string readShaderSource(const char *filePath); bool checkOpenGLError(); void printProgramLog(int prog); void printShaderLog(GLuint shader); GLuint loadTexture(const char *texImagePath); #endif // !UTILS_H
#version 430
layout (location=0) in vec3 pos;
layout (location=1) in vec2 texCoord;
out vec2 tc; // texture coordinate output to rasterizer for interpolation
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
layout (binding=0) uniform sampler2D samp; // not used in vertex shader
void main(void)
{ gl_Position = proj_matrix * mv_matrix * vec4(pos,1.0);
tc = texCoord;
}
#version 430
in vec2 tc; // interpolated incoming texture coordinate
out vec4 color;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
layout (binding=0) uniform sampler2D samp;
void main(void)
{ color = texture(samp, tc);
}
# 以下是记事本的obj内容 # Blender v3.0.1 OBJ File: '' # www.blender.org o Cube v 1.000000 1.000000 -1.000000 v 1.000000 -1.000000 -1.000000 v 1.000000 1.000000 1.000000 v 1.000000 -1.000000 1.000000 v -1.000000 1.000000 -1.000000 v -1.000000 -1.000000 -1.000000 v -1.000000 1.000000 1.000000 v -1.000000 -1.000000 1.000000 vt 0.875000 0.500000 vt 0.625000 0.750000 vt 0.625000 0.500000 vt 0.375000 1.000000 vt 0.375000 0.750000 vt 0.625000 0.000000 vt 0.375000 0.250000 vt 0.375000 0.000000 vt 0.375000 0.500000 vt 0.125000 0.750000 vt 0.125000 0.500000 vt 0.625000 0.250000 vt 0.875000 0.750000 vt 0.625000 1.000000 vn 0.0000 1.0000 0.0000 vn 0.0000 0.0000 1.0000 vn -1.0000 0.0000 0.0000 vn 0.0000 -1.0000 0.0000 vn 1.0000 0.0000 0.0000 vn 0.0000 0.0000 -1.0000 s off f 5/1/1 3/2/1 1/3/1 f 3/2/2 8/4/2 4/5/2 f 7/6/3 6/7/3 8/8/3 f 2/9/4 8/10/4 6/11/4 f 1/3/5 4/5/5 2/9/5 f 5/12/6 2/9/6 6/7/6 f 5/1/1 7/13/1 3/2/1 f 3/2/2 7/14/2 8/4/2 f 7/6/3 5/12/3 6/7/3 f 2/9/4 4/5/4 8/10/4 f 1/3/5 3/2/5 4/5/5 f 5/12/6 1/3/6 2/9/6
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。