天天看点

FBO中如何使用模板缓冲区

FBO常用框架

一般需求只有color buffer,depth buffer,前者一般用纹理,后者一般用rbo。标准程序如下:

// 创建
	// frame buffer object
	glGenFramebuffers(1, &fboId);
	glBindFramebuffer(GL_FRAMEBUFFER, fboId);

	// color buffer with texture object
	glGenTextures(1, &color_rboId);
	glBindTexture(GL_TEXTURE_2D, color_rboId);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, targetWidth, targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

	// depth buffer with render buffer object
	glGenRenderbuffers(1, &depth_rboId);
	glBindRenderbuffer(GL_RENDERBUFFER, depth_rboId);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, targetWidth, targetHeight);
	
	// Attach color buffer to FBO
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_rboId, 0);
	
	//Attach depth buffer to FBO
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_rboId);
	
	
	//Also attach as a stencil
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depth_stencil_rb);

// 删除
	if (fboId != 0)
	{
		glDeleteFramebuffers(1, &fboId);
		fboId = 0;
	}

	if (depth_rboId != 0)
	{
		glDeleteRenderbuffers(1, &depth_rboId);
		depth_rboId = 0;
	}
	
	if (color_rboId)
	{
		glDeleteTextures(1, &color_rboId);
		color_rboId = 0;
	}
           

FBO中如何增加stencil buffer

正常人都会认为stencil buffer 跟depth buffer类似,于是乎写出一套类似depth buffer的框架:

// 创建stencil buffer以RBO形式
	glGenRenderbuffers(1, &stencil_rboId);
	glBindRenderbuffer(GL_RENDERBUFFER, stencil_rboId);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX, targetWidth, targetHeight);
	
// 关联stencil buffer 和FBO
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencil_rboId);
	
// 删除stencil buffer
	glDeleteRenderbuffers(1, &stencil_rboId);
           

但实际测试,发现stencil buffer根本不起作用,下面是一个测试函数:

void stencilRenderTest()
{
	GLdouble dRadius = 0.1; // Initial radius of spiral
	GLdouble dAngle;        // Looping variable
	float x = 100;
	float y = 100;
	float rsize = 25;

	// Clear blue window
	glClearColor(0.0f, 0.0f, 1.0f, 0.0f);

	// Use 0 for clear stencil, enable stencil test
	glClearStencil(0.0f);
	glEnable(GL_STENCIL_TEST);

	// Clear color and stencil buffer
	glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

	// All drawing commands fail the stencil test, and are not
	// drawn, but increment the value in the stencil buffer. 
	glStencilFunc(GL_NEVER, 0x0, 0x0);
	glStencilOp(GL_INCR, GL_INCR, GL_INCR);

	// Spiral pattern will create stencil pattern
	// Draw the spiral pattern with white lines. We 
	// make the lines  white to demonstrate that the 
	// stencil function prevents them from being drawn
	glColor3f(1.0f, 1.0f, 1.0f);
	glBegin(GL_LINE_STRIP);
	for(dAngle = 0; dAngle < 400.0; dAngle += 0.1)
	{
		glVertex2d(dRadius * cos(dAngle), dRadius * sin(dAngle));
		dRadius *= 1.002;
	}
	glEnd();

	// Now, allow drawing, except where the stencil pattern is 0x1
	// and do not make any further changes to the stencil buffer
	glStencilFunc(GL_NOTEQUAL, 0x1, 0x1);
	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

	// Now draw red bouncing square
	// (x and y) are modified by a timer function
	glColor3f(1.0f, 0.0f, 0.0f);
	glRectf(x, y, x + rsize, y - rsize);

}
           

stencil正确时,结果显示是一个蓝色背景,红色小矩形块,矩形内部可以看到圆弧,下图右。 stencil不正确结果是蓝色背景同心圆环 以及一个矩形红色块,图左。

FBO中如何使用模板缓冲区

FBO中正确使用stencil buffer

在官方wiki教程中找到答案:

EVER EVER MAKE A STENCIL buffer. All GPUs and all drivers do not support an independent stencil buffer. If you need a stencil buffer, then you need to make a Depth=24, Stencil=8 buffer, also called D24S8. Please search for the example about GL_EXT_packed_depth_stencil on this page.

翻译过来就是:永远不要单独创建一个模板缓冲区,所有的gpu和驱动都不支持单独的模板缓冲区。如果需要创建模板缓冲时 需要深度、模板共用一个缓冲区,格式是DEPTH_24_STENCIL_8。

具体code如下:

// 创建
	// frame buffer object
	glGenFramebuffers(1, &fboId);
	glBindFramebuffer(GL_FRAMEBUFFER, fboId);

	// color buffer with texture object
	glGenTextures(1, &color_rboId);
	glBindTexture(GL_TEXTURE_2D, color_rboId);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, targetWidth, targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

	// depth buffer and stencil buffer
	glGenRenderbuffers(1, &depth_stencil_rb);
	glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil_rb);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, targetWidth, targetHeight); // not GL_DEPTH_COMPONENT24 but GL_DEPTH24_STENCIL8
	
	// Attach color buffer to FBO
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_rboId, 0);
	
	//Attach depth buffer to FBO
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_stencil_rb);	
	//Also attach as a stencil
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depth_stencil_rb);

// 删除
	if (fboId != 0)
	{
		glDeleteFramebuffers(1, &fboId);
		fboId = 0;
	}

	if (depth_stencil_rb != 0)
	{
		glDeleteRenderbuffers(1, &depth_stencil_rb);
		depth_stencil_rb = 0;
	}
	
	if (color_rboId)
	{
		glDeleteTextures(1, &color_rboId);
		color_rboId = 0;
	}
           

参考

opengl 官方wiki:https://www.opengl.org/wiki/Framebuffer_Object_Examples

history:

1. 2013/8/14 fix 正确创建fbo帧缓冲区的bug,renderbuffer格式应该是GL_DEPTH24_STENCIL8而不是 GL_DEPTH_COMPONENT24。

继续阅读