【问题标题】:Set origin to top-left corner of screen in OpenGL ES 2在 OpenGL ES 2 中将原点设置为屏幕的左上角
【发布时间】:2014-08-21 11:47:55
【问题描述】:

我正在使用 OpenGL ES 2.0 开发一个 Android 应用程序。它由覆盖在 3D 场景上的 2D HUD 组成。 3D 部分一切正常,但在 2D 中绘制时,我无法弄清楚 如何将原点定位在屏幕的左上角(y 轴朝下)。现在我的原点位于屏幕的中心,我只是在绘制时从坐标中减去一半的宽度和高度。 (我知道这是一个 hacky 解决方案,我想解决这个问题!)

以下是相关代码:

GLES20.glViewport(0, 0, surfaceWidth, surfaceHeight);
Matrix.orthoM(projectionMatrix, 0, -width / 2, width / 2, height / 2, -height / 2, -1, 1);
Matrix.setLookAtM(viewMatrix, 0, 0, 0, 2f, 0, 0, 0, 0, -1, 0);
Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, viewMatrix, 0);

以下是相关的着色器:

private final static String vertexShaderCode =
                "uniform mat4 uMVPMatrix;" +
                "attribute vec2 aTexCoordinate;" +
                "varying vec2 vTexCoordinate;" +
                "attribute vec4 aPosition;" +
                "attribute vec4 aColor;" +
                "varying vec4 vColor;" +
                "void main() {" +
                "  vColor = aColor;" +
                "  vTexCoordinate = aTexCoordinate;" +
                "  gl_Position = aPosition * uMVPMatrix;" +
                "}";

private final static String fragmentShaderCode =
                "precision mediump float;" +
                "uniform sampler2D uTexture;" +
                "varying vec2 vTexCoordinate;" +
                "varying vec4 vColor;" +
                "void main() {" +
                "  gl_FragColor = vColor * texture2D(uTexture, vTexCoordinate);" +
                "}";

我尝试过的:

  • 我尝试过使用这条线:

    Matrix.orthoM(projectionMatrix, 0, 0, width, height, 0, -1, 1);
    
  • 我尝试将原点定位在左下角,而不是左上角(我不应该这样做,但我还是尝试了)。

  • 我已尝试在顶点着色器的倒数第二行中切换aPositionuMVPMatrix 的顺序。

这三个更改的组合没有解决我的问题(2D 对象不渲染)。

我尝试的另一件事是将原点设置为偏离中心 1 个像素,然后是 2 个像素,然后是 3 个,依此类推。我越偏离中心,图像就会不断倾斜,最终变得太薄而无法看到 - 但那仍然没有告诉我如何解决这个问题。

同样,问题是:如何在 OpenGL ES 2.0 中将原点定位在左上角?

附:我的合同(第一份工作!)于 7 月 29 日到期,所以我很快就需要一个答复;我不想给下一个人留下这样的 hacky 修复。

【问题讨论】:

    标签: android opengl-es


    【解决方案1】:

    在 OpenGL 中并不是一个规则只有一个 mvpMatrix。这很好,因为您可以自定义很多视图。

    如果您的所有应用程序都基于您在此处显示的 mvpMatrix,我建议您为您提出的建议创建另一个 mvpMatrix:使视图的中心位于左上角。

    所以,答案很简单,让我们重新创建每个矩阵。一开始,viewMatrix:

    Matrix.setLookAtM(viewMatrix, 0, 
         0, 0,  6,   //eye
         0, 0,  0,   //center
         0, 1,  0);  //UP *remove your -1
    

    魔法在下面。你必须颠倒底部和顶部:

    float screenRatio = (float) width / height;
    Matrix.orthoM(projectionMatrix, 0, 
            0, screenRatio, // left, right
            1, 0,           // bottom, top        <----Solution is invert bottom with top
            -1, 10);        // near, far
    

    最后:

        Matrix.multiplyMM(
                viewProjectionMatrix, 0, 
                projectionMatrix, 0, 
                viewMatrix, 0);
    

    P.S:不用改GLES20.glViewport(0, 0, surfaceWidth, surfaceHeight);

    OpenGL 有很多解决这个问题的方法,因为你可以尽可能地处理所有的矩阵。

    另一种解决方案是自定义您自己的矩阵,而不使用Matrix.orthoM(..)Matrix.frustum(..)

    public static final float[] topLeftMatrix(int width, int height){
        float matrix[] = new float[16];
    
        // This is inverse of viewPort matrix
        matrix[0] = 2.0f/width;
        matrix[1] = 0;
        matrix[2] = 0;
        matrix[3] = 0;
    
        matrix[4] = 0;
        matrix[5] = -2.0f/height;
        matrix[6] = 0;
        matrix[7] = 0;
    
        matrix[8] = 0;
        matrix[9] = 0;
        matrix[10] = 1;
        matrix[11] = 0;
    
        matrix[12] = -1;
        matrix[13] = 1;
        matrix[14] = 0;
        matrix[15] = 1;
    
        return matrix;
    }
    

    上面的这个矩阵非常适合处理像素上的对象(如用户界面)。

    为了全面了解,我建议你阅读这篇文章:3D Graphics with OpenGL。它对我理解 opengl 的魔力帮助很大。

    P.S: 你的着色器有错误。将 matrix4x4 乘以向量 4x1 的正确方法是:

    gl_Position = uMVPMatrix * aPosition;

    【讨论】:

    • 我明天上班的时候试试这个。谢谢!
    • 关于着色器的最后一点是有道理的(这就是我在 3D 中的做法)。奇怪的是,在 2D 中 vector * matrix 有效,但 matrix * vector 无效(至少我无法做到)。
    • OpenGL 使用数学规则。因此,您只能将列数与行数相同的矩阵相乘。 Matrix-Wikipedia
    • 是的,我知道如何将矩阵相乘,所以我觉得这对我有用很奇怪。我一直认为居中的原点创建了一个特殊情况,即绘图是正确的,而乘法是相反的。但正如我在问题中所说,使用正确的顺序似乎并没有解决问题。
    • 我还没有尝试过,因为我还有其他工作要做。在我有机会之前可能是星期一或星期二。不过感谢您的帮助,我很感激。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多