模板缓冲测试,是指 将模版缓冲区中的值 与 一个参考值 进行比较,根据比较的结果,来对缓冲区中的值进行修改。进而决定该片段是否有效。
在应用中的体现就比如: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
{
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