Toucanバーチャル博物館
VRML図鑑 3DCG 展示室   開発日誌 お問い合わせ

トコちゃんの修行日誌 2025年6月

6月30日 速度向上

プロファイラー

マーチング四面体の処理をBurst+Jobシステムで高速化して30FPSをなんとか死守しました。一番下段左半分のJob(緑色)が並列化の状況です。後半並列化できていな部分はNativeQueueをArrayにする処理でしかたない部分です。

その後ろのオレンジ色2つはMeshColliderに地面と水面を渡して初期化しています。地面を主人公を歩かせるには必要です。事前に全マップの地面水面の衝突判定用メッシュを作成してしまえば必要ないのですが、管理するプログラムが必要になります。スクロールの度に処理しなくても、地面と水面を交互にとか、足元の衝突判定が無くなる前まで処理しないでおくとか工夫はできそうです。

この処理がなければ、ぎり60FPSです。 

6月29日 草の拡大縮小Unity

拡大縮小Unity

一応Unityで出来たのですが。

なんとなく始めた、マーチング四面体、計算量が多いのでマップで使用するのはギリギリです。いまさらながらメリットは何でしょうか?

適当に作成したHeightマップ(高さ画像)と色画像でマップが作れます。グリッド毎にエディットするような几帳面さが必要なさそうです。

粘土細工のようにボコボコ地面をエディットするのは意外と楽しいです。洞窟も掘り放題。

池程度であれば掘ったところに水が流れ込むようなリアルタイム処理も可能かと思うのですが、川のように流れ込み流れ出しがあると、見えていない画面外の全体もかかわってくるので工夫(ごまかし)が必要でしょう。

拡大縮小時はごつごつと地形が変化して、通常のスムーズな拡縮とは違います。味があると言えなくもないですが。デメリット。

ボクセルデータで保存するとなるとデータ量が膨大になるのもデメリット。空中、地中の圧縮はできそうですが。

とりあえず、ジョブシステムで高速化できそうなところはやってみて、プレイヤーが歩いて移動できるようにしてみようかな。衝突判定が加わります。

6月27日 草の拡大縮小実験

草の拡大縮小Blender

草のEntityの数はそのままで拡大縮小するとなると、工夫が必要です。Blenderで実験してみました。

1番上は配置10、スケール1、一度に1束
2番目は配置5、スケール0.5、一度に7束
3番目は配置2.5、スケール0.25、一度に34束

で並べてみています。さらに遠景なら徐々に束を減らしていき、さらに近景なら詳細の草に切り替えていけば良さそうな気がします。

Unityで実装してみます。

6月26日 拡大縮小

拡大縮小

拡大縮小すると、地形のボクセル、草すべて更新しなくてはなりません。地形のボクセルの再設定37msを、4.63msに短縮しました。Burst コンパイルとパラレルジョブシステムです。

<追記>青い色が自動的に適当についているのだと思ったのですが、[BurstCompile]の付け忘れでした。0.55msに短縮しました。すげー、バーストコンパイル。

一番下段のJobの青と緑がパラレル処理の状態です。一番左の青の部分が今回の処理です。

草のEntityの更新がシステム任せだと若干遅れて更新されます。拡大縮小時などは強制的に更新しないと地面に草が埋もれてしまいます。この処理が意外と重く10msほどかかります。NativeQueueからNativeArrayに変換するのと同様の事例だと思います。

他の処理を高速化しても、15fps程度は必要ですね。拡大縮小は、単純にカメラ移動で拡大縮小して、終わってから再描画するのが現実的かと思います。

6月24日 Blenderで草

Blenderで草

Anime Grass Tutorial | Blender (include Project Files)

いい勉強になりました。DataTransferという新しい技を知ったのですが、相互にDataTransferして嵌るという失態。原因が分からず2時間ほど・・・。

この方法をUnityに実装してみます。

<追記>Unityで草

Unityで草

Lit Shader GraphのBaseColorを緑にして、Normal(World Space)にInstaceNormalを入れるだけでこんな感じに出来ました。

GraphSettingsのFragmentNormalSpaceをTagentにしていて3時間ほど四苦八苦していたのは内緒です。ちなみにUnlitSaderGraphでもMainLightDirectionとDotProductして緑色と掛け算すれば同様にできましたが、影を受けることが難しいようなので断念しました。 Copilot君の受け売りです。

スクロールでは見え始めた場所を追加していくだけなので問題ないのですが、拡大縮小では全面的に草を植え替えます。書き換えで違和感があるかと心配していたのですが、風に草が揺れている程度の違和感で問題なさそうです。

ビルボード表示だと水面下でも水面が上書きされてしまっていて、それを解決するのはややこしそうです。遠景で草が小さくなったら限界までポリゴンで描画、間引いていってごまかすのがいいかな?

なんとか、なりそうです。

6月23日 草表示

草表示

大変だった・・・、なんとか目途がたちました。

まだ、なんとなくしか理解していませんが、DOTSのEntityで描画しています。

Unityのプレハブ、ここでは草のビルボードです。これを最初に(大本)Entityに変換して(ベイクと言う)、インスタンスを配置(ベイクした大本Entityの複数配置)しています。説明が難しい・・・

ただ、そのままだと法線(影の計算に使用)が同じなので均一な明るさの草になってしまいます。そこで、法線だけはマティリアルに個別に設定しています。この手順が・・・

Instance Normal(マティリアルのプロパティ)のNodeSettings
Scope Hybrid Per Instanceの選択


マティリアルのEnable GPU Instancingにチェックが必要?。しなくても大丈夫。

Allow Material OverrideにチェックしなくてもInstanceは有効になる。チェックすると描画に時間がかかるがちらつきが無くなる

草のEntityにNormalのコンポーネントを追加して、[MaterialProperty("_InstanceNormal")]と明記する。

これでGPUのインスタンス描画(まとめて一度に描画)も有効なようです。

Copilot君が色々教えてくれるのですが、余計な情報もあったり、重要な設定が無かったり・・・結局、検索と試行錯誤で時間がかかりました。

このEntityの位置回転は親子関係で変更できないので、(対応するには毎回計算が発生する)表示ロジックを変更しました。いままで地面を回転移動していたのですが、カメラの方を回転移動させることにしました。草を配置するときに位置回転を計算すれば済みます。

副作用として、直方体のクリッピングで回転させると今まではクリップ面は移動しなかったのですが、変更後はサイコロの様に回転します。これが意外と良い。クリップ面のギザギザが目立たないのと、立体感の把握がしやすく、回転しないので表示領域も増やせました。 

水面や草が追加されたので、若干の高速化にも挑戦しました。

マーチング四面体の処理の高速化のためにポリゴンの情報(位置や法線)をNativeQueueに並列書き込みしているのですが、これをNativeArrayのリストにするだけで20msかかっていました。これをBurstCompileのジョブシステムにして10ms。一旦NativeArrayにしてしまえば、他の処理は一瞬です。 

NativeQueueを使用しない方法も試したのですが、かえって遅くなります。NativeQueueは並列処理で最強です。

6月15日 水面表示

水面表示

渓流のHeightMapを作成して、水面を表示してみた。クリッピングは上から円柱、球、直方体。

直方体だとクリップ面のガタガタが規則的になって目立つことが多少あります。地形の表現力はどれもほぼ同じです。画面的に面白味があるのが球、ただ木を植えたりすると上部地形が無くなっているので困ります。そうなると円柱あたりが無難な感じ。

奥のクリッピングされた水面が色が濃くなってしまっているのは、地形が無くなりカメラのFar clip plane(遠方の領域面)までの距離で色の濃さを決めているからです。本来なら水面がクリップされた場所までの薄い色であるべきなので、違和感があります。

Zバッファ(距離を書き込んだバッファ)だけをクリップ面で書き込んでみたのですが、Skybox(空地形)が描画されず黒くなってしまい断念しました。対策方法はあるようなのですが大変なので、気になるようだったら不透明度の最大値を制限して、お茶を濁そうかと考えています。 

6月12日 HeightMap表示

HeightMap

地形データを全部ボクセル(3D)で持つとさすがに大変なので、HeightMap(高さマップ)で表示してみました。拡大縮小するとガタガタしていたのですが、ミップマップに対応してみたらなんとか使い物になりそうです。拡大してから、洞窟やトンネルなど必要に応じてボクセルデータに切り替えるのが良さそうです。表示時にはボクセルデータになっているので、そのまま保存して、必要に応じて穴を掘るなど編集。

色はテクスチャでの表示もしてみたのですが、この頂点カラーでの着色の方が味があります。

Blenderで水の流れを試した渓流マップがあるので、HeightMapを作成して、水面を加えて表示してみようかと思います。

地質などのデータはどうしても必要ですね。平地、岩場、草地など。これも2Dで、Byteデータ256種もあれば十分かと。昔の2Dマップと同じような方式ですね。 

6月5日 GitHub Copilot 加入(AI)

便利だから使いまくっていたら、無料分を使い切ってしまい16日まで待たないと使えないことになってしまいました。

ソースコードを選択してコメント(説明文)を考えてもらったり。英語で変数名を考えてもらったり、コードを作ってもらったり。ボタンを押したとき、どちら方向に回転させるのが一般的かとか、あらゆる事を相談できます。

賢い友人です。たまに小さな大ポカをしてくるので注意が必要です。ソースコードのごく一部+ーを間違っていたり、はまったのが、マトリックスの初期化をお願いしたら、行と列が逆で一見正しいので、デバッグで気が付くのに半日かかりましたが・・・、ほんとに頼れる友人です。

月10ドル、加入しました。 

6月3日 Burst+Jobシステム改良

プロファイラー

マーチング四面体の処理は7.5msほどかかっていたのですが、1.5msほどに短縮しました。出来上がったデータをメッシュに送るための変換は相変わらず10msもかかっています。

地形が変わらなければ計算する必要が無いので、マーチングキュウブの地形値合計が変わらなければ処理をしないようにして処理時間を短縮しました。

地形のスクロールができるようになりました。

最初にシアー変換でひし形にひしゃげてしまっていたデータを並び変え、なるべく直方体に近い形にしました。名付けて千鳥配置(stagger)補正。具体的にはXY軸が2増えるごとに、Z軸を-1ずらします。三角形の頂点がZ=0.5の位置なので三角形2つで1ずれます。

昔のゲーム機のような処理で、スクロールでクリッピング外に出た地形データを前方の地形データで書き換えています。

ここで苦労したのが、千鳥配置の弊害。書き換えが・・・・なんとか解決しました。

あと移動は出来上がったメッシュのトランスホームに移しました。毎回計算していたときは移動分位置に足しこんでいたのですが、データを再利用することになり同じ位置ですむようにした訳です。 

../toucan/TocoDiaryJ.html