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

问题描述 投票:10回答:8

我想将相机预览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变成黑色(不知何故被严重抽样)。我的覆盖层纹理是512x512和CLAMPT_TO_EDGE。此问题仅出现在以下示例:Android模拟器,HTC Evo 3D。但是在SGS3,HTC One X上,它运行得很好。

怎么了?是Evo 3D缺少一些扩展还是什么?

android image opengl-es android-camera textures
8个回答
4
投票

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

每个TEXTURE_EXTERNAL_OES纹理对象可能需要为其绑定的每个纹理单元最多3个纹理图像单元。当设置为TEXTURE_EXTERNAL_OES时,此值将介于1和3之间(包括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);

我相信这会为你锻炼。


3
投票

我在Nexus 7上遇到了同样的问题,它让我发疯了。访问samplerExternalOES或sampler2D工作得很好,但是在同一个着色器中访问它们会产生意外结果。有时输出会是黑色的。有时,其中一个查找的输出会产生不良的量化伪像。行为也会根据采样器绑定到的纹理单位而变化。我确实检查了每个opengl错误和validateProgram结果。

最终,有效的方法是使用单独的着色器来简单地访问相机输出并将其渲染为纹理。然后可以通过常规sampler2D访问生成的纹理,一切都按预期工作。我怀疑有一个与samplerExternalOES相关的错误。


3
投票

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

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);

更改纹理索引是解决此问题的好方法。


3
投票

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

似乎编译器按字母顺序对统一变量进行排序,因此使其适用于两个设备的解决方案是将samplerExternalEoz重命名为zzzTexture或其他东西。


3
投票

这不是一个答案,而是一个问题的详细说明 - 也许它将帮助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方面,这是一个很久以前解决的bug,但Nexus驱动程序仅在稍后更新。所以我必须检查哪个gpu存在,并相应地调整代码。


2
投票

参考user1924406关于分割访问sampler2D纹理和samplerExternalOES纹理的帖子(https://stackoverflow.com/a/14050597/3250829),这是我必须要做的,因为我正在开发的应用程序是从文件读取或从服务器流式传输而不是使用打开的相机装置。在同一着色器中使用两种纹理会导致非常奇怪的着色伪像(Galaxy S3上的情况)或饱和度和对比度问题(Nexus 4上的情况)。

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

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

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


1
投票

我也可能遇到同样的问题。经过几天的努力,我在这里提出我的解决方案。希望这会有助于其他人。

首先,问题陈述。就像LukášJezný一样,我有一个预览纹理和一个叠加纹理。它适用于nexus 4/5和大多数其他类型,但OPPO找不到5,联想A820,联想A720。

解:

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

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

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

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

它适用于OPPO找5,联想A820,联想A720等。没有人知道为什么......


0
投票

为了将外部纹理(非GPU)转换为常规内部纹理,您必须这样做

  • 首先创建一个外部纹理(与创建常规纹理相同,但用GLES20.GL_TEXTURE_2D替换所有GLES11Ext.GL_TEXTURE_EXTERNAL_OES)。
  • 创建要写入的内部/常规纹理
  • 用外部纹理包裹SurfaceTexture
  • 将内容读入外部纹理(如果来自相机,文件等)
  • 覆盖SurfaceTexture的onFrameAvailable并在此处进行转换,提供要读取的外部纹理和要写入的内部纹理。
  • 您可能需要调用getTransformMatrix进行坐标校正(通常是翻转y轴)并提供它。有时不...

这是一些示例着色器:

顶点着色器 -

uniform mat4 transform; // might be needed, and might not
uniform mat4 modelview;
uniform mat4 projection;
attribute vec2 position;

varying vec2 vTexcoord;

void main() {
    gl_Position = projection * modelview * vec4(position.xy, 0.0, 1.0);
    // texture takes points in [0,1], while position is [-1,1];
    vec4 newpos = (gl_Position + 1.0) * 0.5;
    vTexcoord = (transform * newpos).xy ;
}

片段着色器 -

#extension GL_OES_EGL_image_external : require

precision mediump float;

uniform samplerExternalOES sTexture;
varying vec2 vTexcoord;

void main() {
    gl_FragColor = texture2D(sTexture, vTexcoord);
}
© www.soinside.com 2019 - 2024. All rights reserved.