目录
1. 前言
裁剪”就是从大量的事务中进行挑选、删除。对一个庞大的三维体而言,往往存在着大量无助于最终渲染结果的对象;将它们从场景中剔除后,将剩余的场景对象发送到OpenGL管线中,即可完成一帧的绘制工作。这类型的裁剪工作通常称为“可见性裁剪”,即只有真正能够被终端用户看到的对象才会被发送到渲染管线中。
2. 常见的裁剪技术
2.1. 背面裁剪
当我们观察一个不透明物体时,通常大约有一半的物体表面是看不到的,因此完全可以省去这一半的绘制工作,场景的多边形复杂度也将降低1/2左右。osg本身提供了如下图的背面裁剪的实现函数:
osg::ref_ptr<osg::CullFace>cullface=new osg::CullFace(osg::CullFace::Back);
stace->setAttribute(cullface.get());
state->setMode(GL_CULL_FACE,osg::StateAttribute::ON);
2.2. 视椎体裁剪
视椎体裁剪就是将不在视椎体中的物体剔除掉、不绘制,而只绘制视椎体内部或与视椎体相交的物体。此举对性能的提升有着巨大的帮助。通常,物体是不规则的,为了方便,我们用该物体的包围球与当前视锥体进行比较。如果包围球在视锥体外,那么不需要绘制此包围球所表达的节点及其所有的子节点。如下图所示,红色方块在视锥体外,该方块将被裁剪。
视锥体裁剪包括近平面裁剪、远平面裁剪以及视锥体侧面裁剪三部分。下图中setProjectionMatrixAsPerspective中的参数zNear、zFar就是对在osg中对相机的远近裁剪面的设置。NEAR_PLANE_CULLING是近平面裁剪,将超出近平面范围以外的对象裁剪:
osg::ref_ptr<osg::Camera>rpCamera = new osg::Camera();
rpCamera->setProjectionMatrixAsPerspective(dAngle,aspectRatio,zNear,zFar);
rpCamera->setComputeNearFarMode(osg::CullSettings::NEAR_PLANE_CULLING);
2.3. 细节裁剪
场景中某些物体对于观察者而言可能是极其微小的,足以忽略不计,此时可以用细节筛选特性将它们剔除。判断对象是否足够细微,需要用一个像素阈值来决定!注意,这种筛选可能会剔除一些必要的信息(比如用户在屏幕上绘制了一些点,却发现它们全部被吞噬掉了),因此它是一种通过牺牲质量来换取速度的技术。
osg::CullStack::CullingMode cullingMode = viewer.getCamera()->getCullingMode();
cullingMode &= ~ (osg::CullStack::SMAL_FEATURE_CULLING);
viewer.getCamera()->setCullingMode(cullingMode);
2.4. 遮挡裁剪
判断场景中的物体是否有互相遮挡关系,剔除那些被完全遮挡的对象,保留可见物体。但是,完全的遮挡测试算法往往具有过高的复杂度,需要判断每个场景对象与其他对象的遮挡关系,导致计算带来的开销大于绘制带来的开销,并不实用!
比较常见的方法是定义一种“遮挡板”对象(在osg中使用OccluderNode节点),其形状不固定,并且可以遮挡场景中的其他对象。少量的遮挡板可以有效的增加场景的裁剪效率,尤其在室内景物的裁剪等场合,使用遮挡板来模拟墙面和门体是再好不过的选择~。
在osg中OccluderNode本身并不具备遮挡能力,需要指定一个遮挡面osg::ConvexPlanarOccluder来进行遮挡。
//创建遮挡节点对象
osg::ref_ptr<osg::OccluderNode>occluderNode = new osg::OccluderNode;
//创建遮挡平面
osg::ref_ptr<osg::ConvexPlanarOccluder>cpo = new osg::ConvexPlanarOccluder;
//关联遮挡平面
occluderNode->setOccluder(cpo.get());
2.5。 聚集裁剪
这是一种类似于背面筛选的场景筛选方法,但是它可以将多个对象组合起来进行统一的背面筛选,从而加快背面筛选的速度。其基本原理是:使用一种截断圆锥体来包含某组几何体的所有法线方向和所有点。圆锥的顶点位于一个控制点cp,并使用法线n和半角A辅助进行定位。因此对于视点eye如果出现下面的条件:
则认为视点位于该截断圆锥的背面,应当统一剔除它所包含的多个几何体,如下图所示:
在osg中聚集裁剪相关的类名称为ClusterCullingCallback,使用方法如下图所示:
osgText::Text*text = new osgText::FadeText;
osg::Vec3 normal = ellipsoid->computeLocalUpVector(X,Y,Z);
text->setCullCallback(new osg::ClusterCullingCallback(osg::Vec3(X,Y,Z),nrmal,0.0));