OpenGL ES 2.0矢量转换无法通过矩阵乘法工作(在顶点着色器中)

时间:2017-03-04 14:37:33

标签: android matrix opengl-es opengl-es-2.0

我正在使用OpenGL ES 2.0在Java(Android)中构建一个sprite(带纹理的矩形)类。

我的目标是只使用纹理的一部分,因此我将矩阵传递给顶点着色器。在下面的例子中,我只想看到纹理的右半部分(但是我正在看左半部分),在整个精灵宽度上缩放:

/ 0.5, 0, 0, 0.5 \      / x \       / 0.5 * x + 0.5 \
| 0  , 1, 0, 0   |  \/  | y |  ---  |       y       |
| 0  , 0, 1, 0   |  /\  | 1 |  ---  |       1       |
\ 0  , 0, 0, 1   /      \ 1 /       \       1       /

如果我放入我的纹理坐标,它就可以正常工作(在纸上):

(0,1) -> (0.5,1) // bottom left
(1,1) -> (1,  1) // bottom right
(0,0) -> (0.5,0) // top left
(1,0) -> (1,  0) // top right

但实际上我得到了这些结果:

(0,1) -> (0  ,1)
(1,1) -> (0.5,1)
(0,0) -> (0  ,0)
(1,0) -> (0.5,0)

这意味着缩放部分可以工作,但翻译部分不起作用。

代码

顶点着色器

attribute vec4 position;
attribute vec2 texturePosition;
uniform mat4 mvpMatrix;
uniform mat4 textureMatrix;
varying vec2 iTexturePosition;
void main() {
  gl_Position = mvpMatrix * position;

  vec4 tp = vec4(texturePosition.x, texturePosition.y, 1, 1);
  tp = textureMatrix * tp;
  //tp[0] += 0.5;
  iTexturePosition = tp.xy;
}

片段着色器

precision mediump float;
uniform sampler2D textureUnit;
varying vec2 iTexturePosition;
void main() {
  vec4 color = texture2D(textureUnit, iTexturePosition);
  if (color.a <= 0.25) {
    discard;
  }
  if (iTexturePosition[0] <= 0.4) {
    //discard;
  }
  gl_FragColor = color;
}

Java端

private static int textureMatrixHandle = -1;
private static final String textureMatrixName = "textureMatrix";
private float[] textureMatrix = new float[16];

// more code ...

@Override
public void draw { // only relevant lines
    textureMatrixHandle = GLES20.glGetUniformLocation(glProgram, textureMatrixName);

    Matrix.setIdentityM(textureMatrix, 0);
    setTextureSection(textureMatrix, 0, 0.5f, 1, 1, 0);

    GLES20.glUniformMatrix4fv(textureMatrixHandle, 1, false, textureMatrix, 0);

    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, VERTEX_COUNT);
}

protected void translateTextureSection(float[] textureMatrix, float x, float y) {
    Matrix.multiplyMM(textureMatrix, 0, new float[] {
            1, 0, 0, x,
            0, 1, 0, y,
            0, 0, 1, 0,
            0, 0, 0, 1,
    }, 0, textureMatrix, 0);
}

protected void scaleTextureSection(float[] textureMatrix, float x, float y) {
    Matrix.multiplyMM(textureMatrix, 0, new float[] {
            x, 0, 0, 0,
            0, y, 0, 0,
            0, 0, 1, 0,
            0, 0, 0, 1,
    }, 0, textureMatrix, 0);
}

protected void rotateTextureSection(float[] textureMatrix, float angle) {
    angle = (float) Math.toRadians(angle);
    float sin = (float) Math.sin(angle);
    float cos = (float) Math.cos(angle);
    Matrix.multiplyMM(textureMatrix, 0, new float[] {
            cos, -sin, 0, 0,
            sin,  cos, 0, 0,
              0,    0, 1, 0,
              0,    0, 0, 1,
    }, 0, textureMatrix, 0);
}

protected void setTextureSection(float[] textureMatrix, float rotationAngle, float left, float right, float bottom, float top) {
    rotateTextureSection(textureMatrix, rotationAngle);
    translateTextureSection(textureMatrix, left, top);
    scaleTextureSection(textureMatrix, right - left, bottom - top);
}

2 个答案:

答案 0 :(得分:0)

问题在于你打电话Matrix.MultiplyMM的方式。如果结果数组的相同元素用作输入之一,则结果是未定义的:

  

可以为结果,lhs和/或rhs传递相同的float数组。但是,如果结果元素与lhs或rhs元素重叠,则结果元素值是未定义的。

因此,将函数更改为使用临时矩阵,例如:

float[] tempMatrix = new float[16];
protected void translateTextureSection(float[] textureMatrix, float x, float y) {        
    Matrix.multiplyMM(tempMatrix, 0, new float[] {
            1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, 1, 0,
            x, y, 0, 1,
    }, 0, textureMatrix, 0);
    System.arraycopy( tempMatrix, 0, textureMatrix, 0, tempMatrix.length );
}

此外,矩阵需要转置,因为Open GL使用列主要顺序,但是您传递的浮点数是行主要顺序。在Open GLES中不支持在调用glUniformMatrixf4v时设置转置标志,因此您需要自己完成。

答案 1 :(得分:0)

问题是Java在OGL ES only supports column-major matrices时使用了行主矩阵。含义如下矩阵

(0.5, 0.0, 0.0, 0.5, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0)

被解释为

/ 0.5, 0, 0, 0 \      / x \       / 0.5 * x           \
| 0  , 1, 0, 0 |  \/  | y |  ---  |       y           |
| 0  , 0, 1, 0 |  /\  | 1 |  ---  |       1           |
\ 0.5, 0, 0, 1 /      \ 1 /       \       1 + 0.5 * x /

显然不会转换坐标。

在将矩阵传递给OGL ES之前调换矩阵解决了这个问题。