4-osg 拓展线段求交器(Expand LineSegmentIntersector拾取:点,线,面)

4-osg 拓展线段求交器(拾取:点,线,面)

实现功能

  1. 拓展:LineSegmentIntersector, 实现点,线,面的求交
  2. ray: 根据near and far plane 求出frustum所截取的线段;
  3. kdTree, octree(oct tree 在LOD时再补): 加速搜索
  4. intersection: select point, line, face and object
  5. hight light the selection object

实现思路

ray

ray: 单击windows Screen 上的点,映射到实际的三维场景中;
变换过程: P s c r e e n ( x , y ) → P v i e w p o r t ( x , y ) → P n o r m a l i z e d ( x , y , z , 1 ) z ∈ [ − 1 , 1 ] → P c a m e r a ( x , y , z , w ) → P w o r l d ( x , y , z , w ) P_{screen}(x, y) \rightarrow P_{viewport}(x, y) \rightarrow P_{normalized}(x, y, z, 1) z \in[-1, 1] \rightarrow P_{camera}(x, y, z, w) \rightarrow P_{world}(x, y, z, w) Pscreen(x,y)Pviewport(x,y)Pnormalized(x,y,z,1)z[1,1]Pcamera(x,y,z,w)Pworld(x,y,z,w)
实际变换过程如上,涉及到的变换矩阵也比较简单;前面两个是平面二维变换矩阵,在屏幕上找相应的两个点,即可以解除相应矩阵。 后面三个矩阵为MVP的逆矩阵;
P n o r m a l i z e d ( x , y ) P_{normalized}(x, y) Pnormalized(x,y) = n o r m a l i z e d T v i e w p o r ^{normalized}T_{viewpor} normalizedTviewpor v i e w p o r t T s c r e e n ^{viewport}T_{screen} viewportTscreen P s c r e e n ( x , y ) P_{screen}(x, y) Pscreen(x,y)
P w o r l d ( x , y , z , w ) P_{world}(x, y, z, w) Pworld(x,y,z,w)​ = T v i e w − 1 T^{-1}_{view} Tview1 T p r o j e c t i o n − 1 T^{-1}_{projection} Tprojection1 P n o r m a l i z e d ( x , y , z , 1 ) z ∈ [ − 1 , 1 ] P_{normalized}(x, y, z, 1) z \in[-1, 1] Pnormalized(x,y,z,1)z[1,1]
P w o r l d ( x , y , z ) P_{world}(x, y, z) Pworld(x,y,z)​ = P w o r l d ( x , y , z ) / w P_{world}(x, y, z)/w Pworld(x,y,z)/w

void createRay(int screenX, int screenY, int width, int height)
{
      int viewPortX = screenX;
      int viewPortY = height - screenY;

      osgGA::PointerData pd;
      pd.x = viewPortX;
      pd.y = viewPortY;
      pd.xMin = 0;
      pd.yMin = 0;
      pd.xMax = width;
      pd.yMax = height;

      osg::Vec4f startNormalized(pd.getXnormalized(), pd.getYnormalized(), -1, 1);
      osg::Vec4f endNormalized(pd.getXnormalized(), pd.getYnormalized(), 1, 1);

      osg::Camera* camera = _viewer->getCamera();
      osg::Matrixd projectMatrix = camera->getProjectionMatrix();
      osg::Matrixd viewMatrix = camera->getViewMatrix();
      osg::Matrixd viewMatrixInverse = osg::Matrixd::inverse(viewMatrix);
      osg::Matrixd projectMatrixInverse = osg::Matrixd::inverse(projectMatrix);

      osg::Matrix matrix;
      matrix.preMult(viewMatrixInverse);
      matrix.preMult(projectMatrixInverse);
      osg::Vec4f startPoint = matrix.preMult(startNormalized);
      osg::Vec4f endPoint = matrix.preMult(endNormalized);

      startPoint.x() /= startPoint.w();
      startPoint.y() /= startPoint.w();
      startPoint.z() /= startPoint.w();

      endPoint.x() /= endPoint.w();
      endPoint.y() /= endPoint.w();
      endPoint.z() /= endPoint.w();

      osg::Vec3f point1(startPoint.x(), startPoint.y(), startPoint.z());
      osg::Vec3f point2(endPoint.x(), endPoint.y(), endPoint.z());

      osg::Vec3d cameraPosition = viewMatrixInverse.getTrans();
      point1 = osg::Vec3f(cameraPosition.x(), cameraPosition.y(), cameraPosition.z());

      osg::Group *line = createLine(point1, point2);
      _root->addChild(line);

}

kdTree

kdTree的资料网上非常多,这里大概讲一下思路;这里的kdtree作用是用于加速求交,因此primitive包含了(point, line, trangle and quad); 因此与用于point cloudy的二叉树构建是有区别的;
kdTree是一种空间二分的方法,也就是一颗二叉树
数据准备阶段:

  1. 确定需要构建树的深度Level 以及 每个叶子节点所容纳number of primitive
  2. 构建一个包含所有Primitives 的bbox, 根据Level 按照 X, Y,Z 三个轴方向进行划分,总是找最长的轴向进行二分;这样得出每一层的划分轴;
  3. 计算每个primitive的 bbox中心,并且存储;

划分阶段:(递归操作)

  1. 递归结束判断: 达到Level深度,或者primitive < 设定好的的数目;
  2. 在划分时,如果发现左右空间划分,有一个空间中不包含任何primitive(这里用bbox的中心替代)为空时,保持当前父节点不变,再次对不为空的空间进行划分,也就是二次划分,直到左右空间中primitive都不为空时; 才将这两个空间作为两个子节点,添加到父节点中;
  3. 叶子节点根据primitive, 重新构建bbox,并且传递给父节点,父节点根据子节点的bbox进行本节点bbox的构建,以此回溯到根节点;

intersection:

osg提供的LineSegmentIntersector只实现了面的求交,继承线段求交器进行实现即可
ExpandLineSegementPickHandler : public LineSegmentIntersector

求交比较简单,就设计到一些简单的几何计算;包括:
直线1. 求交:

  1. 线段和BBox

  2. 线段和Bounding Sphere

  3. 线段和点

  4. 线段和线段

  5. 线段和三角面

可以看看osg源码,都是些简单几何运算;虽然简单,当然里面有很多编程技巧是值得我们学习的;

其中线段和点以及线段和线段的求交需要自己实现;

hightlight:

这里直接使用了OSG提供的osgFX的特效类,进行实现;
后面再根据自己需求实现自己的高亮特效

  osg::ref_ptr<osgFX::Outline> outline = new osgFX::Outline();
  outline->setColor(osg::Vec4(1, 1, 0, 1));
  outline->setWidth(15);
  outline->addChild(node);
  parent->replaceChild(node, outline);

实现效果

  1. Ray(Line):

在这里插入图片描述

  1. Ray(Polytope)

在这里插入图片描述

  1. kdTree

在这里插入图片描述

  1. 拾取 点、 线,面,以及高亮

在这里插入图片描述

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值