【问题标题】:Texture not drawn using OpenGL ES 2.0 and Android NDK未使用 OpenGL ES 2.0 和 Android NDK 绘制纹理
【发布时间】:2014-01-16 18:58:19
【问题描述】:

我想使用 Android NDK 在带有 OpenGL ES 2.0 的四边形上将图像显示为纹理。

我有以下简单的顶点和片段着色器:

#define DISP_SHADER_V_SRC "\
attribute vec4 aPos;\
attribute vec2 aTexCoord;\
varying vec2 vTexCoord;\
void main() {\
    gl_Position = aPos;\
    vTexCoord = aTexCoord;\
 }"

#define DISP_SHADER_F_SRC "\
precision mediump float;\n\
varying vec2 vTexCoord;\n\
uniform sampler2D sTexture;\n\
void main() {\n\
    gl_FragColor = texture2D(sTexture, vTexCoord);\n\
}"

首先,在创建 GLSurfaceView 时会调用原生的“create”方法。它设置清晰的颜色,构建着色器并使用glGenTextures 为我获取纹理ID。 “resize”方法设置当前视图大小。另一种方法是这样设置纹理数据:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

我不相信那里有什么问题。重要的应该是“绘制”方法。在 glClear、glViewport 和 glUseProgram 之后,我执行以下操作:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texId);

glEnableVertexAttribArray(shAPos);
glVertexAttribPointer(shAPos, 3, GL_FLOAT, false, 0, quadVertices);

glVertexAttribPointer(shATexCoord, 2, GL_FLOAT, false, 0, quadTexCoordsStd);
glEnableVertexAttribArray(shATexCoord);

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// now glDisableVertex...

我可以确认着色器基本上可以工作,因为gl_FragColor=vec4(1.0); 会导致白屏。当我加载纹理时它只是不起作用。我尝试使用memset 将像素数据设置为“全白”,只是为了确认问题与我的图像数据无关,但屏幕仍然保持黑色。我错过了什么?

【问题讨论】:

  • 由于您可以使用修改后的着色器进行绘制,因此采样器似乎只是在纹理图像中寻找零点。您能否确认您在拨打glTexImage2D 之前拨打了glBindTexture(GL_TEXTURE_2D, texId)?纹理是否使用二次幂大小?
  • 我可以确认。我打电话给glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texId);,然后我设置GL_CLAMP_TO_EDGE 并生成mipmap。我还通过设置gl_FragColor = vec4(vTexCoord.s, vTexCoord.t, 1.0, 1.0) 检查了vTexCoord 是否具有有效值。除了绘制该死的纹理之外,这一切都做了它应该做的事情:(
  • 哇,这花了一些时间......好吧,我不完全确定问题是什么,但我这样解决了:我注意到绘制纹理有效当我通过 JNI 直接在 onSurfaceCreated 内部调用纹理加载函数时。但是,我希望在触摸视图时纹理会发生变化。我猜它与调用线程有关。所以我将调用纹理加载函数的代码从OnClickListener 直接移到了实现GLSurfaceView.Renderer 的类中。现在它起作用了。棘手的事情,因为没有抛出任何错误:(
  • 听起来您将其移至不同的线程(UI 线程与 GLSurfaceView 渲染线程)。您是否同时在两个线程中拥有相同的 EGL 上下文?
  • 我没有看到任何代码行将制服的值:sTexture 设置为 0。

标签: android opengl-es android-ndk textures opengl-es-2.0


【解决方案1】:

IsaacKleiner 自己的评论是正确的,我遇到了同样的问题,我使用 NDK 在 C++ 中使用 OpenGL ES 2.0 开发了一个 android 应用程序。加载纹理的功能原本在 C++ 部分。由于某种原因,这不起作用。只有在 我将加载纹理代码移动到 java 部分 之后,它才能正常工作。 我在 java 部分加载纹理,正常绑定,然后将纹理 ID 传递给 C++ JNI 代码。我不知道为什么会出现这样的问题。我可以提供a link,其中有一个使用 OpenGL ES 1.0 和 NDK 显示立方体的示例。虽然是中文,但代码可以自己解释。请注意纹理是如何生成的,以及纹理id是如何在Java和C++之间传递的。

【讨论】:

  • 是的,再次说明这一点:问题的根源在于您不能从两个不同的线程中使用 OpenGL 函数。无论它们是在 Java 还是在应用程序的 C++ JNI 部分中,您都应该始终从同一个线程(创建 EGL 上下文的线程)调用 OpenGL 函数。在我的情况下,我从 UI 线程调用了一个 GL 函数(正如@fadden 解释的那样),它不起作用。将其移动到 GLSurfaceView 渲染线程后,它就可以工作了。
  • 对不起,这个答案是错误的,你绝对可以在 C++ 端加载纹理。正如 Isaac 发现的那样,OpenGL 调用需要在 opengl 线程上调用(这完全是另一回事)。
猜你喜欢
  • 2016-08-26
  • 2011-09-14
  • 1970-01-01
  • 2012-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-18
相关资源
最近更新 更多