【发布时间】:2021-07-17 05:03:04
【问题描述】:
我正在尝试从 OBJ 文件渲染茶壶模型。我正在使用固定功能渲染管道,我无法更改为可编程管道。我也想在场景中应用一些基本的照明和材质,所以我的茶壶应用了绿色闪亮的材质。但是,当我绕 Y 轴旋转茶壶时,我可以清楚地看到茶壶的背面。
这是我迄今为止尝试过的:
-
改变 OpenGL 剔除面的方式(GL_CCW、GL_CW、GL_FRONT、GL_BACK),没有一个会产生正确的结果。
-
更改 OpenGL 计算正面正面的方式(GL_FRONT、GL_CCW、GL_BACK、GL_CW),但都不会产生正确的结果。
-
测试 OBJ 文件以确保其顶点正确排序。当我将文件拖入https://3dviewer.net/ 时,它会显示正确的茶壶,但不是透明的。
-
改变照明,看看是否有任何作用。在某些情况下,改变灯光并不能阻止茶壶被透视。
-
禁用 GL_BLEND。这没有任何作用
这是我目前启用的:
glLightfv(GL_LIGHT0, GL_AMBIENT, light0Color);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0DiffColor);
glLightfv(GL_LIGHT0, GL_SPECULAR, light0SpecColor);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientIntensity);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_NORMALIZE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_CCW);
glFrontFace(GL_CCW);
以下是材料属性:
float amb[4] = {0.0215, 0.1745, 0.0215, 1.0};
float diff[4] = {0.07568, 0.61424, 0.07568, 1.0};
float spec[4] = {0.633, 0.727811, 0.633, 1.0};
float shininess = 0.6 * 128;
glMaterialfv(GL_FRONT, GL_AMBIENT, amb);
glMaterialfv(GL_FRONT, GL_DIFFUSE, diff);
glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
glMaterialf(GL_FRONT, GL_SHININESS, shininess);
这里是渲染代码:
glClearColor(0.0, 0.0, 0.0, 1.0);
glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0, 0, -150);
glRotatef(r, 0.0, 1.0, 0.0);
glScalef(0.5, 0.5, 0.5);
r += 0.5;
m.draw(0, 0, 0);
我不确定这是否是问题的原因,但我在下面包含了模型加载代码以防万一:
while(std::getline(stream, line))
{
if (line[0] == 'v' && line[1] == 'n') // If we see a vertex normal in the OBJ file
{
line = line.substr(3, line.size() - 3); // Removes the 'vn ' from the line
std::stringstream ss(line);
glm::vec3 normal;
ss >> normal.x >> normal.y >> normal.z;
tempNormalData.push_back(normal);
}
if (line[0] == 'v') // If we see a vertex on this line of the OBJ file
{
line = line.substr(2, line.size() - 2); // Removes the 'v ' from the line
std::stringstream ss(line);
glm::vec3 position;
ss >> position.x >> position.y >> position.z;
tempVertData.push_back(position);
}
if (line[0] == 'f') // If we see a face in the OBJ file
{
line = line.substr(2, line.size() - 2); // Removes the 'f ' from the line
std::stringstream ss(line);
glm::vec3 faceData;
ss >> faceData.x >> faceData.y >> faceData.z;
tempFaceData.push_back(faceData);
}
}
if (tempVertData.size() != tempNormalData.size() && tempNormalData.size() > 0)
{
std::cout << "Not the same number of normals as vertices" << std::endl;
}
else
{
for (int i = 0; i < (int)tempVertData.size(); i++)
{
Vertex v;
v.setPosition(tempVertData[i]);
v.setNormal(tempNormalData[i]);
vertices.push_back(v);
}
for (int i = 0; i < tempFaceData.size(); i++)
{
Vertex v1 = vertices[tempFaceData[i].x - 1];
Vertex v2 = vertices[tempFaceData[i].y - 1];
Vertex v3 = vertices[tempFaceData[i].z - 1];
Face face(v1, v2, v3);
faces.push_back(face);
}
}
}
最后,当我绘制面时,我只是循环遍历面列表并在面对象上调用绘图函数。面部绘制函数只是包装了一个 glBegin(GL_TRIANGLES) 和一个 glEnd() 调用:
for (int i = 0; i < (int)faces.size(); i++)
{
auto& f = faces[i];
f.draw(position);
}
面部绘制功能:
glBegin(GL_TRIANGLES);
glVertex3f(position.x + v1.getPosition().x, position.y + v1.getPosition().y, position.z + v1.getPosition().z);
glNormal3f(v1.getNormal().x, v1.getNormal().y, v1.getNormal().z);
glVertex3f(position.x + v2.getPosition().x, position.y + v2.getPosition().y, position.z + v2.getPosition().z);
glNormal3f(v2.getNormal().x, v2.getNormal().y, v2.getNormal().z);
glVertex3f(position.x + v3.getPosition().x, position.y + v3.getPosition().y, position.z + v3.getPosition().z);
glNormal3f(v3.getNormal().x, v3.getNormal().y, v3.getNormal().z);
glEnd();
我真的不想实现我自己的 Z-Buffer 剔除算法,我希望有一个非常简单的方法可以解决我刚刚遗漏的问题。
解决方案(感谢 Genpfault)
我没有向 OpenGL 请求深度缓冲区。我使用 Qt 作为我的窗口 API,所以我必须从我的格式对象中请求它,如下所示:format.setDepthBufferSize(32);
这请求了一个 32 位的深度缓冲区,从而解决了这个问题。
【问题讨论】:
-
在minimal reproducible example 中编辑。就我们所知,在 OpenGL 上下文创建期间没有请求深度缓冲区。随意使用this 作为基础。
-
缺乏深度缓冲区是我的直接猜测 - 很明显,面部正在被剔除,根据喷口底部,他们面对的方式,并且提问者表示问题只有在旋转后才会变得明显(即从适当的角度)。
-
感谢两位的帮助!你是对的,我需要请求一个深度缓冲区。我使用 Qt 作为我的窗口 API,所以我需要从格式请求它。我选择请求一个 32 位深度的缓冲区。感谢您的帮助,帖子已被编辑以反映此解决方案。
标签: c++ opengl opengl-compat wavefront culling