在 OpenGL 3.0 中绘制时将像素坐标转换为标准化坐标 [英] Converting pixel co-ordinates to normalized co-ordinates at draw time in OpenGL 3.0

查看:80
本文介绍了在 OpenGL 3.0 中绘制时将像素坐标转换为标准化坐标的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am drawing a triangle in OpenGL like:

            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.

So since I have experimented with the co-ordinates it doesn't take long to figure out that the visible area of the screen is between -1,1. So then the triangle takes up 80% of the screen. As well I have determined that the pixel dimensions of my GLSurfaceView are 2560 in width and 1600 in height.

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

So then given a triangle with these pixel based co-ordinates (fBoardOuter):

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

我必须将这些像素坐标转换为 -1,1 之间的值,或者找到一种方法让 gl 转换这些坐标在他们被画的时候?由于我对 OpenGL 非常陌生,我正在寻找一些指导来做到这一点?

I have to either convert those pixel co-ordinates to something between -1,1 or find out a way to have gl convert those co-ordinates at the time they are drawn? Since I am very new to OpenGL I am looking for some guidance to do this?

我的顶点着色器是这样的:

My vertex shader is like:

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

那么我说基于像素的系统将被称为世界坐标是否正确?我现在要做的只是为棋盘游戏绘制一些 2D 绘图.

Would I be correct then in saying that a pixels based system would be called world co-ordinates? What I am trying to do right now is just some 2D drawing for a board game.

我发现安卓有这个功能:

I've discovered that Android has this function:

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

然而,到目前为止,我读过的文档中没有任何内容解释矩阵的用法,即如何将具有像素坐标的 float[] 转换为 GLES30 中具有该矩阵的规范化坐标.

However there is nothing in the documentation I've read so far that explain the usage of the matrix of how a float[] with pixel co-ordinates can be transformed to normalized co-ordinates with that matrix in GLES30.

我还在这里找到了文档:

I've also found the documentation here:

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

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

Based off the documentation I have tried to create an example:

http://pastebin.com/5PTsfSdz

在 pastebin 示例中,我认为 fSampleVertices 会小得多并且位于屏幕中央,但事实并非如此,它几乎仍然是整个屏幕,如果我尝试将其放入 glDrawArray,fBoardOuter 只会向我显示一个黑屏.

In the pastebin example fSampleVertices I thought would be much smaller and at the center of the screen but it isn't it's still almost the entire screen and fBoardOuter just shows me a black screen if I try to put it into glDrawArray.

推荐答案

您可能需要找一本书或一些好的教程来深入掌握其中的一些概念.但由于您的问题中有一些特定的项目,我将尝试在这种格式中尽可能地解释它们.

You will probably need to find a book or some good tutorials to get a strong grasp on some of these concepts. But since there some specific items in your question, I'll try and explain them as well as I can within this format.

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

The coordinate system you discovered, where the range is [-1.0, 1.0] in the x- and y coordinate directions, is officially called Normalized Device Coordinates, often abbreviated as NDC. Which is very similar to the name you came up with, so some of the OpenGL terminology is actually very logical. :)

至少只要您处理的是 2D 坐标,这就是您的顶点着色器需要生成的坐标范围.IE.您分配给内置 gl_Position 变量的坐标需要在此范围内才能在输出中可见.如果您正在处理 3D 坐标并应用透视投影,事情会变得稍微复杂一些,但我们现在将跳过该部分.

At least as long as you're dealing with 2D coordinates, this is the coordinate range your vertex shader needs to produce. I.e. the coordinates you assign to the built-in gl_Position variable need to be within this range to be visible in the output. Things gets slightly more complicated if you're dealing with 3D coordinates and are applying perspective projections, but we'll skip over that part for now.

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

Now, as you already guessed, you have two main options if you want to specify your coordinates in a different coordinate system:

  1. 在将它们传递给 OpenGL 之前,您在代码中将它们转换为 NDC.
  2. 您让 OpenGL 将转换应用于您的输入坐标.

选项 2 显然更好,因为 GPU 在执行这项工作时非常高效.

Option 2 is clearly the better one, since GPUs are very efficient at performing this job.

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

On a very simple level, this means that you modify the coordinates in your vertex shader. If you look at your very simple first vertex shader:

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

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

you get the coordinates provided by your app code in the vPosition input variable, and you assign exactly he same coordinates to the vertex shader output gl_Position.

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

If you want to use a different coordinate system, you process the input coordinates in the vertex shader code, and assign those processed coordinates to the output instead.

现代版本的 OpenGL 不再真正为这些坐标系命名.当这些东西中的一些仍然硬连接到固定管道时,曾经有模型坐标"和世界坐标".现在这是通过可编程着色器代码完成的,从 OpenGL 的角度来看,这些概念不再相关.它只关心从顶点着色器出来的坐标.在此之前发生的一切都是您自己的事情.

Modern versions of OpenGL don't really have a name for those coordinate systems anymore. There used to be "model coordinates" and "world coordinates" when some of this stuff was still hardwired into a fixed pipeline. Now that this is done with programmable shader code, those concepts are not relevant anymore from the OpenGL point of view. All it cares about are the coordinates that come out of the vertex shader. Everything that happens before that is your own business.

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

The canonical way of applying linear transformations, which includes the translations and scaling you need for your intended use, is by multiplying the coordinates with a transformation matrix. You already discovered the android.opengl.Matrix package that contains some utility functions for building transformation matrices if you don't want to write the (simple) code yourself.

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

Once you have a transformation matrix, you pass it into the vertex shader as a uniform variable, and apply the matrix in your shader code. The way this looks in the shader code is for example:

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

要设置这个矩阵的值,你需要在链接着色器后获得一次uniform变量的位置,用prog你的着色器程序:

To set the value of this matrix, you need to get the location of the uniform variable once after linking the shader, with prog your shader program:

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

然后,至少一次,每次你想改变矩阵时,你调用:

Then, at least once, and every time you want to change the matrix, you call:

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

其中 mat 是您自己构建的矩阵,或者是从 android.opengl.Matrix 中的实用函数之一获得的矩阵.请注意,此调用需要在之后您使用 glUseProgram() 使程序成为当前程序.

where mat is the matrix you either built yourself, or got from one of the utility functions in android.opengl.Matrix. Note that this call needs to be after you make the program current with glUseProgram().

这篇关于在 OpenGL 3.0 中绘制时将像素坐标转换为标准化坐标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆