2

我开始使用java在android(GL10)中学习open GL,并且我按照一些教程来绘制正方形、三角形等。

现在我开始画一些我有的想法,但我真的对屏幕的绘制顶点感到困惑。当我使用 openGL ES 绘制某些东西时,我必须指定我想要绘制的屏幕部分以及纹理的相同部分......

所以我开始做一些测试,并用这个顶点打印了一个全屏纹理:

(-1, -1, //top left
 -1, 1, //bottom left
 1, -1, //top right
 1, 1); //bottom right

为什么是全屏?OpenGL坐标的中心不是在左上角(0, 0)吗?为什么用那个顶点绘制是正确的?看起来中心真的是屏幕的真正中心,宽度和高度是从-1...1,但我不太明白,因为我认为中心在左上角......

另一个问题......我阅读了很多使用像素打印的c++代码。在使用像素的视频游戏中似乎真的很有必要,因为需要事物的确切位置,而使用 -1...1 我不能非常精确。如何使用像素而不是 -1...1?

真的感谢和抱歉我糟糕的英语。谢谢

4

3 回答 3

9

为什么是全屏?OpenGL坐标的中心不是在左上角(0, 0)吗?为什么用那个顶点绘制是正确的?看起来中心真的是屏幕的真正中心,宽度和高度是从-1...1,但我不太明白,因为我认为中心在左上角......

有 3 件事结合在一起。所谓的viewport,所谓的标准化设备坐标(NDC),以及从模型空间到眼睛空间到剪辑空间到 NDC 空间的投影。

视口选择 NDC 范围所在的窗口部分

[-1…1]×[-1…1]

映射到。函数签名是glViewport(x, y, width, height). OpenGL假设一个坐标系,上升的NDC x坐标向右,上升的NDC y坐标上升。

因此,如果您调用glViewport(0, 0, window_width, window_height),这也是第一次将 OpenGL 上下文绑定到窗口后的默认设置,NDC 坐标 (-1, -1) 将位于左下方,而 NDC 坐标 (1,1) 将位于窗口的右上角。

OpenGL 开始时将所有转换设置为恒等式,这意味着您通过的顶点坐标直接通过 NDC 空间并被解释为这样。然而,在 OpenGL 中,大多数时候你都在应用连续的转换:

  • 模型视图

  • 投影

模型视图转换用于在静止的眼睛/相机(始终位于 (0,0,0) 处)前在世界范围内移动。放置相机只是意味着添加整个世界的额外转换(视图转换),这与您在世界中放置相机的方式完全相反。固定函数 OpenGL 将此称为 MODELVIEW 矩阵如果矩阵模式已设置为 GL_MODELVIEW,则可以访问该矩阵。

投影变换是OpenGL的一种镜头。您可以使用它来设置它是广角还是小角(在透视的情况下)或长方体的边缘(正射投影),甚至是不同的东西。固定函数 OpenGL 将此称为 PROJECTION 矩阵如果矩阵模式已设置为GL_PROJECTION 则可以访问。

在投影图元被剪裁后,然后应用所谓的同质分割,如果应用了透视投影,则创建实际的透视效果。

此时顶点已转换为 NDC 空间,然后如开头所述映射到视口。


关于您的问题:您想要的是一个将顶点坐标 1:1 映射到视口像素的投影。很简单:

glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if( origin_lower_left ) {
    glOrtho(0, width, height, 0, -1, 1);
} else {
    glOrtho(0, width, 0, height, -1, 1);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

现在顶点坐标映射到视口像素。


更新:通过三角形绘制一个完整的视口纹理四边形:

OpenGL-2.1 和 OpenGL ES-1

void fullscreenquad(int width, int height, GLuint texture)
{
    GLfloat vtcs[] = {
      0, 0,
      1, 0,
      1, 1,
      0, 1
    };

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glVertexPointer(2, GL_FLOAT, 0, vtcs);
    glTexCoordPointer(2, GL_FLOAT, 0, vtcs);

    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, 1, 0, 1, -1, 1);

    glMatrixMode(GL_MODELVIEW);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, texture);
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
于 2012-02-19T12:51:33.463 回答
2

您需要阅读更多内容以使事情更清楚。在 openGL 中,您指定一个视口。此视口是您对 OpenGL 空间的视图,因此如果您将其设置为屏幕中心位于屏幕中间并且视图从 -1 延伸到 1,那么这就是您对 OpenGL 的完整视图. 不要将其与 Android 中的屏幕坐标混合(这些坐标的原点位于您提到的左上角)。您需要在这些坐标之间进行转换(例如触摸事件)以匹配其他坐标系。

于 2012-02-19T11:59:45.290 回答
2

默认情况下,opengl 相机放置在指向负 z 轴的原点。无论在平面附近投影在相机上的东西都是屏幕上看到的东西。因此屏幕的中心对应于(0,0)

根据您要绘制的内容,您可以选择使用 GL_POINT、GL_LINE 和 GL_TRIANGLE 进行绘制。

您可以使用 GL_POINTS 为屏幕上的某些像素着色,但如果您需要绘制对象/网格,例如茶壶、立方体等,则不应使用三角形。

于 2012-02-19T11:57:50.950 回答