OPENGL: WHY IS YOUR CODE PRODUCING A BLACK WINDOW?
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?的更多相关文章
- OpenGL的GLUT事件处理(Event Processing)窗口管理(Window Management)函数[转]
GLUT事件处理(Event Processing)窗口管理(Window Management)函数 void glutMainLoop(void) 让glut程序进入事件循环.在一个glut程序中 ...
- Linux(Ubuntu 14.04) setting up OpenGL
1. Install c/c++ compilation package. 2. install openGL and freeGlut library sudo apt-get install me ...
- android opengl es代码功能
/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Versi ...
- [OpenGL] 2、企业版VC6.0自带的Win32-OpenGL工程浅析
一. 建立工程 O(∩_∩)O~上一节介绍了一种非常容易的OpenGL的搭建方法,这一节将就上一节介绍的VC6.0企业版自带的OpenGL Win32 Application建立一个模板工程,并分析这 ...
- 利用JNI技术在Android中调用C++形式的OpenGL ES 2.0函数
1. 打开Eclipse,File-->New-->Project…-->Android-->AndroidApplication Projec ...
- 图解-安卓中调用OpenGL
游戏开发中经常使用到OpenGL,当然很多人都喜欢直接用现有的游戏引擎,但相信了解的更多对你没有坏处 安卓开发中,采用的OpenGL ex2的规范,前几天看了下这个规范,整体上难度比1.0规范难度加大 ...
- Opengl ES 1.x NDK实例开发之六:纹理贴图
开发框架介绍请參见:Opengl ES NDK实例开发之中的一个:搭建开发框架 本章在第三章(Opengl ES 1.x NDK实例开发之三:多边形的旋转)的基础上演示怎样使用纹理贴图,分别实现了三角 ...
- 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 ...
- Opengl ES 1.x NDK实例开发之七:旋转的纹理立方体
开发框架介绍请參见:Opengl ES NDK实例开发之中的一个:搭建开发框架 本章在第六章(Opengl ES 1.x NDK实例开发之六:纹理贴图)的基础上绘制一个旋转的纹理立方体,原理和纹理贴图 ...
随机推荐
- 关于 C 语言,我喜欢和讨厌的十件事
前言:最近有个家伙抱怨道“为什么我还要再用C?”-虽然我不同意他的说法,但至少他随口提到如果你“在一台拇指大小的电脑”上编程,或者为一门语言写引导程序,那么可以用C语言.要我说,写设备驱动,或者特定平 ...
- Revit MEP API连接器类别
连接器的类别,风管不仅有两端,可能在曲线上也有. ; ; ; ; Connector conn = csi.Current ; ...
- CListCtrlEx:一个支持文件拖放和实时监视的列表控件——用未公开API函数实现Shell实时监视
一.需求无论何时,当你在Explorer窗口中创建.删除或重命名一个文件夹/文件,或者插入拔除移动存储器时,Windows总是能非常快速地更新它所有的视图.有时候我们的程序中也需要这样的功能,以便当用 ...
- sqlite数据库实现字符串查找的方法(instr,substring,charindex替代方案)
sqlite数据库是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,资源占用低,执行效率高,可以跨平台使用,已被广泛使用.作为一款轻量级的数据库,功能自然会有所欠缺,比如数据库加密,用户权限设 ...
- C# TextWriter类
来自:https://www.yiibai.com/csharp/c-sharp-textwriter.html C# TextWriter类是一个抽象类.它用于将文本或连续的字符串写入文件.它在Sy ...
- Android Studio 出现 Gradle's dependency cache may be corrupt 错误分析
http://blog.csdn.net/u014231734/article/details/41913775 情况说明: 之前下载了 Android Studio 1.0rc2候选版,那时候把 S ...
- c++ 实现atoi()函数
1. 问题描写叙述 实现c++函数库中atoi()函数,要考虑到各种特殊情况: 空字符串. +和-号. 字符串前中后n个空格. 溢出. 非数字字符. 2. 解决方式 转换过程并不复杂.复杂的是要考虑到 ...
- Windows:C:\Windows\System32\drivers\etc\hosts
原文地址:http://zhumeng8337797.blog.163.com/blog/static/100768914201001983953188/. host是一个没有扩展名的系统文件,可以用 ...
- svn: E155015: 提交失败(细节如下) 解决办法
svn 出现冲突是经常发生的事,最近改用命令操作svn,用界面电脑有些反应慢 出现冲突使用svn 命令肯定也是可以解决的: 查看警告信息提示冲突的文件,执行 svn resolved <文件名& ...
- 实用ExtJS教程100例-001:开天辟地的Hello World
ExtJS功能繁多,要想彻底的了解确实很困难.作为初学者,如何能找到一条快速的通道呢?我觉得,如果你有Javascript的基础,那就不要惧怕ExtJS的复杂,从动手开始,遇到问题,解决问题,积累经验 ...