Introduction

One of the most common problems for novice, and sometimes experienced, OpenGL programmers is that they write new rendering code, run it, and it displays… nothing at all. Being more active on message boards again lately (Stack Overflow and OpenGL Discussion Boards), I noticed that this still covers a large part of the issues people ask about.

Diagnosing and solving these types of issues is often tricky because they can be caused by mistakes in almost any part of the OpenGL pipeline. This article explains some common reasons for the infamous "Black Window" problem, as well as approaches to track down these types of issues.

The following sections are mostly based on working with the Core Profile, which includes writing your own shaders. Much of it will apply to the fixed pipeline as well. If you want to make the transition to the Core Profile, check out my article about the topic.

Check for Errors

With hundreds of API calls, it can easily happen that a wrong argument is passed for one of them. Or less obviously, that API calls are made while not meeting all preconditions. You can check for these types of errors, and should do so routinely. The primary function for doing this is glGetError(). A useful approach is to have an error check that is always executed for debug builds at strategic places in your code. If you use assert macros, add a line like this for example at the end of rendering a frame:

ASSERT(glGetError() == GL_NO_ERROR);

If the assert triggers, temporarily add more of them across your code, gradually narrowing down which call causes the error based on the fact that the error was triggered between the last check that did not report an error, and the first one that did. Once you have isolated the error to a single call, reading the documentation for the call, and looking at the exact error code that was returned, should normally make it clear what went wrong.

Another important area of error checking is shader compilation and linking. At least for debug builds, check the shader compilation status after each shader compilation, using:

GLint status = 0; glGetShaderiv(shaderId, GL_COMPILE_STATUS, &status);

If status is GL_FALSE, you can retrieve the error messages using:

GLint logLen = 0; glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &logLen); GLchar* logStr = new GLchar[logLen]; glGetShaderInfoLog(shaderId, logLen, 0, logStr); // report logStr delete[] logStr;

Checking success after linking the program looks similar, except that you use glGetProgramiv()GL_LINK_STATUS,  and glGetProgramInfoLog().

When working with Frame Buffer Objects (FBO), there is another useful error check. After you finished setting up your FBO, check for success with:

ASSERT(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE));

Geometry Not in Field of View

This is by far one of the most common mistakes, and unfortunately not easy to track down. In this case, the whole rendering pipeline is correctly set up, but the the geometry is not in the coordinate range being mapped to the window.

The only good way to fix, or ideally avoid, this issue is a solid understanding of OpenGL coordinate systems and transformations. It is often best to start simple by placing the geometry around the origin, and placing the camera on the positive z-axis, pointing towards the origin. There is no need to use a projection transformation to get something to appear on the screen. Once this works, you can progress to setting up more advanced transformations, like perspective projections.

Common causes for the geometry not being in the field of view include:

  • The geometry has coordinates that are far away from the origin, while the camera points at the origin. In this case, you will either have to modify the coordinates of your geometry, apply a translation to move the geometry to the origin, or point your camera in the direction at the geometry.
  • The camera is inside the object, and backface culling is enabled. This can easily happen if no viewing transformation is set up at all. Make sure that you set up a viewing transformation.
  • The geometry is behind the camera. A variation of the same problem as the previous, but this typically happens if the viewing transformation is not set up correctly.
  • The clipping planes are set wrong. When using one of the common projection transformations, make sure that the range between the near and far clipping planes is consistent with the distance of your geometry from the camera. When not using a projection transformation, make sure that the z-coordinates after applying the viewing transformation are between -1.0 and 1.0.
  • Less common, but possible: The range of coordinates is much too small, so that in the extreme case, you end up drawing the entire geometry in a single pixel.

Black on Black

If there is a problem in the fragment part of the pipeline, it will often produce black pixels. When using shaders, a typical example is if the fragment shader uses texturing, but the texture was not properly set up. With the fixed pipeline, it can mean that no material color was set.

One very useful method to diagnose if this is happening is to set the clear color to something other than the default of black. I mostly set the clear color to something like yellow during development. If you do this, and see the outline of your geometry show up in black, you know that the problem is with the color of the fragments produced by your pipeline. This can be taken one step farther when using FBOs that are rendered to the primary framebuffer in the end. If you clear each render target with a different color, you can see where things break down.

Another useful approach can be applied when using relatively complex fragment shaders. To verify if there might be a problem with the output of the fragment shader, you can temporarily change it to simply produce a fixed color. If that color shows up, while you previously rendered all black, your problem is with the fragment shader.

 Vertex Data Not Properly Set Up

Current OpenGL requires vertex data to be in vertex buffers. If something goes wrong while setting up the data in those vertex buffers, it can result in no rendering at all. Verify that:

  • The vertex data itself that you store in the vertex buffers contains the correct coordinates for your geometry.
  • The correct vertex buffer is bound with glBindBuffer() when setting the vertex buffer data with a call like glBufferData().
  • All arguments to the vertex setup calls are correct. For example, make sure that the arguments to glVertexAttribPointer() match the format, sizes, etc. of your vertex data.

Faces Are Culled

By default, OpenGL expects the vertices of each face to be arranged in a counter-clockwise orientation. If you get this wrong, and have backface culling enabled, your faces can disappear. If you have any kind of suspicion that this might be happening, disable backface culling:

glDisable(GL_CULL_FACE);

Not Everything Is Bound and Enabled

There is a number of objects that need to be bound, and features that need to be enabled, for rendering to happen. If any of them are missing, you will often get no rendering at all.

There is no way around code inspection, or stepping through the code in a debugger, to make sure that everything is properly bound and enabled when the draw calls are executed. Items to look out for include:

  • The correct program is bound with glUseProgram().
  • Rendering goes to the primary framebuffer when intended, using glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0).
  • Vertex array object is bound with glBindVertexArray().
  • Vertex attributes are properly set up and enabled, using calls like glVertexAttribPointer() and glEnableVertexAttribArray().

Uniforms Were Not Set

Make sure that the uniforms used in your shaders are set to valid values before starting to draw. For example, if you miss to set a value for a uniform matrix used for transformations, it can result in your geometry not showing up.

Code inspection and debugging is the only reasonable way to find this. If you suspect that certain uniforms might not be set correctly, you can also try to temporarily simplify the shader to not use the value, and see if something changes.

Depth Buffer Is Not Cleared

If you use a depth buffer, and have depth testing enabled, make sure that you clear the depth buffer at the start of each frame.

A slight variation of this is that if you do not need a depth buffer for your rendering, make sure that you configure your context/surface without a depth buffer during initialization.

Frame Is Not Displayed

This problem is so trivial that it is almost embarrassing, but it does happen: If you use a double buffered visual (which you should in almost all cases), make sure that the buffers are swapped when you finish rendering the frame, so that the frame you rendered is actually displayed.

How exactly this is done is very system dependent. Some higher level frameworks handle this automatically after they invoked your rendering method. If that is not the case, look for a function that typically has SwapBuffers, or something similar as part of its name, and can be found in the window system interface, or the toolkit you use.

The symptom of this is that nothing at all is displayed, not even the clear color. Like in other cases, setting the clear color to something different from black or white helps recognizing that this might be your problem.

Context Is Not Properly Set Up, or Not Current

When nothing renders, it is possible that there was a problem while setting up the context, pixel format, rendering surface, etc. How this is done is highly platform dependent. Fortunately, it is at least easy to diagnose if the problem is in this area. Set your clear color to something other than black, using glClearColor(), and change your rendering method to only do a glClear(). If the window does not show your clear color, chances are that your context setup failed.

 

From: http://retokoradi.com/2014/04/21/opengl-why-is-your-code-producing-a-black-window/

OPENGL: WHY IS YOUR CODE PRODUCING A BLACK WINDOW?的更多相关文章

  1. OpenGL的GLUT事件处理(Event Processing)窗口管理(Window Management)函数[转]

    GLUT事件处理(Event Processing)窗口管理(Window Management)函数 void glutMainLoop(void) 让glut程序进入事件循环.在一个glut程序中 ...

  2. Linux(Ubuntu 14.04) setting up OpenGL

    1. Install c/c++ compilation package. 2. install openGL and freeGlut library sudo apt-get install me ...

  3. android opengl es代码功能

    /* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Versi ...

  4. [OpenGL] 2、企业版VC6.0自带的Win32-OpenGL工程浅析

    一. 建立工程 O(∩_∩)O~上一节介绍了一种非常容易的OpenGL的搭建方法,这一节将就上一节介绍的VC6.0企业版自带的OpenGL Win32 Application建立一个模板工程,并分析这 ...

  5. 利用JNI技术在Android中调用C++形式的OpenGL ES 2.0函数

    1.                 打开Eclipse,File-->New-->Project…-->Android-->AndroidApplication Projec ...

  6. 图解-安卓中调用OpenGL

    游戏开发中经常使用到OpenGL,当然很多人都喜欢直接用现有的游戏引擎,但相信了解的更多对你没有坏处 安卓开发中,采用的OpenGL ex2的规范,前几天看了下这个规范,整体上难度比1.0规范难度加大 ...

  7. Opengl ES 1.x NDK实例开发之六:纹理贴图

    开发框架介绍请參见:Opengl ES NDK实例开发之中的一个:搭建开发框架 本章在第三章(Opengl ES 1.x NDK实例开发之三:多边形的旋转)的基础上演示怎样使用纹理贴图,分别实现了三角 ...

  8. Setting up an OpenGL development environment in ubuntu

    1.opening terminal window and entering the apt-get command for the packages: sudo apt-get install me ...

  9. Opengl ES 1.x NDK实例开发之七:旋转的纹理立方体

    开发框架介绍请參见:Opengl ES NDK实例开发之中的一个:搭建开发框架 本章在第六章(Opengl ES 1.x NDK实例开发之六:纹理贴图)的基础上绘制一个旋转的纹理立方体,原理和纹理贴图 ...

随机推荐

  1. process information unavailable 的解决办法

    有时候在centos上查看java进程时,会遇到process information unavailable 的情况,如下图: 不同账号之间kill进程时,可能会造成这种现象(比如:deploy用户 ...

  2. HOWTO: Use STM32 SPI half duplex mode

    HOWTO: Use STM32 SPI half duplex mode I’ve got my hands onto some STM32F030F4P6 ARM-Cortex M0 proces ...

  3. Calculate CAN bit timing parameters -- STM32

    Calculate CAN bit timing parameters Calculate CAN bit timing parameters typedef struct { //char name ...

  4. Java 微服务实践 - Spring Boot 系列

    https://segmentfault.com/l/1500000009515571

  5. 使用position:relative制作下边框下的小三角

    在制作tab选项卡的时候,有时会有下边框,且下边框下另一个头向下的小三角,这全然能够用css来实现,而不必使用背景图片. 由于使用背景图片时会有一个问题,选项卡内容字数不同.导致使用背景图片时无法控制 ...

  6. 关于UIImageView的显示问题——居中显示或者截取图片的中间部分显示

    我们都知道在ios中,每一个UIImageView都有他的frame大小,但是如果图片的大小和这个frame的大小不符合的时候会怎么样呢?在默认情况,图片会被压缩或者拉伸以填满整个区域. 通过查看UI ...

  7. iOS内存管理策略和实践

    转:http://www.cocoachina.com/applenews/devnews/2013/1126/7418.html 内存管理策略(memory Management Policy) N ...

  8. epoll的两种工作模式

    epoll有两种模式,Edge Triggered(简称ET) 和 Level Triggered(简称LT).在採用这两种模式时要注意的是,假设採用ET模式,那么仅当状态发生变化时才会通知,而採用L ...

  9. python resize

    import sys import os sys.path.append('/usr/local/lib/python2.7/site-packages') sys.path.append('/usr ...

  10. [转]mysqldump备份还原和mysqldump导入导出语句大全详解

    FROM : http://www.cnblogs.com/zeroone/archive/2010/05/11/1732834.html mysqldump备份还原和mysqldump导入导出语句大 ...