android.grapics.matrix到OpenGL 2.0 ES纹理翻译

时间:2013-06-19 14:38:51

标签: android opengl-es-2.0

目前,该应用程序显示一个成功缩放并在屏幕上平移的ImageView。在该图像的顶部,我想提供一种纹理,当我下面的图像缩放或平移时,我想更新自己以进行缩放或平移。

据我了解,这应该可以在ImageView上使用我当前设置的getImageMatrix(),然后将其应用于原始图像顶部的纹理位图。

编辑&解决方案:(以下所选答案的强力助手)

目前,纹理中的平移以与ImageView不同的速度发生,但是当解析后,我将使用其他编辑更新此发布,并为整个应用程序提供解决方案。然后只剩下解决方案和快速问题描述段落。也许我甚至会发布一个表面视图和渲染器源代码,以便使用可缩放的表面视图。

为了完成ImageView到OpenGL纹理的映射,为了正确地完成此操作,需要完成一些事情。希望这将有助于其他可能希望在未来使用可缩放SurfaceView的人。

着色器代码如下所示。 gl_FragColor从任何ImageView的getImageMatrix获取3x3的转换矩阵,以便从onDraw()方法中更新屏幕。

private final String vertexShader_ =
        "attribute vec4 a_position;\n" +
        "attribute vec4 a_texCoord;\n" +
        "varying vec2 v_texCoord;\n" +
        "void main() {\n" +
        "  gl_Position = a_position;\n" +
        "  v_texCoord = a_texCoord.xy;\n" +
        "}\n";

private final String fragmentShader_ =
        "precision mediump float;\n" +
        "varying vec2 v_texCoord;\n" +
        "uniform sampler2D texture;\n" +
        "uniform mat3 transform;\n" +
        "void main() {\n" +
        "  vec2 uv = (transform * vec3(v_texCoord, 1.0)).xy;\n" +
        "  gl_FragColor = texture2D( texture, uv );\n" +
        "}\n";

一开始,OpenGL的转换矩阵只是一个识别矩阵,我们的ImageView将通过监听器使用着色器更新这些共享值。

private float[] translationMatrix = {1.0f, 0.0f, 0.0f,
                                     0.0f, 1.0f, 0.0f,
                                     0.0f, 0.0f, 1.0f};
...
uniforms_[TRANSLATION_UNIFORM] = glGetUniformLocation(program_, "transform");
checkGlError("glGetUniformLocation transform");
if (uniforms_[TRANSLATION_UNIFORM] == -1) {
    throw new RuntimeException("Could not get uniform location for transform");
}
....
glUniformMatrix3fv(uniforms_[TRANSLATION_UNIFORM], 1, false, FloatBuffer.wrap(translationMatrix));
....

但是,OpenGL代码需要来自Android的OpenGL矩阵计算的反转,以及在将它们传递给渲染器以在屏幕上显示之前对它们执行的转置操作。这与存储信息的方式有关。

protected void onMatrixChanged()
{
    //...
    float[] matrixValues = new float[9];
    Matrix imageViewMatrix = getImageViewMatrix();
    Matrix invertedMatrix = new Matrix();
    imageViewMatrix.invert(invertedMatrix);
    invertedMatrix.getValues(matrixValues);
            transpose(matrixValues);
    matrixChangedListener.onTranslation(matrixValues);
    //...
}

除了输入OpenGL渲染器的值位于错误的位置之外,我们还遇到的问题是我们在imageHeight和imageWidth的范围内处理我们的翻译,而不是标准化的[0,1 ] OpenGL期望的范围。因此,为了纠正这一点,我们必须使用宽度和高度的可分数来定位最后一列。

matrixValues[6] = matrixValues[6] / getImageWidth();
matrixValues[7] = matrixValues[7] / getImageHeight();

然后,完成此操作后,您可以使用ImageView矩阵函数或更新的ImageTouchView矩阵函数(在Android上处理图像时具有一些其他不错的功能)开始映射。

效果可以在下面看到,其背后的ImageView占据了整个屏幕,并且它前面的纹理根据ImageView的更新进行更新。这可以处理两者之间的缩放和平移。

imageview updated opengl texture

此过程中唯一的另一个步骤是更改SurfaceView的大小以匹配ImageView的大小,以便在用户放大时获得全屏体验。为了仅显示表面视图,可以简单地在后台放置一个'隐形'图像视图。只需让ImageTouchView更新就可以改变OpenGL SurfaceView的显示方式。

投票给下面的答案,因为他们帮助我在聊天中离线显着,以便了解将imageview与纹理相关联时需要做些什么。他们应得的。

如果您最终使用下面的顶点着色器修改,而不是片段着色器分辨率,那么似乎不再需要反转这些值以便再次使用捏缩放(并且实际上可以向后工作你保持原样)。此外,平移似乎也比预期的要好。

1 个答案:

答案 0 :(得分:3)

您可以伪造片段着色器,只需将此矩阵设置为片段阴影的统一参数,并使用此矩阵修改纹理坐标。

precision mediump float;
uniform   sampler2D   samp;
uniform   mat3        transform;
varying   vec2        texCoord;

void main()
{
   vec2 uv = (transform * vec3(texCoord, 1.0)).xy;
   gl_FragColor = texture2D(samp, uv);
}

请注意,从图像视图获得的矩阵是行主要顺序,您应该将其转换为获得OpenGL列主要顺序,也可以分别按宽度和高度划分x和y平移分量。

更新:我刚刚想到修改顶点着色器会更好,你可以用你在片段着色器中使用的相同矩阵来缩放你的四边形,它会被夹在你的屏幕上对于大的,当小的时候边缘钳位不会有问题,并且矩阵乘法将仅发生4次而不是每个像素一次。只需在顶点着色器中执行:

gl_Position = vec4((transform * vec3(a_position.xy, 1.0)).xy, 0.0, 1.0);

并在片段着色器中使用未转换的texCoord。