【问题标题】:android.grapics.matrix to OpenGL 2.0 ES texture translationandroid.grapics.matrix 到 OpenGL 2.0 ES 纹理转换
【发布时间】:2013-07-04 00:51:30
【问题描述】:

目前,应用程序会在屏幕上显示一个成功缩放和平移的 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 的更新进行更新。这可以处理两者之间的缩放和平移平移。

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

投票支持下面的答案,因为他们通过聊天极大地帮助我离线了解如何将图像视图与纹理链接起来。他们应得的。

如果您最终使用下面的顶点着色器修改,而不是片段着色器分辨率,那么似乎不再需要反转这些值来使用捏缩放(事实上,如果你保持原样)。此外,平移似乎也比预期的倒退。

【问题讨论】:

  • 您是否已经拥有使用着色器绘制纹理矩形的 OpenGL 代码?您是否只需要知道如何计算合适的矩阵并在着色器中使用它?
  • @GuyRT 没错。也许这对其他人来说被视为简单的事情,不确定。目前我有一个使用着色器显示的图像,需要对其进行更新,以便我基本上获得缩放效果,就像我已经在 ImageView 的纹理后面获得相同的图像一样。

标签: android opengl-es-2.0


【解决方案1】:

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

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。

【讨论】:

  • @q____b 我确实觉得这让我走上了一条更好的道路并感谢它。代码已在上面更新。虽然设置一个身份并从它开始对我来说是有意义的,但屏幕会因为纹理而不是向我显示图片而变成空白,并且它会因 glUniform3fv 函数而崩溃,但我会仔细研究它并尝试理解这些 OpenGl 东西好一些。不过,您已经在这部分项目上为我节省了大量时间,谢谢。
  • @JaySnayder 你能上传一段关于现在事情如何运作的视频,这将有助于了解你在做什么。
  • @JaySnayder 尝试传递反转矩阵,android Matrix 类提供反转方法来获取一个。
  • @JaySnayder 很可能这意味着 Android 矩阵与 OpenGL 所期望的相比是转置的,当将矩阵设置为着色器时,您应该设置标志以将其转回,使用标志来完成您使用的命令设置矩阵。
  • @JaySnayder 我认为调整转换以使翻译正常工作应该很容易。
猜你喜欢
  • 2011-05-19
  • 1970-01-01
  • 2012-01-16
  • 1970-01-01
  • 2012-04-08
  • 1970-01-01
  • 2023-03-04
  • 2012-04-08
  • 2012-03-29
相关资源
最近更新 更多