我试图找到一种方法来为我的OpenGL图像查看器实现“高亮”功能。想法是让用户能够点击图像以突出显示一个区域,这方面进展顺利。我面临的问题是当用户第二次点击时。我希望保持两个高亮渲染在图像上它们被放置的位置。目前,当第二次点击到达时,第一个高亮消失了。
这是我的当前片段着色器:
precision mediump float;
uniform vec4 vColor;
varying vec2 v_TexCoordinate;
uniform sampler2D u_Image;
uniform float u_touchX;
uniform float u_touchY;
void main() {
float radius = 0.1;
float a = v_TexCoordinate.x - u_touchX;
float b = v_TexCoordinate.y - u_touchY;
float d = sqrt(abs(a*a + b*b));
if(d < radius){
gl_FragColor = texture2D(u_Image, v_TexCoordinate) + vColor;
}else{
gl_FragColor = texture2D(u_Image, v_TexCoordinate);
}
}
很简单,我传入图像、高亮颜色以及用户在屏幕上点击的x和y坐标。如果片段在该点的一定距离内,则添加高亮。到目前为止效果非常好。
显然,一旦触摸点移动,原始高亮就消失了。
我的目标是尽可能多地在GPU端运行此功能。以下是我目前考虑的一些想法,但我希望有比我更聪明的人能向我展示更好的方法。
- 我最不喜欢的策略是在CPU端跟踪XY触摸点并在每帧传递更新后的列表。显然的缺陷是,触摸列表可能很快变得很大,从而迅速降低性能。我希望用户能够在需要时突出整个图像,而这种解决方案似乎并不实用。
- 在CPU上跟踪图像中每个像素的状态。我认为我可以通过创建一个与图像完全相同大小的位图(或者可能是表示每个像素的2D布尔数组)来实现这一点,并跟踪哪个片段被“突出显示”。然后,将整个数组作为统一块传递,并将每个v_TexCoordinate与数组中相应的值进行比较。我也不喜欢这个想法(虽然比#1好),因为它再次需要每帧将大量数据移动到GPU。这对于旧的Android设备来说很容易成为非起始器。
- 我发现了这个类似问题的答案here。提问者想要操纵纹理数据,而答案建议使用“Render-To-Texture”方法,其中使用FBO。我有点明白这个想法,但我真的看不出这将如何解决记住先前“高亮显示”的问题。也许我很傻,错过了这个答案可以告诉我的东西,但是... ¯\_(ツ)_/¯
我希望有更好的方法,但目前想不出来,希望有人能指点一下方向。
sqrt( abs( a * a + b * b ) < d
更改为abs( a * a + b * b ) < d * d
,因为这样可以提高性能,避免使用sqrt
。不过驱动程序可能已经进行了优化。如果可以的话,尽量避免条件语句。 - Reaper