目前,该应用程序显示一个ImageView,可以在屏幕上成功地进行缩放和平移。在该图像上方,我想提供一个纹理,并希望当其下方的图像缩放或平移时,该纹理更新自身以进行缩放或平移。
据我所知,使用当前设置中的ImageView的getImageMatrix(),然后将其应用于位于原始图像上方的文本化位图,应该是可能的。
编辑和解决方案:(在下面选择的答案的帮助下)
目前,纹理中的平移发生的速度与ImageView的速度不同,但是当已解决该问题后,我将使用附加编辑更新此帖子并提供整个应用程序的解决方案。只有解决方案和快速问题描述段落才会留下。也许我还会发布一个表面视图和渲染器源代码,用于使用可缩放表面视图。
要将ImageView映射到OpenGL纹理,需要完成一些工作,以正确完成此操作。希望这将对未来可能想要使用可缩放SurfaceView的其他人有所帮助。
着色器代码如下所示。gl_FragColor使用3x3的平移矩阵从onDraw()方法内部的任何ImageView的getImageMatrix来更新屏幕。
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渲染器时位置不正确的问题,我们还面临着处理图像高度和宽度比例而非OpenGL所期望的归一化[0, 1]范围内的转换的问题。因此,为了解决这个问题,我们需要定位到最后一列,同时使其宽度和高度可被整除。
matrixValues[6] = matrixValues[6] / getImageWidth();
matrixValues[7] = matrixValues[7] / getImageHeight();
然后,在完成此操作之后,您可以开始使用ImageView矩阵函数或更新的ImageTouchView矩阵函数(在Android上处理图像时具有一些附加的好功能)进行映射。如下图所示,ImageView在后面占据整个屏幕,而纹理位于其前面,根据来自ImageView的更新进行更新。这会处理两者之间的缩放和平移转换。
唯一的其他步骤是更改SurfaceView的大小以匹配ImageView的大小,以便在用户缩放时获得全屏体验。为了只显示surfaceview,您可以在后台将一个'invisible' imageview置于其后面。让ImageTouchView更新更改OpenGL SurfaceView显示的方式。
如果您最终选择使用下面的顶点着色器修改而不是片段着色器分辨率,则似乎不再需要反转值才能与捏合缩放配合使用(实际上,如果保留原样,它们会向后工作)。此外,平移也似乎与预期的方向相反。请投票支持下面的答案,因为他们通过聊天线下帮助我大大理解了连接ImageView和纹理所需执行的操作。他们值得得到认可。