我正在使用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);
}
答案 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之前调换矩阵解决了这个问题。