首页 > 其他分享 >【八叉树】从上千万个物体中【**瞬间**】就近选取坐标

【八叉树】从上千万个物体中【**瞬间**】就近选取坐标

时间:2024-10-22 17:47:56浏览次数:8  
标签:就近 千万个 point 八叉树 Vector3 rayOrigin Octree var ray

众里寻他千百度,蓦然回首,那人却在灯火阑珊处

前情提要

在某些情况下,我们在场景中创建了数百万个物体,这些物体没有直接的网格或碰撞体(例如,通过GPU绘制的物体),因此无法通过常规的射线检测与碰撞体进行交互。我们仅掌握这些物体的坐标或顶点位置。在这种情况下,我们该如何通过鼠标来“选中”这些物体呢?

常规方式

1.创建鼠标到世界的射线

 Ray ray = _camera.ScreenPointToRay(Input.mousePosition);
 Vector3 rayDirection = ray.direction;
 Vector3 rayOrigin = ray.origin;
 Vector3 rayEnd = rayOrigin + rayDirection * maxPickDistance;

2.遍历所有坐标点

①借用点积夹角计算筛选出与与射线方向一致

foreach (Vector3 point in points)
        {
            //点与射线夹角
            float dotAngle = Vector3.Dot(rayDirection, (point - rayOrigin).normalized);
            if (dotAngle > 0.99f)
            {
                float camDist = Vector3.Distance(rayOrigin, point);
                //点到射线距离
                var pointRayDist = SqDistPointSegment(rayOrigin, rayEnd, point);
                var normCamDist = (camDist / maxPickDistance) * pointRayDist * pointRayDist;

                if (normCamDist < nearestPointRayDist)
                {
                    if (pointRayDist > maxPickDistance) continue;
                    nearestPointRayDist = normCamDist;
                    nearestPoint = point;
                    isFindNearestPoint = true;
                }
            }
        }

②通过点积投影得到点到射线的距离

    public static float SqDistPointSegment(Vector3 start, Vector3 end, Vector3 point)
    {
        var ab = end - start;
        var ac = point - start;
        var bc = point - end;
        float e = Vector3.Dot(ac, ab);
        float f = Vector3.Dot(ab, ab);
        if (e >= f) return Vector3.Dot(bc, bc);
        return Vector3.Dot(ac, ac) - e * e / f;
    }

如此便可求得离射线最近坐标位置。

那么问题来了:当有上千万个点左边信息的时候,如此遍历一遍势必消耗大量的时间。下面我们将借助八叉树来优化该方案。

八叉树优化后的方案

1.创建八叉树

... 
Octree = new Octree(boundingBox, 500);//场景的范围Bounds和Octree迭代限制
//将所有点传入Octree初始化八叉树结构
        foreach (var point in pointCloudData)
        {
            Octree.Insert(point);
        }
... 

2.获取被射线穿过的Octree节点

    public List<Octree> GetNodesIntersectedByRay(Ray ray)
    {
        List<Octree> intersectedNodes = new List<Octree>();

        if (bounds.IntersectRay(ray))
        {
            intersectedNodes.Add(this);

            if (children != null)
            {
                foreach (var child in children)
                {
                    intersectedNodes.AddRange(child.GetNodesIntersectedByRay(ray));
                }
            }
        }

        return intersectedNodes;
    }

3.获取射线穿过Octree节点中的坐标数据

        var nodes = this._octree.GetNodesIntersectedByRay(ray);
        var points = new List<Vector3>();
         foreach (var node in nodes)
         {
             points.AddRange(node.points);
         }

4.通过常规方法遍历经过筛选后的Octree节点中的坐标数据

...
 foreach (Vector3 point in points)
        {
            float dotAngle = Vector3.Dot(rayDirection, (point - rayOrigin).normalized);
            if (dotAngle > 0.99f)
            {
...

经过八叉树优化后几乎可以做到实时选取

注意:可以调整八叉树的迭代分割限制条件来寻找更好的子节点Bounds范围,以此来加快最近点的玄策

标签:就近,千万个,point,八叉树,Vector3,rayOrigin,Octree,var,ray
From: https://www.cnblogs.com/Firepad-magic/p/18493413

相关文章

  • PCL 使用八叉树进行点云变化检测
    目录一、概述二、代码三、结果一、概述  PCL中的pcl::octree::OctreePointCloudChangeDetector函数能够实现同时构建八叉树并完成空间变化检测。二、代码#include<iostream>#include<pcl/io/pcd_io.h>#include<pcl/point_types.h>#include<pcl/octree/oc......
  • 爵士编曲:和弦排列 躯壳排列 四度排列 无根音排列 Drop 就近原则 So what排列
    和弦排列法是和弦在四部和声中的纵向排列方式称为“和弦排列法”。根据和弦排列时上方三声部各相邻声部之间的音程距离,原位三和弦可以有“密集排列”和“开放排列”以及“混合排列”三种排列法。①密集排列法:密集排列法(Closeposition)为上方三声部中相邻声部之间的距离在四度......
  • Python自动化:一键提取千万个Excel指定数据
    一、传统方法的局限性打开每个Excel文件,逐个查找需要的数据。筛选出老板需要的数据列。复制并粘贴到新的工作表中。保存并关闭每个文件。这个过程不仅耗时,而且容易出错。每一次的筛选都可能遗漏数据,每一次的复制粘贴都可能引入错误。二、Python自动化的解决方案i......
  • 八叉树-Unity
    八叉树八叉树简介八叉树(Octree)是一种在三维空间中进行数据组织和存储的树型数据结构。它的工作原理是将一个大的三维空间递归地分割成八个相等的小空间,每个小空间又可以继续分割成八个更小的空间,以此类推,直到达到某个预定的深度或者满足特定的终止条件(例如,空间内元素数量少于一......
  • Unity3D 八叉树划分空间和可视化
    也许更好的阅读体验成果展示代码OctreeNodeusingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassOctreeNode{//空间内包含的物体publicList<GameObject>areaObjects;//空间中心publicVector3center;......
  • 游戏AI寻路——八叉树+A*寻路
    利用八叉树的空中寻路你有思考过在空中如何进行寻“路”吗?来想象一个的场景:飞机从空中基地出发,要避开许多空中建筑,最终到达目的地。这种情况下的寻路是没有路面的,寻路物体的移动方向也比较自由,这该怎么寻呢?如果我们只是在一个平面进行寻路,我们可以直接用A*寻路,铺好一个地面网......
  • 分布式技术:云端部署,大规模会议与就近接入无忧
    超大规模会议支持:依托中国联通强大的云计算能力,云视频平台能够轻松应对超大规模的线上会议需求,支持数千乃至数万参会者同时在线,满足大型企业培训、全球发布会、线上峰会等大规模活动的通信需求。 就近接入,低延迟:通过遍布全国乃至全球的边缘节点和数据中心,云视频服务能够实现用......
  • 主谓一致:就近原则+就远原则
    就近原则 定义::当一个句子中出现多个主语时根据离这个谓语动词更近的主语选择用哪个谓语动词、 就近原则提示词:notonlynutalso;不但,而且not,but;不是,而是;or;或;eitheror;要么,要么;neithernor;既不,也不;therebe;有; 就远原则 定义:当一个句子中出现多个主语时根据离这......
  • 地球怎么进行八叉树分割?
    八叉树=四叉树+高度?1.用一个盒子把地球给罩起来。2.把盒子分八份。3.每一小份继续分割八分。参考:https://zhuanlan.zhihu.com/p/638014132?utm_id=0......
  • 如何将1千万个数据加到List中
    1.如何将1千万个数据加到List中ArraysList可以存下,但是效率低,可以使用LinkedList。2.两个1千万List如何找到,A中有,但B中没有的元素。可以将List转成HashSet,使用HashSet的retainAll方法。retainAll作用是保留集合中与另一个集合相同的元素,即取交集3.使用HashSet的retainAll()......