在某些情况下,需要在用户放大图像时扩展纹理,直到最短边缘填满整个屏幕(如标准图库所示)。但是,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;
}
我在第一次迭代中导致照片撕裂,如下所示。或者由于两个空间之间的不正确转换而剪裁了照片。
宽度似乎保持不变,因此它向我建议可能会出现超出标准范围的值的事情,但我不确定该尝试什么。
答案 0 :(得分:2)
这种条纹正在发生,因为您将纹理包裹设置为夹到边缘。你有类似的东西:
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
GL_REPEAT是默认值,将重复图像。但是你想在底部没有任何“效果”。由于你的MATH,这个底部正在发生。你只能在底部而不是侧面获得条纹。正如有人在评论中所说,你的顶点范围是不正确的。最小值和最大值分别为0和1 ..而不是-1和1.因此,在图片的底部,它是条纹,因为您正在计算0-1范围内的纹理坐标数,并且可能会进入< 0区域或> 1区域。当texture2D(u_textureSampler,v_fragmentTexCoord0)获得0-1范围之外的纹理坐标时,它将落在WRAP_S / WRAP_T设置上以知道要给出的值。它正在重复边缘像素,因为你有GL_CLAMP_TO_EDGE。
你的实际问题不是这个设置。这就是你要开始计算范围之外的S或T.这不是好形式的原因,即使你在那里写黑色片段着色器浪费了周期,也会减慢你的应用程序。基本上,你的公式是错误的。
至于你的数学放大......这是数学。无论你想做什么,你都必须解决它。 (或者寻求帮助。)你可以做这样的事情,这是我在新的照片编辑应用程序中所做的简化版本:
GLfloat aspect = photo.width / photo.height;
if (aspect > 1) {
displayWidth = panelWidth;
displayHeight = panelWidth/aspect;
}
else {
displayHeight = panelHeight;
displayWidth = panelHeight*destAspect;
}
其中panelWidth和panelHeight是您正在显示照片的区域的大小 - 可以是全屏或更小的区域。然后根据显示高度和宽度构建顶点。如果放大超出面板大小,则需要进行裁剪以将图像保持在面板内,通过减小显示宽度或高度(任何一个太大)并将纹理坐标更改为比赛。这非常粗糙,但是这样:
GLfloat sSize = (destSMax-destSMin) / panelZoom;
GLfloat tSize = (destTMax-destTMin) / panelZoom;
displaySMin = destSMin + panelPanX/coreTextureSize;
displayTMin = destTMin + panelPanY/coreTextureSize;
displaySMax = displaySMin + sSize;
displayTMax = displayTMin + tSize;
然后当然要构建你的顶点数据,使用矩阵数学把你想要它的方块移动,并绘制它。
我建议您重新考虑使用更像我上面所做的事情的方法。屏幕熄灭时,请勿删除一定比例的照片。而是计算将要看到的内容并基于此构建数据。
编辑 - 此外,我意识到我的代码是ios代码,这是一个Android问题。但是同样的概念适用。 glTexParameteri调用可能略有不同,它可能是浮点而不是GLfloat。