点群OBJアップロードで未対応曲面命令が問題になる理由
点群OBJをクラウド上の閲覧環境や業務用の管理システムへアップロードすると、拡張子が.objであっても、読み込みが途中で止まったり、未対応命令や構文エラーが表示されたりすることがあります。OBJはポリゴン面だけの形式ではなく、点、線、面に加えて、自由曲線や自由曲面も記述できるためです。実際の対応範囲は読込先ごとに異なり、一般的なポリゴン対応と自由曲面対応は同じではありません。([loc.gov][1])
OBJでは、vが幾何頂点、vtがテクスチャ座標、vnが法線、vpが自由曲線や自由曲面で使うパラメーター空間の頂点を表します。要素としては、点のp、線のl、面のf、空間曲線のcurv、パラメーター空間上の二次元曲線のcurv2、自由曲面のsurfがあります。厳密には、vは頂点データの定義であり、点要素はpで表します。ただし、点群向けの一部の読込環境はvだけを点として表示するため、点群OBJの実運用では読込先独自の解釈も確認が必要です。([Gist][2])
自由曲面を扱わないアップロード先では、surfだけでなく、その前後に現れる自由形状関連の命令で処理が止まることがあります。一方で、これらの命令はOBJの仕様上ただちに不正というわけではありません。正しいOBJであっても、読込先が実装していない命令を含むために互換性の問題が起きます。
対処で特に注意したいのは、自由曲面の属性命令と本体命令を同じものとして扱わないことです。cstype、deg、bmat、stepは状態を設定する命令で、一度設定されると、別の値へ変更されるまで後続の自由曲線や自由曲面へ適用されます。これに対し、curv、curv2、surfからendまでが個々の自由形状要素の本体です。したがって、単純にcstypeから次のendまでを一つのブロックとして削除すると、後続の別要素に必要な属性まで消すおそれがあります。([Gist][2])
また、曲面のトリミング境界は、trimやholeの行だけで完結するとは限りません。これらは先に定義されたcurv2要素を番号で参照します。二つの曲面の接続を表すconは、曲面本体の内側ではなく、曲面とcurv2の参照関係を持つ独立した接続命令です。曲面を安全に除去するには、行の連続範囲だけでなく、要素間の参照関係も確認しなければなりません。([Gist][2])
安全な修正は、元ファイルを複製し、未対応命令と依存関係を調べ、削除かポリゴン化かを決め、対象要素を除去した後に整合性を検証する流れで進めます。アップロード成功だけを目的にせず、必要な点群、ポリゴン、設計形状が残っていることまで確認するのが重要です。
OBJに含まれる曲面命令の基本
OBJの各論理行は、先頭の識別子と引数で構成されます。一般的な識別子には、v、vt、vn、vp、p、l、f、o、g、s、mtllib、usemtlなどがあります。自由曲線や自由曲面に関係する主な識別子は、属性命令、要素命令、本体命令、接続命令の四つに分けて考えると整理しやすくなります。
属性命令はcstype、deg、bmat、stepです。cstypeはBezier、B-spline、Cardinal、Taylor、basis matrixなどの曲線・曲面型と、必要に応じて有理形式を指定します。degは曲線のu方向、曲面のu方向とv方向の次数を設定します。bmatとstepはすべての曲面に共通する近似設定ではなく、basis matrix型で使う基底行列と制御点の進み幅です。([Gist][2])
要素命令はcurv、curv2、surfです。curvは幾何頂点vを参照して三次元空間の曲線を定義します。curv2はパラメーター空間頂点vpを参照して、曲面上のトリミングなどに使う二次元曲線を定義します。surfは幾何頂点を制御点として自由曲面を定義します。
本体命令は、要素命令の後からendまでに置かれるparm、trim、hole、scrv、spなどです。parmはパラメーター値またはノットベクトルを設定します。trimは外側のトリミングループ、holeは内側の穴、scrvは三角形分割に反映させる特別な曲線、spは特別な点を指定します。仕様上、これらの本体命令はcurv、curv2、surfとendの間でだけ意味を持ちます。([Gist][2])
conは本体命令ではありません。二つの曲面と、それぞれの曲面上にあるcurv2を参照して接続関係を記述します。曲面を削除した後に、その曲面を参照するconを残すと参照先が失われるため、削除または再構成が必要です。([Gist][2])
ここで重要なのが状態設定の範囲です。たとえば、cstype bsplineとdeg 3 3の後に複数のsurfが続く場合、属性命令が一度しか書かれていなくても、後続の複数曲面へ適用されることがあります。最初の曲面だけを消すために属性命令まで削除すると、残した二つ目の曲面が解釈できなくなる可能性があります。
反対に、ファイル内の自由曲線と自由曲面をすべて除去し、点やポリゴンだけを残す方針であれば、使われなくなった属性命令も削除候補になります。ただし、curvやcurv2を一部残す場合は、その要素に必要な属性が直前またはそれ以前から有効になっているかを確認します。
似た識別子を混同しないことも大切です。sはスムージンググループで、surfとは別命令です。vとvpも別の頂点リストです。curvとcurv2は参照する頂点の種類と用途が異なります。文字列の前方一致だけで削除すると、必要な命令まで消すおそれがあります。
コメントと継続行にも注意します。OBJでは#で始まるコメント行が使われます。また、長い命令は行末のバックスラッシュで次行へ継続できるため、物理的な一行だけを見て命令を判定すると、長いsurfやbmatを途中で切断する可能性があります。大容量ファイルを自動処理するときは、物理行ではなく継続を結合した論理行として判定する設計が安全です。([loc.gov][1])
ステップ1 ファイルを複製して未対応命令を特定する
最初に、元のOBJを直接編集せず、読み取り専用の原本と作業用の複製を分けます。ファイル名には、原本、調査用、曲面除去後、検証済みなどの状態を付けます。修正日時、元の容量、ハッシュ値を記録しておくと、似た名前のファイルを取り違えにくくなります。
次に、アップロード時のエラー内容を保存します。命令名、行番号、解析段階が表示される場合は記録します。ただし、最初に表示された命令だけが唯一の原因とは限りません。解析が最初の未対応命令で停止している場合、その命令を除去した後に別の未対応命令が見つかることがあります。
ファイル全体から先頭識別子を集計し、v、vp、p、l、f、curv、curv2、surf、parm、trim、hole、scrv、sp、end、conなどの件数を確認します。行頭の空白やタブを除外し、コメント行と継続行を正しく扱います。単に本文中の文字列を検索するだけでは、コメント内の語や材質名を誤検出する可能性があります。
その後、各curv、curv2、surfから対応するendまでを一つの本体として確認します。本体の中にあるparm、trim、hole、scrv、spを記録し、曲面がどのcurv2を参照しているかを調べます。trimやholeの参照番号は頂点番号ではなく、先に定義された二次元曲線要素の番号です。
conがある場合は、削除候補の曲面やcurv2が参照されていないかを調べます。conは曲面本体の外側にあるため、surfからendまでを削除するだけでは残ります。参照先を失ったconは、読込先によって構文エラーや未解決参照の原因になります。
属性命令の有効範囲も一覧にします。どのcstype、deg、bmat、stepが、どの後続要素に適用されているかを確認します。属性命令は要素ごとに必ず繰り返されるわけではありません。削除対象の直前にあるからといって、その曲面専用とは限りません。
曲面の制御点にはv、二次元曲線の制御点にはvpが使われます。削除対象が参照する頂点番号を抽出し、それらがf、l、p、残すcurv、残すsurfからも参照されていないかを確認します。この段階では頂点行を削除せず、参照関係を把握するだけに留めます。
小さな切り分け用OBJも有効です。ただし、vだけを抜き出したファイルは、厳密なOBJでは点要素を持たないため、読込先が裸の頂点を点群として扱うかどうかで結果が変わります。必要に応じてpを付けた版とvだけの版を作り、アップロード先の点群解釈を確認します。
ステップ1の完了条件は、未対応命令の名前だけでなく、削除対象となる自由形状要素、その本体範囲、参照するvとvp、依存するtrimやcon、共有される属性命令まで把握できていることです。
ステップ2 曲面を削除するかポリゴン化するか決める
未対応命令を特定したら、曲面を失ってもよいのか、形状を別表現で残す必要があるのかを判断します。点群の閲覧だけが目的で、自由曲面が補助的な設計要素であれば、曲面と関連曲線を除去する方針を選べます。
一方、曲面が設計面、施工面、比較対象、完成形状を表している場合は、単純削除では情報を失います。その場合は、元の作成環境で自由曲面を三角形または四角形のポリゴンへ変換し、vとfを中心とする構成で再出力します。自由曲面対応が限定的でも、ポリゴン面は広く対応される傾向があります。([loc.gov][1])
ポリゴン化では分割密度を利用目的に合わせます。粗すぎると曲率の大きい部分で形状誤差が増え、細かすぎると頂点数、面数、容量、解析時間が増えます。見た目の確認用と、施工照合や断面評価用では、求める許容差が異なります。
変換後は、元のsurfやcurv2が残っていないか確認します。ソフトウェアによっては、ポリゴン面と元の自由曲面を同時に出力する場合があります。ポリゴン化しただけで未対応命令が自動的に消えるとは限りません。
削除を選ぶ場合は、対象を三段階に分けます。第一は削除するsurf本体、第二はその曲面だけに使われるcurv2本体、第三は削除対象を参照するconです。属性命令は共有状態であるため、自由形状要素が残るかどうかを見て個別に判断します。
曲面本体を削除しても、制御点のvとトリミング曲線用のvpは自動的には消えません。読込先が裸のvを点として表示する場合、曲面用の制御点が不要点として見える可能性があります。一方、vpは通常の三次元点群として表示される頂点ではありませんが、未対応命令として扱われる可能性は読込先によって異なります。
不要頂点を削除する場合は、参照の再構築が必要です。OBJの正の参照番号は各頂点リスト内の順序に基づくため、途中のvやvpを削除すると後続番号が変わります。f、l、p、curv、curv2、surfなどをすべて更新しなければなりません。最初の修正では頂点を残し、曲面エラーが解消した後に未使用頂点の整理を別工程で行う方が安全です。
元データへ戻れる場合は、テキスト編集より再出力を優先します。元の作成環境では、点群、設計曲面、補助曲線、メッシュの役割が分かれているため、必要な要素だけを選んで出力しやすくなります。
ステップ2の完了条件は、削除かポリゴン化かが決まり、消える要素、残る要素、必要な精度、頂点整理を後工程に回すかどうかを説明できる状態です。
ステップ3 関連する曲面命令をまとまりで除去する
削除方針が決まったら、作業用OBJから対象要素を除去します。基本単位はsurfから対応するendまでです。曲面が参照するcurv2も不要で、ほかの曲面やconから参照されていない場合は、各curv2から対応するendまでを別の要素として削除します。
ここで、cstypeからendまでを機械的に削除してはいけません。cstype、deg、bmat、stepは後続要素へ継続して効く状態命令です。削除対象の直前にあっても、後ろに残す自由曲線や自由曲面が同じ設定を利用している場合があります。属性命令を削除するのは、その設定を必要とする要素が残らないことを確認した後です。([Gist][2])
反対に、自由曲線と自由曲面をすべて除去する方針なら、未使用になった属性命令、vp、conも整理対象になります。ただし、vpを削除する場合も、残すcurv2がないことを確認します。
対象曲面を参照するconは、曲面本体とは別に削除または再構築します。片方の曲面だけを削除してconを残すことはできません。二つの曲面をポリゴン化した場合も、ポリゴン面にはOBJ自由曲面のconをそのまま適用できないため、通常は接続命令を除去します。
識別子の判定は完全一致で行います。sとsurf、vとvp、curvとcurv2を区別します。コメント行は削除対象から除外し、行末のバックスラッシュによる継続を結合してから、論理行の識別子を判定します。
大容量OBJでは、ファイル全体をメモリーへ読み込まず、ストリーム処理で新しいOBJへ書き出します。ただし、依存関係を調べずに一回の読み流しだけで安全に削除するのは難しい場合があります。最初の走査で要素番号、参照関係、属性状態を収集し、二回目の走査で削除する二段階処理が確実です。
処理中は、現在の要素がcurv、curv2、surfのどれか、対応するendへ到達したか、継続行の途中かを管理します。仕様上、本体の途中に自由形状以外の一般命令を置くことは想定されていないため、予想外の識別子が現れた場合は自動削除を続けず、対象箇所を記録して確認します。([Gist][2])
出力先は一時ファイルにし、処理が最後まで完了した後に正式名へ変更します。入力行数、出力行数、削除した要素数、削除した識別子別件数、入力容量、出力容量を記録します。元ファイルへ上書きしないことが重要です。
文字コードと改行コードは、アップロード先の条件に合わせて維持または明示的に統一します。オブジェクト名、グループ名、材質名に非ASCII文字が含まれる場合は、読込先の対応状況を確認します。改行処理を誤って二つの命令を連結すると、別の構文エラーが発生します。
このステップでは、曲面削除と未使用頂点の詰め直しを同時に行わない方が原因を切り分けやすくなります。まず自由形状関連の最小変更版を作り、その後に容量削減や頂点整理を行います。
ステップ4 整合性を検証して再アップロードする
修正版を作成したら、未対応命令が消えたかだけでなく、OBJ全体の整合性を確認します。最初に識別子を再集計し、削除予定だったsurf、curv2、trim、hole、conなどが残っていないかを確認します。
自由形状要素を一部残した場合は、各curv、curv2、surfに対応するendがあり、必要なparmと属性設定が有効であることを確認します。属性命令を削除した結果、残した曲線や曲面にcstypeやdegがなくなっていないかを調べます。
次に、con、trim、hole、scrvが参照する要素番号を検証します。削除によって自由曲線や曲面の要素番号が変わる場合は、残す参照を更新しなければなりません。すべての自由形状を削除するなら、これらの参照命令も残さない方針が明確です。
ポリゴン面を残す場合は、fの幾何頂点、テクスチャ頂点、法線の参照範囲を確認します。正の番号は各リストの先頭から数え、負の番号はその要素位置より前に定義された頂点を相対参照します。負の参照は仕様上可能ですが、読込先が対応していない場合があるため、互換性を優先するなら正の番号へ変換した試験版も用意します。([Gist][2])
点要素を使う場合は、pの参照番号も検証します。vだけを点群として扱う独自運用では、アップロード先の仕様に合わせて、p付きとvのみのどちらを標準にするか決めます。
処理前後でv、vt、vn、vp、p、l、fの件数を比較します。曲面命令だけを除去したのにvやfが大きく減っていれば、削除範囲が広すぎる可能性があります。反対に、全自由形状を除去したのにsurfやcurv2が残っていれば、見落としがあります。
論理行の継続、改行、ファイル末尾も確認します。行末バックスラッシュを含む命令を途中で切っていないか、二つの命令が一行へ連結されていないか、出力が途中で停止していないかを調べます。
構文検査の後は、ローカルの表示環境で点群、面、色、座標、向き、縮尺、欠落範囲を確認します。曲面の制御点vを残した場合、読込先の実装によっては不要点として見えることがあります。遠方の制御点が残ると表示範囲が広がり、本体が極端に小さく見える場合があります。
テスト用領域へ再アップロードし、エラーの有無だけでなく、表示された点数、範囲、色、位置、形状を修正前後で比較します。エラーメッセージが別内容へ変わった場合は、最初の問題が解消し、次の問題が検出された可能性があります。
ステップ4の完了条件は、アップロード処理が終了し、必要な点群とポリゴンが正しい状態で保持され、削除した曲面に関連する未解決参照が残っていないことです。
曲面命令だけを削除しても直らない原因
未対応曲面命令を除去してもアップロードできない場合は、別の構造問題を切り分けます。代表的なのは、f、l、pが参照する頂点番号の範囲外、vtやvnの不一致、負の相対参照への非対応です。
途中のvを削除して正の参照番号を更新していない場合、面や線が別の頂点を参照したり、存在しない番号を参照したりします。未使用頂点の削除は、全参照を再構築できる処理で行う必要があります。
材質参照も確認します。mtllibが示す材質定義ファイルや、材質から参照される画像が同梱されていない場合、警告で済む環境もあれば、処理を中断する環境もあります。点群座標だけが必要なら、材質を外した試験版で切り分けます。
頂点色は標準仕様の中心機能ではなく、v x y z r g bのように座標の後ろへRGBを付ける慣習が広く使われています。読込先がこの拡張へ対応していなければ、列数の多いvを受け付けない可能性があります。座標だけの版と色付き版を比較します。([loc.gov][1])
一行が異常に長い場合は、継続行の解釈や、複数命令の連結を確認します。OBJは行末バックスラッシュによる継続を許すため、単純に物理行の長さだけで不正と判断せず、読込先が継続記法へ対応しているかも確認します。
数値に無効値、欠損、桁区切り、想定外の小数点表記が含まれていないかも確認します。座標や法線に非数値が混ざると解析できません。大きな実座標では、読み込み後の表示精度やローカル原点の扱いが別問題として現れることもあります。
ファイル容量や解析時間の上限も原因になります。曲面命令がなくても、頂点数や面数が大きすぎれば、通信、展開、サーバー側メモリー、変換時間の制限に達する可能性があります。点群分割や不要要素の除去は、曲面修正とは別の工程として検証します。
圧縮してアップロードする場合は、圧縮方式、内部階層、同梱ファイル名、文字コードを確認します。修正版と原本の名前が似ている場合は、選択したファイルの容量やハッシュ値を照合し、原本を再送していないか確認します。
原因切り分けでは、一度に曲面削除、頂点削減、座標変換、材質除去をまとめて行わないことが重要です。工程ごとに別ファイルを作り、エラーの変化を記録します。
大容量の点群OBJを安全に編集する方法
数百MBから数GB規模のOBJは、一般的なテキスト編集環境で開くと、検索や保存に大量のメモリーを使います。大容量ファイルでは、ストリーム処理と複数回走査を組み合わせる方法が適しています。
第一走査では、論理行を復元しながら識別子を集計し、自由形状要素の番号、開始位置、終了位置、属性状態、参照関係を記録します。第二走査では、その結果に基づいて対象要素だけを除外し、新しいOBJへ書き出します。
継続行を扱うため、物理行の末尾がバックスラッシュで終わる場合は次行と結合します。コメントや空行を保持するかは運用方針を決めますが、命令途中の改行を誤って切らないことが重要です。
削除処理では、現在の自由形状要素と対応するendを追跡します。要素番号を詰め直す必要がある場合は、旧番号から新番号への対応表を作り、trim、hole、scrv、conの参照を更新します。すべて削除する場合は、参照更新より関連命令の除去を選べます。
一時ファイルへ書き出し、正常終了後にファイル名を確定します。処理結果には、入力と出力の容量、行数、論理行数、識別子別件数、削除要素数、警告箇所を残します。
複数ファイルを一括処理する場合は、同じ書き出し元でも構造が同一とは限らないため、各ファイルを事前走査します。自由曲面が不要なファイルと、必要な設計面を含むファイルを同じ条件で削除しないようにします。
処理前後のハッシュ値を保存し、原本と修正版を別フォルダーで管理します。バックアップは同じ保存先だけに置かず、復元できる場所へ保管します。
小さな試験ファイルでロジックを確認することも有効です。ただし、試験版では自由形状の参照関係を保ちます。単に先頭数千行だけを切り出すと、参照先やendが欠け、元ファイルとは別のエラーになる可能性があります。
大容量OBJの編集では、速さより再現性を優先します。誰が同じ処理を行っても同じ結果になるよう、削除条件と検証条件を記録します。
アップロード前に確認したい運用チェック
未対応曲面命令の再発を防ぐには、アップロード前の検査を標準化します。最初に、データの用途を点群、ポリゴンメッシュ、設計曲面、または混在データのどれかに分類します。
点群だけが必要なら、自由曲面、自由曲線、法線、UV、材質、テクスチャ、ポリゴン面を含める必要があるかを見直します。必要な要素が少ないほど構造は単純になります。
識別子集計では、vだけでなくvp、p、curv、curv2、surf、conも確認します。点群用として出力したファイルに自由形状命令が含まれていれば、書き出し対象や設定を再確認します。
ただし、自由形状命令があるだけで不良とは判断しません。設計曲面を含める目的があり、アップロード先が対応していれば正しい構成です。用途と対応仕様を組み合わせて判定します。
頂点数、点要素数、面数、線数、自由曲線数、自由曲面数、ファイル容量を記録し、過去の正常ファイルと比較します。急激な面数増加やvpの追加は、書き出し設定が変わった兆候になります。
参照番号、論理行、継続行、文字コード、改行、ファイル末尾も機械的に確認します。材質を使用する場合は、材質定義ファイルと画像の名前、階層、文字の大小を確認します。
圧縮アップロードでは、OBJ、材質定義ファイル、画像の配置を統一します。案件ごとに内部階層が変わると、参照やファイル検出の切り分けが難しくなります。
ファイル名には用途と処理状態を含めます。点群用、メッシュ用、自由曲面除去済み、ポリゴン化済み、座標変換済み、検証済みを区別します。
修正履歴には、削除した自由形状要素、削除したcon、属性命令の扱い、頂点数の変化、アップロード結果を記録します。正常に読み込めた命令構成を基準として保存すれば、次回の異常を早く検出できます。
外部から受領したOBJは、点群、メッシュ、自由曲面のどれを含むかを提供元へ確認します。推測だけで曲面を削除すると、必要な設計情報を失うおそれがあります。
点群OBJの再出力で問題を防ぐ考え方
元データから再出力できる場合は、OBJを直接修正するより、アップロード先に合った構造で書き出し直す方が安全です。点群用途なら、計測点と必要な色情報だけを選び、自由曲面や補助曲線を除外します。
アップロード先が点要素pを必要とするか、vだけを点群として扱うかを小さな試験データで確認します。成功した構成を標準設定として記録します。
点群とメッシュを両方使う場合は、一つのOBJへ混在させる方法だけでなく、点群用とメッシュ用に分ける方法も検討します。別ファイルにすると、自由曲面や材質の問題を切り分けやすくなります。
自由曲面を残す必要がある場合は、読込先が対応する形式へポリゴン化します。分割密度は業務上の許容差から決め、変換後に元のsurfやcurv2が残っていないかを実ファイルで確認します。
座標の単位と基準位置も確認します。OBJの座標値だけでは単位を一律に保証できないため、書き出し元と読込先の前提を合わせます。大きな実座標を扱う場合は、表示精度とローカル原点の運用を決めます。
小数桁を減らすと容量を抑えられますが、過度な丸めは位置関係や計測結果へ影響します。表示用と測量・施工確認用で同じ精度設定にする必要はありません。
色情報を使う場合は、頂点色の拡張形式か、材質とテクスチャを使う形式かを確認します。読込先が対応する方式へ合わせます。
再出力後は、識別子、件数、容量、参照範囲、座標、色、表示結果を検証します。設定画面で曲面を除外したつもりでも、実ファイルへ残る可能性があるため、出力結果の検査を省略しません。
正常にアップロードできた設定は、出力対象、点要素の形式、面の有無、ポリゴン化精度、単位、小数桁、色、材質、座標基準を含めて手順化します。
まとめ
点群OBJアップロード時の未対応曲面命令は、OBJ自体が不正だからではなく、自由曲線や自由曲面を含む正しい記述を、読込先が実装していないために起きることがあります。
修正では、cstype、deg、bmat、stepを個々の曲面本体と混同しないことが重要です。これらは後続要素へ効く状態設定であり、curv、curv2、surfからendまでが個々の要素本体です。
また、trimやholeは先に定義されたcurv2を参照し、conは二つの曲面と曲線の接続関係を持ちます。surfの行だけを削除しても、依存する曲線や接続命令が残る可能性があります。
ステップ1では原本を複製し、識別子、属性状態、要素本体、vとvp、参照関係を特定します。ステップ2では曲面を削除するかポリゴン化するかを決めます。ステップ3では対象のsurf本体、不要なcurv2本体、依存するconを整理し、共有属性は必要性を確認して扱います。ステップ4では参照番号、件数、継続行、表示結果、アップロード結果を検証します。
曲面命令を除去しても直らない場合は、頂点参照、材質、頂点色、数値形式、容量、圧縮構成、座標精度を別問題として切り分けます。
再発防止には、点群用と設計形状用の出力を分け、アップロード先がvだけの点群を扱うかpを必要とするかを確認し、正常な書き出し設定を標準化することが有効です。
現場で取得した点群を効率よく共有し、取得から確認までの工程を整理したい場合は、LRTK Phoneを活用した点群運用も選択肢になります。