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

news/2024/10/22 18:02:45

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

前情提要

在某些情况下,我们在场景中创建了数百万个物体,这些物体没有直接的网格或碰撞体(例如,通过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范围,以此来加快最近点的玄策

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

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

相关文章

Python 数据分析与可视化有什么区别

在当今的数据驱动时代,Python已成为数据分析和数据可视化的重要工具。尽管这两个领域经常在数据科学项目中相互交织,但它们在功能和目的上存在本质区别。本文旨在详细探讨Python在数据分析和数据可视化方面的差异,包括它们的定义、使用的主要库、应用场景以及在实际项目中的…

python第六章课后习题

点击查看代码print("学号:2023310143028")点击查看代码def prim(graph, start): num_nodes = len(graph) visited = [False] * num_nodes min_heap = [(0, start, -1)] mst_cost = 0 mst_edges = [] while min_heap: weight, u, parent = heapq.heappop(min…

go1.18版本下 beego/bee安装无法生成exe问题已解决

转自: https://www.cnblogs.com/leijiangsheng/p/17392795.html 我原来的项目是教育学习APP使用gin框架,很多东西都是自己原来实现的。最近开发小程序,需要重新独立后台,又重新找了下go框架研究了下,beego确实是个好框架,至少项目能用到的都考虑进去了。 然后发现我本地装…

哈希碰撞

问:两个字符串hashcode相同equals一定相同吗?equals相同hashcode一定相同吗? 答:equals相同hashcode一定相同,hashcode因为哈希碰撞所以equals不一定相同。 Hash如何存数据hash表的本质其实就是数组,hash表中通常存放的是键值对Entry。 如下图:这里的学号是个key,哈希表…

实景三维助力智慧水利建设

随着信息技术的快速发展,智慧水利作为智慧城市的重要组成部分,正受到越来越多的关注。实景三维技术,以其独特的优势,为智慧水利建设提供了强有力的支撑。本文将探讨实景三维技术如何助力智慧水利建设。一、智慧水利建设的背景智慧水利是指运用现代信息技术,对水利设施进行…

python第四章课后习题

点击查看代码 import numpy as np import cvxpy as cpx=cp.Variable(6,pos=True) obj=cp.Minimize(x[5]) a1=np.array([0.025, 0.015, 0.055, 0.026]) a2=np.array([0.05, 0.27, 0.19, 0.185, 0.185]) a3=np.array([1, 1.01, 1.02, 1.045, 1.065]) k=0.05; kk=[]; qq=[] while …

Go语言net/http包源码学习

0.前言 该笔记为笔者第一次学习go的net/http包源码的时候所记,也许写的并不是很精确,希望大家多多包涵,一起讨论学习。 该笔记很大程度的参考了网名为“小徐先生”的前辈所分享的博客,推荐大家可以先看一看它的博客来一起学习,我的只是照葫芦画瓢还有一些代码更新的讲解而…

linux之core文件调试

linux之core文件调试 前言 有时候程序会异常退出而不带任何日志,此时就可以使用 core 文件进行分析,它会记录程序运行的内存,寄存器,堆栈指针等信息 什么是core文件 通常在 Linux 下遇到程序异常退出或者中止,我们都会使用 core 文件进行分析,其中包含了程序运行时的内存…