【发布时间】:2013-10-08 22:38:03
【问题描述】:
在某些情况下,当用户放大图像直到最短边填满整个屏幕(如标准图库中所见)时,需要扩展纹理。但是,OpenGL 着色器的输入是来自 ImageView 的矩阵,因此需要进行某些转换以及针对不同空间的校正计算。
编辑:
顶点着色器代码比较简单,如下:
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";
其中 a_position 引用下面的 verticesData_。加载到屏幕上时,图像的位置是根据显示宽度和所占用的屏幕部分计算得出的准确位置。
另外,我有以下片段着色器代码:
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";
mat3 转换的输入是来自 ImageView 的输入。本质上,OpenGLSurfaceView 下面有一个 ImageView。这是一个分辨率低得多的图像,当用户滑动时,SurfaceView 被隐藏,ImageView 位于其下方,与用户在 SurfaceView 中的位置相同。
但是,稍后当我想扩展此纹理时,我发现自己会得到意想不到的结果。
来回平移时,屏幕会移动到预期移动的位置。因此,矩阵中 x 和 y 坐标的平移正常。但是,放大时,图像会撕裂。只有当纹理的边界超出屏幕尺寸时才会撕裂。如下图所示,高度在增长时并没有引入额外的像素,但宽度在增长时会撕裂。
为了传递适当的矩阵,从 ImageView 到 OpenGL SurfaceView 的值被反转和转置,因为空间需要它进行适当的转换。将比例因子传递给 Activity 正在侦听的侦听器。
@Override
public void onTranslation(float imageScaleF, float[] matrixTranslationF)
{
currentScaleForImage_ = imageScaleF;
//If we are currently using the entire screen, then there is not need anymore to resize the texture itself.
if(surfaceViewWidth_ * imageScaleF > displayViewWidth_ && surfaceViewHeight_ * imageScaleF > displayViewHeight_)
{
}
else //Expand the size of the texture to be displayed on the screen.
{
maximumScaleForImage_ = imageScaleF;
photoViewRenderer_.updateTextureSize(imageScaleF);
photoSurfaceView_.requestRender();
}
matrixTranslationF = updateTranslationBasedOnTextureSize(matrixTranslationF);
photoViewRenderer_.updateTranslationOfTexture(matrixTranslationF);
photoSurfaceView_.requestRender();
}
但是,使用上面的以下代码,滚动的图像部分总是被剪短,如果我试图通过取消注释更新翻译的行来根据比例更正它,它会导致眼泪。所以,似乎在这一点上,下面的用户通过他们的输入让我处于一个更好的位置,但我仍然只有一步之遥,我认为它在这个函数中。以下现在更新的代码进行了必要的更正,以便在 ImageView 中的矩阵和 OpenGL 纹理/坐标之间提供适当的转换。
private float[] updateTranslationBasedOnTextureSize(float[] matrixTranslationsF)
{
if(scaleDirection_ == ScaleDirection.WIDTH)
{
matrixTranslationsF[0] = matrixTranslationsF[0] * maximumScaleForImage_;
}
else if(scaleDirection_ == ScaleDirection.HEIGHT)
{
matrixTranslationsF[4] = matrixTranslationsF[4] * maximumScaleForImage_;
}
return matrixTranslationsF;
}
我在第一次迭代中导致照片撕裂,如下所示。或者由于两个空间之间的不正确转换,它正在剪裁照片。
宽度似乎保持不变,所以它暗示我可能会在标准范围之外的值发生某些事情,但我不确定要尝试什么。
【问题讨论】:
-
纹理坐标范围实际上不是 (-1,-1) - (1,1)。它们被归一化为 (0,0) - (1,1)。此范围之外的任何内容都受您的纹理环绕模式的影响,在这种情况下,您看起来像是在使用
CLAMP_TO_EDGE。如果您期望它们在 (-1,-1) 到 (1,1) 的范围内,这可以解释一些奇怪的行为 - 坐标空间实际上是用于投影后的顶点,就在它们映射到视口之前. -
我不确定您在这里尝试产生的行为是什么。如果您正在平移,那么在桌面 GL 中您可以使用
GL_CLAMP_TO_BORDER并设置黑色边框颜色,当然 GLES 中不存在这种钳制模式。您必须通过检测超出范围的纹理坐标在片段着色器中手动实现它。 -
我很想赢得你的赏金,但我不知道你还在寻找什么。想一想……您可以通过放大图片的宽度和高度、使用矩阵数学放大或缩小纹理坐标来放大图片。我在回答中给你的公式是我在我的应用程序中用来放大/缩小和平移图像的公式。就像我在我的 cmets 中所说的那样。我的回答是正确的。你的纹理坐标超出了界限——正如我和安东所说的那样。但您似乎在寻找其他东西 - 不确定是什么。
-
事实上,我需要使用其中的多个进行扩展。这对我来说有点棘手;特别是因为我不会在诸如此类的小时刻之外使用 OpenGL。我需要放大纹理以使其填充屏幕,但从那里我需要使用来自 Android ImageView 的矩阵数学来匹配我传递给 OpenGL 代码的矩阵。当然,在纹理调整大小的过程中也会发生矩阵变化以进行补偿。并且发现最新纹理大小和矩阵输入之间的相关性给我带来了问题。
标签: android opengl-es opengl-es-2.0