在OpenGL 3.0中将绘制时将像素坐标转换为标准化坐标

时间:2015-07-02 21:14:22

标签: android opengl-es orthographic

我在OpenGL中绘制一个三角形,如:

            MyGLRenderer( )
            {
                fSampleVertices = ByteBuffer.allocateDirect( fSampleVerticesData.length * 4 )
                        .order ( ByteOrder.nativeOrder( ) ).asFloatBuffer( );

                fSampleVertices.put( fSampleVerticesData ).position ( 0 );

                Log.d( TAG, "MyGLRender( )" );
            }

            private FloatBuffer fSampleVertices;

            private final float[] fSampleVerticesData =
                    { .8f, .8f, 0.0f, -.8f, .8f, 0.0f, -.8f, -.8f, 0.0f };

            public void onDrawFrame( GL10 unused )
            {
                GLES30.glViewport ( 0, 0, mWidth, mHeight );

                GLES30.glClear ( GLES30.GL_COLOR_BUFFER_BIT );

                GLES30.glUseProgram ( dProgramObject1 );

                GLES30.glVertexAttribPointer ( 0, 3, GLES30.GL_FLOAT, false, 0, fSampleVertices );

                GLES30.glEnableVertexAttribArray ( 0 );

                GLES30.glDrawArrays( GLES30.GL_TRIANGLES, 0, 3 );

                //Log.d( TAG, "onDrawFrame( )" );
            }

因为我已经尝试过坐标,所以不需要花很长时间才能弄清楚屏幕的可见区域 介于-1,1之间。那么三角形占据屏幕的80%。我也确定了我的像素尺寸 GLSurfaceView的宽度为2560,高度为1600。

然后给出一个带有这些基于像素的坐标的三角形(fBoardOuter):

    1112.0f
    800.0f
    0.0f
    -1280.0f
    800.0f
    0.0f
    -1280.0f
    -800.0f
    0.0f

我必须将这些像素坐标转换为-1,1之间的某个坐标,或者找出一种方法来转换那些坐标 在他们被吸引的时候?由于我是OpenGL的新手,我正在寻找一些指导来做到这一点?

我的顶点着色器就像:

    String sVertexShader1 =
              "#version 300 es              \n"
            + "in vec4 vPosition;           \n"
            + "void main()                  \n"
            + "{                            \n"
            + "   gl_Position = vPosition;  \n"
            + "}                            \n";

我会说基于像素的系统会被称为世界坐标吗?我现在想做的只是一些棋盘游戏的2D绘图。

我发现Android具有此功能:

    orthoM(float[] m, int mOffset, float left, float right, float bottom, float top, float near, float far)

然而,到目前为止,我所阅读的文档中没有任何内容可以解释矩阵的用法,该矩阵用于如何将带有像素坐标的float []转换为GLES30中与该矩阵的标准化坐标。

我也在这里找到了文档:

http://developer.android.com/guide/topics/graphics/opengl.html

根据我试图创建示例的文档:

http://pastebin.com/5PTsfSdz

在pastebin示例fSampleVertices中,我认为它会小得多,位于屏幕的中心,但它几乎不是整个屏幕,如果我尝试将fBoardOuter显示为黑屏把它放进glDrawArray。

1 个答案:

答案 0 :(得分:1)

您可能需要找一本书或一些好的教程才能掌握其中的一些概念。但是由于你的问题中有一些特定的项目,我会尝试在这种格式下解释它们。

您发现的坐标系在x和y坐标方向上的范围是[-1.0,1.0],正式称为标准化设备坐标,通常缩写为NDC。这与您提出的名称非常相似,因此一些OpenGL术语实际上非常合乎逻辑。 :)

至少只要你处理2D坐标,这就是你的顶点着色器需要产生的坐标范围。即您为内置gl_Position变量指定的坐标必须在此范围内才能在输出中可见。如果您正在处理3D坐标并应用透视投影,事情会变得稍微复杂一点,但我们暂时会跳过这部分。

现在,正如您已经猜到的,如果您想在不同的坐标系中指定坐标,则有两个主要选项:

  1. 在将代码传递给OpenGL之前,将它们转换为代码中的NDC。
  2. 您已将OpenGL应用转换为输入坐标。
  3. 选项2显然是更好的选择,因为GPU在执行此工作时非常有效。

    在一个非常简单的层面上,这意味着您可以修改顶点着色器中的坐标。如果你看一下非常简单的第一个顶点着色器:

    in vec4 vPosition;
    void main()
    {
        gl_Position = vPosition;
    }
    

    您可以在vPosition输入变量中获取应用代码提供的坐标,并将相同的坐标分配给顶点着色器输出gl_Position

    如果要使用不同的坐标系,可以在顶点着色器代码中处理输入坐标,并将这些处理过的坐标分配给输出。

    现在版本的OpenGL实际上并没有这些坐标系的名称。当一些东西仍然硬连线到固定管道时,曾经有“模型坐标”和“世界坐标”。现在,这是通过可编程着色器代码完成的,从OpenGL的角度来看,这些概念不再相关。所有它关心的是从顶点着色器出来的坐标。之前发生的一切都是你自己的事。

    应用线性变换的规范方法,包括您的预期用途所需的平移和缩放,是通过将坐标与变换矩阵相乘。如果您不想自己编写(简单)代码,那么您已经发现了android.opengl.Matrix包,其中包含一些用于构建转换矩阵的实用函数。

    获得变换矩阵后,将其作为 uniform 变量传递到顶点着色器中,并在着色器代码中应用矩阵。它在着色器代码中的显示方式例如是:

    in vec4 vPosition;
    uniform mat4 TransformMat;
    void main()
    {
        gl_Position = TransformMat * vPosition;
    }
    

    要设置此矩阵的值,您需要在使用着色器程序prog链接着色器后获取统一变量的位置

    GLint transformLoc = GLES20.glGetUniformLocation(prog, "TransformMat");
    

    然后,至少一次,每次想要更改矩阵时,请调用:

    GLES20.glUniformMatrix4fv(transformLoc, 1, GL_FALSE, mat, 0);
    

    其中mat是您自己构建的矩阵,或来自android.opengl.Matrix中的一个效用函数。请注意,此调用需要 之后才能使程序与glUseProgram()保持同步。