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. LPC43xx SGPIO Slice 示意图

    SGPIO inverted clock qualifier Hi, With bits 6:5 of SGPIO_MUX_CFG the QUALIFIER_MODE is selected (0x ...

  2. LPC1800 and LPC4300 Boot/ISP/CRP

    MCU的启动方式有很多种:UART接口,扩展的静态存储单元(NOR Flash), SPI Flash,quad SPI Flash,高速USB0和USB1.另外可以通过对OTP存储单元的编程. 首先 ...

  3. ElasticSearch-.net平台下c#操作ElasticSearch详解

    ElasticSearch系列学习 ElasticSearch第一步-环境配置 ElasticSearch第二步-CRUD之Sense ElasticSearch第三步-中文分词 ElasticSea ...

  4. C#中POST数据和接收的几种方式

    POST方式提交数据,一种众所周知的方式: html页面中使用form表单提交,接收方式,使用Request.Form[""]或Request.QueryString[" ...

  5. swift笔记(二) —— 运算符

    基本运算符 Swift支持大部分的标准C语言的操作符,而且做了一些改进,以帮助开发人员少犯低级错误,比方: 本该使用==的时候,少写了个=, if x == y {-} 写成了 if x = y {- ...

  6. 采用模拟账号读取Exchange server未读邮件的注意事项(链接邮箱问题)【转】

    最近做项目碰到Exchange中,用EWS API方法读取的未读邮箱(ConnectingIdType.PrincipalName设置该属性的方法)附带代码部分: 核心代码 using Microso ...

  7. INotifyPropertyChanged接口的实现

    何时实现INotifyPropertyChanged接口 官方解释:INotifyPropertyChanged  接口用于向客户端(通常是执行绑定的客户端)发出某一属性值已更改的通知.官方解释的很模 ...

  8. C#编程(十二)----------函数

    类和结构 类和结构实际上都是创建对象的模板 ,每 个对象都包含数据 ,并 提供了处理和访问数据的方法. 类定义了类的每个对象 (称 为实例 )可 以包含什么数据和功能 . 例如 ,如 果 一 个类表示 ...

  9. HDR和bloom效果的区别和关系

    什么是HDR?        谈论游戏画面时常说的HDR到底是什么呢?HDR,本身是High-Dynamic Range(高动态范围)的缩写,这本来是一个CG概念.HDR的含义,简单说,就是超越普通的 ...

  10. mysql between and 遇到日期查询边界问题

    最近实现一个按日期范围查询列表,例如输入的是日期 2015-11-01到2015-11-03,想得到1号到3号的数据, 执行 select * from table where create_date ...