拡充ロードマップ
対応済みの種は草・ひまわり・クローバー・葦・小花・雑草・穀物・たんぽぽの 8 種です。ここでは、これを
四季の草花と樹木まで広げるまでの計画と、その過程で決めた設計上の線引きを
記録します。
計画は 1 つの PR にまとめず、下の表の単位で切ります。1 PR あたりの検証範囲を
Unity 無しのオフラインテストで押さえられる大きさに保つためです。
マイルストーン
| 版 | 内容 | 状態 |
|---|---|---|
| 0.2.0 | 季節(色・姿・枯れ方)、サンプルシーンの季節別再編 | 完了 |
| 0.3.0 | 種の拡充(小花・雑草・穀物・たんぽぽ) | 完了 |
| 0.4.0 | Foliage Palette(配合とパラメータを決めて Scene へ置く常設 UI) | リリース準備済み |
| 0.5.0 | 樹木パッケージの分離と再帰枝ジェネレータ | リリース準備済み |
| 0.6.0 | ツタ(サーフェスに沿わせる配置モード)と根茎パッチ | リリース準備済み |
季節を種より先に置いているのは手戻りを避けるためです。季節の色変換はFoliageMeshBuilder.Build() の出口で全種に一律に掛かるので、先に入れておけば
以降に追加する種は最初から四季分を持てます。逆順にすると、追加した種ごとに
季節対応を後付けすることになります。
0.2.0 季節パレット
生成時に頂点カラーへ焼き込みます。実行時コストはゼロで、生成結果は
シードから決まるため決定論的です。
シェーダーにグローバルな季節パラメータを持たせて実行時に色相を回す案も
検討しました。1 メッシュで四季を賄えて Udon から切り替えられる利点が
ありますが、全種へ一様に効くため「イチョウは黄、モミジは赤」のような
種ごとの枯れ方の違いが出せません。将来の拡張として残し、既定は焼き込みと
します。
制約として、頂点カラーの A は風の位相シードに使っているため、季節変換はRGB にしか触れてはなりません。
0.3.0 種の拡充
| 種 | 実装方針 |
|---|---|
SmallFlower | 花弁数・花弁形状・花芯色・草丈をパラメータ化した汎用の小花。ネモフィラ、ジャガイモの花などを 1 つのジェネレータで賄います |
Weed | 幅広の葉と不揃いな高さを持つ雑草。ブレード生成を草と共有します |
Grain | 麦と稲。芒の有無、穂の垂れ角、粒の段数で作り分けます |
Dandelion | 鋸歯のあるロゼット葉。花と綿毛をフラグで切り替えます |
葦(Reed)は 0.1.1 で公開済みのため、ReedParams の意味は変えません。
麦と稲はフィールドを流用せず別の種として追加します。公開済みアセットの
シリアライズを壊さないためです。
綿毛や薄い花弁はアルファテストを使えば簡単ですが、不透明 1 パスという前提を
崩すと数千インスタンスでの描画コストが跳ね上がります。形状で近似し、
近距離での粗さは LOD 側で吸収します。
0.4.0 Foliage Palette
Tools/SabaProps にあるのは一度だけ叩くもの(既定アセットの作成、サンプルシーンの
生成、ドキュメント)ばかりで、日常的に触る面がありません。配合とパラメータを
決める UI は GameObject メニューの奥のウィザードにあり、しかも作成時に一度きり
です。決め直すには作ったフィールドの Inspector と Species アセットの Inspector を
往復することになります。
ドッキング可能な常設ウィンドウにまとめます。
- 配合: 種の一覧と比率スライダー
- パラメータ: 選択中の種の形状パラメータ
- プレビュー: いじった結果をその場でメッシュ表示する。Scene に置かずに形が分かる
- 配置: Scene ビューをクリックした地点に、その設定のフィールドを生成する
編集先は 2 つのモードを持ちます。
| モード | 挙動 |
|---|---|
| 作業用コピー | パネル内でだけ値を持ち、配置したときに Species アセットへ書き出します。試行中に既存の見た目を壊しません |
| 既存 Species を直接編集 | アセットをその場で書き換えます。全フィールドへ即座に反映される代わりに、他のフィールドの見た目も変わります |
2 つある理由は、用途が別だからです。前者は「これから置くものを決める」ための場で、
後者は「もう置いてあるものを直す」ための場です。片方だけにすると、試すたびに
既存のワールドが変わるか、直したいのに新しいアセットが増えるかのどちらかになります。
Undo は全操作で通します。既存 Species の編集は SerializedObject 経由なので Unity が
面倒を見て、配置は生成ルートを 1 グループにまとめる既存の経路に乗ります。
ただしメッシュアセットの書き出しだけは AssetDatabase への書き込みで、Unity の
Undo の対象外です。ここは仕組み上どうにもなりません。作業用コピーのモードが、
実質的に「取り消せる試行」の役割を果たします。
ブラシで塗る配置は第 2 段階に回します。クリックで置く方は既存のフィールド生成と
Undo の経路にそのまま乗りますが、塗る方は塗った結果の保持・消しゴム・再生成を
新しく設計する必要があり、同じ増分に入れると両方が中途半端になります。
第 1 段階は Window > SabaProps > Foliage Palette として実装しました。作業用コピーはHideAndDontSave の一時 FoliageSpecies として保持し、配置するたびにAssets/SabaProps/Foliage/Species/Palette/ へスナップショットを保存します。これにより、
配置済みフィールドが次の試行に引きずられません。既存 Species の直接編集はSerializedObject、Scene への配置は既存の FoliageFieldBuilder を使います。
0.5.0 樹木
樹木は別パッケージ io.github.sabas0ba.sabaprops.trees に分離し、vpmDependencies でこのパッケージに依存させます。シェーダー、風のチャンネル
規約、スキャッタラーは共有し、樹木固有のジェネレータと LOD だけを持たせます。
同居させない理由は、草と前提が食い違うためです。
- Distance Shrink(遠景で根元へ縮退させる LOD)は草では正しく、木では破綻します。木は縮むのではなく、遠景でこそ残らなければなりません
Cast Shadowsの既定 OFF は草では妥当ですが、木では不自然です- 三角形数が 2 桁から 3 桁違い、想定インスタンス数も桁違いです
- 風は幹が動かず枝先だけ揺れるため、風の pivot を枝の付け根ごとに置く階層構造が要ります
広葉樹・針葉樹・枯れ木・砂漠の枯れ枝は、1 つの再帰的な枝分かれジェネレータの
パラメータ違い(葉の有無、葉形、色、枝の歪み)として実装します。
第 1 段階として io.github.sabas0ba.sabaprops.trees を分離し、4 preset、決定的な
再帰枝メッシュ、3 段階 LOD、樹木用 Material と Scene 用 LODGroup を実装しました。
一次枝以下は同じ UV3 pivot と連続した bend 値を使い、風で接続点が開かない構造に
しています。複数個体の配置は Trees 側へ複製せず、Foliage のスキャッタラーを
汎用化する次段階で共有します。
第 2 段階では Foliage のエリア走査、Density Mask、地面レイキャスト、高度制限、
除外判定を FoliageSurfaceScatterer として分離しました。既存 Foliage Field の
決定的な Seed 列は互換テストで固定しています。Trees 側は共有 API の callback として
種の Weight、傾斜、最小間隔、スケール、姿勢だけを定義します。
TreeField は配置結果を通常の LODGroup と MeshRenderer に焼き込みます。3 段階の
LOD Mesh は Species ごとに一度だけ生成して全個体で共有し、AssetDatabase の書き込みが
個体数に比例しない構造にしています。これで 0.5.0 の予定範囲は完了です。
0.6.0 ツタ
これは種の追加ではなく配置系の新機能です。現在の FoliageField は
「エリア内に散らす」モデルですが、ツタは「サーフェスに沿って這う」モデルで、
地面へのレイキャストとは相性が良くありません。
2 段階に分けて実装しました。
- 垂れ下がるツタを 1 個体のメッシュとして生成し、既存の配置のまま壁の上端に沿って並べる
- Surface Crawl 配置モード。対象メッシュの表面を辿りながら分岐して伸ばす
第 1 段階は Vine Species として実装しました。根をローカル Y=0 に固定し、茎と葉を
−Y 方向へ生成するため、壁上端の細い Foliage Field と上面 Collider だけで配置できます。
決定的な Seed、季節色、風、GPU Instanced/Merged Chunks の両出力は既存経路を通ります。
第 2 段階では、投影と形態生成の間に SurfaceGrowthGraph を置きました。各 Node は
ローカル座標の位置・法線・親 Node・根からの距離・分岐深度を持ちます。経路生成は次の
2 モードですが、後段のメッシュ生成は同じ Graph を受け取ります。
| モード | 用途 |
|---|---|
ProjectedSpline | ローカル空間のガイド点列を Catmull–Rom 補間し、その流れへ経路を引き寄せながら Collider へ投影します。建物全体の流れを指定する場合に使います |
SurfaceCrawl | 表面の接平面上を決定的な乱数で歩きます。小規模な自生や根茎の広がりに使います |
どちらも Path Count、Coverage、Branches Per Metre、Max Branch Depth、Step Length、Node Budget を共有します。Root Spread は根元を面内へ散らし、Guide Attraction はガイドを固定線ではなく流れとして使い、Path Length Variance は
同じ終点へ揃うことを避けます。これにより「壁の一部へ数本」から「家を覆う
密度」まで同じモデルで制御でき、形態側の葉数を増やして経路不足を隠す必要がありません。
投影先は単一 Collider に限定せず、主対象と追加対象の集合から step ごとに最も近い hit を
選びます。これにより床から壁、床から斜面を経て壁へ連続する経路を同じ Graph で表現します。
Collider 間の隙間は Projection Distance 以下である必要があります。根 Node には最初の
Edge と逆方向へ短いテーパー付き collar を加え、始端の切断面を見せません。
SurfaceVine は茎幅、1 m あたりの葉数、葉サイズ範囲、幅比、葉形、葉序、節間隔と角度の
ばらつき、若葉・成葉・秋色・枯葉の 4 色と混合率を持ちます。葉身は内側と外側のリングへ
分け、葉縁、主脈、葉柄に別の頂点色を持たせます。Preset は次の形態を出発点にしています。
- オオイタビ(Ficus pumila): 付着根で壁に張り付き、幼葉が小さい心形で密に付くため、
Cordateと高い葉密度 - セイヨウキヅタ(Hedera helix): 幼葉が 3〜5 裂するため、
Lobedと濃緑の常緑パレット - ナツヅタ(Parthenocissus tricuspidata): 夏は光沢のある濃緑で、秋に緑から赤紫へ変わります。通常 preset は緑の葉身を主体とし、紫褐色は葉縁・主脈・葉柄・若い茎と少数の秋葉へ限定
RhizomePatch は Graph の Edge を地下茎として扱い、Node 間隔に応じて地上茎・葉・花を
配置します。既定は地下茎で急速に広がり、心形葉と白い 4 枚の苞を持つ
ドクダミ(Houttuynia cordata)です。
地下の Edge は既定で描画しませんが、構造確認時だけ Render Rhizomes で表示できます。
表面に付く茎は高い stiffness で固定し、葉は付着点ごとの UV3 pivot を持たせます。
壁面全体を 1 本の根から揺らさないため、既存の垂下 Vine とは風の単位を分けています。
生成は Editor 時に完了し、Scene には通常の MeshFilter / MeshRenderer と永続 Mesh asset
だけが残ります。
想定規模について
利用のされ方は、ワールド 1 つを埋める場合、中距離から遠景にだけ使う場合、
一部分にだけ生やす場合と幅があり、単一の想定インスタンス数は置いていません。
既定値は「一部分に密に生やす」ケースで破綻しないように決め、広域は
Distance Shrink とチャンク分割で吸収する方針です。