Android OpenGL结合了SurfaceTexture(外部图像)和普通纹理

我想混合相机预览SurfaceTexture与一些覆盖纹理。 我正在使用这些着色器进行处理:

private final String vss = "attribute vec2 vPosition;\n" + "attribute vec2 vTexCoord;\n" + "varying vec2 texCoord;\n" + "void main() {\n" + " texCoord = vTexCoord;\n" + " gl_Position = vec4 ( vPosition.x, vPosition.y, 0.0, 1.0 );\n" + "}"; private final String fss = "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES sTexture;\n" + "uniform sampler2D filterTexture;\n" + "varying vec2 texCoord;\n" + "void main() {\n" +" vec4 t_camera = texture2D(sTexture,texCoord);\n" //+" vec4 t_overlayer = texture2D(filterTexture, texCoord);\n" //+ " gl_FragColor = t_overlayer;\n" + "}"; + " gl_FragColor = t_camera;\n" + "}"; 

我的目标是混合t_camera和t_overlayer。 当我分别显示t_camera或t_overlayer时,它可以工作(显示相机预览或纹理)。 但是当我取消t_overlayer的注释时,那么t_camera变成了黑色(不知何故采样很严重)。 我的覆盖层纹理是512×512和CLAMPT_TO_EDGE。 此问题仅出现在Android模拟器HTC Evo 3D上。 但在SGS3,HTC One X,它工作得很好。

哪里不对? 是Evo 3D缺less一些扩展或什么?

Solutions Collecting From Web of "Android OpenGL结合了SurfaceTexture(外部图像)和普通纹理"

我在Nexus 7上遇到同样的问题,这让我疯狂。 访问samplerExternalOES或者sampler2D是完全正常的,但是在同一个着色器中访问它们却得到了意想不到的结果。 有时输出会是黑色的。 有时候,其中一个查找的输出会有不好的量化伪像。 行为也将取决于采样器绑定到的纹理单元。 我没有检查每个opengl错误和validateProgram结果。

最终,有效的方法是使用单独的着色器来访问相机输出并将其渲染为纹理。 然后可以通过常规的sampler2D来访问产生的纹理,并且所有的东西都可以按照预期的那样工作。 我怀疑有一个与samplerExternalOES相关的bug。

我想你有这个问题,因为你没有在你的代码上设置正确的纹理ID。 这是一个逻辑错误的假设,但实际上在文档中没有这样定义。 如果您检查此扩展的文档,您将看到以下(编辑)文本:

每个TEXTURE_EXTERNAL_OES纹理对象可能需要多达3个纹理图像单位,用于每个纹理单元的绑定。 当设置为TEXTURE_EXTERNAL_OES时, 该值将介于1和3之间 (包括)。 对于其他有效的纹理目标,此值始终为1.请注意,当绑定TEXTURE_EXTERNAL_OES纹理对象时,单个纹理单元所需的纹理图像单元可能为1,2或3 ,而对于其他纹理对象纹理单元只需要1个纹理图像单元。

这意味着,只要你使用id 0,额外的就可以工作。 在你的情况下:

 GLES20.glUniform1i(sTextureHandle, 1); GLES20.glActiveTexture(GLES20.GL_TEXTURE1); GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, sTextureId); 

对于你的2D纹理:

 GLES20.glUniform1i(filterTextureHandle, 0); GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, filterTextureID); 

我相信这会为你锻炼。

上面的方法节省了我很多的时间。 谢谢大师:

 GLES20.glUniform1i(sTextureHandle, 1); GLES20.glActiveTexture(GLES20.GL_TEXTURE1); GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, sTextureId); 

对于你的2D纹理:

 GLES20.glUniform1i(filterTextureHandle, 0); GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, filterTextureID); 

改变纹理索引是解决这个问题的好方法。

这似乎是OpenGl实现中的一个错误。 相同的代码在Samsung Note上运行良好,而不是在nexus 4上。似乎getUniformLocation在某些设备上中断了所有位于samplerExternalOES之后的variables。

它也似乎是编译器按字母sorting统一variables,所以使这两个设备上工作的解决scheme是将您的samplerExternalEoz重命名为zzzTexture什么的。

这不是一个答案,而是一个问题的阐述 – 也许这将有助于OpenGl ES专家了解这个问题。


我有3个纹理用于​​叠加,一个外部纹理,用于捕获媒体播放器的输出。 如果我只使用外部纹理,输出如预期的那样,来自MPlayer的帧。 在Nexus4,三星Galaxy S3,S4等(所有设备都使用adreno gpus,或Arm的Mali400)上,相同的完整代码工作正常。硬件的区别在于,Nexus 7使用Nvidia Tegra 3主板。


编辑 (如何解决在我身边)

Nvidia Tegra 3要求外部纹理采样器在采样器之间以名称的最低字母顺序进行调用,而Adreno 220似乎要求相反。 另外,T3要求最后采样外部纹理。 使用Android 4.3及更新版本的设备,这些错误可能会得到解决。 在Nvidia方面,这是一个很久以前解决的错误,但Nexus驱动程序只是在稍后更新。 所以我不得不检查一下哪个gpu存在,并相应地修改代码。

我可能也有同样的问题。 经过几天的尝试,我在这里提出我的解决scheme。 希望这会帮助别人。

首先是问题陈述。 就像LukášJezný,我有一个预览纹理和一个覆盖纹理。 它适用于nexus 4/5和大多数其他types,但在OPPO上找不到5,Lenovo A820,Lenovo A720。

解:

(1)就像LukášJezný一样,在着色器中使用YUV数据并将其转换为RGB。

(2)多遍绘制,预览纹理一次画到帧缓冲区,读取,然后再画到屏幕上。

(3)在使用自己的程序之前使用另一个程序,

  GLES20.glUseProgram(another one); GLES20.glUseProgram(your "real" program); 

它只适用于OPPO发现5,联想A820,联想A720等。 没有人知道为什么……

参考user1924406的post( https://stackoverflow.com/a/14050597/3250829 )关于拆分访问sampler2D纹理和samplerExternalOES纹理,这是我所要做的,因为我正在开发的应用程序正在从文件读取或从服务器stream式传输而不是使用设备上的摄像头。 在同一着色器中使用两个纹理都会导致非常奇怪的着色伪像(Galaxy S3上的情况)或饱和度和对比度问题(Nexus 4上的情况)。

因此,解决samplerExternalOES纹理错误(从目前为止我所看到的)的唯一方法就是执行两个着色器程序:一个将samplerExternalOES纹理中包含的内容写入FBO,另一个将来自FBO的内容并将其直接写入表面。

有一点你需要检查的是,有时当你给FBO写信时,纹理坐标会翻转。 在我的情况下,V(或T或Y)坐标被翻转,导致水平轴上的镜像。 在第二阶段编写片段着色器时,我必须考虑到这一点。

这是一个我想分享的战争故事,以防有些人可能需要从服务器读取文件或数据stream,而不是直接从相机中读取数据。