Foliage Modeler

学習用にAgentCodingで生成したデモです

枝と葉を含む塊を、木に取り付ける部品として制作する実験です。クラスごとに共通のIBを持ち、形状の異なるバリエーションをStorage Bufferへ保持してMassInstance描画します。

v03 Rendererでは同じ生成処理を使い、地形へのGPU配置・描画を確認できます。この画面の配置はCPUで行い、幹LODは手動選択です。枝葉は4段LODを手動選択でき、RendererではGPUが自動選択します。

実行ボタンで開始します

ドラッグ:回転 · ホイール:拡大・縮小

メッシュ未生成

操作

「実行」で開始します。ドラッグで回転、ホイールで拡大・縮小、「正面」「斜め」「上面」で視点を切り替えます。

初期表示は単木です。主幹・主要枝を管メッシュとして生成し、骨格上の取り付け位置へ枝葉を配置します。「枝葉を表示」をOFFにすると幹だけを確認できます。

  • プレビューを「複数樹木・Instanced Draw」にすると1〜100本を配置できます。ユニーク形状数は1〜4で、シードを変えて作った形状を順番に再利用します
  • 「幹LOD」で3段階を手動比較できます。枝葉のLOD・距離による自動選択は未実装です
  • 樹形プリセットを選ぶと、主要枝数と骨格・枝葉配置の初期値を読み込みます。その後は全項目を編集できます
  • 「骨格・枝葉配置のパラメータ」を開くと、発生高さ・方位・分岐角・長さ・曲がり・下垂などを調整できます
  • 主要枝はどのプリセットでも0〜3本。円錐形の初期値は0本ですが、追加することもできます
  • 「枝葉シルエット」は幹と枝葉を白、背景を黒で表示します。中心線もOFFにするとメッシュの輪郭を確認できます
  • 樹冠幅は部品のスケールを決める基準値です。枝葉の姿勢や主幹の曲がりによって外形の幅は変わります
  • 枝葉クラスを指定すると同一クラスで配置、「全クラス」では上ほど小さな部品へ配分します。距離によるLODではありません
  • バリエーションは固定するか、4種類を取り付け位置ごとに選べます
  • プレビューを「枝葉単体」にすると、4種類の比較や単独形状の調整へ戻れます
  • シード、枝の広がり、葉の開き、奥行き、葉の大きさ、識別色は両プレビューで共有します
  • 枝葉単体の目印の幹・塊のスケールは樹木配置には使いません

ビュー下に表示中の樹木の合計Tri数・1本あたりの平均、幹のTri数、ZPrePass・Forward・骨格ライン・TonemappingのDraw数を表示します。Tri数はモデルの形状数で、複数パスによる描画回数や全画面ポストプロセスは含みません。枝葉単体モードでは、目印の幹を含む表示モデル全体を集計します。

形状や樹高を大きく変えて画面から出た場合は「全体を表示」で合わせます。

枝葉の構築

枝の付け根を少しずつずらし、プリセットごとに横方向・奥行き・高さを変えています。以前の枝先に集中する配置から、枝の途中から葉を分散して付ける配置へ変更しました。

葉1枚は平面のひし形4頂点・2三角形です。葉の付け根を所属する枝の上に置き、長軸の方向と葉面のロールを別に決めます。全ての葉が同じ上向き面にならないよう傾きを変え、正面と上面のどちらからも輪郭を確認します。被覆率や性能の最適化を実測したものではなく、低Prim予算で形を詰める段階です。

クラス枝の区間数枝のtri葉の枚数葉のtri合計tri頂点数/バリエーション
小21210203252
中424204064104
大42452104128232

小クラスは根元から2本の枝を開く構成、中・大は主枝1区間と小枝3区間です。枝は三角断面の側面のみで、1区間6三角形。端面や厳密な分岐接合は省略しています。小クラスは葉が10枚しかないため、密な樹冠をそのまま表せるものではありません。各クラスは部品の規模・構造の違いであり、LODではありません。

枝葉LOD

規模クラスを切り替えてLODにするのではなく、それぞれのクラス・バリエーションからLOD0〜3を作ります。同じクラス・同じLODの接続は全バリエーションで共通です。

規模クラスLOD0LOD1LOD2LOD3
小32tri16tri6tri4tri
中64tri32tri16tri6tri
大128tri64tri32tri12tri

LOD0の葉の位置と向きを使い、空間的に離れた代表葉を順に選びます。各代表へ近い葉を割り当て、その重心と広がりから位置・寸法・平均色を求めます。拡大はLODごとの上限とLOD0の外接範囲内に制限します。細い枝も段階的に減らします。

低LODのポリゴンは個別の葉ではなく葉群の代理です。輪郭とボリューム感を近似する初版で、全方向からの輪郭一致や枝への接続は保証しません。アルファテストや遷移モーフは使っていません。正面・斜め・上面やシルエット表示で比較できます。

共有IBとバリエーションStorage VB

主幹・主要枝へ再利用する枝葉の塊を取り付けるBranch cluster Treeの構成です。同じトポロジの形状違いをInstanced Drawへまとめる仕組みは、Rendererの技術説明にも記載しています。

return (placement.variation.x * leafClass.verticesPerVariation + vertexIndex) * 9u;

固定機能のuint16共有IBが与えるvertexIndexに、配置ごとのバリエーションの先頭を足します。枝も葉も同じStorage VBへ展開し、位置・法線・リニアRGBの9 float、36 bytes/頂点で保持します。

pass.drawIndexed(resource.count, resource.instances);

同じ規模クラス・同じLODの枝葉を1 Draw/パスにまとめます。樹木では取り付け数やバリエーション数が増えても、枝葉が単一クラスなら、幹1 Draw+枝葉1 DrawをZPrePassとForwardで実行し、計4 Drawです。中心線は任意の1 Draw、Tonemappingは別の1 Drawです。樹木本数や同じトポロジ内の形状数を増やしてもDraw数は変わりません。枝葉単体では目印のマーカーが各パスに1 Draw加わります。

枝葉部品の形状変更は既存のStorage VBへ上書きします。木の骨格・幹形状を変えると木アセットを再生成してGPU資源を置き換えますが、配置本数・向き・枝葉や中心線の表示だけを変える場合は、幹の共有IBとStorage VBを維持します。

樹形と骨格

樹形骨格と配置の方針
円錐形 / Conical一本の主幹に沿って配置し、上へ向かって枝葉を小さくする
卵形 / Oval比較的高い主幹から主要枝を伸ばし、中ほどの葉群を大きくする
球形 / Rounded短めの主幹から主要枝を広げ、主幹上部にも葉群を配る
傘形 / Umbrella高い位置から横へ主要枝を伸ばし、上部へ葉群をまとめる
杯形 / Vase低い位置で分岐し、主要枝を上へ開く。中央の空きを残す
しだれ形 / Weeping主要枝を一度持ち上げてから下げ、枝葉も下向きに配置する

形状を作るための初期プリセットで、樹種の成長を再現するシミュレーションではありません。枝葉の形や配置数によっては樹冠が分かれた塊に見えるため、中心線を消して正面・上面・斜めから品質を確認します。

tree-model.tsが主幹の13点と、主要枝ごとの9点の中心線を生成します。各主要枝は親IDと親線分上の接続位置を持ちます。主要枝の根元は親上に置き、枝葉の取り付け点も所属する骨格枝の線分上に置きます。主要枝0本でも生成できますが、杯形・しだれ形等の特徴は分岐がある場合のほうが明確です。

樹形名による生成処理の分岐はありません。プリセットは共通パラメータの値の組であり、読み込んだ後に値を編集すると、そのまま別の樹形を作れます。シードと全パラメータが同じなら、同じ骨格・配置を生成します。

パラメータ役割
主幹の高さ比樹高の基準に対する主幹の長さ。主要枝はこの主幹から伸びる
発生開始・終了高さ、偏り主幹上の0〜1の区間へ主要枝を配分。偏り1は均等、1超は低い側、1未満は高い側へ寄せる
開始方位角、方位角の間隔上から見た主要枝の配置。0°は+X、90°は+Z方向
分岐角、長さ比、高い位置での短縮上向きからの角度と、樹高を基準とする長さ。高い位置の枝ほど短くする量も独立して調整
曲がる角度、開始位置、先端の下垂接線の方向変化を8区間で積分。下垂は先端に近づくほど強くする幾何的な補正で、物理シミュレーションではない
不規則さ方位・分岐角・長さ・枝葉サイズに加えるシード依存の揺らぎ
主幹への枝葉配分、配置開始・終了位置枝葉の取り付け数を主幹と主要枝へ分配し、各枝上の配置区間を指定
枝葉サイズ・下部/中部/上部配置区間の始点・中点・終点で部品サイズを指定し、間を線形補間
枝葉の上向き補正骨格の接線と外向き方向から決めた姿勢へ、上下方向の補正を加える

発生高さは主幹上の位置、配置位置はそれぞれの骨格枝上の位置です。開始値は終了値以下にします。主幹への配分は主要枝0本の場合には使わず、すべて主幹へ配置します。樹高・樹冠幅は生成の基準であり、曲がりや枝の伸長、枝葉の張り出しを含む最終的な外接寸法ではありません。

Weber–Pennの幾何的な樹木生成にある分岐角・方位・長さ・曲がり等の考え方を参考にした簡略な構成です。論文のアルゴリズム全体を再実装したものではなく、骨格の再帰分岐や成長シミュレーションは行いません。

木インスタンスのデータ

枝葉のVB/IBを木ごとに複製する処理はありません。木は分岐骨格と、所属する骨格枝ID・線分・位置、クラス/バリエーションID、回転、一様スケールを持ちます。枝葉そのものの元データもCPUで保持します。

配置Storageは48 bytes/個です。位置とスケール16 bytes、単位Quaternion16 bytes、バリエーションIDと予約領域16 bytesを格納します。VSでは位置と法線を回転し、ZOnlyとForwardが同じ位置を使います。配置容量を超えたときだけバッファを拡張し、IBと形状Storage VBは維持します。

主幹・主要枝のメッシュ

wood-mesh.tsが骨格中心線をサンプリングし、円形断面を掃引します。断面フレームは接線間の最短回転で運び、根元半径と先細りから各リングの位置・法線を生成します。位置・法線・リニアRGBを36 bytes/頂点で保持する展開済み頂点方式です。VSで骨格曲線を毎回評価しません。

主幹と最大3本の主要枝は1メッシュに格納します。主要枝数とLODが同じ形状はuint16 IBを共有し、形状ごとの頂点を1本のStorage VBに連続格納します。クラス内ではどの形状も同じ頂点数・接続順序です。このプレビューでは同時に選ぶ主要枝数は共通で、異なる枝数のクラスを混在配置する機能は未実装です。

幹LOD円周分割主幹の区間数主要枝1本の区間数主要枝3本・端面込みTri数
08128640
1664264
2432104

LOD間で同じ骨格をサンプリングするので、葉の取り付け位置は変わりません。Modelerでの自動LOD・遷移モーフはありません。枝葉LODは幹LODと独立に選択します。

主要枝の根元は主幹の内部へ埋め込む交差管です。接合部は溶接しておらず、近距離での継ぎ目や、極端な太さ・曲がりによる自己交差は今後の品質課題です。各管の両端には独立法線の端面を作ります。

複数樹木のInstanced Draw

tree-preview.tsでN個の単木アセットを生成し、グリッドへ配置します。例えば4形状を100本配置しても、選択LODの幹データは共有IB 1個と、4形状分のStorage VBだけです。木の配置情報は48 bytes×100本です。VSはインスタンスの形状IDでStorage VBの先頭を選び、共有IBの頂点番号を加算します。幹はZPrePass・Forwardでそれぞれ1回のdrawIndexed(indexCount, instanceCount)です。

枝葉部品のVB/IBも共有します。ただし初版では、形状ごとのソケット情報をCPUで各木のワールド配置へ展開し、枝葉クラスごとに48 bytes/配置のStorageへ送ります。ソケットをGPUで二段階参照する方式やGPUカリング・Indirect生成にはまだ対応していません。

ユニーク形状は現在のパラメータを共通にしてシードだけを変えます。異なる樹形プリセットを同時に並べる機能はありません。表示中LODの幹頂点数・形状数・Storage VB容量・木配置容量をビュー下へ表示し、形状データが配置本数に比例して増えていないことを確認できます。

主幹のデバッグ表示

主幹と主要枝の中心線を橙色のline-listとしてForwardの後、HDRターゲットへ重ねます。深度テストを行い、枝葉に隠れる箇所は描かず、デプスへの書き込みもしません。OFFではライン用のDrawを実行しません。中心線表示のON/OFFは幹メッシュ・枝葉の配置・外接範囲を変えません。

骨格の分岐は一段で、主要枝から先の骨格分岐は未実装です。GPUカリング、Indirect引数生成、自動LOD、保存・読み込みは未実装です。

プレビュー描画

幹は不透明・背面カリング、枝葉は不透明・両面で描画し、discardを使いません。ZOnlyとForwardは位置計算を共有し、Reversed ZのZPrePassとEqual比較のForwardを通します。簡易Lambert照明をHDRへ出力し、別パスのACES近似とsRGB変換で表示します。静止時には連続描画しません。

ソース

直接表示