我一直在玩OpenGL一整周或同等学历。 2D之后我现在尝试3D。我想在http://johnnylee.net/projects/wii/的第三个视频中重现您可以看到的3D场景 我很难用纹理和深度使一切正常工作。
最近我遇到了两个在视觉上有同样影响的问题:
我已经解决了这两个问题,但我想知道我是否做对了,尤其是第二点。
对于第一个,我想我已经明白了。 我有一个圆形目标的图像,对于光盘外的任何东西都有alpha。它在OpenGL中加载得很好。 一些(由于我的z排序问题)背后的其他目标遭受了我用来绘制它的自然方形四边形的透明区域的隐藏。
原因在于,对于深度缓冲区,假设纹理的每个部分都是完全不透明的。
使用带有glEnable(GL_ALPHA_TEST)
测试的glAlphaFunc(GL_GREATER, 0.5f)
会使纹理的alpha图层充当每像素(布尔值)不透明度指示符,从而使得混合非常无用(因为我的图像具有布尔透明度)。
补充问题:顺便说一句,是否有指定alpha测试的不同来源而不是用于混合的alpha层?
第二次,我找到了解决问题的方法。
在清除颜色和深度缓冲区之前,我已将默认深度设置为0 glClearDepth(0.0f)
,并且我使用了“更大”深度函数glDepthFunc(GL_GREATER)
。
对我来说很奇怪的是,默认情况下,深度为1.0,深度函数为“较少”GL_LESS
。
我基本上是反转它,以便我的对象不会反转显示...
我见过没有这样的黑客攻击,但另一方面我看到没有任何对象被系统地以错误的顺序绘制,无论我绘制它们的顺序!
好的,这是我想要的现在的代码(被剥离,而不是太多希望):
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(600, 600); // Size of the OpenGL window
glutCreateWindow("OpenGL - 3D Test"); // Creates OpenGL Window
glutDisplayFunc(display);
glutReshapeFunc(reshape);
PngImage* pi = new PngImage(); // custom class that reads well PNG with transparency
pi->read_from_file("target.png");
GLuint texs[1];
glGenTextures(1, texs);
target_texture = texs[0];
glBindTexture(GL_TEXTURE_2D, target_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, pi->getGLInternalFormat(), pi->getWidth(), pi->getHeight(), 0, pi->getGLFormat(), GL_UNSIGNED_BYTE, pi->getTexels());
glutMainLoop(); // never returns!
return 0;
}
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1, 1, -1, 1);
gluPerspective(45.0, w/(GLdouble)h, 0.5, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void display(void) {
// The stared *** lines in this function make the (ugly?) fix for my second problem
glClearColor(0, 0, 0, 1.00);
glClearDepth(0); // ***
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glEnable(GL_DEPTH_FUNC); // ***
glDepthFunc(GL_GREATER); // ***
draw_scene();
glutSwapBuffers();
glutPostRedisplay();
}
void draw_scene() {
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(1.5, 0, -3, 0, 0, 1, 0, 1, 0);
glColor4f(1.0, 1.0, 1.0, 1.0);
glEnable(GL_TEXTURE_2D);
// The following 2 lines fix the first problem
glEnable(GL_ALPHA_TEST); // makes highly transparent parts
glAlphaFunc(GL_GREATER, 0.2f); // as not existent/not drawn
glBindTexture(GL_TEXTURE_2D, target_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Drawing a textured target
float x = 0, y = 0, z = 0, size = 0.2;
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(x-size, y-size, z);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(x+size, y-size, z);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(x+size, y+size, z);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(x-size, y+size, z);
glEnd();
// Drawing an textured target behind the other (but drawn after)
float x = 0, y = 0, z = 2, size = 0.2;
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(x-size, y-size, z);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(x+size, y-size, z);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(x+size, y+size, z);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(x-size, y+size, z);
glEnd();
}
答案 0 :(得分:4)
通常深度清除值为1(实际上是无限远),深度传递函数为LESS,因为您想要模拟真实世界,在那里您可以看到它们背后的事物。通过将深度缓冲区清除为1,您基本上是说应该绘制比最大深度更近的所有对象。除非您真正了解自己在做什么,否则更改这些参数通常不是您想要做的事情。
使用相机参数传递给gluLookAt和物体的位置时,z = 2四边形将比相机的z = 0对象更远。你想要完成什么,这似乎不正确?
实现顺序正确的alpha混合的标准方法是渲染所有不透明对象,然后将所有透明对象渲染回前方。始终使用常规/默认深度函数。
另请注意,您可能会从设置透视矩阵的方式中获得一些奇怪的行为。通常你会打电话给gluOrtho或gluPerspective。但不是两个。这会将两个不同的透视矩阵相乘,这可能不是你想要的。
答案 1 :(得分:0)
补充问题:顺便说一下,是 有一个指定不同的意思 alpha测试的来源比 用于混合的alpha层?
是的,如果你使用着色器,你可以自己计算输出片段的alpha值。
答案 2 :(得分:0)
关于第二个问题:你的modelViewProjection矩阵可能有问题。
我遇到了同样的问题(并且可以用你的黑客“修复”它)是由于我使用了一个奇怪错误的矩阵。我解决了它实现我自己的矩阵生成。
答案 3 :(得分:0)
在标准glOrtho函数映射中实现的公式z接近-1,zFar为1,默认情况下映射到窗口坐标为[0,1](可通过glDepthRange更改为固定管道,不确定是否仍支持该功能) 。深度测试确实在这些方面起作用。 解决这个问题的方法只是假设zNear离投影平面最远,或者自己生成矩阵,如果你想摆脱传统的管道,无论如何都需要它。