OSG 使用整理(5):模板测试与边缘效果

发布时间 2023-07-08 12:48:14作者: 王小于的啦

osg 使用整理 (5):模板测试与边缘效果

1 模板测试

​ 在渲染管线中,模板测试在片段着色器后执行,通过像素与模板缓冲中的模板值比较,选择性丢弃或者保存这个像素颜色。我们可以通过更新模板测试来获得一些很有意思的效果。下图为LearnOpenGL网站一个例子。

image-20230613222935211

​ 可以发现,颜色缓冲经过模板测试后,只保留了模板值为1的像素颜色。

​ 使用模板缓冲通常的流程:

a $$.$$ 开启模板测试

  glEnable(GL_STENCIL_TEST);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

b $$.$$ 设置模板测试函数,决定如何使用模板缓冲丢弃片段

  glStencilMask(0xFF); // 每一位写入模板缓冲时都保持原样
  glStencilMask(0x00); // 每一位在写入模板缓冲时都会变成0(禁用写入)
  
  /* brief:模板缓冲测试函数
     para[in]: func   测试规则
     para[in]: ref    模板测试参考值
     para[in]: mask   掩码
  */
  glStencilFunc(GLenum func, GLint ref, GLuint mask)
函数 描述
GL_ALWAYS 永远通过深度测试
GL_NEVER 永远不通过深度测试
GL_LESS 在片段深度值小于缓冲的深度值时通过测试
GL_EQUAL 在片段深度值等于缓冲区的深度值时通过测试
GL_LEQUAL 在片段深度值小于等于缓冲区的深度值时通过测试
GL_GREATER 在片段深度值大于缓冲区的深度值时通过测试
GL_NOTEQUAL 在片段深度值不等于缓冲区的深度值时通过测试
GL_GEQUAL 在片段深度值大于等于缓冲区的深度值时通过测试
**c $$.$$ 渲染模型,更新模板缓冲,更新函数为**
  /* brief:模板缓冲更新函数
     para[in]: sfail  模板测试失败时采取的行为
     para[in]: dpfail 模板测试通过,但深度测试失败时采取的行为
     para[in]: sfail  模板测试和深度测试都通过时采取的行为
  */
  glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)
 
行为 描述
GL_KEEP 保持当前储存的模板值
GL_ZERO 将模板值设置为0
GL_REPLACE 将模板值设置为glStencilFunc函数设置的ref
GL_INCR 如果模板值小于最大值则将模板值加1
GL_INCR_WRAP 与GL_INCR一样,但如果模板值超过了最大值则归零
GL_DECR 如果模板值大于最小值则将模板值减1
GL_DECR_WRAP 与GL_DECR一样,但如果模板值小于0则将其设置为最大值
GL_INVERT 按位翻转当前的模板缓冲值

2 osg::Effect 后处理效果类

	osg::Effect类如作者所述,用于实现特殊的渲染效果,其派生包括散射光,亮光,卡通等。它是一系列属性状态stateset的集合,允许采用多个osg::technique封装渲染状态,不同technique可以使用不同的渲染上下文。在使用时,只需要创建所需effect实例,然后添加到场景树中,最后把这个effect要影响的模型节点挂载到effect节点上。要创建自定义渲染效果类,可以继承osg::Effect类,然后重写 define_techniques方法,其中可以使用自定义的technique类,添加technique的顺序十分关键。

​ 勾勒对象的轮廓是用于在游戏,多媒体与工业应用表示特殊效果的实践技术。OpenGL的一个实现是在stencil buffer中写入固定值,然后使用细边线渲染对象。在两遍渲染过程之后,对像周围的轮廓就会显示出来。幸运的是,该效果已经由osgFX库中的osgFX::Effect的派生类osgFX::Outline类实现了。下面是使用示例。

#include <osg/Group>
#include <osgDB/ReadFile>
#include <osgFX/Outline>
#include <osgViewer/Viewer>
void main()
{

    osg::ref_ptr<osg::Node> model = osgDB::readNodeFile( "cessna.osg" );

    osg::ref_ptr<osgFX::Outline> outline = new osgFX::Outline;
    outline->setWidth( 8 );
    outline->setColor( osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f) );
    outline->addChild( model.get() );
    
    osg::DisplaySettings::instance()->setMinimumNumStencilBits( 1 );
    
    osgViewer::Viewer viewer;
    viewer.getCamera()->setClearMask(
        GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    viewer.setSceneData( outline.get() );
    return viewer.run();
}