夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

obj形式のファイルフォーマットを理解する② フェイスの構造理解とobjファイルをcsvに変換する

本日は3Dモデリング枠です。

最近pythonを持ちいてOpen3DのライブラリでBlendetやMayaにあるような機能の独自実装を行いながら3DCGに関しての知識を深めています。

その中で一度open3dライブラリで処理をしてエクスポートしたモデルを再度Open3Dライブラリで処理を行う際にモデルのフォーマットエラーで読み込めないというエラーが発生しました。

これはobjを正確にエクスポートできていないことを示しています。

 しかし厄介なのがBlenderではある程度であれば破断しているフォーマットのデータも読み込むことができてしまう点です。

 これによって具体的にどのようにモデルのobj化が失敗しているのかの判別ができない状態にありました。

前回はobjのモデルがどのようなデータでできているのかを見ていきました。

redhologerbera.hatenablog.com

〇OBJとは?

 objはサーフェスモデルの中間拡張子として用いられるフォーマットです。

 ほかのフォーマットと異なりリグ構造などを含めることができず、汎用性が高いとは呼べませんが、シンプルであるうえに軽量であることが特徴であり、単にメッシュデータのみを扱いたい場合やもともとリグなどを含めることを想定していないスキャンデータ等に用いられる傾向があります。

〇面 -face

OBJモデルに含まれる面に関してはfのヘッダーとして次のようにあらわされます。

f 13/13/13 12/12/12 10/10/10

頂点や法線同様に3次元情報ですが、各成分はさらに3次元の値を持っていることがわかります。

 この意味は頂点/テクスチャ座標/法線ベクトルを意味します。

つまりf 13/13/13 12/12/12 10/10/10f v[13]/vt[13]/vn[13] v[12]/vt[12]/vn[12] v[10]/vt[10]/vn[10]であり v13とv12とv10の頂点を結んだ面ということになります。


元々objフォーマットの中身を見ようと思った理由はOpen3Dライブラリで生成したobjモデルを再読み込みする際にエラーが発生したことです。

Unable to load file uploads\1741062069\default.obj with ASSIMP: OBJ: Invalid face index.

というものです。

これはfで参照しているデータがない

 例えば f n/n/n m/m/m t/t/tであったとして v[n]が存在しない場合などに生じていると考えられます。

 つまりエラーを解消するためにはまずはfで参照されている各頂点インデックスが存在しているかを検証すればよいということになります。

 そしてその対応表がきちんと機能しているのかを調べます。

 これを人力で行うことは大変ですのでまずはPythonを使用してobjのデータを扱いやすい形式としてcsv形式に変換していきます。

今回はPythonで実現していきます。

import csv

# ファイルパス
obj_file = 'objのパス'
csv_file = 'output.csv'

# データを格納するリスト
vertices = []
vertex_normals = []
texture_coords = []
faces = []

# OBJファイルを読み込む
with open(obj_file, 'r') as file:
    for line in file:
        parts = line.strip().split()
        if not parts:
            continue
        if parts[0] == 'v':
            vertices.append(parts[1:4])
        elif parts[0] == 'vn':
            vertex_normals.append(parts[1:4])
        elif parts[0] == 'vt':
            texture_coords.append(parts[1:3])
        elif parts[0] == 'f':
            faces.append(parts[1:])

# CSVファイルに書き出す
with open(csv_file, 'w', newline='') as file:
    writer = csv.writer(file)
    writer.writerow(['Type', 'X', 'Y', 'Z'])

    # 頂点データを書き出す
    for vertex in vertices:
        writer.writerow(['v'] + vertex)

    # 法線ベクトルデータを書き出す
    for normal in vertex_normals:
        writer.writerow(['vn'] + normal)

    # テクスチャ座標データを書き出す
    writer.writerow(['Type', 'U', 'V'])
    for tex_coord in texture_coords:
        writer.writerow(['vt'] + tex_coord)

    # 面データを書き出す
    writer.writerow(['Type', 'Vertex1', 'Vertex2', 'Vertex3'])
    for face in faces:
        writer.writerow(['f'] + face)

print("OBJファイルの全てのデータがCSVファイルに書き出されました。")

これをVSCodeなどで実行することでcsvファイルが得られます。

以上でExelで読み込むことができました。これによって肉眼によるデバッグが可能になりました。

 本日は以上です。