【问题标题】:2D openGL engine simple lightsources and framebuffers (c++)2D openGL 引擎简单光源和帧缓冲区 (c++)
【发布时间】:2014-08-19 20:02:02
【问题描述】:

我目前正在尝试学习 openGL,但在为我的应用程序制作一个非常简单的照明引擎时遇到了困难。它是 2D 的,我发现的大多数资源只涵盖相当复杂的 3D 操作。我想做的就像本教程中介绍的一样简单:http://www.alcove-games.com/opengl-es-2-tutorials/lightmap-shader-fire-effect-glsl/

它把我推向了正确的方向,我明白我将使用带有“光照贴图”的帧缓冲区,我将它与我正在渲染的纹理一起发送到我的着色器,这样我就可以将这些组合起来值以创建照明效果。首先要做的事:我无法让我的帧缓冲区工作!

我遵循了以下教程:http://open.gl/framebuffers,这已经足够简洁了。它引导我使用以下代码非常简单地创建帧缓冲区:

GLuint frameBuffer;
glGenFramebuffers(1, &frameBuffer);

glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, myTexture2.texture_id, 0);

这里 myTexture2 是我的纹理类,texture_id 是这个纹理的 GLuint。 (我可以使用默认的帧缓冲区很容易地将它渲染到屏幕上,并且它显示得很好,所以我知道这是可行的)。完成此操作后,我运行测试以检查一切是否正常(如教程所述):

    GLenum check_framebuffer = glCheckFramebufferStatus(frameBuffer);
    if (check_framebuffer == GL_FRAMEBUFFER_COMPLETE)
    {
        std::cout << "Everything is fine\n";
    }
    else{
        std::cout << "glCheckFramebufferStatus returned: " << glCheckFramebufferStatus(frameBuffer) << std::endl;
        std::cout << "GlError: " << glGetError() << std::endl;
    }

glCheckFramebufferStatus 返回 0,GLerror 为 1280(无效枚举?)。

不出所料,如果我在绘制之前绑定到这个帧缓冲区,一切都是黑色的(glClearColor 设置为红色,所以至少如果它正在工作,它应该是红色的)。如果我将其设置回

glBindFramebuffer(GL_FRAMEBUFFER, 0);

然后一切正常。我的帧缓冲区有什么问题?我一直在到处寻找一个简单的项目示例,我可以复制粘贴并运行它以查看它是否有效,但它要么是错误的语言,要么使用了一些我不打算使用的库。此外,我并不完全确定我是否了解帧缓冲区的工作原理。我知道这只是另一个要绘制的屏幕(或者据我所知,在渲染过程中添加另一个步骤?)。

目前我正在通过绑定纹理来绘制所有内容,绘制具有纹理大小的四边形,然后移动到下一个纹理。这意味着对于我的应用程序中的每一个图像,它们都运行一个着色器(或者我应该说,当前完全相同的着色器的副本)。我是否理解如果我有例如 20 个不同的图像首先在屏幕上运行 20 个着色器,然后我可以通过一个额外的“步骤”运行这些图像以将它们与我在帧缓冲区中创建的光照贴图混合,还是我弄错了?

很抱歉,如果这些问题听起来很愚蠢,但我现在浏览了大量教程,每个教程提出的问题都比看起来要回答的要多,我通常通过实验学得最好,但是当我什至无法得到我的帧缓冲区正在运行,我有点卡住了!

【问题讨论】:

  • 你的纹理进入这个状态是什么?您是否已致电TexImage2D 确定其大小和格式?
  • 是的,这就是我制作纹理的方式。大小(宽度和高度)存储在我的纹理类中。
  • ...您是否检查过您正在获取 3.2 或更高版本的 OpenGL 版本的上下文?那是glFramebufferTexture 到达的时候。
  • 在创建帧缓冲区对象之前尝试调用 glGetError() 看看是否一切正常,这可能是一个过时的错误。使用 opengl 编程的一个重要技巧:创建一个调用 glGetError() 的函数,如果有错误,记录其枚举名称(例如 GL_INVALID_ENUM)、来自 API 的错误描述以及 __FILE__ 和 __LINE__。然后在每个 gl* 函数调用之后添加该函数调用。使调试变得轻而易举。我将我的调试宏包装在一个调试宏中,该宏仅在定义了调试标志时才编译。
  • 在测试帧缓冲区之前运行 glGetError() 返回 0,在返回 1280 之后。对于 Tommy,我实际上没有使用 openGL 3.2 或更高版本,我使用的是 3.1!没有看到任何地方提到的。请注意,尝试将我的上下文从 3.2 更改为 3.1,我的 openGL 将不再初始化。埃加德。

标签: c++ opengl shader framebuffer


【解决方案1】:

此调用中的参数不正确:

GLenum check_framebuffer = glCheckFramebufferStatus(frameBuffer);

此调用的参数不是帧缓冲区 ID(名称),而是帧缓冲区目标。这应该是:

glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
GLenum check_framebuffer = glCheckFramebufferStatus(GL_FRAMEBUFFER);

如果您使用此调用,它应该会为您提供有关实际渲染失败原因的更多详细信息。 glFramebufferTexture2D() 电话看起来基本没问题。所以很可能与贴图的设置方式有关,贴出的代码中没有显示。

【讨论】:

  • 你知道什么。这对我来说很典型,它一直在起作用。谢谢!
【解决方案2】:

DirectX 中帧缓冲对象技术的名称是“渲染到纹理”。所以它不是“另一个要绘制的屏幕”;这是一个离线纹理。

一些关键概念:

  1. 数据存储在纹理中。 FBO(framebuffer object)只是告诉OpenGL如何渲染到这个纹理。
  2. 只有一个“屏幕”对象,即后台缓冲区。所有其他“渲染目标”(OpenGL 中的 AKA FBO)都处于脱机状态。如果要在屏幕上显示某些内容,则必须绘制到后台缓冲区。

使用FBO的基本步骤是:

  1. 创建纹理
  2. 创建一个 FBO;将纹理绑定到 FBO;将 FBO 绑定为“渲染目标”
  3. 画到 FBO
  4. 切换回后台缓冲区 (glBindFramebuffer(GL_FRAMEBUFFER, 0);)
  5. 将纹理绑定为“纹理”
  6. 在后台缓冲区中绘制一些东西,您现在就可以对纹理进行采样了

详细代码示例可以参考http://www.songho.ca/opengl/gl_fbo.html

【讨论】:

  • 感谢您解决这个问题。我已经看过那个例子了,我还是不明白为什么 glCheckFramebufferStatus 返回 0。
猜你喜欢
  • 2013-12-19
  • 2014-06-26
  • 1970-01-01
  • 2015-11-04
  • 1970-01-01
  • 2013-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多