LDraw + Unity。 レゴの生成方法

来てすべて! 私の名前はグリシャで、CGDevsの創設者です。 休日はすぐそこにあります。誰かがすでにクリスマスツリーを飾り、みかんを食べて、新年の気分でいっぱいです。 しかし、今日はそれについてではありません。 今日は、LDrawと呼ばれる素晴らしいフォーマットと、私が実装してOpenSourceにアップロードしたUnityのプラグインについてお話します。 いつものように、記事へのプロジェクトとソースコードへのリンクが添付されています。 私と同じようにレゴが好きなら、猫にようこそ。







LDrawフォーマット



LDrawとは何ですか? LDrawは、ユーザーがLEGOモデルとシーンを作成できるようにするLEGO CADプログラムのオープンスタンダードです。 一般に、LDrawを視覚化できるさまざまなプログラムとプラグインがあります(たとえば、Blenderのプラグインがあります)。



形式自体は十分に文書化されており、その最新バージョン、つまり1.0.2について説明します。



LDrawは、ファイルをUTF-8エンコードで作成する必要があるテキスト形式です。 この形式でサポートされるファイルには、拡張子ldr、dat、またはmdpが必要です。 ファイルの各行は、特定の機能を担当する個別のコマンドです。



フォーマットの重要な詳細は右手座標系です(Yは上に向けられています)-ユニットのコンテキストで後ほど詳しく説明します。また、フォーマットが再帰的であるという事実(ほとんどのファイルには他のファイルの指示が含まれます)。







LDrawコマンド



一般に、この情報は公式のドキュメントにありますが、Unityのコンテキストで少し見てみましょう。 合計で、LDraw形式は6種類のコマンドをサポートしています。



0. コメントまたはメタコマンドは、プラグインではほとんど触れない特別なコマンドです。 例: 0 !META command additional parameters







1. ファイルにリンクします 。 実際、最も統合が難しく、興味深いチームです。 1 colour xyzabcdefghi file



ように見えます。パラメーターはTRSマトリックスです(TRSの詳細については、この記事を参照してください )。 の形での統一の文脈で



 / adg 0 \ | beh 0 | | cfi 0 | \ xyz 1 /
      
      





2. -Unityの場合は使用されません。CADシステムで特定の色のエッジを強調する必要があります。



3.4。 三角形と正方形 。 コマンドは非常に簡単ですが、1つの重要なニュアンスがあります。LDraw形式は3Dモデリング用に設計されていないため、三角形と四角形のバイパスは標準化されていません。 これは重要です。ユニットは、三角形のラウンドに応じて、計算された法線の方向と、三角形のどちらの側が背面で、どちらが前面であるかを決定するためです(描画とカリングにも重要です)



コマンド例:

三角形3 colour x1 y1 z1 x2 y2 z2 x3 y3 z3





正方形4 colour x1 y1 z1 x2 y2 z2 x3 y3 z3 x4 y4 z4







5. オプション行 -使用されません。







LDrawの色



レンダリングを担当するほとんどのチームでわかるように、色はコマンドの種類の直後になります。 色は、これら2つの記事www.ldraw.org/article/299.htmlおよびwww.ldraw.org/article/547.html詳しく記載されていますが、実装中に遭遇した機能について話しましょう 。 ここで、形式といわゆる「スコープ」形式についてもう少し説明する価値があります。 この形式には3種類のファイルが含まれます。



DAT-実際、これらはパーツがすでに組み立てられている基本的な要素、またはいくつかの基本的なパーツです。 個々の詳細をレンダリングしない場合、それらに示される色は重要ではありません。 ほとんどの場合、公式標準の標準色があります。



LDRは色の点で最も興味深いものであり、スコープが役割を果たします。 このサイトは複雑な言語を説明していますが、ルールは非常に簡単です。 1つのldrから別のものを参照する場合、ルートで指定された色を無視します。



たとえば、ファイル30051-1の一部-X-wing Fighter-Mini.mpd(上の図のX-wing):



 1 71 -10 0 50 0 0 1 0 1 0 -1 0 0 60470a.dat 1 71 10 0 50 0 0 -1 0 1 0 1 0 0 60470a.dat 0 STEP 1 19 0 8 50 0 0 -1 0 1 0 1 0 0 4032b.dat 0 STEP 0 ROTSTEP 35 55 0 ABS 1 19 0 -16 0 0 0 -1 0 1 0 1 0 0 3623.dat 1 72 0 -16 50 0 0 -1 0 1 0 1 0 0 3022.dat 0 STEP 1 72 0 -8 -70 1 0 0 0 1 0 0 0 1 30051 - Nose.ldr
      
      







すべてのdatファイルで、指定された色を考慮し、コマンドで1 72 0 -8 -70 1 0 0 0 1 0 0 0 1 30051-Nose.ldr -72を無視し、ファイル30051-Nose.ldrの値を使用します。



MDPはモデルファイルです。ほとんどの場合、複数のldrファイルの説明が含まれています。 色に関しても、それほど重要ではありません。 解析時に考慮する唯一のことは、 FILEメタコマンドです。







LDrawのモデル



LDrawフォーマットの最大の利点は、彼がレゴファンの中に多くのファンを持っていることです。 多くの興味深いキットが公式ウェブサイトomr.ldraw.orgにありますが、これに加えて、多くのキットが別のフォーラムにあります。



フォーマットについて説明しましたが、Unityのプラグインについて少し説明します。







Unityのプラグイン



プラグインは、LDrawファイルに基づいて3Dモデルを生成する機能を提供します。 記事の写真で結果を見ることができます。 重要:デバイスが弱い場合は、Demoフォルダーのミニシーンのみを開くことをお勧めします。 モデルは最適化されておらず、常に背面を生成します。



それでは、実装について少し話しましょう。 現時点では、上記のほとんどがサポートされています。



おそらく最も重要な機能の1つは、異なる座標系です。 問題は、形式では右手座標系であり、Unityでは左手です。 これは、本質的に、すべてのターンとTRSマトリックスが正しく機能しないことを意味します。 負のYは簡単にビートになります。Vector3.upに関連するすべての座標を反映し、必要な座標を取得します(-1で乗算)。 しかし、TRSマトリックスの場合、すべてがより複雑です。 フォーマットは再帰的であるため、Matrix.Identityはどこでも反射マトリックスになり、各ネストはモデルをY軸に沿って反映するため、マトリックスを反映することは単に不可能です(正のスケールを維持する場合)。 これまでのところ、負のスケールを許可するという形で誤った決定に至りました。これは将来のバージョンでやり直す必要があります。



2番目の機能は、三角形の向きです。 四角形の場合、三角形は一方向に見えることがわかります。



正方形の準備コード
 public override void PrepareMeshData(List<int> triangles, List<Vector3> verts) { var v = _Verts; var nA = Vector3.Cross(v[1] - v[0], v[2] - v[0]); var nB = Vector3.Cross(v[1] - v[0], v[2] - v[0]); var vertLen = verts.Count; triangles.AddRange(new[] { vertLen + 1, vertLen + 2, vertLen, vertLen + 1, vertLen + 3, vertLen + 2 }); var indexes = Vector3.Dot(nA, nB) > 0 ? new int[] {0, 1, 3, 2} : new int[] {0, 1, 2, 3}; for (int i = 0; i < indexes.Length; i++) { verts.Add(v[indexes[i]]); } }
      
      







しかし、ここでは、形式に基づいて、原則としてどの方向に三角形を向けるべきかを決定することは明白です-重要な作業です。 このため、両方の側が常に生成されます。



さらに、形式が再帰的であるという事実により、Unity階層システムはこれまでにないほど便利になりました。



2つの方法で再帰を使用して、必要なメッシュを生成し、TRSを適用します(実装は前の記事で確認できます)。したがって、必要なすべてのオフセットを便利な形式で取得します。



ステージでモデルを生成する方法
 public class LDrawModel { public GameObject CreateMeshGameObject(Matrix4x4 trs, Material mat = null, Transform parent = null) { if (_Commands.Count == 0) return null; GameObject go = new GameObject(_Name); var triangles = new List<int>(); var verts = new List<Vector3>(); for (int i = 0; i < _Commands.Count; i++) { var sfCommand = _Commands[i] as LDrawSubFile; if (sfCommand == null) { _Commands[i].PrepareMeshData(triangles, verts); } else { sfCommand.GetModelGameObject(go.transform); } } if (mat != null) { var childMrs = go.transform.GetComponentsInChildren<MeshRenderer>(); foreach (var meshRenderer in childMrs) { meshRenderer.material = mat; } } if (verts.Count > 0) { var visualGO = new GameObject("mesh"); visualGO.transform.SetParent(go.transform); var mf = visualGO.AddComponent<MeshFilter>(); mf.sharedMesh = PrepareMesh(verts, triangles); var mr = visualGO.AddComponent<MeshRenderer>(); if (mat != null) { mr.sharedMaterial = mat; } } go.transform.ApplyLocalTRS(trs); go.transform.SetParent(parent); return go; } } public class LDrawSubFile : LDrawCommand { public void GetModelGameObject(Transform parent) { _Model.CreateMeshGameObject(_Matrix, GetMaterial(), parent); } }
      
      







その結果、次のような美しい視覚化が得られます。











詳細については、Githubリポジトリをご覧ください。



一般に、プラグインの開発には多くのアイデアがあります。次のような機能を紹介します。



  1. いくつかの形状を滑らかにする
  2. 前面生成のみ
  3. モデルを作成してLDraw形式に戻す
  4. 表面下散乱を伴うプラスチック用のクーラーシェーダー(および適切なマテリアルセット全般)
  5. ライトマップのUVのラップ解除
  6. モデルの最適化(現在、それらのほとんどは500k +で構成されており、たとえばエッフェル塔のモデルは280万ポリゴンです)


しかし現時点では、このプラグインを使用すると、Unity3dでLegoのモデルを使用できます。これは非常に便利です。 (記事のすべての画像はプラグインを使用して作成されました)すべてのプロジェクトコードは MITライセンスの下でレイアウトされていますが、LDrawリソース上の特定のモデルのライセンスを確認することをお勧めします。



ご清聴ありがとうございました。あなた自身のために何か新しいことを学んだことを願っています。フォーマットとプラグインに興味があります! 時間があれば、私はそれを開発し続け、この困難な問題を手伝って喜んでいます。



All Articles