基于trimesh计算两个几何体相交体积

最近正在做与三维物体相关的工作,遇到一个困难:如何计算两个几何体的布尔相交,以及这部分的体积?

我尝试了三个路径:

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(交集)

### 使用 Trimesh计算 3D 模型体积 为了计算一个 `Trimesh` 对象的体积,可以直接利用库中的内置属性。`Trimesh` 提供了一个简单的方法来访问模型体积数据。 ```python import trimesh # 加载模型 mesh = trimesh.load_mesh('model.obj') # 获取模型体积 volume = mesh.volume print(f"The volume of the model is {volume} cubic units.") ``` 上述代码展示了如何通过调用 `mesh.volume` 属性轻松获得整个模型的总体积[^2]。需要注意的是,在某些情况下,如果模型不是完全封闭或者存在拓扑错误,则可能会导致体积计算不准确。对于这种情况,建议先修复模型再尝试重新计算体积。 另外一种更复杂但更为可靠的方式是采用蒙特卡罗方法估算体积。这种方法涉及在包围盒内部随机抽样大量点,并统计位于网格内的比例从而估计实际体积: ```python def estimate_volume(mesh, sample_count=100000): points, _ = mesh.sample(sample_count) inside_points = [] for point in points: if mesh.contains([point]): inside_points.append(point) ratio_inside = len(inside_points)/sample_count bounding_box_vol = abs((mesh.bounds[1]-mesh.bounds[0]).prod()) estimated_volume = bounding_box_vol * ratio_inside return estimated_volume estimated_volume = estimate_volume(mesh) print(f"Estimated volume using Monte Carlo method: {estimated_volume}") ``` 此函数定义了一种基于采样的方式来近似计算给定网格所围成的空间体积[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值