我在开源游戏torcs(http://torcs.sourceforge.net/)上工作。 游戏的图形管道仍在使用OpenGL 1.3的固定功能管道(FFP)。
我尝试将游戏场景渲染到FBO(Framebuffer对象)中的纹理,以便对渲染的纹理进行一些后处理。我使用的是OpenGL 3.3。在我的机器上。
目前,我已经在GL_COLOR_ATTACHMENT0&1
设置了附加纹理的FBO(2为了在着色器中有两个连续的帧可读),并在GL_DEPTH_ATTACHMENT
设置了附加的渲染缓冲区。
绑定FBO后,执行游戏渲染功能。当我之后取消绑定FBO并进行验证时,通过着色器程序将纹理写回窗口缓冲区,场景不完整。更具体地说,仅渲染汽车的轮廓,轮胎的滑动痕迹和一些烟雾也是如此。这表明某些内容会呈现给FBO的纹理,但不是所有内容。其中没有纹理(树木,房屋,草等)被渲染到FBO中的纹理。这表明我的纹理设置不正确,但不幸的是我对OpenGL的了解有限,这就是为什么我希望得到你的帮助。
值得注意的另一件事是,如果我在绘图发生之前省略了行glActiveTexture(GL_TEXTURE0);
,那么将显示一个纹理(即将被写入FBO并写回窗口系统帧缓冲而不是汽车大纲。
以下代码显示了FBO的初始化(来自https://en.wikibooks.org/wiki/OpenGL_Programming/Post-Processing):
int screen_width = 640;
int screen_height = 480;
/* Texture A*/
glGenTextures(1, &fbo_texture);
glBindTexture(GL_TEXTURE_2D, fbo_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
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);
/* Texture B*/
//glActiveTexture(GL_TEXTURE1);
glGenTextures(1, &fbo_texture_a);
glBindTexture(GL_TEXTURE_2D, fbo_texture_a);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
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);
/* Depth buffer */
glGenRenderbuffers(1, &rbo_depth);
glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screen_width, screen_height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
/* Framebuffer to link everything together */
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_texture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, fbo_texture_a, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo_depth);
GLenum status;
if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) {
fprintf(stderr, "glCheckFramebufferStatus: error 0x%x", status);
return 0;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
/* Compile and link shaders */
...
以下代码显示了绘图的位置:
修改:如果use_fbo=false
,那么所有内容都会像以前一样直接呈现给屏幕。我所做的唯一更改是在括号内。
if (use_fbo)
{
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0,0,grWinw, grWinh);
if (fbo_a) // drawing to fbo_texture_a
{
glDrawBuffer(GL_COLOR_ATTACHMENT1);
glActiveTexture(GL_TEXTURE0+11);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, fbo_texture_a);
}
else
{
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glActiveTexture(GL_TEXTURE0+12);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, fbo_texture);
}
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
}
glClearColor(0.7f, 0.1f, 0.1f, 1.0f); //clear with red to see what is drawn to the fbo
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
grScreens[0]->update(s, grFps);//THIS IS WHERE THE DRAWING HAPPENS unchanged from original drawing in TORCS
if (use_fbo)
{
glPopAttrib();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glEnable(GL_TEXTURE_2D);
glDrawBuffer(GL_BACK);
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glUseProgram(program_postproc);
if (fbo_a) // drawn to fbo_texture_a
{
glUniform1i(uniform_fbo_texture, 11);
glUniform1i(uniform_fbo_texture_a, 12);
fbo_a=!fbo_a;
}
else
{
glUniform1i(uniform_fbo_texture, 12);
glUniform1i(uniform_fbo_texture_a, 11);
fbo_a=!fbo_a;
}
glEnableVertexAttribArray(attribute_v_coord_postproc);
glBindBuffer(GL_ARRAY_BUFFER, vbo_fbo_vertices);
glVertexAttribPointer(
attribute_v_coord_postproc, 2, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(attribute_v_coord_postproc);
glUseProgram(0);
}
我希望我能为您提供足够的信息来帮助我。任何建议表示赞赏。
编辑:我再次检查了我的着色器代码和FBO实现(将其简化为只有一个颜色附件等,并使用简化的图纸)并且一切正常。我认为麻烦的是用于绘图的固定功能管道和我对FBO的实现......
编辑:以下是use_fbo = true与false结果的两张图片: (注意:绑定FBO后,红色是清晰的颜色,看看有什么呈现给fbo:除了阴影和防滑标记之外什么都没有)
我还试图可视化深度缓冲区(将实现更改为深度的纹理附件),即使我线性化,也没有信息。我想深度也没有正确写入FBO。
答案 0 :(得分:0)
当我将您的代码与我的工作引擎进行比较时,我会看到这些差异,因此请逐一尝试:
纹理格式
你正在使用:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
将你所有的东西合并到:
GL_COLOR_ATTACHMENT0: GL_RGBA,GL_RGBA,GL_UNSIGNED_BYTE
GL_COLOR_ATTACHMENT1: GL_RGBA,GL_RGBA,GL_UNSIGNED_BYTE
我正在使用:
GL_COLOR_ATTACHMENT0 : GL_RGBA , GL_RGBA8 , GL_UNSIGNED_BYTE
GL_DEPTH_ATTACHMENT : GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT16, GL_UNSIGNED_BYTE
GL_STENCIL_ATTACHMENT: GL_STENCIL_INDEX , GL_STENCIL_INDEX8 , GL_UNSIGNED_BYTE
您需要更改纹理的内部像素格式以指定位宽。如果我在编写代码时(几年前)我的记忆效果很好,那么只有GL_RGBA,GL_RGBA
才能使用。
深度目标
我使用depth
和stencil
纹理的方式与color attachment
相同。我不使用任何RenderBuffer
次调用。这并不意味着你的代码是错误的,但我的代码是经过测试和运作的。
纹理尺寸
这很可能不再有效,因为大多数gfx卡支持矩形纹理扩展,但 OpenGL 纹理应该是2分辨率的功率。因此,对于初学者来说,请尝试使用512x512
而不是640x480
并在代码运行时进行更改(只是为了确保......)。
如果它有帮助,我的 C ++ FBO class
取自我的引擎,所以你有比较的东西(不会单独工作,因为它使用纹理和引擎的东西) :
//------------------------------------------------------------------------------
//--- Open GL FBO object ver 2.31 ----------------------------------------------
//------------------------------------------------------------------------------
#ifndef _OpenGL_FBO_h
#define _OpenGL_FBO_h
//------------------------------------------------------------------------------
class OpenGL_FBO
{
public:
GLuint fbo;
int xs,ys;
struct _dst
{
GLint txr; // texture id
GLenum dst; // GL_DEPTH_COMPONENT, GL_COLOR_ATTACHMENT0, ...
_dst() { txr=-1; dst=GL_COLOR_ATTACHMENT0; }
_dst(_dst& a) { *this=a; }
~_dst() {}
_dst* operator = (const _dst *a) { *this=*a; return this; }
//_dst* operator = (const _dst &a) { ...copy... return this; }
};
List<_dst> dst;
OpenGL_FBO() { fbo=0xFFFFFFFF; xs=1; ys=1; dst.reset(); }
OpenGL_FBO(OpenGL_FBO& a) { fbo=0xFFFFFFFF; dst.reset(); *this=a; }
~OpenGL_FBO() { if (fbo!=0xFFFFFFFF) glDeleteFramebuffers(1,&fbo); }
OpenGL_FBO* operator = (const OpenGL_FBO *a) { *this=*a; return this; }
//OpenGL_FBO* operator = (const OpenGL_FBO &a) { ...copy... return this; }
void resize(OpenGLscreen &scr,int _xs=-1,int _ys=-1)
{
int i;
_dst *d;
if (_xs<=0) _xs=scr.xs;
if (_ys<=0) _ys=scr.ys;
// for (xs=1;xs<_xs;xs<<=1);
// for (ys=1;ys<_ys;ys<<=1);
xs=_xs; ys=_ys; // ****
if (fbo==0xFFFFFFFF) glGenFramebuffers(1,&fbo);
glBindFramebuffer(GL_FRAMEBUFFER,fbo);
for (d=dst.dat,i=0;i<dst.num;i++,d++)
{
scr.txrs.bind(d->txr);
scr.txrs.resize(d->txr,xs,ys,1);
// glFramebufferTexture2D(GL_FRAMEBUFFER,t->dst,GL_TEXTURE_2D,scr.txrs.names[d->txr],0);
glFramebufferTexture(GL_FRAMEBUFFER,d->dst,scr.txrs.names[d->txr],0);
// glCheckFramebufferStatus(GL_FRAMEBUFFER);
}
scr.txrs.unbind();
glBindFramebuffer(GL_FRAMEBUFFER,0);
}
int add(OpenGLscreen &scr,int _dest=GL_COLOR_ATTACHMENT0) // add txr to fbo
{
_dst d;
OpenGL_TXR tmp;
// colro atachments
tmp.pixelformat =GL_RGBA;
tmp.pixeliformat=GL_RGBA8;
tmp.pixeltype=GL_UNSIGNED_BYTE;
tmp.mag=GL_NEAREST;
tmp.min=GL_NEAREST;
if (_dest==GL_DEPTH_ATTACHMENT)
{
tmp.pixelformat =GL_DEPTH_COMPONENT;
tmp.pixeliformat=GL_DEPTH_COMPONENT16;
// tmp.pixeltype=GL_FLOAT;
tmp.pixeltype=GL_UNSIGNED_BYTE;
}
if (_dest==GL_STENCIL_ATTACHMENT)
{
tmp.pixelformat =GL_STENCIL_INDEX;
tmp.pixeliformat=GL_STENCIL_INDEX8;
tmp.pixeltype=GL_UNSIGNED_BYTE;
}
tmp.xs=xs;
tmp.ys=ys;
tmp.zs=1;
tmp._mipmap=0;
tmp.txrtype=GL_TEXTURE_2D;
d.txr=scr.txrs.add(tmp);
d.dst=_dest;
dst.add(d);
return d.txr;
}
void bind(OpenGLscreen &scr) // init fbo >> txr
{
// init and resize
if (fbo==0xFFFFFFFF) glGenFramebuffers(1,&fbo);
glBindFramebuffer(GL_FRAMEBUFFER,fbo);
glViewport(0,0,xs,ys);
scr.cls();
}
void unbind(OpenGLscreen &scr)
{
glBindFramebuffer(GL_FRAMEBUFFER,0);
glViewport(scr.x0,scr.y0,scr.xs,scr.ys);
}
};
//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------
//--- end. ---------------------------------------------------------------------
//------------------------------------------------------------------------------
<强>其中:强>
OpenGLscreen scr
是我的渲染引擎
scr.cls()
只是glClear
和初始框架的东西
scr.x0,y0,xs,ys
是目标窗口的视口
scr.txrs
是纹理系统类(处理所有纹理),如add
新纹理加载/从文件保存, CPU / GPU 之间的转换等等更多。
我也使用我的动态列表模板:
List<double> xxx;
与double xxx[];
相同
xxx.add(5);
将5
添加到列表的末尾
xxx[7]
访问数组元素(安全)
xxx.dat[7]
访问数组元素(不安全但快速直接访问)
xxx.num
是数组的实际使用大小
xxx.reset()
清除数组并设置xxx.num=0
xxx.allocate(100)
为100
项目预分配空间
典型用法是:
// [globals and init]
OpenGLScreen scr; // can ignore this
OpenGL_FBO fbo;
scr.init(window_handle); // init OpenGL stuff can ignore this
fbo.add(scr,GL_COLOR_ATTACHMENT0);
fbo.add(scr,GL_DEPTH_ATTACHMENT);
fbo.resize(scr,512,512);
// [render loop]
fbo.bind(scr);
// here render
fbo.unbind(scr);
// here you can use the textures fbo.dst[].txr
在这里查看具体示例:
对于那些坚持使用较旧的英特尔高清显卡的人来说,粗略的,不要指望这会因驱动程序中的错误而起作用。看到这个缓慢的解决方法: