osg节点的包围球

osg数据组织方式采用的是树形节点的组织方式,每个节点都由相应的包围球。

void createBound() {
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
	viewer->addEventHandler(new osgViewer::WindowSizeHandler());

	osg::ref_ptr<osg::Group> root = new osg::Group;

	root->addChild(osgDB::readNodeFile("cow.osgt"));

	//更新节点的包围体
	root->dirtyBound();
	//获取节点的包围体
	osg::BoundingSphere bound = root->getBound();

	//绘制节点的包围体
	osg::ref_ptr<osg::Geode> geode = new osg::Geode;
	osg::ref_ptr<osg::Sphere> sphere = new osg::Sphere;
	sphere->set(bound.center(), bound.radius());
	osg::ref_ptr<osg::ShapeDrawable> sd3 = new osg::ShapeDrawable(sphere);
	geode->addDrawable(sd3);
	root->addChild(geode);

	viewer->setSceneData(root.get());

	viewer->realize();
	viewer->run();
}
### OpenSceneGraph 中的 OBB 包围盒实现 在计算机图形学中,包围盒是一种用于加速碰撞检测和可见性测试的技术。OBB( Oriented Bounding Box )相对于 AABB(Axis-Aligned Bounding Box),能够更紧密地贴合物形状,因此常被用来优化复杂的几何操作。 #### 背景介绍 OpenSceneGraph (OSG) 是一种开源的高性能场景图库,广泛应用于三维可视化领域。为了支持高效的碰撞检测和裁剪功能,OSG 提供了多种类型的包围盒结构,其中包括轴向对齐包围盒(AABB)[^1] 和方向包围盒(OBB)。然而,默认情况下,OSG 的 `BoundingSphere` 或 `BoundingBox` 类主要用于简单的边界表示,而未直接提供现成的 OBB 实现方法。这意味着开发者需要自行扩展来满足特定需求。 以下是基于 OSG 构建自定义 OBB 包围盒的一种可能方案: --- #### 自定义 OBB 结构设计 首先定义一个类来描述 OBB 的基本属性,通常包括中心位置、半径以及旋转矩阵或法向量集合等参数: ```cpp #include <osg/Vec3> #include <osg/BoundingBox> class OBB { public: osg::Vec3 center; // Center of the box. osg::Matrix rotation; // Rotation matrix defining orientation. osg::Vec3 halfSize; // Half-size extents along each axis. OBB(const osg::Vec3& c, const osg::Matrix& r, const osg::Vec3& h) : center(c), rotation(r), halfSize(h) {} bool intersectsWith(const OBB& other) const; }; ``` 上述代码片段展示了如何创建一个基础版本的方向包围盒对象[^2] 。其中包含了三个核心成员变量分别代表盒子的位置(`center`) , 方位 (`rotation`) 及大小范围(`halfSize`)。 --- #### 计算节点树中的 OBB 数据 当处理复杂模型时,可以通过遍历整个场景图并收集所有子节点的相关信息来动态构建合适的 OBB 表示形式。下面是一个递归函数的例子,它会沿着指定路径读取每个叶子级别的几何数据,并将其转换为相应的局部空间坐标系下的顶点列表以便进一步分析: ```cpp void computeLocalVertices(osg::Node* node, std::vector<osg::Vec3>& vertices){ if(auto geode = dynamic_cast<osg::Geode*>(node)){ for(auto drawable : geode->getDrawables()){ auto geometry = dynamic_cast<osg::Geometry*>(drawable); if(geometry && geometry->getVertexArray()){ osg::Vec3Array* array = static_cast<osg::Vec3Array*>(geometry->getVertexArray()); for(unsigned int i=0;i<array->size();i++) vertices.push_back((*array)[i]); } } }else{ for(unsigned int i=0;i<node->getNumChildren();i++) computeLocalVertices(node->getChild(i),vertices); } } ``` 此部分逻辑负责提取目标区域内的全部有效顶点样本集合作为基础素材参与后续运算过程[^3]. --- #### 使用 PCA 方法求解最佳拟合平面 主成分分析(Principal Component Analysis,PCA)算法可以帮助找到一组正交基底使得原始多维分布投影后的方差最大化从而得到最优近似结果。具来说就是先统计所有采样点关于质心坐标的协方差阵再通过特征分解获取主导方向作为新的参考框架完成最终定位调整工作流程如下所示: ```cpp std::tuple<osg::Vec3, osg::Matrix> calculateOrientations(const std::vector<osg::Vec3>& points){ // Compute centroid and covariance matrix... Eigen::MatrixXd covMat(3,3); Eigen::VectorXd meanPoint(3); for(int dim=0;dim<3;++dim){ double sumDim=0.; for(auto &p:points){sumDim+=p[dim];}meanPoint(dim)=sumDim/(double)(points.size()); for(int row=0;row<=dim;++row){ double prodSum=0.; for(auto &p:points){prodSum += p[row]*p[dim];} covMat(row,dim)=(prodSum-(meanPoint(row)*meanPoint(dim)*(double)(points.size())))/(double)(points.size()-1); if(row<dim)covMat(dim,row)=covMat(row,dim); } } // Perform eigenvalue decomposition on covariance matrix to get principal axes... Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(covMat); Eigen::Vector3d evals = es.eigenvalues(); Eigen::Matrix3d evecs = es.eigenvectors(); // Convert back into OSG types ... osg::Vec3 xAxis(evecs.col(0).data()), yAxis(evecs.col(1).data()), zAxis(evecs.col(2).data()); osg::Matrix rot(xAxis.x(),yAxis.x(),zAxis.x(), xAxis.y(),yAxis.y(),zAxis.y(), xAxis.z(),yAxis.z(),zAxis.z(), 0., 0., 0.); return {osg::Vec3(meanPoint.data()),rot}; } ``` 该段程序实现了从给定的一系列离散点集中推导出适配它们的最佳定向矩形框姿态的过程[^4]. --- #### 集成至现有渲染管道 最后一步则是将新生成好的 OBB 描述符应用回实际绘图环节当中去。这一般涉及到修改原有材质状态或者额外附加辅助显示层等内容。例如我们可以借助于 LineSet 来勾勒轮廓边缘线条效果达到直观展示目的: ```cpp osg::ref_ptr<osg::Group> createDebugLinesForOBB(const OBB& obb){ osg::ref_ptr<osg::LineSet> lines(new osg::LineSet); osg::ref_ptr<osg::Vec3Array> coords(new osg::Vec3Array); // Define corners based off local space dimensions transformed by global pose... osg::Vec3 cornerOffsets[]={ {-obb.halfSize.x(),-obb.halfSize.y(),-obb.halfSize.z()}, {+obb.halfSize.x(),-obb.halfSize.y(),-obb.halfSize.z()}, {+obb.halfSize.x(),+obb.halfSize.y(),-obb.halfSize.z()}, {-obb.halfSize.x(),+obb.halfSize.y(),-obb.halfSize.z()}, {-obb.halfSize.x(),-obb.halfSize.y(),+obb.halfSize.z()}, {+obb.halfSize.x(),-obb.halfSize.y(),+obb.halfSize.z()}, {+obb.halfSize.x(),+obb.halfSize.y(),+obb.halfSize.z()}, {-obb.halfSize.x(),+obb.halfSize.y(),+obb.halfSize.z()} }; for(auto &offset:cornerOffsets)(*coords)+=(obb.rotation * offset + obb.center); // Connect pairs appropriately forming wireframe representation... unsigned short indices[]={0,1,2,3,0, 4,5,6,7,4, 0,4,1,5,2,6,3,7}; lines->setVertexArray(coords.get()); lines->setColorArray(new osg::Vec4Array({{1.f,.8f,.2f,1.f}})); lines->setColorBinding(osg::Geometry::BIND_OVERALL); lines->addPrimitiveSet(new osg::DrawElementsUInt(GL_LINE_LOOP,sizeof(indices)/sizeof(*indices),(unsigned*)indices)); osg::ref_ptr<osg::Geode> debugGeo=new osg::Geode; debugGeo->addDrawable(lines.release()); return new osg::Group(debugGeo.release()); } ``` 这样就完成了完整的 OBB 创建与调试视图呈现链条搭建[^5]. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wb175208

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值