10

我想将相机预览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_camerat_overlayer. 当我显示t_camerat_overlayer单独显示时,它可以工作(显示相机预览或纹理)。但是当我取消注释时t_overlayer,就会t_camera变成黑色(不知何故采样不好)。我的覆盖层纹理是 512x512 和CLAMPT_TO_EDGE. 此问题仅在以下情况下发生:Android Emulator、HTC Evo 3D。但在 SGS3、HTC One X 上,它工作得很好。

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

4

8 回答 8

5

我想你有这个问题,因为你没有在你的代码上设置正确的纹理 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);

我相信这会为你锻炼。

于 2013-03-27T13:36:45.860 回答
3

我在 Nexus 7 上遇到了同样的问题,这让我发疯了。访问 samplerExternalOES 或 sampler2D 工作得很好,但是在同一个着色器中访问它们会产生意想不到的结果。有时输出会是黑色的。有时,其中一个查找的输出会出现不良的量化伪影。行为也会因采样器绑定到的纹理单元而异。我确实检查了每个 opengl 错误并验证程序结果。

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

于 2012-12-27T06:48:22.987 回答
3

它似乎是 OpenGL 实现中的一个错误。相同的代码在三星 Note 上运行良好,而不是在 nexus 4 上运行良好。对于位于 samplerExternalOES 之后的所有变量,getUniformLocation 似乎在某些设备上中断。

似乎编译器按字母顺序对统一变量进行排序,因此使其在两种设备上都可以工作的解决方案是将您的 samplerExternalEoz 重命名为 zzzTexture 或其他东西。

于 2013-11-03T05:07:29.563 回答
3

这不是一个答案,而是对问题的详细说明——也许它会帮助 OpenGl ES 专家了解问题。


我有 3 个用于叠加的纹理和一个外部纹理,用于捕获媒体播放器的输出。如果我只使用外部纹理,输出是预期的,来自 MPlayer 的帧。相同的完整代码在 Nexus4、Samsung Galaxy S3、S4 等设备上运行良好(所有设备都使用 adreno gpus 或 Arm 的 Mali400) 硬件差异在于 Nexus 7 使用 Nvidia Tegra 3 板。


编辑 (我这边是如何解决的)

Nvidia Tegra 3 要求外部纹理采样器以采样器中字母顺序最低的名称调用,而 Adreno 220 似乎需要相反的名称。此外,T3 要求最后采样外部纹理。对于使用 Android 4.3 及更高版本的设备,这些错误可能会得到解决。在 Nvidia 方面,这是一个错误,很久以前就解决了,但后来才更新 Nexus 驱动程序。所以我必须检查存在哪个 gpu,并相应地调整代码。

于 2013-05-31T20:19:37.680 回答
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);

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

于 2013-07-26T02:34:06.210 回答
2

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

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

您需要检查的一件事是,有时当您写入 FBO 时,纹理坐标会翻转。在我的例子中,V(或 T 或 Y)坐标被翻转,从而在水平轴上形成镜像。在第二阶段编写片段着色器时,我必须考虑到这一点。

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

于 2014-02-04T18:24:32.433 回答
2

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

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

这是一些示例着色器:

顶点shdaer -

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);
}
于 2019-03-03T11:54:41.877 回答
1

我可能也有同样的问题。经过几天的尝试,我在这里提出了我的解决方案。希望这对其他人有帮助。

首先,问题陈述。就像 Lukáš Jezný 一样,我有一个预览纹理和一个叠加纹理。它适用于 nexus 4/5 和大多数其他类型,但在 OPPO find 5、联想 A820、联想 A720 上没有显示任何内容。

解决方案:

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

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

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

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

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

于 2013-12-30T10:28:21.357 回答