从OBJ文件导入模型渲染时部分多边形消失的技术求助
OBJ模型导入渲染后部分多边形消失的解决方法
导入OBJ模型并渲染时出现部分多边形消失的情况,但使用glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)切换为线框模式后模型显示正常。
导入器代码
void load_m(string filename) { string line; char c; int i, j, k; double x, y, z; double xt, yt, zt; string si, sj, sk; ifstream in(filename); while (getline(in, line)) { if (line.find_first_of("vVfFtT") == string::npos) continue; std::istringstream ss(line); ss >> c; switch (c) { case 'v': case 'V': ss >> x >> y >> z; vertices.push_back({ x, y, z }); break; case 't': case 'T': ss >> xt >> yt >> zt; texture.push_back({ xt, yt, zt }); break; case 'f': case 'F': ss >> si >> sj >> sk; i = stoi(si); j = stoi(sj); k = stoi(sk); faces.push_back({ i, j, k }); break; } } in.close(); }
渲染代码
string draw_model() { sf::Texture::bind(&tt); glEnable(GL_TEXTURE_2D); glColor3f(1, 1, 1); glBegin(GL_TRIANGLES); for (int i = 0; i < faces.size(); i++) { Point v1 = vertices[faces[i].v1 - 1]; Point v2 = vertices[faces[i].v2 - 1]; Point v3 = vertices[faces[i].v3 - 1]; glVertex3f(v1.x, v1.z, v1.y); glVertex3f(v2.x, v2.z, v2.y); glVertex3f(v3.x, v3.z, v3.y); glTexCoord3f(texture[i].xt, texture[i].yt, texture[i].zt); //Draw texture } return "123"; glEnd(); }
错误显示效果

已尝试的方法
- 自行编写模型加载器,加载速度更快但模型瑕疵更多
- 修改顶点坐标顺序为
glVertex3f(v1.x, v1.z, v1.y),修正了模型方向但未解决多边形消失问题
问题原因及解决办法
1. 渲染代码中glEnd()位置错误
glEnd()放在了return "123";之后,这行代码永远不会被执行。glBegin(GL_TRIANGLES)必须和glEnd()配对使用,否则OpenGL的渲染状态会混乱,导致部分三角形无法正确渲染。
修正后的渲染代码:
string draw_model() { sf::Texture::bind(&tt); glEnable(GL_TEXTURE_2D); glColor3f(1, 1, 1); glBegin(GL_TRIANGLES); for (int i = 0; i < faces.size(); i++) { Point v1 = vertices[faces[i].v1 - 1]; Point v2 = vertices[faces[i].v2 - 1]; Point v3 = vertices[faces[i].v3 - 1]; // 每个顶点对应一个纹理坐标,需先设置纹理坐标再调用glVertex glTexCoord3f(texture[faces[i].t1 - 1].xt, texture[faces[i].t1 - 1].yt, texture[faces[i].t1 - 1].zt); glVertex3f(v1.x, v1.z, v1.y); glTexCoord3f(texture[faces[i].t2 - 1].xt, texture[faces[i].t2 - 1].yt, texture[faces[i].t2 - 1].zt); glVertex3f(v2.x, v2.z, v2.y); glTexCoord3f(texture[faces[i].t3 - 1].xt, texture[faces[i].t3 - 1].yt, texture[faces[i].t3 - 1].zt); glVertex3f(v3.x, v3.z, v3.y); } glEnd(); // 移到return之前 return "123"; }
2. 纹理坐标绑定与加载错误
当前加载器只读取了顶点的索引,但OBJ文件的面格式通常是f v/t/vn(顶点/纹理/法线索引),直接用stoi(si)读取整个字符串会得到错误索引;同时渲染时每个三角形只设置一次纹理坐标,不符合OpenGL“每个顶点对应一个纹理坐标”的要求。
修改加载器的面解析部分,拆分顶点、纹理索引:
case 'f': case 'F': // 拆分面索引,处理"v/t/vn"格式 auto parse_face_index = [](const string& s) { vector<int> indices; stringstream ss(s); string part; while (getline(ss, part, '/')) { indices.push_back(part.empty() ? 0 : stoi(part)); } return indices; }; ss >> si >> sj >> sk; auto idx1 = parse_face_index(si); auto idx2 = parse_face_index(sj); auto idx3 = parse_face_index(sk); // 假设faces结构体包含v1/v2/v3(顶点索引)和t1/t2/t3(纹理索引)字段 faces.push_back({ idx1[0], idx2[0], idx3[0], idx1[1], idx2[1], idx3[1] }); break;
3. 开启深度测试(可选但推荐)
若模型存在遮挡关系,未开启深度测试会导致后面的面错误覆盖前面的面,开启后可正确剔除被遮挡的面:
// 在初始化阶段调用 glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS);
内容的提问来源于stack exchange,提问作者Proger
相关产品推荐
相关产品推荐

