最近正在做与三维物体相关的工作,遇到一个困难:如何计算两个几何体的布尔相交,以及这部分的体积?
我尝试了三个路径:
1. open3d通过is_intersecting()方法先求二者的交集然后算这部分交集的体积,但是发现会报错,报错信息是交集不是水密的(watertight),刚开始以为是模型问题,结果发现交集的mesh就是有问题。
2. open3d先得到每个物体的体素,然后计算体素的交集,交集的大小乘以每个体素的体积就是交叠体积。但是实现之后仍然出错,原来是网格物体转体素只是把表面转化成体素了,,,当然也有另一种方法,就是在物体范围内生成很多点,然后从每一个点发射一条射线来判断该点是否在网格内。这有点太费时了,而且自己写还需要做优化,因此放弃
3. 在open3d找不到方法,转向trimesh库,这是一个处理三角形网格的库。示例代码如下:
import open3d as o3d
import numpy as np
import trimesh
import os
import manifold3d
def create_cube(center, size):
mesh = o3d.geometry.TriangleMesh.create_box(width=size, height=size, depth=size)
mesh.compute_vertex_normals()
mesh.translate(np.array(center) - size / 2)
return mesh
def create_sphere(center, radius):
mesh = o3d.geometry.TriangleMesh.create_sphere(radius=radius)
mesh.compute_vertex_normals()
mesh.translate(np.array(center))
return mesh
def convert_to_trimesh(o3d_mesh):
vertices = np.asarray(o3d_mesh.vertices)
faces = np.asarray(o3d_mesh.triangles)
mesh=trimesh.Trimesh(vertices=vertices, faces=faces)
return mesh
def compute_intersection_volume(mesh1, mesh2):
mesh1_trimesh = convert_to_trimesh(mesh1)
mesh2_trimesh = convert_to_trimesh(mesh2)
intersection_mesh = trimesh.boolean.boolean_manifold([mesh1_trimesh, mesh2_trimesh],'intersection')
#intersection_mesh = trimesh.boolean.intersection([mesh1_trimesh, mesh2_trimesh])
return intersection_mesh.volume, intersection_mesh
# 创建一个正方体和一个球体
cube = create_cube(center=[0, 0, 0], size=1)
sphere = create_cube(center=[0.5, 0.5, 0.7], size=1)
# 确保网格是封闭的体积网格
cube.merge_close_vertices(1e-5)
sphere.merge_close_vertices(1e-5)
if not cube.is_watertight():
print("Cube mesh is not watertight!")
if not sphere.is_watertight():
print("Sphere mesh is not watertight!")
# 计算相交体积
intersection_volume, intersection_mesh = compute_intersection_volume(cube, sphere)
print(f"Intersection Volume: {intersection_volume}")
# 可视化
intersection_o3d_mesh = o3d.geometry.TriangleMesh()
intersection_o3d_mesh.vertices = o3d.utility.Vector3dVector(intersection_mesh.vertices)
intersection_o3d_mesh.triangles = o3d.utility.Vector3iVector(intersection_mesh.faces)
o3d.visualization.draw_geometries([cube, sphere, intersection_o3d_mesh])
需要安装trimesh库和manifold3d库,如果报错,尝试将后者版本修改成2.2.2
其中:
trimesh.boolean.boolean_manifold([mesh1_trimesh, mesh2_trimesh],'intersection')
最后一个参数可以修改成
difference(差)
union(并集)
intersection(交集)