首页 > 极客资料 博客日记
【八叉树】从上千万个物体中【**瞬间**】就近选取坐标
2024-10-22 18:00:03极客资料围观17次
这篇文章介绍了【八叉树】从上千万个物体中【**瞬间**】就近选取坐标,分享给大家做个参考,收藏极客之家收获更多编程知识
众里寻他千百度,蓦然回首,那人却在灯火阑珊处
前情提要
在某些情况下,我们在场景中创建了数百万个物体,这些物体没有直接的网格或碰撞体(例如,通过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范围,以此来加快最近点的玄策
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签:
相关文章
最新发布
- Nuxt.js 应用中的 prerender:routes 事件钩子详解
- 【问题解决】Tomcat由低于8版本升级到高版本使用Tomcat自带连接池报错无法找到表空间的问题
- 【FAQ】HarmonyOS SDK 闭源开放能力 —Vision Kit
- 六、Spring Boot集成Spring Security之前后分离认证流程最佳方案
- 《JVM第7课》堆区
- .NET 8 高性能跨平台图像处理库 ImageSharp
- 还在为慢速数据传输苦恼?Linux 零拷贝技术来帮你!
- 刚毕业,去做边缘业务,还有救吗?
- 如何避免 HttpClient 丢失请求头:通过 HttpRequestMessage 解决并优化
- 让性能提升56%的Vue3.5响应式重构之“版本计数”