python 实现raycast射线检测的两种方法记录和对比:trimesh vs. python mesh raycast(更好)

2021/9/19 1:05:09

本文主要是介绍python 实现raycast射线检测的两种方法记录和对比:trimesh vs. python mesh raycast(更好),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

背景需求

项目需要用python实现常见的raycast射线检测。即:
给定一个点,一个方向,一个mesh。
求:从改点沿该方向发送射线,与mesh是否有交点,如果有,给出交点坐标,距离等信息。

找到两种亲测可行的解决方案:

  • 用trimesh包:https://github.com/mikedh/trimesh
  • 用python mesh raycast 包: https://github.com/szabolcsdombi/python-mesh-raycast

两个包的安装

trimesh
支持 pip install 直接下载安装

python mesh raycast 包:
需要按照github主页里的说明进行安装,即运行命令:
git clone https://github.com/cprogrammer1994/python-mesh-raycast
cd python-mesh-raycast
python setup.py develop

两个包的用法:

没有找到全面的文档,都是看的github里面的example和源码。

trimesh

https://github.com/mikedh/trimesh/blob/master/examples/ray.py

注意他的origins和directions都是n*3的,也就是需要默认用不同点和方向,做多次raycast检测。只有一个点和方向的话,也要套一层[]

    # test on a sphere mesh
    mesh = trimesh.primitives.Sphere()

    # create some rays
    ray_origins = np.array([[0, 0, -5],
                            [2, 2, -10]])
    ray_directions = np.array([[0, 0, 1],
                               [0, 0, 1]])

  # run the mesh- ray test
    locations, index_ray, index_tri = mesh.ray.intersects_location(
        ray_origins=ray_origins,
        ray_directions=ray_directions)
    print(locations) # 打印相交的点的坐标

python mesh raycast

单个三角形的mesh:

import mesh_raycast

triangles = np.array([
    [0.0, 0.0, 0.0],
    [4.0, 0.0, 0.0],
    [0.0, 4.0, 0.0],
], dtype='f4')

result = mesh_raycast.raycast(source=(0.4, 0.8, 5.0), direction=(0.0, 0.0, -1.0), mesh=triangles)

结果如下,result包含很多字段,需要自取。可以看到比trimesh多了我们想要的distance:

{
    'face': 0,
    'point': (0.4, 0.8, 0.0),
    'normal': (0.0, 0.0, 1.0),
    'coeff': (0.1, 0.2),
    'distance': 5.0,
    'dot': 1.0,
}

多个三角形的mesh也可以:

 triangles = np.array([
        [0.0, 0.0, 0.0],
        [4.0, 0.0, 0.0],
        [0.0, 4.0, 0.0],

        [0.0, 0.0, 2.0],
        [2.0, 0.0, 2.0],
        [0.0, 2.0, 2.0],
    ], dtype='f4')

    source = (1.0, 1.0, 5.0)
    direction = mesh_raycast.direction(source, (0.5, 0.5, -0.5))
    result = mesh_raycast.raycast(source=source, direction=direction, mesh=triangles)

二者对比

这里用trimesh读入本地的一个obj文件作为mesh。

import trimesh
    import numpy as np
    import mesh_raycast
    import time
    objPath = 'DatasetGen/untitled.obj'
    mesh = trimesh.load_mesh(objPath) #load or load_mesh

    if (type(mesh) == trimesh.scene.scene.Scene):
        print("scene")
        print(list(mesh.geometry.values())[0])

    elif (type(mesh) == trimesh.base.Trimesh):
        print("single object")
        # 移动到中心
        mesh=mesh_centerize(mesh)
        print(np.min(mesh.vertices,0))
        print(np.max(mesh.vertices, 0))

然后进行碰撞检测:

		# 全局变量
        UAV_height = 50
        # 计算raycast
  		ray_origins = np.array([0,UAV_height,0]) # 3*1
        ray_directions =  np.array([0,-1,0]) # 3*1
        # raycast方法一:trimesh
        t1 = time.time()
        locations, index_ray, index_tri = mesh.ray.intersects_location(
            ray_origins=[ray_origins], # n*3*1
            ray_directions=[ray_directions]) # n*3*1
        print(locations)
        t2 = time.time()
        print("Ran in {0:.3f} s".format(t2 - t1))


        # raycast方法二:
        t1 = time.time()
        triangles = mesh.vertices[mesh.faces]
        triangles = np.array(triangles, dtype='f4')  # 一定要有这一行,不然会有错。

        result = mesh_raycast.raycast(ray_origins, ray_directions, mesh=triangles)
        first_result = min(result, key=lambda x: x['distance'])
        print(first_result['point'])
        t2 = time.time()
        print("Ran in {0:.3f} s".format(t2 - t1))
        

主要的注意点是triangles一定要用np.array处理一下,不然直接用会不对。

结果是:

single object
[-35.7634975  -0.066495  -44.813048 ]
[35.7634975 12.359008  44.813048 ]
[[0.       0.292007 0.      ]]
Ran in 1.129 s
(0.0, 0.2920074462890625, 0.0)
Ran in 0.015 s

可见方法二,python mesh raycast快多了。
这是意料之中的,因为在trimesh的ray.py代码中,已经说了自己速度很慢:
https://github.com/mikedh/trimesh/blob/master/examples/ray.py

Do simple mesh- ray queries. Base functionality only
requires numpy, but if you install pyembree you get the
same API with a roughly 50x speedup.

这个pyembree我还没试过。

而方法二是用C实现的,那当然快了:

SThis module is using glm and the Python’s c-api. The implementation can be found in the mesh_raycast.cpp.

而且我的应用里确实需要用到distance。那当然选python mesh raycast了~



这篇关于python 实现raycast射线检测的两种方法记录和对比:trimesh vs. python mesh raycast(更好)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程