osgUtil::PolytopeIntersector源码解析

相关知识

OSG交运算、选取和碰撞
计算几何中基础几何
解析参考原文

osgUtil/IntersectionVisitor.cpp

void IntersectionVisitor::apply(osg::Geode& geode)

  • geode是叶子节点,求交运算中最后一定会访问该函数
void IntersectionVisitor::apply(osg::Geode& geode)
{
    // osg::notify(osg::NOTICE)<<"apply(Geode&)"<<std::endl;
	// 
    if (!enter(geode)) return;

    // osg::notify(osg::NOTICE)<<"inside apply(Geode&)"<<std::endl;

    for(unsigned int i=0; i<geode.getNumDrawables(); ++i)
    {
        intersect( geode.getDrawable(i) );
    }

    leave();
}
  • enter是调用求交访问器中设置的求交器的enter方法
// IntersectionVisitor
typedef std::list< osg::ref_ptr<Intersector> > IntersectorStack;
IntersectorStack _intersectorStack;

inline bool enter(const osg::Node& node) { return _intersectorStack.empty() ? false : _intersectorStack.back()->enter(node); }
  • 须知class OSGUTIL_EXPORT PolytopeIntersector : public Intersector
bool PolytopeIntersector::enter(const osg::Node& node)
{
    if (reachedLimit()) return false;// 由下可知当LIMIT_ONE 或 已经有交集了就false
    // 只有在启用cull或者当前node被求交器的几何体contains才进行求交判断,即true
    return !node.isCullingActive() || _polytope.contains( node.getBound() );
}
inline bool Intersector::reachedLimit() { return _intersectionLimit == LIMIT_ONE && containsIntersections(); }

virtual bool PolytopeIntersector::containsIntersections() { return !getIntersections().empty(); }
  • 之后便用intersect,对geode节点下的所有可绘制图元进行求交测试
  • 是调用求交访问器中设置的求交器的intersect方法
inline void intersect(osg::Drawable* drawable) { _intersectorStack.back()->intersect(*this, drawable); }
void PolytopeIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable)
{
    if (reachedLimit()) return;

    if ( !_polytope.contains( drawable->getBoundingBox() ) ) return;

    osg::ref_ptr<PolytopeIntersectorUtils::Settings> settings = new PolytopeIntersectorUtils::Settings;
    settings->_polytopeIntersector = this;
    settings->_iv = &iv;
    settings->_drawable = drawable;
    settings->_limitOneIntersection = (_intersectionLimit == LIMIT_ONE_PER_DRAWABLE || _intersectionLimit == LIMIT_ONE);
    settings->_primitiveMask = _primitiveMask;

    osg::KdTree* kdTree = iv.getUseKdTreeWhenAvailable() ? dynamic_cast<osg::KdTree*>(drawable->getShape()) : 0;

// 重点看以下,PolytopePrimitiveIntersector 构造了一个func 后(并设置多面体,和参考平面) 
//然后再设置到drawable中,类似vistor的操作
    if (getPrecisionHint()==USE_DOUBLE_CALCULATIONS)
    {
        osg::TemplatePrimitiveFunctor<PolytopeIntersectorUtils::IntersectFunctor<osg::Vec3d> > intersector;
        intersector._settings = settings;

        if (kdTree) kdTree->intersect(intersector, kdTree->getNode(0));
        else drawable->accept(intersector);
    }
    else
    {
        osg::TemplatePrimitiveFunctor<PolytopeIntersectorUtils::IntersectFunctor<osg::Vec3f> > intersector;
        intersector._settings = settings;

        if (kdTree) kdTree->intersect(intersector, kdTree->getNode(0));
        else drawable->accept(intersector);
    }
}

  • 在osg中drawable里头已经是最后的顶点等所有数据存放的地方.drawable其实只是个抽象类,可以简单的通过它的一个特例:Geometry 来讲述这一段内容:
  • 实际上就是将顶点数据取出来,然后functor.setVertexArray,以便之后的functor操作。
void Geometry::accept(PrimitiveFunctor& functor) const
{
    if (!_vertexData.array.valid() || _vertexData.array->getNumElements()==0) return;

    if (!_vertexData.indices.valid())
    {
        switch(_vertexData.array->getType())
        {
           /** 部分省略……*/
        case(Array::Vec3ArrayType): 
            functor.setVertexArray(_vertexData.array->getNumElements(),static_cast<const Vec3*>(_vertexData.array->getDataPointer()));
         /** 部分省略……*/
        }
        for(PrimitiveSetList::const_iterator itr=_primitives.begin();
            itr!=_primitives.end();
            ++itr)
        {
            (*itr)->accept(functor);
        }
     }
    /** 后面对于存在索引数组的暂时省略……*/
}
  • 其后最主要的还是在于对于drawable里的每个primitiveset 进行接受fuctor访问操作 (*itr)->accept(functor)。
  • 我们知道.primitiveset里头拥有的数据是顶点最后绘制的规则,而我们所要求交集的目的在于获得跟这些基础图元的交集。
  • PrimitiveSet又是一个虚类.因此,我们选一个实体类:DrawArray来深究
void DrawArrays::accept(PrimitiveFunctor& functor) const
{
    functor.drawArrays(_mode,_first,_count);
} 

所以最终的结果 都将回到fuctor里头进行交集运算的处理…_mode _first _count 将拥有的规则送往functor,然后又回到functor里面的操作,而functor就是在void PolytopeIntersector::intersect中设置的IntersectFunctor(详见PolytopeIntersector.cpp)。
但是首先我们需要先了解上面的drawArrays函数,该函数定义在osg::TemplatePrimitiveFunctor中:

virtual void drawArrays(GLenum mode,GLint first,GLsizei count)
        {
            if (_vertexArrayPtr==0 || count==0) return;

            switch(mode)
                {
                case(GL_TRIANGLES): {
                    const Vec3* vlast = &_vertexArrayPtr[first+count];
                    for(const Vec3* vptr=&_vertexArrayPtr[first];vptr<vlast;vptr+=3)
                        this->operator()(*(vptr),*(vptr+1),*(vptr+2),_treatVertexDataAsTemporary);
                    break;
                }
       /** *//** 后面的其他省略…… */
}

可见实际上drawArrays就是在调用IntersectFunctor的各种operator,支持很多种类型,.参数的不同,包括一个点(points)(两个点)lines,三个点(Triangles),四个点(quads)。
我们可以从最基础的三角形的处理上进行深究:

// handle triangles
    void operator()(const osg::Vec3& v0, const osg::Vec3& v1, const osg::Vec3& v2, bool /*treatVertexDataAsTemporary*/)
    {
        if (_settings->_limitOneIntersection && _hit) return;

        if ((_settings->_primitiveMask&PolytopeIntersector::TRIANGLE_PRIMITIVES)==0)
        {
          ++_primitiveIndex;
          return;
        }

        src.clear();
        src.push_back(v0);
        src.push_back(v1);
        src.push_back(v2);
        src.push_back(v0);

        if (contains())
        {
            addIntersection();
        }
        ++_primitiveIndex;
    }
bool contains()
    {
        const osg::Polytope& polytope = _settings->_polytopeIntersector->getPolytope();
        const osg::Polytope::PlaneList& planeList = polytope.getPlaneList();

        osg::Polytope::ClippingMask resultMask = polytope.getCurrentMask();
        if (!resultMask) return true;

        osg::Polytope::ClippingMask selector_mask = 0x1;

        for(osg::Polytope::PlaneList::const_iterator pitr = planeList.begin();
            pitr != planeList.end();
            ++pitr)
        {
            if (resultMask&selector_mask)
            {
                //OSG_NOTICE<<"Polytope::contains() Plane testing"<<std::endl;

                dest.clear();

                const osg::Plane& plane = *pitr;
                typename Vertices::iterator vitr = src.begin();

                vec_type* v_previous = &(*(vitr++));
                value_type d_previous = plane.distance(*v_previous);

                for(; vitr != src.end(); ++vitr)
                {
                    vec_type* v_current = &(*vitr);
                    value_type d_current = plane.distance(*v_current);

					// 代表点在几何体的里面,请回想多面体各个平面的正面必须都是属于这个区域内的,
					//即平面的法线应当是指向该空间区域内部
					//就是这个原因!
                    if (d_previous>=0.0)
                    {
                        dest.push_back(*v_previous);
                    }

					// 一个在外一个在内
                    if (d_previous*d_current<0.0)
                    {
                        // edge crosses plane so insert the vertex between them.
                        value_type distance = d_previous-d_current;
                        value_type r_current = d_previous/distance;
                        vec_type v_new = (*v_previous)*(1.0-r_current) + (*v_current)*r_current;
                        dest.push_back(v_new);
                    }

                    d_previous = d_current;
                    v_previous = v_current;

                }

                if (d_previous>=0.0)
                {
                    dest.push_back(*v_previous);
                }

                if (dest.size()<=1)
                {
                    // OSG_NOTICE<<"Polytope::contains() All points on triangle culled, dest.size()="<<dest.size()<<std::endl;
                    return false;
                }

                dest.swap(src);
            }
            else
            {
                // OSG_NOTICE<<"Polytope::contains() Plane disabled"<<std::endl;
            }

            selector_mask <<= 1;
        }

        //OSG_NOTICE<<"Polytope::contains() triangle within Polytope, src.size()="<<src.size()<<std::endl;

        return true;
    }
  • void PolytopeIntersector::intersect中,含有 settings->_polytopeIntersector = this;,所以实际上是将intersection,即求交结果设置到使用的多面体求交器中,即每一个drawable里的每个primitiveset都会进行求交,都有可能获得intersection。
  • primitiveset就是opengl中GL_LINES,GL_TRIANGLES等绘制规则。
void addIntersection()
    {

        vec_type center(0.0,0.0,0.0);
        double maxDistance = -DBL_MAX;
        const osg::Plane& referencePlane = _settings->_polytopeIntersector->getReferencePlane();
        for(typename Vertices::iterator itr = src.begin();
            itr != src.end();
            ++itr)
        {
            center += *itr;
            double d = referencePlane.distance(*itr);
            if (d>maxDistance) maxDistance = d;

        }

        center /= value_type(src.size());

        PolytopeIntersector::Intersection intersection;
        intersection.primitiveIndex = _primitiveIndex;
        intersection.distance = referencePlane.distance(center);
        intersection.maxDistance = maxDistance;
        intersection.nodePath = _settings->_iv->getNodePath();
        intersection.drawable = _settings->_drawable;
        intersection.matrix = _settings->_iv->getModelMatrix();
        intersection.localIntersectionPoint = center;

        if (src.size()<PolytopeIntersector::Intersection::MaxNumIntesectionPoints) intersection.numIntersectionPoints = src.size();
        else intersection.numIntersectionPoints = PolytopeIntersector::Intersection::MaxNumIntesectionPoints;

        for(unsigned int i=0; i<intersection.numIntersectionPoints; ++i)
        {
            intersection.intersectionPoints[i] = src[i];
        }

        // OSG_NOTICE<<"intersection "<<src.size()<<" center="<<center<<std::endl;
		// 
        _settings->_polytopeIntersector->insertIntersection(intersection);
        _hit = true;

        // OSG_NOTICE<<"addIntersection() center="<<center<<std::endl;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/919081.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在Unity中使用Epplus写Excel

Overview 本文旨在帮助你快速入门,该库发展多年内容庞大(官方文档写的极好:https://github.com/EPPlusSoftware/EPPlus/wiki),有些功能在Unity环境可能你永远都不会使用. 官方的一个Demo: https://github.com/EPPlusSoftware/EPPlus.Samples.CSharp 如果你只有读的需求,可以…

leetcode 删除有序数组的重复项

26. 删除有序数组中的重复项 已解答 简单 相关标签 相关企业 提示 给你一个 非严格递增排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 n…

HNUST-党校培训自动下一集油猴脚本

1.起初 好烦&#xff0c;这个系统看视频需要一直点按键&#xff0c;还没有自动下一集的功能&#xff0c;于是就有了这个js代码 2.效果 实现自动点击是否观看&#xff0c;检测按键自动播放下一集 3.代码(你需要下载油猴&#xff0c;打开管理面板&#xff0c;新建代码) // UserS…

深入了解 GIS 地理信息系统和前端五大 GIS 技术,GIS地理信息系统介绍及前端五大 GIS 技术解析

目录 前言 地理信息系统 (GIS) 是现代数据化社会的重要工具&#xff0c;广泛应用于智慧城市、环境保护、交通管理等领域。随着 Web 前端技术的发展&#xff0c;GIS 可视化在浏览器端的表现能力越来越强&#xff0c;成为许多开发者关注的焦点。这里分享记录 GIS 的基础知识&am…

美团单车上线暖手套,美团贴心服务会给市场带来什么?

首先&#xff0c;美团单车上线暖手套这一举措主要是为了提升市民在秋冬季节骑行共享单车、电单车的出行体验。这一贴心的设计能够解决骑行者在寒冷天气中手部受冻的问题&#xff0c;使得骑行更加舒适和安全。 其次&#xff0c;美团的这一贴心服务会对市场产生积极影响。一方面…

Mysql-DQL语句

文章目录 DQL 语句简单查询查询表所有数据查询指定列 别名查询清除重复值查询结果参与运算 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Mysql专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年11月16日11点39分 DQL 语句 DQL 语句数据…

【cpp中的继承】

什么是继承&#xff1f; 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。继承呈现了面向对象程序设计的层次结构&…

iOS 18 导航栏插入动画会导致背景短暂变白的解决

问题现象 在最新的 iOS 18 系统中,如果我们执行导航栏的插入动画,可能会造成导航栏背景短暂地变为白色: 如上图所示:我们分别向主视图和 Sheet 弹出视图的导航栏插入了消息,并应用了动画效果。可以看到,前者的导航栏背景会在消息插入那一霎那“变白”,而后者则没有任何…

《Java核心技术 卷I》Collection接口和迭代器

Collection接口 Java类库中&#xff0c;集合类的基本接口是Collection接口&#xff0c;两个基本方法&#xff1a; public interface Collection<E>{boolean add(E element);Iterator<E> iterator();...... } add方法用于向集合中添加元素&#xff0c;如果元素确…

《Python制作动态爱心粒子特效》

一、实现思路 粒子效果&#xff1a; – 使用Pygame模拟粒子运动&#xff0c;粒子会以爱心的轨迹分布并运动。爱心公式&#xff1a; 爱心的数学公式&#xff1a; x16sin 3 (t),y13cos(t)−5cos(2t)−2cos(3t)−cos(4t) 参数 t t 的范围决定爱心形状。 动态效果&#xff1a; 粒子…

109. UE5 GAS RPG 实现检查点的存档功能

在这一篇文章里&#xff0c;我们接着实现存档的功能&#xff0c;保存当前玩家的生成位置&#xff0c;游戏里有很多中方式去实现玩家的位置存储&#xff0c;这里我们采用检查点的方式&#xff0c;当玩家接触到当前检查点后&#xff0c;我们可以通过检查点进行保存玩家的状态&…

浅谈电力行业网络安全与防护

3月7日&#xff0c;委内瑞拉发生迄今为止最大规模停电事件&#xff0c;让这个身处危机之中的国家雪上加霜。千里之堤溃于蚁穴&#xff0c;切莫忽视任何不安全因素的存在。电力基础设施薄弱&#xff0c;设备维护不到位&#xff0c;技术人员水平低下&#xff0c;工业控制系统防护…

UE5 第一人称射击项目学习(一)

因为工作需要&#xff0c;需要掌握ue5的操作。 选择了视频资料 UE5游戏制作教程Unreal Engine 5 C作为学习。 第一个目标是跟着视频制作出一款第一人称射击项目。 同时作为入门&#xff0c;这个项目不会涉及到C&#xff0c;而是一个纯蓝图的项目。 项目目标 这个项目将实…

Excel数据动态获取与映射

处理代码 动态映射 动态读取 excel 中的数据&#xff0c;并通过 json 配置 指定对应列的值映射到模板中的什么字段上 private void GetFreightFeeByExcel(string filePath) {// 文件名需要以快递公司命名 便于映射查询string fileName Path.GetFileNameWithoutExtension(fi…

博客文章怎么设计分类与标签

首发地址&#xff08;欢迎大家访问&#xff09;&#xff1a;博客文章怎么设计分类与标签 新网站基本上算是迁移完了&#xff0c;迁移之后在写文章的过程中&#xff0c;发现个人的文章分类和标签做的太混乱了&#xff0c;分类做的像标签&#xff0c;标签也不是特别的丰富&#x…

solana链上智能合约开发案例一则

环境搭建 安装Solana CLI&#xff1a;Solana CLI是开发Solana应用的基础工具。你可以通过官方文档提供的安装步骤&#xff0c;在本地环境中安装适合你操作系统的Solana CLI版本。安装完成后&#xff0c;使用命令行工具进行配置&#xff0c;例如设置网络环境&#xff08;如开发网…

腾讯云存储COS上传视频报错

bug表现为&#xff1a;通过COS上传视频时报错"Class \"QCloud\\COSSTS\\Sts\" not found" 修复办法为&#xff1a;找到文件crmeb/services/upload/storage/Cos.php 将Sts引入由QCloud\COSSTS\Sts;改为crmeb\services\upload\extend\cos\Sts; 修改后重启服…

已有docker增加端口号,不用重新创建Docker

已有docker增加端口号&#xff0c;不用重新创建Docker 1. 整体描述2. 具体实现2.1 查看容器id2.2 停止docker服务2.3 修改docker配置文件2.4 重启docker服务 3. 总结 1. 整体描述 docker目前使用的非常多&#xff0c;但是每次更新都需要重新创建docker&#xff0c;也不太方便&…

Win11 24H2新BUG或影响30%CPU性能,修复方法在这里

原文转载修改自&#xff08;更多互联网新闻/搞机小知识&#xff09;&#xff1a; 一招提升Win11 24H2 CPU 30%性能&#xff0c;小BUG大影响 就在刚刚&#xff0c;小江在网上冲浪的时候突然发现了这么一则帖子&#xff0c;标题如下&#xff1a;基准测试&#xff08;特别是 Time…

C#桌面应用制作计算器

C#桌面应用制作简易计算器&#xff0c;可实现数字之间的加减乘除、AC按键清屏、Del按键清除末尾数字、/-按键取数字相反数、%按键使数字缩小100倍、按键显示运算结果等...... 页面实现效果 功能实现 布局 计算器主体使用Panel容器&#xff0c;然后将button控件排列放置Pane…