プログマのプログラマ日記

技術メモや自社サービスに関する記事を書いていく予定です。

open3dでテクスチャ付きのglTFを出力できなかったときの対応

open3dはテクスチャ付きglTFの出力に未対応?

とある案件で、open3dでglTF(glb)を出力したくなったときがあったのですが、

# テクスチャ付きメッシュ生成
mesh_textured = ...

# glb形式で書き出し
o3d.io.write_triangle_mesh("./output/hogehoge.glb", mesh_textured)

のようなコードでglTFを出力しようとしたときに、

[Open3D WARNING] This file format does not support writing textures and uv coordinates. Consider using .obj

のような警告が出力されてテクスチャを出力できませんでした。そんなぁ~…
(試した時のバージョンはopen3d 0.16.0)
言われた通り.obj形式で試したところ、無事テクスチャ付きのデータを出力できるようです。
でも今回出力したいのはglTFのデータ。さてどうしたものか。

trimeshを使ってみる

PythonでglTFを扱えそうなライブラリを探してみたところ、trimeshというライブラリが見つかりました。これは便利そうです!

github.com

出来上がったソースコードは以下の通り。
いったんobjファイルを出力して、それを読み込んで...ってやっているのでパフォーマンス的にはあまりよろしくありません。
(今回の私のケースではそれほど問題にならなかったのでこのままとしました)

import tempfile
import os
import open3d as o3d
import trimesh

def export_via_trimesh(
    o3d_mesh: o3d.geometry.TriangleMesh,
    file_type: str,
    file_path: str) -> trimesh.Trimesh:
    """
    o3d.geometry.TriangleMeshをtrimesh経由でエクスポート
    """
    with tempfile.TemporaryDirectory() as dname:
        # 1. TriangleMeshをobj形式で出力
        obj_path = os.path.join(dname, "temp.obj")
        o3d.io.write_triangle_mesh(obj_path, o3d_mesh)

        # 2. 1をtrimeshで読み込み
        tri_mesh = trimesh.load(obj_path)

        # 3. 2を指定の形式で出力
        tri_mesh.export(file_type=file_type, file_obj=file_path)

このように使います。

# テクスチャ付きメッシュ生成(open3d)
mesh_textured = ...

# glb形式で書き出し
export_via_trimesh(mesh_textured, "glb", "./output/test.glb")

参考にした記事

この記事の投稿者さんのコードを参考にさせてもらいました。
(元記事の方はなぜかこのコードではうまくテクスチャ出力できなかったようですが、私のケースでは正常に動作しました)

stackoverflow.com

github.com

※the incredibly ugly solutionって書きたくなるときの気持ち、すごくわかるなあ。。