SabaProps

拡充ロードマップ

対応済みの種は草・ひまわり・クローバー・葦・小花・雑草・穀物・たんぽぽの 8 種です。ここでは、これを
四季の草花と樹木まで広げるまでの計画と、その過程で決めた設計上の線引きを
記録します。

計画は 1 つの PR にまとめず、下の表の単位で切ります。1 PR あたりの検証範囲を
Unity 無しのオフラインテストで押さえられる大きさに保つためです。

マイルストーン

版内容状態
0.2.0季節(色・姿・枯れ方)、サンプルシーンの季節別再編完了
0.3.0種の拡充(小花・雑草・穀物・たんぽぽ)完了
0.4.0Foliage 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. 垂れ下がるツタを 1 個体のメッシュとして生成し、既存の配置のまま壁の上端に沿って並べる
  2. 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 とチャンク分割で吸収する方針です。