OpenGL - 在 NVIDIA 卡上渲染到纹理时出现 FBO 黑屏
Posted
技术标签:
【中文标题】OpenGL - 在 NVIDIA 卡上渲染到纹理时出现 FBO 黑屏【英文标题】:OpenGL - FBO black screen when rendering to texture on NVIDIA card 【发布时间】:2015-09-27 01:02:29 【问题描述】:我学习了一些关于如何设置和渲染 FBO 的教程。起初它运行良好,场景渲染良好,但事实证明该程序使用的是集成 GPU。 (我正在使用我的笔记本电脑)
然后,出于好奇,我用“更高性能”的 GPU(Nvidia GeForce GT540M
)运行它,然后屏幕全黑了。此时我尝试将 FBO 的颜色纹理保存到一个文件中,并且场景实际上正在那里绘制。
但最终我找到了解决方案。以前我只会清除 FBO(颜色和深度缓冲区),但现在我会清除 FBO 和默认帧缓冲区,然后再次渲染场景。
所以问题是,我必须调用 glClear 两次是不是很糟糕?我真的需要调用 glClear 两次吗?为什么一个 clear 能在集成卡上工作?
如果有帮助,我可以展示一些代码。
帧缓冲初始化
bool FrameBufferObject::initializeFBO( int width, int height )
glActiveTexture( GL_TEXTURE0 );
if ( !_colorTexture.createEmptyTexture( width, height ) )
return false;
_textureId = _colorTexture.getTextureId();
if ( !_depthTexture.createDepthTexture( width, height ) )
return false;
_depthTextureId = _depthTexture.getTextureId();
glGenFramebuffers( 1, &_frameBufferID );
glBindFramebuffer( GL_FRAMEBUFFER, _frameBufferID );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _textureId, 0 );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depthTextureId, 0 );
if ( glCheckFramebufferStatus( GL_FRAMEBUFFER ) != GL_FRAMEBUFFER_COMPLETE )
return false;
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
_width = width;
_height = height;
_isInitialized = true;
return true;
颜色纹理
bool Texture::createEmptyTexture( int width, int height )
if ( isLoaded() )
closeTexture();
GLuint textureId = 0;
glGenTextures( 1, &textureId );
if ( getOpenGLError( "Unable to generate TextureID." ) )
return false;
glBindTexture( GL_TEXTURE_2D, textureId );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glBindTexture( GL_TEXTURE_2D, 0 );
if ( getOpenGLError( "Error creating empty texture." ) )
glDeleteTextures( 1, &textureId );
return false;
_isLoaded = true;
_textureWidth = _imageWidth = width;
_textureHeight = _imageHeight = height;
_textureId = textureId;
return true;
深度纹理是相同的,只是它使用 GL_DEPTH_COMPONENT 格式,
glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL );
后处理着色器
顶点着色器
#version 330 core
in vec2 inVertex;
in vec2 inTexture;
out vec2 texCoords;
void main()
texCoords = inTexture;
gl_Position = vec4( inVertex.x, inVertex.y, 0, 1 );
片段着色器
#version 330 core
in vec2 texCoords;
uniform sampler2D texture0;
layout(location = 0) out vec4 outColor;
void main()
vec4 color = texture( texture0, texCoords );
outColor = color;
渲染代码是这样的,
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
fbo.bindFBO();
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// .. render scene ..
fbo.unbindFBO();
// This is a namespace
PostProcShader::shader.useShader();
PostProcShader::render( fbo.getColorTexture() );
PostProcShader::shader.disableShader();
SDL_GL_SwapWindow( window );
后处理着色器只是在屏幕大小的四边形上渲染纹理。该场景使用 3 个着色器:一个用于 3D 对象,第二个用于天空盒,最后一个用于字体。
我在 VS 2015 中使用 C++、SDL2 和(当然)OpenGL/Glew。
编辑:
深度测试初始化
glEnable( GL_DEPTH_TEST );
glDepthMask( GL_TRUE );
glDepthFunc( GL_LEQUAL );
glDepthRange( 0.0f, 1.0f );
glClearDepth( 1.0f );
【问题讨论】:
当您将 FBO 绘制到屏幕上时,您是否启用了深度测试?你的深度函数是什么? 是的,那么我应该在将 FBO 绘制到屏幕时禁用深度测试吗? (我编辑了问题) 嗯,是的,如果你不想进行深度测试,你应该禁用深度测试。此外,如果您从未对默认帧缓冲区使用深度测试,则可以在没有深度缓冲区的情况下创建它。另一种选择是使用glBlitFramebuffer()
将FBO 内容复制到默认帧缓冲区。然后你就不需要那么多状态设置,不需要额外的着色器等等。
@aslg 你不妨试试。不知道能不能解决你的问题。
glBlitFramebuffer
看起来很有希望,我会试一试。 @immibis 禁用深度测试也可以。
【参考方案1】:
当我从 Intel HUD 转到 Nvidia 时,我遇到了类似的问题。但是我的解决方案很简单。在渲染到新的帧缓冲区(在 Nvidia 上)之前,我必须确保我调用了 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
,否则我将看不到任何渲染。我怀疑在 Nvidia 上,深度缓冲区未设置为与 Intel 相同的默认值,因此清除它会将其设置为 opengl 默认清除值。
【讨论】:
以上是关于OpenGL - 在 NVIDIA 卡上渲染到纹理时出现 FBO 黑屏的主要内容,如果未能解决你的问题,请参考以下文章
在 nvidia opengl 上混合 glGetTexImage 和 imageStore 的问题