OSG学习笔记-Group(2-3-6)-OccluderNode

2.3.15 遮挡裁剪节点

遮挡裁剪节点(osg::OccluderNode)继承自osg::Group节点。osg::OccluderNode节点的主要作用是裁剪被遮挡的物体,也就是场景中被其它物体所遮挡的物体。最优的遮挡裁剪算法只选择其中可见的物体,从某种意义上来说,Z缓冲器只选择并绘制那些可见的物体,但是必须将这些物体都送入管线的大部分阶段。高效的遮挡算法背后的思想是:提前执行一些简单从测试,从而避免将所有的数据送入管线的大部分阶段。

目前遮挡裁剪算法主要有两种,分别是基于点的遮挡裁剪和基于单元的遮挡裁剪。基于点的可见性通常用于绘制,也就是从单个视点位置看到所有的物体。基于单元的可见性判断主要针对一个方体或者圆体单元进行可见性判断,利用这种方法判断出的不可见物体在单元内部的所有点看上去是不可见的,它的优点是:一旦计算出一个单元的可见性,只要视点在这个单元中,通常就可以将可见性判断结果用于很多真实画面。但这种算法有一个缺陷,就是所需计算的开销比基于视点的可见性大得多。因此,通常将其作为一个预处理步骤。可以用这样一个形象的比喻来说明这两种算法,那就是基于点的可见性和基于单元的可见性可以认为分别是一个点光源和区域光源。

osg::OccluderNode主要采用的是基于点的遮挡算法,但节点本身不具备遮挡能力,因此,在判断时需要指定一个遮挡面,可以调用下面的函数:

void setOccluder(ConvexPlanarOccluder*occluder)// 该平面应该是一个凸多边形

2.3.16 遮挡裁剪节点示例

#include<osgViewer/Viewer>
#include<osg/Node>
#include<osg/Geode>
#include<osg/Group>
#include<osg/Geometry>
#include<osg/OccluderNode>
#include<osg/StateSet>
#include<osg/ConvexPlanarOccluder>
#include<osg/BoundingBox>
#include<osg/BoundingSphere>
#include<osgDB/ReadFile>
#include<osgDB/WriteFile>
#include<osgUtil/Optimizer>
#include<iostream>
//-------------------------------------------------------------------------------------------------------------------------
// 创建遮挡节点
osg::ref_ptr<osg::Node>createOccluder(const osg::Vec3&,v1,const osg::Vex3& v2,const osg::Vec3& v3,const osg::Vec3& v4)
{
    // 创建遮挡节点对象
    osg::ref_ptr<osg::OccluderNode> occluderNode = new osg::OccluderNode();
    
    // 创建遮挡平面
    osg::ref_ptr<osg::ConvexPlanarOccluder>cpo = new osg::ConvexPlanarOccluder;
    
    // 关联遮挡平面
    occluderNode->setOccluder(cpo.get());
    occluderNode->setName("occluder");
    
    // 初始化一个遮挡平面
    osg::ConvexPlanarPolygon& occluder = cpo->getOccluder();
    occluder.add(v1);
    occluder.add(v2);
    occluder.add(v3);
    occluder.add(v4);
    
    // 为遮挡面画一个四边形
    osg::ref_ptr<osg::Geometry>geom = new osg::Geometry;
    osg::ref_ptr<osgVec3Array>coords = new osg::Vec3Array(occluder.getVertexList().begin(),occluder.getVertexList.end());
    geom->setVertexArray(coords);
    
    osg::ref_ptr<osg::Vec4Array>colors = new osg::Vec4Array(1);
    (*color)[0].set(1.0f,1.0f,1.0ff0.5f);
    geom->setColorArray(colors.get());
    geom->setColorBinding(osg::Geometry::BIND_OVERALL);
    geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
    osg::ref_ptr<osg::Geode>geode = new osg::Geode;
    geode->addDrawable(geom.get());
    
    osg::ref_ptr<osg::StateSet>stateSet = new osg::StateSet();
    // 关闭光照
    stateSet->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
    // 使用混合,以保证Alpha纹理正确
    stateSet->setMode(GL_BLEND,osg::StateAttribute::ON);
    // 设置透明渲染元
    stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
    geom->setStateSet(stateSet.get());
    
    // 添加四边形作为遮挡节点,遮挡节点本身不具备遮挡能力
    occluderNode->addChild(geode.get());
    
    return occluderNode.get();
}
//--------------------------------------------------------------------------------------------------------------------------------
// 创建绕模型的遮挡场景
osg::ref_ptr<osg::Group>createOccludersAroundModel(osg::ref_ptr<osg::Node> model)
{
    // 创建场景组节点
    osg::ref_ptr<osg::Group>scene = new osg::Group();
    scene->setName("OccluderScene");
    
    // 添加子节点
    scene->addChild(model.get());
    model->setName("cow.osg");
    
    // 计算模型的包围盒
    const osg::BoundingSphere bs = model->getBound();
    
    // 根据包围盒创建前后左右4个遮挡面
    osg::BoundingBox bb;
    bb.expandBy(bs);
    
    // 前遮挡面
    scene->addChild(createOccluder(bb.corner(0),bb.corner(1),bb.corner(5),bb.corner(4)));
    
    // 右遮挡面
    scene->addChild(createOccluder(bb.corner(1),bb.corner(3),bb.corner(7),bb.corner(5)));
    
    // 左遮挡面
    scene->addChild(createOccluder(bb.corner(2),bb.corner(0),bb.corner(4),bb.corner(6)));
    
    // 后遮挡面
    scene->addChild(createOccluder(bb.corner(3),bb.corner(2),bb.corner(6),bb.corner(7)));
    
    return scene.get();
}
//------------------------------------------------------------------------------------------------------------------------
int main()
{
    osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
    
    osg::ref_ptr<osg::Group>root = new osg::Group();
    osg::ret_ptr<osg::Node> node = osgDB::readNodeFile("cow.osg");
    
    // 添加遮挡场景
    root->addChild(createOccludersAroundMode(node.get()));
    
    // 优化场景数据
    osgUtil::Optimizer optimizer;
    optimizer.optimize(root.get());
    viewer->setSceneData(root.get());
    viewer->realize();
    viewer->run();
    
    return 0;
}
//-----------------------------------------------------------------------------------------------------------------------

猜你喜欢

转载自blog.csdn.net/liangfei868/article/details/123621812
今日推荐