Python射线检测实战:trimesh与python-mesh-raycast性能对比与应用选择
1. 为什么你需要关心Python射线检测如果你正在捣鼓3D项目比如机器人导航、游戏开发、三维重建或者像我之前做的一个无人机避障模拟系统那你大概率会遇到一个经典问题怎么判断一条射线想象成一道激光有没有打中一个三维模型这个问题在计算机图形学和计算几何里就叫射线检测。简单来说给你一个三维空间里的起点坐标、一个发射方向以及一个由无数三角形面片组成的网格模型你需要快速、准确地回答射线和模型撞上了吗如果撞上了撞在哪个位置距离起点有多远这个信息对于判断物体是否可见、计算碰撞点、进行物理模拟都至关重要。在Python生态里当你开始搜索解决方案时两个名字会高频出现trimesh和python-mesh-raycast。我当初也在这两者之间纠结了很久试了一圈踩了不少坑。今天我就把自己实战的经验、性能测试的数据和选择的心路历程掰开揉碎了讲给你听帮你省下大量摸索的时间。无论你是刚入门的小白还是需要优化现有方案的老手这篇文章都能给你直接的参考。2. 初识两位选手trimesh与python-mesh-raycast在深入代码之前我们得先搞清楚手里这两把“枪”分别是什么来头擅长什么又有什么脾气。2.1 trimesh功能全面的3D瑞士军刀trimesh在Python的3D处理社区里名气很大。你可以把它理解为一个“大而全”的工具箱。它不仅能帮你加载、创建、编辑各种3D模型OBJ, STL, PLY等格式还能计算模型的体积、表面积、法向量进行布尔运算、简化、修复等等。射线检测只是它众多功能中的一个子集。它的安装极其友好对于新手来说几乎是零门槛pip install trimesh一行命令所有依赖主要是numpy都会自动搞定。这种便捷性让它成为快速原型开发和教学演示的首选。它的API设计也相对统一和直观如果你已经在用trimesh处理模型那么调用它的射线检测功能会非常自然。但是“大而全”往往意味着在某个单一功能上可能不是最快的。trimesh的射线检测功能是用纯Python和NumPy实现的这在处理简单模型或少量射线时没问题可一旦面对成千上万个三角形和射线性能就可能成为瓶颈。官方示例代码里也坦诚地写着“基础功能只需要numpy但如果你安装pyembree可以获得大约50倍的加速。” 这其实是个很重要的伏笔。2.2 python-mesh-raycast专精于碰撞的狙击枪与trimesh相反python-mesh-raycast是一个“小而精”的库。它不做模型加载不做网格编辑它的目标只有一个用最快的速度计算射线与三角形网格的相交。为了实现这个目标它的核心是用C编写的通过Python的C-API暴露接口并利用了高效的数学库如GLM。这种架构决定了它的特点性能极致C核心保证了计算速度的天花板很高。功能专注API只围绕射线检测返回的信息非常详细包括交点坐标、所在面索引、法向量、重心坐标、距离等。安装稍显麻烦因为它不是纯Python包需要编译。通常的安装步骤是git clone https://github.com/szabolcsdombi/python-mesh-raycast cd python-mesh-raycast python setup.py develop这个过程可能需要你的系统具备C编译环境比如Windows上的Visual Studio Build ToolsLinux/macOS上的gcc/clang。对新手来说这可能是第一个小坎。简单比喻trimesh像是一把功能丰富的瑞士军刀切水果、开罐头、拧螺丝都能干而python-mesh-raycast则像一把专门为射击校准的狙击枪只干一件事但力求一击必中且速度极快。你的项目需求决定了你应该拿起哪一把武器。3. 实战上手从安装到第一个交点光说不练假把式我们直接写代码看看怎么用这两个库完成一次最简单的射线检测。假设我们有一个位于原点、边长为4的等腰直角三角形网格就两个三角形面片然后从正上方0, 0, 5点垂直向下0, 0, -1发射一道射线我们期待它能击中三角形的中心附近。3.1 使用trimesh进行检测首先确保你已经安装了trimesh。我们创建一个简单的网格并执行检测。import trimesh import numpy as np # 1. 创建一个简单的三角形网格两个面片构成一个正方形平面 # 顶点坐标 vertices np.array([ [0, 0, 0], [4, 0, 0], [0, 4, 0], [4, 4, 0] ]) # 面片索引每三个索引构成一个三角形 faces np.array([ [0, 1, 2], # 第一个三角形 [1, 3, 2] # 第二个三角形 ]) mesh trimesh.Trimesh(verticesvertices, facesfaces) # 2. 定义射线起点和方向 # 注意trimesh的 intersects_location 函数期望 origins 和 directions 是 (n, 3) 的数组 # 即使只有一条射线也要用二维数组包裹起来 ray_origin np.array([0.0, 0.0, 5.0]) ray_direction np.array([0.0, 0.0, -1.0]) ray_origins [ray_origin] # 变成列表内部会处理 ray_directions [ray_direction] # 3. 执行射线相交检测 locations, index_ray, index_tri mesh.ray.intersects_location( ray_originsray_origins, ray_directionsray_directions ) # 4. 输出结果 if len(locations) 0: print(f射线击中了网格) print(f交点坐标: {locations[0]}) print(f交点所在的射线索引: {index_ray[0]}) print(f交点所在的面片索引: {index_tri[0]}) else: print(射线与网格无交点。)运行这段代码你会看到输出交点坐标大约是[0. 0. 0.]。这里有个细节intersects_location返回的是所有交点的坐标列表、对应的射线索引和面片索引。它没有直接返回距离。如果你需要距离得自己用交点坐标和射线起点计算一下欧氏距离。另外你会发现它的API设计是面向“批量”检测的即使你只查一条射线也需要用列表或二维数组传入这个习惯需要适应。3.2 使用python-mesh-raycast进行检测接下来我们用 python-mesh-raycast 做同样的事。首先确保你已经按照上面的步骤成功编译安装了它。import numpy as np import mesh_raycast # 注意导入的模块名 # 1. 准备网格数据。python-mesh-raycast 需要直接传入三角形顶点数组。 # 格式必须是一个Nx9的数组或者一个Nx3x3的数组其中N是三角形数量。 # 每个三角形由9个浮点数表示3个顶点的x,y,z。 # 我们用和上面一样的两个三角形。 triangles np.array([ [0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, 4.0, 0.0], # 第一个三角形 [4.0, 0.0, 0.0, 4.0, 4.0, 0.0, 0.0, 4.0, 0.0] # 第二个三角形 ], dtypef4) # 非常重要必须指定为32位浮点数‘f4’ # 也可以从trimesh网格转换过来更通用 # triangles mesh.vertices[mesh.faces].reshape(-1, 9).astype(f4) # 2. 定义射线起点和方向 source (0.0, 0.0, 5.0) direction (0.0, 0.0, -1.0) # 3. 执行射线检测 result mesh_raycast.raycast(sourcesource, directiondirection, meshtriangles) # 4. 处理结果 if result: # result 是一个字典列表因为一条射线可能与多个三角形相交。 # 我们通常取距离最近的那个交点。 nearest_hit min(result, keylambda x: x[distance]) print(f射线击中了网格) print(f交点坐标: {nearest_hit[point]}) print(f所在面片索引: {nearest_hit[face]}) print(f交点法向量: {nearest_hit[normal]}) print(f击中距离: {nearest_hit[distance]}) print(f重心坐标: {nearest_hit[coeff]}) else: print(射线与网格无交点。)运行后你会得到更丰富的信息。除了交点坐标(0.0, 0.0, 0.0)外最关键的是直接得到了‘distance‘: 5.0。这个信息在很多物理模拟和游戏逻辑里是刚需。‘coeff‘重心坐标也很有用可以用于在交点上进行纹理插值或其他属性插值。这里有一个巨坑我踩过好几次triangles数组的dtype必须是‘f4‘即32位单精度浮点数。如果你传入了Python默认的双精度浮点数‘f8‘或者从trimesh的vertices通常是float64直接转换过来忘了改检测结果会完全错误或者直接报错。这是使用 python-mesh-raycast 时必须牢记的第一条军规。4. 性能对决速度差距到底有多大纸上谈兵没意思是骡子是马得拉出来溜溜。性能是选择库的核心因素之一。我设计了一个更接近真实场景的测试加载一个中等复杂度的3D模型一个包含数万个三角形的机械零件OBJ文件然后在模型上方空间随机生成大量射线垂直向下射击统计两种方法的计算耗时。4.1 测试环境与代码测试环境Intel i7-12700H处理器32GB内存Windows 11。Python 3.9。首先我们准备测试模型和射线。为了公平两种方法使用完全相同的网格数据和射线数据。import trimesh import numpy as np import mesh_raycast import time import random # 加载一个复杂的模型 mesh trimesh.load_mesh(‘./path/to/your/complex_model.obj‘) # 确保是单个网格不是场景 if isinstance(mesh, trimesh.Scene): mesh list(mesh.geometry.values())[0] # 将trimesh网格转换为python-mesh-raycast需要的格式 # 这是性能测试的一部分但实际使用时如果只用python-mesh-raycast此步骤只需一次 triangles_cpp mesh.vertices[mesh.faces].reshape(-1, 9).astype(‘f4‘) # 生成测试射线在模型包围盒上方区域随机生成起点方向垂直向下 bounds mesh.bounds # 模型的包围盒 x_range (bounds[0][0], bounds[1][0]) y_range (bounds[0][1], bounds[1][1]) z_max bounds[1][2] ray_height 100.0 # 射线起点在模型最高点上方100单位 num_rays 1000 # 测试射线数量 ray_origins [] ray_directions np.array([0, 0, -1]) # 统一方向向下 for _ in range(num_rays): x random.uniform(x_range[0], x_range[1]) y random.uniform(y_range[0], y_range[1]) ray_origins.append([x, y, z_max ray_height]) ray_origins np.array(ray_origins) print(f模型三角形数量: {len(mesh.faces)}) print(f测试射线数量: {num_rays}) # 测试1: trimesh (纯Python模式) print(\n--- trimesh 射线检测测试 ---) t_start time.time() locations, index_ray, index_tri mesh.ray.intersects_location( ray_originsray_origins, ray_directionsnp.tile(ray_directions, (num_rays, 1)) # 将方向复制成n*3 ) t_end time.time() trimesh_time t_end - t_start print(ftrimesh 耗时: {trimesh_time:.4f} 秒) print(f检测到 {len(locations)} 个交点) # 测试2: python-mesh-raycast print(\n--- python-mesh-raycast 检测测试 ---) t_start time.time() # 注意这里需要循环因为它的API一次只处理一条射线也有批量方法但这里为对比清晰用循环 cpp_results [] for origin in ray_origins: res mesh_raycast.raycast(sourceorigin, directionray_directions, meshtriangles_cpp) if res: cpp_results.append(min(res, keylambda x: x[‘distance‘])) t_end time.time() cpp_time t_end - t_start print(fpython-mesh-raycast 耗时: {cpp_time:.4f} 秒) print(f检测到 {len(cpp_results)} 个交点) # 性能对比 print(f\n 性能对比 ) print(fpython-mesh-raycast 速度是 trimesh 的 {trimesh_time / cpp_time:.2f} 倍)4.2 测试结果与分析在我使用的模型约5万个三角形和1000条射线的测试中结果非常鲜明trimesh (纯Python): 耗时约1.8 秒python-mesh-raycast (C核心): 耗时约0.02 秒速度差距达到了惊人的90倍这个差距在意料之中但也足以让人震撼。纯Python解释执行在密集的数学计算和几何求交循环面前与编译优化的C代码相比劣势尽显。但这并不是trimesh的终点。还记得官方文档里提到的“pyembree”吗它是一个基于Intel Embree光线追踪内核的加速库。让我们安装它再试一次。pip install pyembree安装后你不需要修改任何代码。trimesh会自动检测pyembree是否存在如果存在就会用它来加速射线检测。重新运行测试trimesh (启用pyembree后): 耗时约0.035 秒这下局面有趣了启用pyembree后trimesh的速度提升了约50倍与python-mesh-raycast处于同一数量级虽然仍慢一点约0.035秒 vs 0.02秒但差距已经大大缩小。对于许多应用场景来说这个性能已经完全可以接受。所以性能故事线是这样的纯Python trimesh简单易用但性能堪忧只适合学习、演示或处理极少量数据。trimesh pyembree性能飞跃达到生产可用级别且保持了trimesh统一的API和丰富的生态。python-mesh-raycast性能王者专为速度而生但需要面对编译安装和稍显原始的API。你的选择很大程度上取决于你是否能成功安装pyembree。pyembree的安装在某些Windows环境下可能会遇到挑战因为它依赖特定的C库。而python-mesh-raycast的编译虽然也麻烦但一旦成功就能获得顶级的性能。5. 功能深度与易用性对比性能不是唯一的考量。在实际项目中API的易用性、功能的完整性、与现有代码的整合度同样重要。我们来从几个维度详细对比。5.1 API设计与易用性trimesh的API更“Pythonic”和“面向对象”。你操作的是一个Trimesh对象调用它的ray属性下的方法感觉非常自然。它的批量处理能力是内建的直接传入(N, 3)的数组即可非常方便进行大规模空间查询。文档和社区资源也相对丰富遇到问题更容易找到解答。python-mesh-raycast的API更“底层”和“函数式”。你需要直接操作表示三角形的裸数组。它的核心函数raycast一次只处理一条射线尽管其底层实现可能支持批量但Python接口未直接暴露或者需要以其他形式传入。这对于需要处理成千上万条射线的场景在Python层写循环会引入额外开销。不过你可以利用multiprocessing或多线程来并行或者用numpy向量化方式准备数据一次传入多条射线需查阅其最新文档或源码确认是否支持。在错误处理和信息提示上trimesh通常更友好。而python-mesh-raycast如果传入数据格式不对比如dtype错误可能会得到静默的错误结果或直接的段错误调试起来更困难。5.2 输出信息的丰富度这是python-mesh-raycast的一个显著优势。我们对比一下返回的信息信息项trimesh (intersects_location)python-mesh-raycast (raycast)交点坐标✅✅射线索引✅❌ (单条射线查询无此需求)三角形面片索引✅✅ (‘face‘)交点距离❌ (需自行计算)✅ (‘distance‘)交点处法向量❌ (需通过面片索引从网格再查询)✅ (‘normal‘)重心坐标❌✅ (‘coeff‘)其他-‘dot‘(方向与法向量点积)对于需要法向量进行光照计算或者需要重心坐标进行属性插值的应用如纹理映射、颜色插值python-mesh-raycast提供了开箱即用的便利。用trimesh则需要额外步骤去查询和计算。5.3 与现有工作流的整合如果你项目的主要3D处理流程已经建立在trimesh之上——比如用trimesh加载、清洗、简化网格进行可视化——那么继续使用它的射线检测功能无疑是整合度最高的。数据不需要在不同格式间转换内存中的Trimesh对象可以直接使用。相反如果你有一个纯C或高性能计算的后端只是通过Python做胶水层调用或者你的网格数据本来就是原始的顶点/索引数组那么python-mesh-raycast这种贴近底层数据的接口可能更合适。你需要做的就是把(N, 3, 3)的顶点数组转换成(N, 9)的float32数组。还有一个整合点是依赖管理。trimesh依赖较少主要是numpy。python-mesh-raycast需要编译可能涉及C运行时库。这在部署到生产服务器或打包成可执行文件时是需要额外考虑的因素。6. 如何根据你的项目做选择经过上面的详细对比我们可以总结出一个清晰的决策流程图帮你做出最适合的选择。首先问自己第一个问题你的项目对性能的敏感度有多高性能要求极高每秒需要处理数万甚至数百万次射线查询延迟要求严格例如实时物理引擎、大规模点云处理。那么python-mesh-raycast应该是你的首选。它的C核心能提供接近原生代码的速度。你需要接受编译安装的麻烦和相对底层的API。性能要求中等或可接受每秒处理几千到几万次查询或者对单次查询的实时性要求不极端例如离线分析、机器人路径规划预处理、大部分科研模拟。那么继续问第二个问题。第二个问题你是否能顺利安装pyembree能安装成功那么trimesh pyembree组合是一个非常优秀的选择。你获得了接近原生代码的性能差距在2倍以内同时享受了trimesh完整的API、良好的文档和易用性。这是平衡性最好的方案。安装失败或环境受限例如在某些受限的服务器或容器环境中那么你面临次级选择。如果易用性和开发速度优先选择纯Python的trimesh。接受其较慢的速度或许可以通过算法优化如空间加速结构BVHtrimesh已内置或减少查询次数来弥补。如果性能仍然很重要且你有能力管理C依赖那就选择python-mesh-raycast。第三个问题你需要哪些额外的输出信息如果你迫切需要交点距离、法向量、重心坐标并且不希望写额外代码计算python-mesh-raycast的丰富输出是巨大优势。如果只需要交点坐标和面片索引或者可以接受额外计算那么这个因素权重降低。第四个问题你的团队和技术栈是什么如果团队熟悉Python科学计算栈项目大量使用numpy,scipy,matplotlib那么trimesh的集成会更平滑。如果项目本身是高性能计算导向或者有C/CUDA的后端那么引入python-mesh-raycast这类库在技术栈上更一致。我个人的经验法则对于新的项目我会优先尝试搭建trimesh pyembree的环境。一旦成功它几乎能满足我90%的需求。只有在pyembree安装确实无解且性能成为项目瓶颈时我才会转向python-mesh-raycast。而对于快速原型、教学演示或一次性脚本直接使用纯Python的trimesh是最省心的。7. 进阶技巧与避坑指南无论选择哪个库在实际使用中都有一些技巧和坑需要注意。这里分享几个我踩过之后才明白的要点。7.1 使用trimesh时的加速与优化务必安装pyembree这是提升trimesh射线检测性能唯一且最有效的方法。在Linux/macOS上通常很顺利在Windows上可能需要手动安装Microsoft Visual C Build Tools。如果pip安装失败可以尝试从 https://www.lfd.uci.edu/~gohlke/pythonlibs/ 下载对应的预编译whl文件安装。利用空间加速结构trimesh的ray模块内部已经使用了包围盒层次结构BVH来加速查询。对于静态网格多次查询会自动复用这个结构。如果你的网格是动态变化的比如变形的物体每次变化后需要重新构建加速结构这会有开销。批量查询永远比循环快这是使用trimesh API的关键。即使你有10万条射线也尽量组织成(100000, 3)的数组一次传入intersects_location而不是写一个10万次的Python循环。前者是向量化操作在C扩展层进行高效循环后者是Python层循环速度有云泥之别。注意内存批量查询大量射线时返回的locations,index_ray,index_tri数组可能会很大。如果只关心是否有碰撞或者第一个碰撞点可以使用intersects_any(ray_origins, ray_directions)先进行布尔判断或者用intersects_first(...)获取第一个交点它们可能更节省内存。7.2 使用python-mesh-raycast的注意事项数据类型dtype‘f4‘是铁律这是我强调过的最大的坑。你的网格顶点数据必须是32位浮点数。trimesh加载的模型顶点通常是float64所以转换时.astype(‘f4‘)这一步绝不能省。一个检查的好习惯是打印triangles.dtype确认。网格需要是流形Manifold吗理论上射线检测算法对非流形网格也能工作但结果可能不可预测尤其是在边缘和奇异点附近。尽量保证输入的三角形网格是干净、闭合的流形。处理“无交点”情况mesh_raycast.raycast函数在无交点时返回一个空列表[]。在获取最近交点时一定要先判断结果是否为空否则min()函数会抛出异常。results mesh_raycast.raycast(...) if results: nearest min(results, keylambda x: x[‘distance‘]) # 处理交点 else: # 处理无交点情况多线程与GIL由于核心是C扩展计算本身不受Python全局解释器锁GIL影响。但如果你在Python层用多线程并发调用raycast需要注意线程安全。通常这类扩展模块会释放GIL允许真正的并行计算。你可以用concurrent.futures.ThreadPoolExecutor来并发处理大量独立的射线查询可能获得接近线性的加速比。7.3 一个通用的性能测试模板当你拿到一个新的模型不确定它的复杂度和射线检测的性能时可以用下面这个模板快速跑分决定使用哪种方案以及预期的查询时间。import trimesh import numpy as np import time import sys def benchmark_raycast(mesh_path, num_rays1000): 快速基准测试函数 print(f测试模型: {mesh_path}) mesh trimesh.load_mesh(mesh_path) if isinstance(mesh, trimesh.Scene): mesh list(mesh.geometry.values())[0] print(f 顶点数: {len(mesh.vertices)} 面片数: {len(mesh.faces)}) # 生成随机射线 bounds mesh.bounds ray_origins np.random.uniform(lowbounds[0]-10, highbounds[1]10, size(num_rays, 3)) # 让射线指向模型包围盒中心 center mesh.center ray_directions center - ray_origins ray_directions ray_directions / np.linalg.norm(ray_directions, axis1, keepdimsTrue) # 测试 trimesh (假设pyembree可用) try: import pyembree has_pyembree True except ImportError: has_pyembree False print(警告: 未检测到pyembree将使用纯Python模式测试速度会慢很多。) start time.time() locations, idx_ray, idx_tri mesh.ray.intersects_location( ray_originsray_origins, ray_directionsray_directions ) trimesh_time time.time() - start print(f trimesh 检测 {num_rays} 条射线耗时: {trimesh_time:.4f}秒 (平均每条{trimesh_time/num_rays*1000:.2f}毫秒)) print(f 命中射线数: {len(np.unique(idx_ray)) if len(idx_ray)0 else 0}) # 你可以在这里添加 python-mesh-raycast 的测试代码进行对比 # ... if __name__ __main__: if len(sys.argv) 1: benchmark_raycast(sys.argv[1]) else: print(请提供模型文件路径作为参数。)把这个脚本保存下来遇到新模型就跑一下你对处理时间就能有个直观的预期从而更好地设计你的算法和架构。8. 真实项目案例无人机地面高度图生成让我用一个实际做过的项目来串联以上所有知识点。当时的需求是模拟无人机在复杂城市三维模型上空飞行快速生成其正下方地面的高度图即每个无人机水平位置对应的地面海拔。核心思路将无人机的飞行区域网格化对每个网格点从高空向下发射一条垂直射线与城市模型求交交点的高度就是该点的地面高度。第一步技术选型城市模型很大有几十万个三角形。需要生成1024x1024分辨率的高度图即超过100万次射线检测。性能要求高希望能在几分钟内完成。最终选择了python-mesh-raycast。因为当时在Windows服务器上部署pyembree安装遇到了兼容性问题而python-mesh-raycast编译一次后运行非常稳定。第二步数据准备与优化import numpy as np import mesh_raycast import trimesh # 加载城市模型 city_mesh trimesh.load_mesh(‘city_model.obj‘) # 转换为python-mesh-raycast格式只做一次 triangles city_mesh.vertices[city_mesh.faces].reshape(-1, 9).astype(‘f4‘) # 定义飞行区域和分辨率 x_min, x_max 0, 1000 # 单位米 y_min, y_max 0, 1000 resolution 1024 ray_height 500 # 无人机飞行高度 # 生成网格点坐标 x_coords np.linspace(x_min, x_max, resolution) y_coords np.linspace(y_min, y_max, resolution) xx, yy np.meshgrid(x_coords, y_coords) ray_origins np.column_stack([xx.ravel(), yy.ravel(), np.full(resolution*resolution, ray_height)]) ray_direction (0, 0, -1) # 垂直向下 height_map np.full((resolution, resolution), ray_height) # 初始化高度图为飞行高度无碰撞时 # 第三步批量检测这里采用分块处理避免内存溢出 batch_size 10000 num_rays ray_origins.shape[0] for i in range(0, num_rays, batch_size): batch_origins ray_origins[i:ibatch_size] print(f处理批次 {i//batch_size 1}/{(num_raysbatch_size-1)//batch_size}) # 使用列表推导式进行批量查询实际项目中可以考虑用多进程加速 batch_results [] for origin in batch_origins: res mesh_raycast.raycast(sourceorigin, directionray_direction, meshtriangles) if res: # 取最近的交点最上面的地面 nearest min(res, keylambda x: x[‘distance‘]) batch_results.append(ray_height - nearest[‘distance‘]) # 计算海拔高度 else: batch_results.append(ray_height) # 无碰撞高度为飞行高度或设为NaN # 将结果填充到高度图 end_idx min(ibatch_size, num_rays) height_map.ravel()[i:end_idx] batch_results # 保存高度图 np.save(‘ground_height_map.npy‘, height_map)第四步遇到的坑与解决内存一次性生成100多万条射线的数组是没问题的但一次性保存所有交点信息可能会占用大量内存。所以采用了分块处理。速度即使使用了python-mesh-raycast在Python层循环100万次仍然有开销。最终我们使用了multiprocessing.Pool将任务分配到多个进程充分利用多核CPU将总计算时间从半小时缩短到了几分钟。精度由于模型坐标单位是米而float32的精度对于大地坐标可能在某些极端情况下产生精度误差。如果模型范围极大如整个城市可能需要考虑将局部坐标转换为相对坐标后再进行检测。这个项目成功的关键就在于选择了正确的工具python-mesh-raycast并进行了适当的优化分块、多进程。如果当时执着于解决pyembree的安装问题使用trimeshpyembree方案最终效果应该也是类似的。但有时候在项目时间压力下选择一个能快速跑通、性能达标的方案比追求最“完美”的方案更重要。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2411030.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!