osgUtil集合了场景图形处理、几何体修改工具及高层次的遍历等功能。
// 创建一个线段交集检测对象
osgUtil::LineSegmentIntersector::Intersection intersection;// 用于存放
viewer->computeIntersections(x,y,intersection);// x,y可通过osgGA::GUIEventAdapter获得
// 通过相交运算,更多的是希望得到相交的点,可以通过申请一个迭代器来实现:
for(osgUitl::LineSegmentIntersector::Intersections ::iterator it = intersection.begin();it!=intersection.end();it++)
{
...
it->getWorldIntersectPoint().....
...
}
- double distance :表示从当前这个交集的所有顶点的中心点到参考平面的距离.
- Vec3_type localIntersectionPoint :表示所有交点的中心点
- Vec3_type intersectionPoints[MaxNumIntesectionPoints] :所有交点的一个数组…目前最多的顶点个数是6… enum { MaxNumIntesectionPoints=6 };
- unsigned int numIntersectionPoints :所有顶点的个数
setNodeMask(0x0)
,求交完,即accept之后再回复。例如可以获取一条由屏幕鼠标位置到3D场景的光线
- 求交器的containsIntersections()方法可以被用来检测是否存在交集结果,getIntersections方法返回一个Intersection集合变量,依据距离查看器的远近进行排序。
- 某些求交器的Intersection包含特殊接口,例如osgUtil::LineSegmentIntersector::Intersection::getLocalIntersectPoint / getWorlIntersectPoint
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector =
new osgUtil::LineSegmentIntersector(
osgUtil::Intersector::WINDOW, ea.getX(), ea.getY()
);
osgUtil::IntersectionVisitor iv( intersector.get() );
camera->accept( iv );
osgUtil::LineSegmentIntersector::Intersection& result =
*( intersector->getIntersections().begin());
osg::Vec3 point = result.getWorldIntersectPoint(); // in world space
IintersectVisitor :弃用,被IntersectionVisitor替代
- 维护一个进行交集测试的线段列表,而对于其中的每一条线段,访问器都会创建一个交点列表(osgUtil::IntersectVisitor::HintList实例),用于搜索场景图形中与指定几何体相交的节点.
- 交点列表osgUtil::IntersectVisitor::HintList的作用为:一条单一的线段可能与场景中的多个几何体实例(或多次与同一个几何体)产生交集。对于每一条参与交集测试的线段,系统均会产生一个列表,包含了所有交集测试产生的Hit实例。
而最后相交测试的工作将在osgUtil::Intersector的继承类(线段求交器、多面体求交器等)中完成。
每个求交器可能有些许不同
- 在vistor中我们有pushNodepath() popNodePath()来保存这个路径操作…所以这个路径是从vistor中获得的。
- osg::computeLocalToWorld(nodePath );可以获得从该节点局部坐标系统到世界坐标系统的变换矩阵。
#include <osgUtil/PolytopeIntersector>
#include <osgGeometry>
void processIntersection(const osgUtil::PolytopeIntersector::Intersection& intersection) {
osg::Drawable* drawable = intersection.drawable.get();
osg::Geometry* geometry = drawable ? drawable->asGeometry() : nullptr;
if (geometry) {
osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
if (vertices) {
// 假设每个基本体(例如三角形)由三个连续的顶点组成
unsigned int startIdx = intersection.primitiveIndex * 3;// 即primitiveIndex表示图元的索引
if (startIdx + 2 < vertices->size()) {
osg::Vec3 v0 = (*vertices)[startIdx];
osg::Vec3 v1 = (*vertices)[startIdx + 1];
osg::Vec3 v2 = (*vertices)[startIdx + 2];
// 输出相交的图元的顶点数据
std::cout << "Intersected Primitive: " << std::endl;
std::cout << "Vertex 0: (" << v0.x() << ", " << v0.y() << ", " << v0.z() << ")" << std::endl;
std::cout << "Vertex 1: (" << v1.x() << ", " << v1.y() << ", " << v1.z() << ")" << std::endl;
std::cout << "Vertex 2: (" << v2.x() << ", " << v2.y() << ", " << v2.z() << ")" << std::endl;
}
}
}
}
如果使用了索引缓冲(osg::DrawElements,例如osg::DrawElementsUInt保存的是一系列索引),则 primitiveIndex 可能指向的是索引缓冲中的位置(从而获得索引值),而非直接的顶点数组索引。如下:
#include <osgUtil/PolytopeIntersector>
#include <osg/Geometry>
void processIndexedIntersection(const osgUtil::PolytopeIntersector::Intersection& intersection) {
osg::Drawable* drawable = intersection.drawable.get();
osg::Geometry* geometry = drawable ? drawable->asGeometry() : nullptr;
if (geometry) {
osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
if (!vertices) return;
// 遍历每个 PrimitiveSet 以找到正确的 DrawElements
for(unsigned int i = 0; i < geometry->getNumPrimitiveSets(); ++i) {
osg::PrimitiveSet* primSet = geometry->getPrimitiveSet(i);
if (auto* drawElements = dynamic_cast<osg::DrawElementsUInt*>(primSet)) {
// 计算出 startIdx 是如何划分的,比如 GL_TRIANGLES 需乘以3
// 即primitiveIndex表示了索引数组中的位置
unsigned int base = intersection.primitiveIndex * 3;
if (base + 2 < drawElements->size()) {
// 由索引位置获取顶点索引值
unsigned int vi0 = drawElements->at(base);
unsigned int vi1 = drawElements->at(base + 1);
unsigned int vi2 = drawElements->at(base + 2);
// 用索引值查找具体的顶点
osg::Vec3 v0 = (*vertices)[vi0];
osg::Vec3 v1 = (*vertices)[vi1];
osg::Vec3 v2 = (*vertices)[vi2];
std::cout << "Intersected Indexed Primitive: " << std::endl;
std::cout << "Vertex 0: (" << v0.x() << ", " << v0.y() << ", " << v0.z() << ")" << std::endl;
std::cout << "Vertex 1: (" << v1.x() << ", " << v1.y() << ", " << v1.z() << ")" << std::endl;
std::cout << "Vertex 2: (" << v2.x() << ", " << v2.y() << ", " << v2.z() << ")" << std::endl;
}
break; // Assuming a single PrimitiveSet contains the correct index, you can exit the loop
}
}
}
}
int main()
{
.......
// 这里省略:定义viewer,group,和创建一个Box添加到group中,以及将group加入到场景
osg::ref_ptr<osgUtil::LineSegmentIntersector> ls = new osgUtil::LineSegmentIntersector(osg::Vec3(0,0,15),osg::Vec3(0,0,-15));
// 该访问器用来遍历group下面的成员
osg::ref_ptr<osgUtil::IntersectionVisitor> iv = new osgUtil::IntersectionVisitor(ls);
// 结果存放在osgUtil::LineSegmentIntersector::Intersections中
osgUtil::LineSegmentIntersector::Intersections intersections;
// 可以用camera,也可以用group启动访问器,因为启动函数是osg::Node accept()
group->accept(*iv.get());// 会自动调用访问器中Apply、Enter、Leave等成员函数
// 如果有碰撞,则输出所有的交点
if(ls->containsIntersections())// 有交点即有碰撞,或者用hits()
{
intersections = ls->getIntersections();
for(osgUitl::LineSegmentIntersector::Intersections ::iterator it = intersections.begin();it!=intersections.end();it++)
{
std::cout << it->getWorldIntersectPoint().x() <<" "<<it->getWorldIntersectPoint().y()<<" "<<it->getWorldIntersectPoint().z()<<std::endl;
}
}
viewer->run();
}
#include <osg/MatrixTransform>
#include <osg/ShapeDrawable>
#include <osg/PolygonMode>
#include <osgDB/ReadFile>
#include <osgUtil/LineSegmentIntersector>
#include <osgViewer/Viewer>
class PickHandler : public osgGA::GUIEventHandler
{
public:
osg::Node* getOrCreateSelectionBox();
virtual bool handle( const osgGA::GUIEventAdapter& ea,
osgGA::GUIActionAdapter& aa );
protected:
osg::ref_ptr<osg::MatrixTransform> _selectionBox;
};
// 选取框,注意我们是靠matrixTransform来对框位置进行变换
osg::Node* PickHandler::getOrCreateSelectionBox()
{
if ( !_selectionBox )
{
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
geode->addDrawable(
new osg::ShapeDrawable(new osg::Box(osg::Vec3(), 1.0f)) );
_selectionBox = new osg::MatrixTransform;
_selectionBox->setNodeMask( 0x1 );// 求交器不会对该选取框进行判断!因为遍历器获得不了!
_selectionBox->addChild( geode.get() );
osg::StateSet* ss = _selectionBox->getOrCreateStateSet();
ss->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
ss->setAttributeAndModes(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::LINE));
}
return _selectionBox.get();
}
// 选取响应事件
bool PickHandler::handle( const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa )
{
if ( ea.getEventType()!=osgGA::GUIEventAdapter::RELEASE ||
ea.getButton()!=osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON ||
!(ea.getModKeyMask()&osgGA::GUIEventAdapter::MODKEY_CTRL))
return false;
osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
if ( viewer )
{
osg::ref_ptr<osgUtil::LineSegmentIntersector>
intersector =
new osgUtil::LineSegmentIntersector(
osgUtil::Intersector::WINDOW, ea.getX(), ea.getY()
);
osgUtil::IntersectionVisitor iv( intersector.get() );
iv.setTraversalMask( ~0x1 );// 并不会获得自定义选取框,即求交的时候不会对选取框进行判断!
viewer->getCamera()->accept( iv );
if ( intersector->containsIntersections() )
{
osgUtil::LineSegmentIntersector::Intersection& result =
*(intersector->getIntersections().begin());
// 获得求交成功的几何体
osg::BoundingBox bb = result.drawable->getBound();
// 从根节点到求交成功的几何体的父节点路径获得该求交成功的几何体从局部坐标系统到世界坐标系统的变换矩阵。
osg::Vec3 worldCenter = bb.center() *
osg::computeLocalToWorld(result.nodePath);
_selectionBox->setMatrix(
osg::Matrix::scale(bb.xMax()-bb.xMin(),
bb.yMax()-bb.yMin(),
bb.zMax()-bb.zMin()) *
osg::Matrix::translate(worldCenter) );
}
}
return false;
}
// 启用
osg::ref_ptr<osg::Node> model1 = osgDB::readNodeFile( "cessna.osg"
);
osg::ref_ptr<osg::Node> model2 = osgDB::readNodeFile( "cow.osg" );
osg::ref_ptr<osg::Group> root = new osg::Group;
root->addChild( model1.get() );
root->addChild( model2.get() );
osg::ref_ptr<PickHandler> picker = new PickHandler;
root->addChild( picker->getOrCreateSelectionBox() );
osgViewer::Viewer viewer;
viewer.setSceneData( root.get() );
viewer.addEventHandler( picker.get() );// 在后续仿真循环中,上面添加的picker->getOrCreateSelectionBox()将动态变换。
return viewer.run();
_selectionBox->setNodeMask( 0x1 );
iv.setTraversalMask( ~0x1 );
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- yrrf.cn 版权所有 赣ICP备2024042794号-2
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务