【问题标题】:OpenGL ES 2.0 in Android NDK: Nothing being drawnAndroid NDK 中的 OpenGL ES 2.0:未绘制任何内容
【发布时间】:2014-10-28 01:36:29
【问题描述】:

我有一个 2D 游戏项目,我将其移植到使用 OpenGL ES 2.0 的 Android 上。我无法在屏幕上绘制任何内容(清除屏幕后的纯色除外)。在我的 Windows 环境中运行时,一切都呈现得很好,但当然,对于不同版本的 OpenGL,环境设置不同。

我遵循了本机活动示例,并从其他几个 OpenGL ES 2.0 资源中获得了建议,以组成我目前拥有的内容。

我已经检查了所有我知道的方法,没有发现异常结果。如前所述,glClear 有效,并显示由glClearColor 设置的颜色。我也知道每一帧都在渲染,因为逐帧更改 glClearColor 会显示不同的颜色。当然,应用程序可以正确编译。我的纹理是从应用程序缓存中的正确位置加载的。 glGetError 在过程中的每一步都返回GL_NO_ERROR,所以我所做的似乎被 OpenGL 接受。我的着色器加载没有错误。我还在几个模拟器和我的物理 android 设备上对此进行了测试,因此它没有本地化到特定的设备配置。

我推测在我如何初始化和设置 OpenGL 时一定有一些错误。我希望比我更精通 OpenGL ES 的人能够帮助解决我的问题。我在下面粘贴我的代码的不同相关部分。 engine 是我目前出于懒惰而使用的全局结构。

初始化显示

static int AND_InitDisplay() {

    // Desired display attributes
    const EGLint attribs[] = {
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL_BLUE_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_RED_SIZE, 8,
            EGL_ALPHA_SIZE, 8,
            EGL_DEPTH_SIZE, 16,
            EGL_NONE
    };
    EGLint w, h, dummy, format;
    EGLint numConfigs;
    EGLConfig config;
    EGLSurface surface;
    EGLContext context;

    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglInitialize(display, 0, 0);
    eglChooseConfig(display, attribs, &config, 1, &numConfigs);
    eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);

    ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);

    surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);

    EGLint const attrib_list[3] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
    context = eglCreateContext(display, config, NULL, attrib_list);

    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
        LOGW("Unable to eglMakeCurrent");
        return -1;
    }

    eglQuerySurface(display, surface, EGL_WIDTH, &w);
    eglQuerySurface(display, surface, EGL_HEIGHT, &h);

    engine->display = display;
    engine->context = context;
    engine->surface = surface;
    engine->width = w;
    engine->height = h;

    // Initialize GL state.
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

    return 0;
}

画框

static void AND_drawFrame() {
    if (engine->display == NULL) {
        LOGW("DB E: DISPLAY IS NULL");
        // No display.
        return;
    }

    // Clearing with red color. This displays properly.
    glClearColor(1.f, 0.f, 0.f, 1.f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // eglSwapBuffers results in no visible change
    eglSwapBuffers(engine->display, engine->surface);
}

准备 VBO 数据的示例

我知道很多人不喜欢对同一几何图形使用多个 VBO 的想法。我很想知道这段代码是不是正统的或不正确的,但除非它是我问题的根源,否则我不会专注于此。

GLfloat charPosVerts[] = {

    p0.x, p0.y, 0.f,
    p1.x, p0.y, 0.f,
    p1.x, p1.y, 0.f,

    p0.x, p0.y, 0.f,
    p1.x, p1.y, 0.f,
    p0.x, p1.y, 0.f
};

GLfloat charTexVerts[] = {
    0.0, 0.0,
    textures[texid].w, 0.0,
    textures[texid].w, textures[texid].h,

    0.0, 0.0,
    textures[texid].w, textures[texid].h,
    0.0, textures[texid].h
};

GLfloat charColorVerts[] = {
    e->color.r, e->color.g, e->color.b, e->color.a,
    e->color.r, e->color.g, e->color.b, e->color.a,
    e->color.r, e->color.g, e->color.b, e->color.a,

    e->color.r, e->color.g, e->color.b, e->color.a,
    e->color.r, e->color.g, e->color.b, e->color.a,
    e->color.r, e->color.g, e->color.b, e->color.a
};

glGenBuffers(1, &(e->vboPos));
glGenBuffers(1, &(e->vboTex));
glGenBuffers(1, &(e->vboColor));

glBindBuffer(GL_ARRAY_BUFFER, e->vboPos);
glBufferData(GL_ARRAY_BUFFER, sizeof(charPosVerts), charPosVerts, GL_DYNAMIC_DRAW);
glVertexAttribPointer(shaderIDs.attribPosition, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(shaderIDs.attribPosition);

glBindBuffer(GL_ARRAY_BUFFER, e->vboTex);
glBufferData(GL_ARRAY_BUFFER, sizeof(charTexVerts), charTexVerts, GL_DYNAMIC_DRAW);
glVertexAttribPointer(shaderIDs.attribTexCoord, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(shaderIDs.attribTexCoord);

glBindBuffer(GL_ARRAY_BUFFER, e->vboColor);
glBufferData(GL_ARRAY_BUFFER, sizeof(charColorVerts), charColorVerts, GL_DYNAMIC_DRAW);
glVertexAttribPointer(shaderIDs.attribColors, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(shaderIDs.attribColors);

绘制 VBO 的示例

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, CORE_GetBmpOpenGLTex(texix));
glUniform1i(shaderIDs.uniTexture, 0);

// Draw the sprite
glBindBuffer(GL_ARRAY_BUFFER, e->vboPos);
glVertexAttribPointer(shaderIDs.attribPosition, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(shaderIDs.attribPosition);

glBindBuffer(GL_ARRAY_BUFFER, e->vboTex);
glVertexAttribPointer(shaderIDs.attribTexCoord, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(shaderIDs.attribTexCoord);

glBindBuffer(GL_ARRAY_BUFFER, e->vboColor);
glVertexAttribPointer(shaderIDs.attribColors, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(shaderIDs.attribColors);

glDrawArrays(GL_TRIANGLES, 0, 18);

顶点着色器

着色器非常简单。

attribute vec3 position;
attribute vec2 texCoord;
attribute vec4 colors;

varying vec2 texCoordVar;
varying vec4 colorsVar;

void main() {
    gl_Position = vec4(position, 1.0);
    texCoordVar = texCoord;
    colorsVar = colors;
}

片段着色器

uniform sampler2D texture;

varying vec2 texCoordVar;
varying vec4 colorsVar;

void main()
{
    gl_FragColor = texture2D(texture, texCoordVar) * colorsVar;
}

感谢您阅读这篇长文。非常感谢您的帮助。

【问题讨论】:

  • 你的着色器编译没有错误吗?我一直认为 OpenGL ES 2.0 需要为片段着色器中的浮点数添加精度,但我可能弄错了。
  • @harism 没错。此外,在发布的代码中,AND_drawFrame() 实际上并没有绘制任何东西。
  • 我现在三重检查着色器编译。 @Reto Koradi 我猜函数名称用词不当。你是对的,它只是在做交换。除非我误解了你,我应该做点别的事情。
  • 它正在清除窗口,然后进行交换,中间没有任何内容。如果你想渲染一些东西,你必须在 glClear() 调用和 eglSwapBuffers() 调用之间进行。
  • 哇,真是菜鸟的错误。这显然是问题所在。非常感谢您挽救了一天,Reto。您可能希望将其添加为问题的答案。

标签: android c++ opengl-es android-ndk opengl-es-2.0


【解决方案1】:

发布的代码没有绘制任何东西。来自AND_drawFrame() 函数:

// Clearing with red color. This displays properly.
glClearColor(1.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// eglSwapBuffers results in no visible change
eglSwapBuffers(engine->display, engine->surface);

基于此,绘制代码要么永远不会被调用,要么在绘制之后清除窗口,这将清除之前绘制的所有内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-26
    • 2011-09-14
    • 1970-01-01
    • 2012-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多