我的OpenGL学习进阶之旅解决使用VAO的时候误用glDisableVertexAttribArray导致无法渲染出现白屏或者黑屏的问题

Posted 字节卷动

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我的OpenGL学习进阶之旅解决使用VAO的时候误用glDisableVertexAttribArray导致无法渲染出现白屏或者黑屏的问题相关的知识,希望对你有一定的参考价值。

一、问题描述

今天将OpenGL项目运行到android真机的时候,发现一个简单的矩形居然白屏。然而在模拟器上是可以正常渲染的,如下所示:

  • 模拟器正常渲染

  • 真机白屏

二、分析问题

通过对比日志来分析:

2.1 分析GL版本信息

  • 小米9手机打印
2022-02-22 15:04:41.833 9504-9615/com.oyp.openglesdemo I/NDK_JNI_LOG_TAG: [utils\\GLUtils.h][printGLString][54]: GL Version = OpenGL ES 3.2 V@0502.0 (GIT@42297a4, I9e9b240040, 1616178534) (Date:03/19/21) 
2022-02-22 15:04:41.833 9504-9615/com.oyp.openglesdemo I/NDK_JNI_LOG_TAG: [utils\\GLUtils.h][printGLString][54]: GL GLSL Version = OpenGL ES GLSL ES 3.20 
2022-02-22 15:04:41.833 9504-9615/com.oyp.openglesdemo I/NDK_JNI_LOG_TAG: [utils\\GLUtils.h][printGLString][54]: GL Vendor = Qualcomm 
2022-02-22 15:04:41.833 9504-9615/com.oyp.openglesdemo I/NDK_JNI_LOG_TAG: [utils\\GLUtils.h][printGLString][54]: GL Renderer = Adreno (TM) 640 
2022-02-22 15:04:41.833 9504-9615/com.oyp.openglesdemo I/NDK_JNI_LOG_TAG: [utils\\GLUtils.h][printGLString][54]: GL Extensions = GL_OES_EGL_image GL_OES_EGL_image_external GL_OES_EGL_sync GL_OES_vertex_half_float GL_OES_framebuffer_object GL_OES_rgb8_rgba8 GL_OES_compressed_ETC1_RGB8_texture GL_AMD_compressed_ATC_texture GL_KHR_texture_compression_astc_ldr GL_KHR_texture_compression_astc_hdr GL_OES_texture_compression_astc GL_OES_texture_npot GL_EXT_texture_filter_anisotropic GL_EXT_texture_format_BGRA8888 GL_EXT_read_format_bgra GL_OES_texture_3D GL_EXT_color_buffer_float GL_EXT_color_buffer_half_float GL_QCOM_alpha_test GL_OES_depth24 GL_OES_packed_depth_stencil GL_OES_depth_texture GL_OES_depth_texture_cube_map GL_EXT_sRGB GL_OES_texture_float GL_OES_texture_float_linear GL_OES_texture_half_float GL_OES_texture_half_float_linear GL_EXT_texture_type_2_10_10_10_REV GL_EXT_texture_sRGB_decode GL_EXT_texture_format_sRGB_override GL_OES_element_index_uint GL_EXT_copy_image GL_EXT_geometry_shader GL_EXT_tessellation_shader GL_OES_texture_stencil8 GL_EXT_shader_io_blocks GL_OES_shader_
  • 模拟器打印
2022-02-22 15:03:20.616 10135-10171/com.oyp.openglesdemo I/NDK_JNI_LOG_TAG: [utils\\GLUtils.h][printGLString][54]: GL Version = OpenGL ES 3.1 (4.5.0 - Build 26.20.100.8142) 
2022-02-22 15:03:20.620 10135-10171/com.oyp.openglesdemo I/NDK_JNI_LOG_TAG: [utils\\GLUtils.h][printGLString][54]: GL GLSL Version = OpenGL ES GLSL ES 3.10 
2022-02-22 15:03:20.624 10135-10171/com.oyp.openglesdemo I/NDK_JNI_LOG_TAG: [utils\\GLUtils.h][printGLString][54]: GL Vendor = Google (Intel) 
2022-02-22 15:03:20.626 10135-10171/com.oyp.openglesdemo I/NDK_JNI_LOG_TAG: [utils\\GLUtils.h][printGLString][54]: GL Renderer = Android Emulator OpenGL ES Translator (Intel(R) HD Graphics 530) 
2022-02-22 15:03:20.638 10135-10171/com.oyp.openglesdemo I/NDK_JNI_LOG_TAG: [utils\\GLUtils.h][printGLString][54]: GL Extensions = GL_EXT_debug_marker GL_EXT_robustness GL_OES_EGL_sync GL_OES_EGL_image GL_OES_EGL_image_external GL_OES_depth24 GL_OES_depth32 GL_OES_element_index_uint GL_OES_texture_float GL_OES_texture_float_linear GL_OES_compressed_paletted_texture GL_OES_compressed_ETC1_RGB8_texture GL_OES_depth_texture GL_OES_texture_half_float GL_OES_texture_half_float_linear GL_OES_packed_depth_stencil GL_OES_vertex_half_float GL_OES_texture_npot GL_OES_rgb8_rgba8 GL_EXT_color_buffer_float GL_EXT_color_buffer_half_float GL_EXT_shader_framebuffer_fetch GL_EXT_texture_format_BGRA8888 GL_APPLE_texture_format_BGRA8888 ANDROID_EMU_CHECKSUM_HELPER_v1 ANDROID_EMU_native_sync_v2 ANDROID_EMU_native_sync_v3 ANDROID_EMU_native_sync_v4 ANDROID_EMU_dma_v1 ANDROID_EMU_YUV420_888_to_NV21 ANDROID_EMU_YUV_Cache ANDROID_EMU_sync_buffer_data GL_OES_EGL_image_external_essl3 GL_OES_vertex_array_object GL_KHR_texture_compression_astc_ldr ANDROID_EMU_host_side_tracing ANDROID_EMU_gles_max_version_3_1  

看的出来:

  • 模拟器的版本是OpenGL ES 3.1 (4.5.0 - Build 26.20.100.8142)
  • 而真机的版本是OpenGL ES 3.2 V@0502.0 (GIT@42297a4, I9e9b240040, 1616178534) (Date:03/19/21)

2.2 看程序运行的日志

接着看程序运行的日志

  • 真机
2022-02-22 15:04:41.834 9504-9615/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [MyGLRenderContext.cpp][OnSurfaceChanged][376]: MyGLRenderContext::OnSurfaceChanged [w, h] = [1080, 2221]
2022-02-22 15:04:41.834 9504-9615/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [sample\\GLBaseSample.h][Change][30]: Change() width = 1080 , height = 2221
2022-02-22 15:04:41.835 9504-9615/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [NativeRectangle.cpp][Draw][75]: CHECK_GL_ERROR Draw glGetError = 0, line = 75, 
2022-02-22 15:04:41.835 9504-9615/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [NativeRectangle.cpp][Draw][77]: CHECK_GL_ERROR Draw glGetError = 0, line = 77, 
2022-02-22 15:04:41.840 9504-9615/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [NativeRectangle.cpp][Draw][75]: CHECK_GL_ERROR Draw glGetError = 0, line = 75, 
2022-02-22 15:04:41.840 9504-9615/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [NativeRectangle.cpp][Draw][77]: CHECK_GL_ERROR Draw glGetError = 0, line = 77, 
  • 模拟器
2022-02-22 15:11:31.492 10135-10292/com.oyp.openglesdemo D/eglCodecCommon: setVertexArrayObject: set vao to 1 (1) 1 0
2022-02-22 15:11:31.492 10135-10292/com.oyp.openglesdemo D/eglCodecCommon: setVertexArrayObject: set vao to 0 (0) 1 2
2022-02-22 15:11:31.493 10135-10292/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [MyGLRenderContext.cpp][OnSurfaceChanged][376]: MyGLRenderContext::OnSurfaceChanged [w, h] = [720, 1136]
2022-02-22 15:11:31.493 10135-10292/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [sample\\GLBaseSample.h][Change][30]: Change() width = 720 , height = 1136
2022-02-22 15:11:31.493 10135-10292/com.oyp.openglesdemo D/eglCodecCommon: setVertexArrayObject: set vao to 1 (1) 1 2
2022-02-22 15:11:31.494 10135-10292/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [NativeRectangle.cpp][Draw][75]: CHECK_GL_ERROR Draw glGetError = 0, line = 75, 
2022-02-22 15:11:31.496 10135-10292/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [NativeRectangle.cpp][Draw][77]: CHECK_GL_ERROR Draw glGetError = 0, line = 77, 

对比差异,看起来好像模拟器多了几个设置VAO 的时候eglCodecCommon: setVertexArrayObject的操作日志

好吧,看起来问题和VAO相关,继续分析吧!

2.3 出问题的原因

最后,经过一番排查,定位到原因是因为使用VAO的时候,误用了glDisableVertexAttribArray导致出了问题。

  • 错误代码
void NativeRectangle::Draw() 
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(m_ProgramObj);

    // Bind the VAO
    glBindVertexArray(vaoId);
    GO_CHECK_GL_ERROR()
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
    GO_CHECK_GL_ERROR()

    glDisableVertexAttribArray(0);


  • 修改后的正确代码
void NativeRectangle::Draw() 
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(m_ProgramObj);

    // Bind the VAO
    glBindVertexArray(vaoId);
    GO_CHECK_GL_ERROR()
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
    GO_CHECK_GL_ERROR()

    glBindVertexArray(0);

2.4 总结一下

下面是绑定和解除绑定VAO的正确操作应该是这样的:

// 绑定VAO
glBindVertexArray(vaoId);
// 绘制
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
// 解除绑定VAO
glBindVertexArray(0);

至于为啥会出现我那些错误的搭配,因为时间很久了一个月之前写的代码,我回想一下,应该是一开始没有使用VAO和VBO,后来改成VAO和VBO实现的时候,部分垃圾代码忘记删除了。

下面是启用和禁用 通用顶点属性数组 的正确搭配。


// 启用 通用顶点属性数组
 glEnableVertexAttribArray(VERTEX_POS_INDX);
// 绘制
 glDrawArrays(GL_TRIANGLES, 0, 3);

 // 禁用 通用顶点属性数组
 glDisableVertexAttribArray(0);

下次改代码的时候,千万别误搭配了!!!!!!

三、运行

修改完后,重新运行,查看下日志:

  • 模拟器
2022-02-22 15:29:00.442 10701-10763/com.oyp.openglesdemo D/eglCodecCommon: setVertexArrayObject: set vao to 1 (1) 1 0
2022-02-22 15:29:00.443 10701-10763/com.oyp.openglesdemo D/eglCodecCommon: setVertexArrayObject: set vao to 0 (0) 1 2
2022-02-22 15:29:00.443 10701-10763/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [MyGLRenderContext.cpp][OnSurfaceChanged][376]: MyGLRenderContext::OnSurfaceChanged [w, h] = [720, 1136]
2022-02-22 15:29:00.444 10701-10763/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [sample\\GLBaseSample.h][Change][30]: Change() width = 720 , height = 1136
2022-02-22 15:29:00.444 10701-10763/com.oyp.openglesdemo D/eglCodecCommon: setVertexArrayObject: set vao to 1 (1) 1 2
2022-02-22 15:29:00.444 10701-10763/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [NativeRectangle.cpp][Draw][75]: CHECK_GL_ERROR Draw glGetError = 0, line = 75, 
2022-02-22 15:29:00.447 10701-10763/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [NativeRectangle.cpp][Draw][77]: CHECK_GL_ERROR Draw glGetError = 0, line = 77, 
2022-02-22 15:29:00.447 10701-10763/com.oyp.openglesdemo D/eglCodecCommon: setVertexArrayObject: set vao to 0 (0) 1 2
2022-02-22 15:29:00.531 10701-10763/com.oyp.openglesdemo D/eglCodecCommon: setVertexArrayObject: set vao to 1 (1) 1 2
2022-02-22 15:29:00.532 10701-10763/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [NativeRectangle.cpp][Draw][75]: CHECK_GL_ERROR Draw glGetError = 0, line = 75, 
2022-02-22 15:29:00.532 10701-10763/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [NativeRectangle.cpp][Draw][77]: CHECK_GL_ERROR Draw glGetError = 0, line = 77, 
2022-02-22 15:29:00.532 10701-10763/com.oyp.openglesdemo D/eglCodecCommon: setVertexArrayObject: set vao to 0 (0) 1 2
  • 真机
2022-02-22 15:30:43.739 13143-13881/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [MyGLRenderContext.cpp][OnSurfaceChanged][376]: MyGLRenderContext::OnSurfaceChanged [w, h] = [1080, 2221]
2022-02-22 15:30:43.739 13143-13881/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [sample\\GLBaseSample.h][Change][30]: Change() width = 1080 , height = 2221
2022-02-22 15:30:43.740 13143-13881/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [NativeRectangle.cpp][Draw][75]: CHECK_GL_ERROR Draw glGetError = 0, line = 75, 
2022-02-22 15:30:43.740 13143-13881/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [NativeRectangle.cpp][Draw][77]: CHECK_GL_ERROR Draw glGetError = 0, line = 77, 
2022-02-22 15:30:43.742 13143-13881/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [NativeRectangle.cpp][Draw][75]: CHECK_GL_ERROR Draw glGetError = 0, line = 75, 
2022-02-22 15:30:43.742 13143-13881/com.oyp.openglesdemo D/NDK_JNI_LOG_TAG: [NativeRectangle.cpp][Draw][77]: CHECK_GL_ERROR Draw glGetError = 0, line = 77, 

真机还是没有那些设置VAO 的时候eglCodecCommon: setVertexArrayObject的操作日志,但是改完之后真机正常渲染出来了。

以上是关于我的OpenGL学习进阶之旅解决使用VAO的时候误用glDisableVertexAttribArray导致无法渲染出现白屏或者黑屏的问题的主要内容,如果未能解决你的问题,请参考以下文章

我的OpenGL学习进阶之旅介绍 顶点数组对象VAO并实战一下

我的OpenGL学习进阶之旅解决Android OpenGL ES 调试工具 GAPID 无法识别Android设备的问题

我的OpenGL学习进阶之旅解决Android OpenGL ES 调试工具 GAPID 无法识别Android设备的问题

我的OpenGL学习进阶之旅解决OpenGL绘制带透明通道的png纹理时出现黑边问题,并彻底了解其原理

我的OpenGL学习进阶之旅解决OpenGL绘制带透明通道的png纹理时出现黑边问题,并彻底了解其原理

我的OpenGL学习进阶之旅解决OpenGL在使用glUniform系列api时出现了 GL_INVALID_OPERATION 1282错误