以下の内容はhttps://redhologerbera.hatenablog.com/entry/2025/03/01/234833より取得しました。


Open3Dを使用してメッシュのブーリアンを行う

本日はPython枠です。

先日Open3Dを用いたポリゴン削減を行いました。

redhologerbera.hatenablog.com

今回はブーリアン演算を実装していきます。

先日よりはてなブログのサーバーが不具合があったようで2日ぶりの記事になります。

〇環境

・Windows11PC

・Open3D

・Anaconda Prompt

・Python3.11

ブーリアンとは?

ブーリアンは複数の3Dオブジェクトの体積の足し算、引き算を行う処理です。

BlenderやMayaでは標準で搭載されている機能ですが、Unityなどで独自に実装を行おうとするとそのアルゴリズムは複雑です。

open3Dではv0.16以降でブーリアンをサポートしています。

https://www.open3d.org/docs/release/python_api/open3d.t.geometry.TriangleMesh.html#open3d.t.geometry.TriangleMesh.boolean_difference

〇実装

 今回はinputフォルダおよびoutputフォルダを用意しinputフォルダに配置した2つのobjを処理し、outputフォルダにエクスポートする処理になります。

import open3d as o3d
import open3d.core as o3c
import os

def boolean_operation(input_folder, output_folder, operation="union"):
    """
    指定フォルダ内の2つのOBJファイルに対してブーリアン演算を行う。

    Args:
        input_folder (str): 入力フォルダのパス
        output_folder (str): 出力フォルダのパス
        operation (str): "union"(和)、"difference"(差)、"intersection"(交差)の3種類から選択
    """
    os.makedirs(output_folder, exist_ok=True)

    # OBJファイルの取得
    obj_files = [f for f in os.listdir(input_folder) if f.lower().endswith(".obj")]
    if len(obj_files) < 2:
        print("エラー: OBJファイルが2つ必要です")
        return

    obj1_path = os.path.join(input_folder, obj_files[0])
    obj2_path = os.path.join(input_folder, obj_files[1])

    print(f"Processing: {obj1_path} and {obj2_path}")

    # Open3D Tensor Mesh としてロード
    mesh1 = o3d.io.read_triangle_mesh(obj1_path)
    mesh2 = o3d.io.read_triangle_mesh(obj2_path)

    # Mesh を tensor ベースのフォーマットに変換
    mesh1_t = o3d.t.geometry.TriangleMesh.from_legacy(mesh1)
    mesh2_t = o3d.t.geometry.TriangleMesh.from_legacy(mesh2)

    # ブーリアン演算の実行
    if operation == "union":
        result = mesh1_t.boolean_union(mesh2_t)
    elif operation == "difference":
        result = mesh1_t.boolean_difference(mesh2_t)
    elif operation == "intersection":
        result = mesh1_t.boolean_intersection(mesh2_t)
    else:
        print("エラー: operationは 'union', 'difference', 'intersection' のいずれかを指定してください")
        return

    # Open3D 形式に変換し、出力ファイルとして保存
    result_legacy = result.to_legacy()
    output_file = os.path.join(output_folder, f"boolean_{operation}.obj")
    o3d.io.write_triangle_mesh(output_file, result_legacy)

    print(f"ブーリアン演算完了: {output_file}")

if __name__ == "__main__":
    input_folder = "input"
    output_folder = "output"
    boolean_operation(input_folder, output_folder, operation="union")  # 和演算

この処理を実装するとブーリアンが行われます。

元メッシュ(左)と比較するとブーリアンによって閉じたメッシュとして構成されていることがわかると思います。

以上でブーリアンを実装できましたが、問題としてはブーリアンを行った場合ジオメトリが変わるため、メッシュの法線を再計算しなければならないのですが、現状では法線が崩れてしまう問題があります。

この法線に関してもOpen3Dに良い機能がないか次回以降見て生きたと思います。

本日は以上です。




以上の内容はhttps://redhologerbera.hatenablog.com/entry/2025/03/01/234833より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14