首页 > 代码库 > OpenGL ES 学习教程(十三) Stencil_TEST(模板缓冲测试)

OpenGL ES 学习教程(十三) Stencil_TEST(模板缓冲测试)

模板缓冲测试,是指 将模版缓冲区中的值 与 一个参考值 进行比较,根据比较的结果,来对缓冲区中的值进行修改。进而决定该片段是否有效。

在应用中的体现就比如:Unity中的Mask 。


大致的工作流程:

1、第一次Draw的时候,将所有的片段都设置为不通过模版测试。然后修改模版缓冲区的值,比如+1.

2、第二次Draw的时候,给定一个值 与 模版缓冲区中的值进行比较,比如用 1 与模版缓冲区中的值进行比较 。 因为第一步中,已经+1,所以模版缓冲区中值已经是1,然后用相等 作为条件判定 模版测试通过。那么这个片段就可以绘制。

3、这样做的最终效果是,只有第一次绘制的区域,第二次绘制才可以显示。就如同Unity中的Mask,用一张图,Mask掉第二张图。

转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn

在不使用模版测试的情况下,画了两个三角形。

技术分享


首先 就如同深度测试一样,也要申请模版缓冲区。

bool initDevice()
{

	const EGLint attribs[] =
	{
		EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
		EGL_BLUE_SIZE, 8,
		EGL_GREEN_SIZE, 8,
		EGL_RED_SIZE, 8,
		EGL_ALPHA_SIZE,8,
		EGL_DEPTH_SIZE, 24, //请求深度缓冲区
		EGL_STENCIL_SIZE, 8,//请求模版缓冲区
		EGL_NONE
	};
	EGLint 	format(0);
	EGLint	numConfigs(0);
	EGLint  major;
	EGLint  minor;

	//! 1
	m_EGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
	
	......
}

然后要开启模版测试

//重写初始化函数;
virtual void onInit()
{
	Light3dWinAPP::onInit();

	m_program.Initialize();

	glEnable(GL_STENCIL_TEST);//开启模版测试


	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS); //基准设置为 1.0,那么GL_LESS 则深度小余 1.0 的通过测试
}

然后要设置默认模版值

//重写Render;
virtual void render()
{
	glClearColor(0, 0, 0, 1.0);
	glClearDepthf(1.0f);//深度测试的基准,注意1.0代表从近裁剪面到远裁剪面 这一段范围!!并不是指Z轴的1个单位
	glClearStencil(0);



	glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT |GL_STENCIL_BUFFER_BIT);
	
转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn

然后在第一次绘制的时候,指定所有的都不通过模版测试,并且模版值 +1 。

m_program.begin();
{
	glStencilFunc(GL_NEVER, 0x0, 0xFF);//第一次绘制,通通不通过模版测试。
	glStencilOp(GL_INCR, GL_INCR, GL_INCR);//第一次绘制的像素的模版值 0+1 = 1

然后在第二次绘制的时候,比较深度缓冲区中的值,值为 1 的通过测试。

{
	glStencilFunc(GL_EQUAL, 0x1, 0xFF);//等于1 通过测试 ,就是上次绘制的图 的范围 才通过测试。
	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);//没有通过测试的,保留原来的,也就是保留上一次的值。

	glm::vec4 pos[] =
	{
		glm::vec4(0.0f, -2.0f, 1.5f, 1.0f),
		glm::vec4(4.0f, -2.0f, 1.5f, 1.0f),
		glm::vec4(2.0f, 2.0f, 1.5f, 1.0f),
	};

	glm::vec4 color[] =
	{
		glm::vec4(1, 1, 0, 1),
		glm::vec4(1, 1, 0, 1),
		glm::vec4(1, 1, 0, 1),
	};

	glUniformMatrix4fv(m_program.m_mvp, 1, false, &proj[0][0]);

	glVertexAttribPointer(m_program.m_position, 4, GL_FLOAT, false, sizeof(glm::vec4), pos);
	glVertexAttribPointer(m_program.m_color, 4, GL_FLOAT, false, sizeof(glm::vec4), color);

	glDrawArrays(GL_TRIANGLES, 0, 3);
}

这样我们得到的效果就是Mask的效果,只有第一次绘制的范围里,才能显示第二次绘制。

技术分享


如果将比较修改为 不等于 1 的通过测试,那么效果就是第一次绘制的区域被抹除掉。


{
	glStencilFunc(GL_EQUAL, 0x1, 0xFF);//等于1 通过测试 ,就是上次绘制的图 的范围 才通过测试。
	glStencilFunc(GL_NOTEQUAL, 0x1, 0xFF);//不等于1 通过测试 就是除了上次绘制的图案之外的像素通过测试,所以上次绘制的像素之外的像素才可以进行第二幅图的绘制。
	//glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);//没有通过测试的,保留原来的,也就是保留上一次的值。

	glm::vec4 pos[] =
	{
		glm::vec4(0.0f, -2.0f, 1.5f, 1.0f),
		glm::vec4(4.0f, -2.0f, 1.5f, 1.0f),
		glm::vec4(2.0f, 2.0f, 1.5f, 1.0f),
	};

	glm::vec4 color[] =
	{
		glm::vec4(1, 1, 0, 1),
		glm::vec4(1, 1, 0, 1),
		glm::vec4(1, 1, 0, 1),
	};

	glUniformMatrix4fv(m_program.m_mvp, 1, false, &proj[0][0]);

	glVertexAttribPointer(m_program.m_position, 4, GL_FLOAT, false, sizeof(glm::vec4), pos);
	glVertexAttribPointer(m_program.m_color, 4, GL_FLOAT, false, sizeof(glm::vec4), color);

	glDrawArrays(GL_TRIANGLES, 0, 3);
}
转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn

技术分享


示例项目下载:

链接: http://pan.baidu.com/s/1mhMlVAg 密码: 77cg


OpenGL ES 学习教程(十三) Stencil_TEST(模板缓冲测试)