Showing posts with label Japanese. Show all posts
Showing posts with label Japanese. Show all posts

Thursday, August 15, 2019

[Unreal Summit 2019] FortniteでUnrealGameSyncを作った経緯とイテレーション改善について

Fortniteの開発チームにエディタを配布する過程は慎重過ぎるあまりイテレーションが遅かったそうです。これを改善すべくUnrealGameSyncという新ツールが開発され、イテレーションを短縮した過程が解説されています。

 


(スライド原題:Workflow on Fortnite、セッション原題:포트나이트 워크플로)

動画とpdfはこちら

三行要約

  • イテレーションのためUnrealGameSync(UGS)を開発した
  • ソースのコミットから10分で自動テストまで完了
  • 実行バイナリをPerforceにサブミットせず、ローカルのVisual Studioでエディタをビルド(プログラマ以外の職種も!)



本ポストでは、アジェンダのうち、Distributing the Editorについて解説します。ほぼUGSの話です。



長年使われてきた従来型のビルドパイプラインはイテレーションが遅く、使えるビルド(good build)が一日に1回か2回しか得られませんでした。遅さゆえゲームプログラマーとコンテントクリエーターの連携が困難です。

CIでビルドされたバイナリはPerforce等にサブミットされ、QAセクションでテストされた結果大きな問題がない場合、ラベル付けされて開発で使えるようになっていたようです。開発が進むにつれテストの量も増えていきます。


バイナリ(exeやdll等の実行ファイル)とコンテンツのバージョンが一致していないとデータを壊す危険をはらみます。

エンジニアがローカルでビルドしたエディタはバージョン付けがされてないため、エンジニアがコンテンツを編集するためにはPerforce上のバイナリを取得して編集しなければいけませんでした。

一方、Battle Breakerチームでは当時のFortniteのような従来型のビルドパイプラインを好みませんでした。Perforce上にバイナリはなく、企画職やアーティストを含む全職種(計8人)が、Visual Studioからソースコードをビルドしてエディタを起動していました。
問題があれば隣のエンジニアに聞いて解決します。コミュニケーションが密になりました。
この体制の柔軟さに気づき、Fortniteに適用できないか考えました。


Fortniteへ適用する現実の壁がありました。
安全に導入せねばならず、コンパイル時間も問題です。
チームが大きいので通常エンジニアとアーティストは別室であり対話が難しいです。
これらを解決するツールが必要と考えました。


初期のUnrealGameSync(UGS)です。
CL(Change List)をダブルクリックするとビルドが始まります。ビルド結果はDBに格納され、GUIからは青信号又は赤信号で結果が見れます。
また、CLを右クリックしてコメントを残せます。(コメントの例:「このビルドはおかしい」「調査中です」)


現在のUGSです。
複数の(Perforceの)ストリームが見えます。
Automation Testの結果がみえます。


UGSクライアントにメッセージを送信する機構を用意しました。ビルドやテストが失敗するとUGSを経由してデスクトップにポップアップで通知できます。


ビルドからテストまで10分で完了するそうです。
メインのCI(セッション内ではCISと表現)は1台のマシンです。
Incremental editor buildとし、unity buildは切っていたそうです。
サブミットされたアセットの無効な参照のチェックを行います。
ログインとゲームプレイループまでを自動テストしています。
2台目のマシンは他のプラットフォーム向けのビルドを行っていました。



ParagonチームはFortniteチームと違い全員がローカルでビルドしませんが、UGSがCLに対応するビルド済みZIPを取得して実行していたそうです。


Sync Filter
作業に不要なプラットフォームを除外してSyncできます。コンソール担当ではないスタッフはPS4やXBOXを除外します。自宅からリモートで作業するスタッフはムービーファイルを除外するでしょう。

Clean Workspace
Intermediateを削除し、ワークスペースをディポから取得したばかりの初期状態と同じにする機能です。

Bisect
複数のCLを選択し、どこで問題が発生しているかバイナリサーチで探す過程を支援するツールです。

カスタマイズ機能
ブランチごとにロゴを設定できます。
赤いのはリリースブランチであり、ロックしているのでここに変更が加わることがないことを表示しています。
朝に自動シンクし、出勤時に既に最新状態が取得できている状態にすることもできます。
任意のリンクを挿入できます。例えば深刻なバグが発見されたらそのリンクを入れられます。
任意のテキストを入れて、重要な情報、例えば次回リリース日などを表示できます。

これらは公開されており、未公開の機能などはなく、全て皆さんが使えます。
どのバージョンのエンジンでも使えます。



まとめ


「従来型のビルドパイプライン」は普通のゲーム開発の現場で行われている事に近いのではないでしょうか。ビルド済みバイナリを待つ場合(自動化されていたとしても)バイナリが得られるまでに数十分のタイムラグが発生することもあります。
ソースコードを含むCLを配布そのものと見なし、タイムラグを0とするのは示唆に富んだ事例と言えそうです。

追加の解説が欲しい点としては、各自のPCでのビルドに時間が掛かったりしないかということです。特にエンジンに手を加えた場合はビルドマシンでも10分では終わらない気がします。全員の席で出勤前にデイリービルドが行われるので、日中はインクリメンタルビルドで凌ぐのでしょうか。IncrediBuildも全職種のPCで導入されているかもしれません。おそらくはソフトウェアのライセンス費も惜しまず投資をしていると推測されます。

2019/09/01 追記:
Unreal Fest Europe 2019の同名のセッションで、FortniteにUGS導入当時アーティストの席に導入されたのはVisual Studio Expressであったと言及されていました。

Saturday, April 13, 2019

[GDC 2019] UE4の新物理エンジンChaosの紹介と内製の理由

GDC 2019のセッションで、UE4.23からEarly Access扱いで登場する新物理エンジンChaosについて、内製が必要になった背景と用途について解説されています。

(原題:Order from Chaos - Destruction in UE4)




特に重要そうなポイントを要約します

  • UE4.23でプレビュー版が搭載される
  • 最終的にはNVIDIA PhysXを置き換える
  • 破壊の表現に強い
  • Niagaraインテグレーション
  • 破壊結果でAIのナビゲーションメッシュを書き換える
  • モバイルプラットフォームをサポート
  • ネットワーク対応
  • 物理シミュレーション結果を事前キャッシュすることで負荷を軽量化する機能あり





まず、最終的にはNVIDIA PhysXを置き換える、UE4.23でプレビュー版が搭載される、破壊の表現に強い、などの特徴が挙げられましたが、今回のセッションでは特に破壊表現を中心に解説されています。



今までのUE4の破壊表現の実装方法について振り返っています。単純な破壊可能なメッシュはエディタ上でStatic Meshから生成可能でしたが、より複雑な破壊となるとDCCツール上の編集、アプリケーション側の実装などが必須になり、結果として開発イテレーションが遅くなると解説されていました。




新しいシステムはエディタ上ですべての作業が完結します。
破壊は、あらゆるスケールで可能で、人スケール、ビルのスケール、街の区画スケールを例として挙げられていました。
Niagaraとは密な統合が行われています。
コリジョンの形状は凸状に制限されることはなくなりました。

今までの破壊はゲームに与える影響が限定的でした。例えば道に大きな破片が落ちていた場合AIは単純にぶつかって進めなくなるなど、これをどうするか決めることができませんでした。Chaosはナビゲーションメッシュを変化させます。AIは道に落ちた破片を避けるか乗り越えるか選択することになります。また、壁に空いた穴を通り抜けられる事を認識します。

NVIDIA PhysXはモバイルプラットフォームをサポートしませんでしたが、Chaosはあらゆるプラットフォームで動作します。

アスタリスクがついている「Persistence」と「Network replication」は今は実装できていませんが将来にサポートが予定されているものです。



いくつかの新しい概念が登場します。




Geometry Collectionsは新しいアセットタイプです。Static Meshを束ねて破壊可能な一つの構造を定義します。
1つのGeometry Collectionは1回のドローコールで描画が完了するそうです。


Geometry Collectionの作り方の実演です。




Fracturingとは割れ方を定義するものです。



Clusteringは、1つのGeometry Collectionの壊れ方を階層構造にします。
実演では、Level 1は10個、Level 2は30個まで増え、Level 6は681個までに分けていました。


FieldsとはUE4の「Volume」であり、特定範囲内での物理挙動のパラメータを定義するものと思われます。
実演ではいくつかの定義済みのフィールドがアセットとして用意されていました。

挙動から推測するに「Anchor」フィールドが物理オブジェクトがその場に「留まる」場所を定義し、「Strain」フィールドは銃弾を撃つと発生した破片が外向きの衝撃を受けて飛び散る様を定義、
「Disable」フィールドは、落ちた破片同士が重なってガタガタするのを抑えるために破片をすぐに停止状態にする場所を定義していました。

また、それら機能にBlueprintからアクセス可能であることに言及されていました。


 
Connection Graphはチャンクの結びつきを定義します。黄色は固定されているチャンクで、青はコネクションが破壊されると落下を始めるという意味のようです。



Cached Simulationsは、非常に大きな物を破壊するときに有用になると思われます。
破壊を事前計算しておくため高速ですが、インタラクト可能で、Cached Simulationの一部に触れた瞬間その部分がキャッシュではない物理挙動を開始するそうです。

 
Chaosが発生させるイベントはNiagaraからアクセス可能です。Niagaraからは破片の物理及びマテリアルのプロパティを参照可能です。



建物の破壊をエディタ上の編集で作れるようになるのはうれしいですね。
PhysXが無くなるということは既存の物理挙動が変わってしまう可能性があり、エンジンのバージョンを変えるときは気をつけるポイントになりそうです。
ただし、UE4.23でpreviewなのでしばらくはPhysXと共存することになるのかなと思います。

Saturday, August 25, 2018

[Unreal Summit 2018] Fortniteモバイル版のオクルージョンカリングについて

前回前々回に引き続きUnreal Summit 2018の話題です。

韓国がモバイルゲーム開発においてのUE4採用の最前線になっているためか、Unreal Summitはモバイル向けの話題が多めです。その中から今回はEpic Games KoreaのDmitriy Dyominさんによる、ソフトウェアオクルージョンカリングのセッションを読んでみました。モバイル版のオクルージョンカリングはPC版とは異なる手法で実装されており、このテーマ1つでなかなかの分量です。題名にモバイルとありますが、PC版の実装にも触れています。


残念ながら動画の音質が非常に悪く字幕も生成されていないので、以下のスライドをおすすめします。
https://replay.unrealsummit.co.kr/data2018/usm2018_44.pdf 

要約

  • モバイル版のためにSoftware occlusion culling実装(今回の主題)
  • PC版やコンソール版ではHardware occlusion queries、HiZ occlusionというGPUを活用した手法を使う
  • モバイル版(OpenGL ES)でもHiZ occlusionを実装したが採用せず、エンジンにも組み込まなかった
  • iOSではSoftware occlusion cullingはうまくいかず、Hardware occlusion queriesを使うことに
  • UE4.20からモバイルでSoftware occlusion cullingとHardware occlusion queriesが使えるように

要求仕様

  • PCやコンソールとのクロスプラットフォーム対戦可能
  • モバイルのスペックが足りないからと言って視距離を制限するなどゲームプレイ上不利になる事はできない
  • terrain以外は破壊可能なので、precomputed visibilityはつかえない

Hardware occlusion queries

  • OpenGL ES3以降
  • bounding boxを頂点シェーダのみ、ピクセルシェーダ抜きで描画してクエリ
  • PCやコンソールではdepth pre-passの後にクエリを投げ、1フレーム待機で結果を得られる
  • モバイルではdepth pre-passがない、最低2フレームかかるがFortniteでは3フレーム待つ
  • 平均50%くらいドローコールを削れる
  • UE4.20で、r.AllowOcclusionQueries=1 がモバイルでサポート

Hardware occlusion queriesの問題点

  • 結果を得るまで3フレームの遅延
  • クエリ1回当たり追加でドローコール1回。FORTNITEは150ドローコール増加。
  • Adrenoは512クエリの制限

Software occlusion cullingを実装してみる

  • メインメモリにデプスバッファを作る
  • SIMDで頂点変換
  • CPUでラスタライズ、クリッピング、カリング
  • 重い! ~1100 オブジェクト、~60万ポリゴン

Software occlusion cullingの高速化

  • 良いoccluderをアセット単位でアーティストが手動で選別(悪いoccluderとされたらバッファに描画しない)
  • 描画に使うLODもアーティストが指定
  • 良いoccluderもそのフレームでoccluderとして使う価値があるかはヒューリスティックに判断(カメラから近い程良い)
  • 1フレームあたり200個ぐらいまでが適切

Occludeeの最適化

  • 二次元Bounding Boxでまず判定
  • 三次元Bounding Boxを三角形に分解してデプステスト

デプスバッファの最適化

  • デプスはいらない、1ピクセル1ビットで十分、以下occlusion bufferと呼ぶ
  • occluderとoccludeeの三角形を全てデプスでソートして手前から処理
  • occluderは三頂点の最も奥のZを採用
  • occludeeは三頂点の最も手前のZを採用

occlusion bufferのレイアウト

  • 384x256ピクセル
  • 6x4の 'bin'という単位に分ける。binは64x64ピクセル
  • bin1つは uint64 Bin[64]
  • 描画とテストはビット演算
  • binごとに別スレッドで処理させることもできる

結果

  • 一万個の三角形を 5-8msで処理(Galaxy S8)
  • 30-50%のオブジェクトをカリング
  • 1フレームのレイテンシ

Software occlusion cullingについて

  • UE4.20で、r.Mobile.AllowSoftwareOcclusion=1 で使える
  • iOSでは採用せず。オープンワールドではうまく機能しなかったため、3フレームのレイテンシを我慢してHardware occlusion cullingを採用

インテルのソフトウェアオクルージョンの紹介

HiZ occlusion - PC版の実装

  • デプスバッファのMip Chainを作る
  • 複数のOccludeeのBBoxをテクスチャに書き込んでピクセルシェーダから参照
  • Render Targetの1ピクセルは1Occludeeに対応していて、隠蔽されたかどうかが書き込まれる
  • 次のフレームで結果を利用
  • occludeeが増えてもコストはほぼ変わらないメリット

HiZ occlusion - OpenGL ESの実装

  • PC版の実装のようにRender TargetをCPUから参照しようとするとすごく待たされた
  • ピクセルシェーダの代わりに頂点シェーダ+Transform Feedbackで処理した
  • 3フレームレイテンシで結果を取れた
  • Occlusion queryのほうが結果が良かった
  • 不採用、エンジンにも反映せず


モバイルGPUのオクルージョンクエリは待たされる等の制限があるとのことで、代わりにCPUでラスタライザを実装、更にそれを実用レベルにしてしまうのは驚きでした。

Galaxy S8基準でソフトウェアカリングに5~8msかかるとはいえ、バックグラウンドスレッドで動くのでゲームスレッドやレンダリングスレッドの仕事を増やしているわけではないと想像します。

余談ですが、Samsungは仕向地などによって同じブランドでもSoCが違うことがあります。Galaxy S8の場合、日本やアメリカはSnapdragonですが、韓国ではExynos+Maliの構成です。Snapdragonのほうがゲーム向けで、Exynosは相対的にグラフィック性能が落ちる代わりにCPU性能は高いです。スライド上のGalaxy S8は韓国モデルと思われますが、もしかするとゲームでCPUが遊びがちなExynos向けの実装を試みた結果だったかもしれません。

Sunday, August 12, 2018

[Unreal Summit 2018/GDC 2018] FORTNITEのリアルタイムライティング技術について

前回に続き、Unreal Summit 2018の動画とスライドを見ていきます。
動画とスライドは https://replay.unrealsummit.co.kr/ にあります。

Epic GamesのZak Parrishさんによるセッション(原題:Fortnite’s Real-Time Lighting Techniques and Tools)で、FORTNITEのライティングについて具体的な手法が解説されています。

GDC 2018でもほぼ同じ内容で講演されていますが、Unreal Summitの講演にはVolumetric LightingやTime of Dayの実演や質疑応答が追加で含まれています。


要約
  • 事前計算の影は使わず、影はリアルタイムに計算している
  • レベルに配置されたStatic MeshからMesh Distance Fieldが生成されている
  • Mesh Distance Fieldにより、ソフトシャドウ、アンビエントオクルージョン、パーティクルコリジョンを実現
  • スケルタルメッシュの影生成は影生成専用のカプセルで構成されたモデルが使われている
  • Time of Dayを実現。24時間どの時間にも設定可能で、太陽と月が時間に追従して動く。これはFORTNITE専用に組まれた機能だが、エンジンレベルで事前計算の影が使われていないことを示している




MESH DISTANCE FIELDについて
  • FORTNITEでは様々なオブジェクトを壊せるので事前計算した影は使えないが、リアルな影を使いたい
  • Mesh Distance Fieldをレイトレースすることでソフトシャドウを実現
  • 3Dテクスチャに最も近いメッシュの面までの距離を格納している。プラスならメッシュの外、マイナスならメッシュの中(Signed Distance Field、SDFとも)
  • 3Dテクスチャはエディタで事前計算される

DISTANCE FIELDの影の作り方(実演あり)
  • Mesh Distance Fieldはプロジェクト設定によって有効化しなければいけない
  • Mesh Distance Fieldのビジュアライズ機能で可視化して確認できる
  • ダイナミックライトを使ってもソフトシャドウが出来る。(Spot LightアクタのRay Traced Distance Shadowsにチェック)
  • Static Meshをエディタで開き、Distance Field Resolution Scaleで解像度を調節
  • Static MeshのDistance Field Replacement Meshはレンダリング用のメッシュとDistance Field生成用のメッシュを別にしたいときに使う。
  • Distance Field Replacement Meshを指定する副次的メリットとして、LODをビルボードにしているときにもボリューメトリックシャドウを描ける。
パフォーマンスや制限など
  • DFはCascade Shadow Mapに比べ30%から50%程軽量
  • 近景はCascade Shadow Map、遠景はDistance Field Shadowにすることでパフォーマンスとクオリティを両立。境界近くではブレンドも行う
  • DFはGPUにおいて数ミリセカンド節約になる
DISTANCE FIELD AMBIENT OCCLUSIONについて
  • Visualize機能で DFAOを可視化できる
  • SkyLightをMovableに設定し、スカイライトで設定値を変更する。(ただし、FORTNITEではWorld Settingの中にライティング設定値をもたせているので、実演ではWorld Settingで)
  • Occlusion Max Distanceを大きくすると暗くなる。他のオブジェクトに到達しやすくなるため。ただし、大きくすると重くなる
  • Occlusion ContrastでAOの強度設定
  • Occlusion ExponentでAOの"fall-off"を調整

GLOBAL DISTANCE FIELDについて
  • 全てのメッシュにDFをもたせる必要はなく、Global Distance Fieldが存在する。これはカメラの移動に伴い計算が実行される
  • DFAOの他、パーティクルコリジョンにも使う
  • プレイヤーがテレポートするとGlobal DFが全計算され、一瞬重くなる

MESH DISTANCE FIELDの制限と考慮点
  • DX11以上のみ
  • メッシュの変形が反映されないという欠点がある(ゆれる木等)
  • 軸ごとのスケール値が異なる不均等スケールに対応できない(多少の不均等は許容できる場合も)
  • 大きなメッシュはディテールを損なわれる傾向。小さいメッシュに向いている。FORTNITEは小さなメッシュの組み合わせで大きな建物を構成
  • 解像度は慎重に設定すべき

MESH DISTANCE FIELDの最適化について
  • r.AOListMeshDistanceFields でDFに使われているメモリをダンプ
  • プロジェクト設定でMesh Distance Fieldを圧縮できる。メモリを節約できるが、レベルのストリーミングで解凍処理が走りヒッチ(Hitch=瞬間的な負荷でフレームレートが落ちること)が発生するかもしれない
  • プロジェクト設定で8-bit Mesh Distance Fieldにできる(デフォルトは16-bit) 品質は落ちるが、FORTNITEでは8-bitでも悪くなかった。
キャラクタのカプセルシャドウ
  • 軽い、ソフトシャドウもできる
  • SkeletalMeshActorのCapsule Direct Shadowをチェックすることで有効化
  • shadow physics assetを用意しなければいけない。キャラクタを構成する剛体の形状はカプセルだけが許されている(ソフトシャドウの計算に向いている)
  • 仕組み上、影が壁や床を突き抜けて生成されることも
ダイナミックライトの距離カリング
  • ポイントライトなどに個別に設定
  • 見えなくて気づかないかもしれないが、距離内にあると計算が発生していることに注意
  • パフォーマンスのために必ず忘れずに設定するように!(アーティストがいつも設定し忘れるそうです)
DYNAMIC SHADOW CACHING
  • 動いていないライトと動いていないオブジェクトがあったら影計算結果を再利用
  • 初回フレームはキャッシュしない場合と同様の負荷がかかる
  • 何も設定しなくてもいい!デフォルトで有効になっている
  • ただし条件あり。プリミティブはStaticかStationary、ライトはMovable
VOLUMETRIC LIGHTING
  • 最近Volumetric Fogが実装された
  • Volumetric FogはExponential Height Fog Actorの設定項目になっている
  • スライドによると、Volumetric LightingのGDCセッションがある (これかと思います  https://www.youtube.com/watch?v=Xd7-rTzfmCo
VOLUMETRIC FOGの実演デモ(以下の項目それぞれFORTNITEを使って値を変えて実演)
  • Density - 霧の濃さ
  • Scattering Distribution - フォグが指向性をもつか
  • Albedo フォグがどれだけ光を反射させるか(色で指定)
  • Extinction Scale Controls  - フォグのfalloffの調整 ライトが霧に隠れる程度の調整
  • View Distance - Volumetric FogとExponential Height Fogとの切り替え地点の調整
  • ポイントライトアクタに Cast Volumetric Shadowにチェックを入れることで霧の中にライトを遮蔽した影を入れることができる。Volumetric Scattering Intensityでその程度を調整できる

FORTNITEのTime of Day(TOD)
  • 以下はFORTNITEに特化した実装の話
  • TOD機能が実装され、World Settingから朝、昼、夕、夜(又はスライダから24時間中のどんな時間でも)を選ぶだけで太陽、月、Exponential Height Fog、スカイライト、atmosphericsが設定される
  • 上の環境設定は全てのレベルで一律であり、エンジニアがC++で実装した。アーティストはレベル毎に個別に設定する必要がない
  • (質疑応答時間の回答にて)リリースされているUE4にはこの機能は無いが、望むならあなたが同じようなものを作ればいい。ただし、もしかすると後日サンプルを公開するかも?
    (追記 2019/04/06 UE4.21で Sun Position Calculator pluginとして提供されています!)


Time of Dayを実装したゲームエンジンとしてCRYENGINEがありましたが、Mesh/Global Distance FieldはそれらをUE4で実装するのに使えそうです。

UE4上でTODを実現するためには必要な機能をプログラマが組む必要があり、手法の検証にコストがかかりそうな印象でした。これもFORTNITEにより手法が提示されたことでハードルが下がったと感じます。後日TODの機能またはサンプルがEpic Gamesから提供されれば、更にオープンワールドの様なゲームの開発がはかどりそうです。

Monday, August 6, 2018

[Unreal Summit 2018] Material Layering Systemの概要

韓国で開催されたUnreal Summit 2018のスライドや動画が上がっています。
https://replay.unrealsummit.co.kr/

今回はその中からEpic GamesのAlan WillardさんによるMaterial Layering Systemに関する動画を見てみました。


  • 新しいアセットの名前は"Material Layer Blend"
  • 複雑なマテリアルをシンプルに定義するための機能である(Photoshopのレイヤーのような用途と理解すればよい)
  • 開発中の機能であり、現時点でプロダクトでの使用は勧めない(将来のバージョンアップで編集内容が壊れる可能性がある)
  • レイヤー機能を使っても使わなくても出来上がるシェーダは全く同じものになる。編集の利便性のための機能にすぎない
  • PC、モバイルなどプラットフォームに関係なく利用できる。
  • ブレンドのウェイト値としてテクスチャを使うこともできるし、頂点カラーを使うこともできる
  • マテリアルインスタンス側で特定レイヤーを省くという編集も可能

今現在、"マテリアル レイヤー UE4"などで検索すると出てくるページは以下のようなものですが、これは今回のUnreal Summit 2018で紹介された機能ではありません。
http://api.unrealengine.com/INT/Engine/Rendering/Materials/HowTo/CreatingLayeredMaterials/index.html
既存の機能で作るいわゆるLayered MaterialはMaterial Functionを駆使して作られていましたが、"Material Layer Blend"はより幾重にも折り重なったレイヤーを直感的かつ機能的に扱うことができそうです。

Unreal Summit 2018の続き

Monday, November 27, 2017

[UE4] マンデルブロ集合マテリアルを作る

GLSL Sandboxにマンデルブロ集合があり、面白そうだったのでちょっと使いやすそうに加工してからUE4のマテリアルにしてみました。



ループがあるのでCustomノードに書きます。発散の判定は絶対値が2を超えた時点とし、発散と判定されるまでの計算回数が多い程輝度が上がるようにしました。



探検できるように300倍に拡大した'Plane'にマテリアルを貼り付けます。

Spectator Pawnで探検します。

離れてみると分かりにくいですが、近くから輪郭部を見ると非常に輝度が高いのがわかります。集合の左側は特に輝度が高く、更に拡大しても複雑なパターンが現れてきそうです。

プロジェクトをgithubにアップしました。

Thursday, November 16, 2017

[ゲルストナー波] 水面に物を浮かべる

ゲルストナー波の実装は前々回前回をご覧ください。


Copyright (c) 2011 NVIDIA Corporation. All rights reserved.

NVIDIAのIsland11を改造して作っています。

題の通り物を水面に浮かべたいのですが、ゲルストナー波はHLSLで実装したので現状CPUから水面の動きを取得する方法がありません。しかし、波のパラメータはCPU側でも分かっているので、C++でも同じ計算を実装すれば目的を達成できます。


ほぼ機械的にHLSLからそのまま持ってきただけです。ImmutableCBはコンスタントバッファになる構造体で、GPUと共有する波のパラメータの集まりです。この波のパラメータは一度決定したら書き換えません。変化するのはtimeだけで、現在時刻だけ毎フレームC++とHLSLで同期すれば任意の地点の海水面の移動量が一意に決定します。

あとは、描画したいメッシュの座標をCalcGerstnerWaveOffsetにlocationとして渡せばVec3の移動量が取得できるので、それを足して描画すれば上のアニメーションが得られます。

更に、ここからキューブを波に沿って傾けることを考えてみます。


Copyright (c) 2011 NVIDIA Corporation. All rights reserved.

HLSLでやったように微分して法線を得る事でもできそうですが、予想される結果として戦艦のような大きなものを局所的な法線で傾けるとおかしくなりそうです。今回は海面から任意の3点を取得してそれの属する平面の法線を使うことにします。これなら、大きな物体は3点をなるべく離れた場所に設定することで傾きすぎないようにするなどの調整ができます。

キューブの中心からやや離れた3点を波で動かし、offsetXZ, offsetNegX, offsetNegZの3点を得ました。ここから得た法線と真上に向かうベクトルとのなす角を回転量とし、同様に法線と真上に向かうベクトルとの外積で回転軸を求めています。

Sunday, November 5, 2017

[Vulkan] vkCmdPipelineBarrierで指定するVkPipelineStageFlagBitsとは? [SDC 2017]

Samsung Developer Conference 2017で行われた、VulkanのvkCmdPipelineBarrierの使い方の技術セッションがYouTubeで公開されています。

vkCmdPipelineBarrierに指定するsrcStageMaskとdstStageMaskの指定方法に関して説明されており、Khronosの文書が関数リファレンスのレベルしか言及していない現状で、動作原理を解説する貴重なセッションとなっています。

連続する2つのパスはGPUで並行に実行される可能性がありますが、前のパスの結果に後のパスが依存する場合、vkCmdPipelineBarrierを置くことで後のパスを待たせる必要があります。ただし、GPUコア間の並行性が失われて待機時間が生じます。これがPipeline Bubbleと呼ばれます。

srcStageMaskは前のパスのパイプラインステージ(例:vertex shader等)、dstStageMaskは後のパスのパイプラインステージを表します。前のパスのsrcStageMaskで指定のステージが終わるまで、後のパスのdstStageMaskで指定のステージは始めてはいけないという意味になります。

VK_PIPELINE_STAGE_TOP_OF_PIPE_BITとVK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BITは存在しない一種の仮想のパイプラインステージで、それぞれ全てのパイプラインステージの前と後を意味しています。

保守的には、srcStageMask=VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT、dstStageMask=VK_PIPELINE_STAGE_TOP_OF_PIPE_BITとすることで並列動作を出来なくします。

逆に、srcStageMask=VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT、dstStageMask=VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BITとすることで、2つのパスは並列に動き出すそうです。

残念ながら、どのように依存関係を解決しながら平行動作させるかには言及されていませんでしたが、2つのパスの依存関係の無い場合には並列動作させることでpipeline bubbleを取り除こうという趣旨と思われます。

また、AMDのサイトでもVulkan barriers explained と題してvkCmdPipelineBarrierを解説しています。

おそらく最も使用頻度が多いのが、前のパスで作った絵を次のパスのfragment shaderで使うというシナリオだと思いますが、srcStageMask=VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT、dstStageMask=VK_PIPELINE_STAGE_FRAGMENT_SHADER_BITとすればよいそうです。これなら前のパスが絵を描き終わる前に次のパスの頂点処理を平行させることが出来そうです。

DX12では、ID3D12GraphicsCommandList::ResourceBarrierでリソースのステートを遷移させるには前後のD3D12_RESOURCE_STATESを指定すればタイミングはドライバが決めてくれました。Vulkanでは前後のVkImageLayoutに加えてVkPipelineStageFlagBitsでタイミングまでプログラマが把握して指定しなければいけません。

Sunday, October 22, 2017

[Vulkan] GeForceでスワップチェーンはRGBAでは無くBGRA

グラフィックスAPIにおいて紛らわしかったカラーチャンネルの並びの問題ですが、DirectX11やDirectX12ではRGBAだけ使えば良く、BGRAは忘れても良い存在になっていました。ところが、GeForceやIntelの統合型GPUのVulkanではスワップチェーンがBGRAでなければいけないようです。

vkGetPhysicalDeviceSurfaceFormatsKHR関数で列挙したと思われるリストが、gpuinfo.orgにあります。(Surfaceタブ→Surface formatsタブ)
https://vulkan.gpuinfo.org/displayreport.php?id=1895#surface - GTX 1050
https://vulkan.gpuinfo.org/displayreport.php?id=1922#surface - Mali-G71
https://vulkan.gpuinfo.org/displayreport.php?id=1945#surface - Radeon RX 560
https://vulkan.gpuinfo.org/displayreport.php?id=1973#surface - Adreno 540

AdrenoやMaliは逆にRGBAのみのサポートで、RadeonはRGBAとBGRAの両方をサポートしていることがわかります。

レンダーターゲットのフォーマットはRenderPassに含まれ、RenderPassはPSOが参照します。スワップチェーンに直接描画するPSOはデバイスに合わせてRGBAかBGRAかどちらかで生成されたRenderPassを指定しなければいけないことになります。

中間バッファにBGRAを使うことは無いはずなので、結局Vulkanでは同じシェーダでも「描画対象がスワップチェーンか中間バッファか」によって出来上がるPSOが別物になると考えなければいけません。

PSO生成の際のパラメータが増えて管理が煩雑になりそうですが、実際の所スワップチェーンに直接描画するものといえばUIかポストプロセスくらいなので、場合分けは難しくないと思います。

Sunday, October 15, 2017

[Vulkan] RadeonでVK_FORMAT_D24_UNORM_S8_UINTのdepth stencilテクスチャが作れない

近年多く使われていたD24_UNORM_S8_UINTのdepth stencilテクスチャはPCのVulkanで生成できないケースがあります。例えば、Radeon 560 RXでは、D24_UNORM_S8_UINTが未サポートです。代わりにD32_SFLOAT_S8_UINTを使わなければいけません。
https://vulkan.gpuinfo.org/displayreport.php?id=1945#formats

GTX 1050の場合はD24_UNORM_S8_UINTがサポートされています。
https://vulkan.gpuinfo.org/displayreport.php?id=1895#formats

DirectX12ではRadeon 560 RXでもDXGI_FORMAT_D24_UNORM_S8_UINTが作れましたが、内部でエミュレートしていると思われます。

Vulkanといえば、モバイルデバイスも気になるところですが、Adreno 540、Mali-G71共に、D24_UNORM_S8_UINTしか対応していないようです。Radeonとは逆ですね。
https://vulkan.gpuinfo.org/displayreport.php?id=1925#formats
https://vulkan.gpuinfo.org/displayreport.php?id=1922#formats
いずれのプラットフォームもD32_SFLOATは存在しているので、stencilを使わないならD32_SFLOAT、stencilを使いたいならプラットフォーム毎に分岐しなければいけなさそうです。

Monday, October 9, 2017

ゲルストナー波の法線を計算する

前回に引き続き、ゲルストナー波をやります。

ゲルストナー波の法線を計算してみます。安直な方法としては、CalcGerstnerWaveOffset関数が波のあらゆる地点の頂点位置の移動量を求められるものであることを利用し、x方向とz方向に1センチずらしてそれぞれCalcGerstnerWaveOffsetを呼び、これを三角形に見立てて法線を求めます。

これでも実用上問題無いレベルになるとは思いますが、GPU GemsのEffective Water Simulation from Physical Modelsによると、Xで偏微分するとBinormal、Yで偏微分するとTangent、それらの外積からNormalを求めることができます。親切にもNormal, Binormal, Tangentそれぞれの式がEquation 10~12として提示されていますので、そのままHLSL化してみます。ただし、Island11はYが上、論文ではZが上なので、YとZを入れ替えてあります。そのせいで、Normal = Binormal X Tangentとはならず、Normal = Tangent X Binormalになっています。


あえてくどくどと関数を分けてありますが、論文で使われている式や変数名をなるべく残すためで、現場で使う場合は1ループで一気にfloat3x3の回転行列まで求めると良いと思います。

Island11のドメインシェーダの既存の法線はそのままワールド空間の法線として使われていましたが、それをゲルストナー波の接空間(tangent space)とみなしてワールド空間に配置します。


次回は水面に物を浮かべてみます。

Saturday, October 7, 2017

HLSLでゲルストナー波を実装

NVIDIAのIsland11サンプルを改造してゲルストナー波を加えてみました。

Copyright (c) 2011 NVIDIA Corporation.


ゲルストナー波の実装例はいくつかのサイトで紹介されていますが、多くはGPU GemsのEffective Water Simulation from Physical ModelsのEquation 9の式が引用されています。

以下はこの式をHLSLで実装してみたものです。
引数のvで海面の頂点座標を受け取り、その位置においてどれだけ頂点を移動させればいいのかオフセットを返しています。C++側から乱数で生成した100個の波のパラメ ータを受け取っていますが、試行錯誤の結果20個だけ使っています。

C++でパラメータを生成するコードは以下です。

randomRadの計算で、最後の0.3fを無くすと全方向への波をランダムに生成することになります。0.3を掛けてある程度似た方向に向けて生成するようにしています。

amplitudeは波の高さで、waveLengthは波の幅です。特に決まった式があるわけではなく、見た目から数値や式を適当に選んだ結果です。ただし、GPU GemsによるとwaveLengthは中央値を基準に半分の長さから2倍の長さの波を作るといいと書いてあります。

下のgifはオリジナルのIsland11の波です。RGBをノーマル、Aをハイトマップとしたテクスチャを元に頂点を移動するだけというシンプルなアルゴリズムですが、このテクスチャの出来がいいのでとてもきれいです。

Copyright (c) 2011 NVIDIA Corporation.


波による頂点移動処理はドメインシェーダ内あり、そこをゲルストナー波に置き換えてみます。うねる波が表現できた半面、海らしい荒さが足りない気がします。

Copyright (c) 2011 NVIDIA Corporation.


そこで、Island11のオリジナルの波と合成してみると、それなりに見られるものになりました。結局ゲルストナー波単体できれいな絵はできず、さざ波や白波の表現も工夫していく必要がありそうです。

Copyright (c) 2011 NVIDIA Corporation.


次回は法線を求めてみます。

References:
Effective Water Simulation from Physical Models
Ocean Shader with Gerstner Waves
GERSTNER WAVE IMPLEMENTATION
DX11 Samples

Monday, July 17, 2017

[UE4] JAXAのGioTIFFから実物大ランドスケープを生成する

JAXAが無償公開している全世界の標高データをUE4に読み込ませてみました。 
標高データは http://www.eorc.jaxa.jp/ALOS/aw3d/index.htm からダウンロード可能です。

GeoTIFFという形式になっており、そのままではUE4では使えません。
gdal_translate.exeという変換プログラムを使って16bit PNG形式に変換します。
gdal_translateは、 http://www.gisinternals.com/ のものを使用しました。

北緯42度、東経140度のデータをUE4で使えるように16bit PNGに変換します。

gdal_translate.exe -of PNG -ot UInt16 -scale -32768 32767 0 65535  N042E140_AVE_DSM.tif 

-scaleというオプションを付けて、-32768~32767の範囲の値を0~65535の範囲にマッピングし直します。UE4ではどうやら32768をゼロとみなしており、-scale指定無しでははるか下方に地面が生成されてしまいます。一方、元データは符号付きのメートル単位の標高なので、32768を足してUE4に合わせました。

スケールの設定ですが、 せっかくなので標高を実物大にしてみます。https://wiki.unrealengine.com/Landscape_-_Sizes_and_Height_Guide
この資料によると、Zのスケールが100なら範囲が-256メートルから+256メートルになるそうです。Zのスケール1あたり2.56メートルですね。PNGに変換するときに-scaleオプションで標高の最大を32768にしたので、32768 / 2.56 = 12800 をZのスケールにすると実物大になります。

次に、XY方向を実物大にすることを考えてみます。上の資料によるとどうやらハイトマップの1ピクセルが1メートルに対応しているようです。JAXAの標高データは地球の1arcsecである約30メートル解像度なので、3000cmを掛ければY方向(南北)は実物大になります。X方向(東西)は北緯42度地点では1arcsecが赤道を1とした場合cos(42)にしないと大きさが合いませんが、UE4のランドスケープの仕様上XとYの方向の倍率を別々に指定できません。今回はX方向も3000にして我慢します。



これがほぼ実物大でインポートするScale設定になります。

マテリアルはレイヤーを用いず、標高で緑と青を塗り分ける適当なものです。


ところで、実物大になったゆえの問題が、100km四方に及ぶ広大な領域を持て余していまいち面白くないというのがあります。またUE4特有の問題として、座標値にして100万くらい(約10km)を超える場所では正常なレンダリングが保証されない問題があります。その大きさはソースコード上にHALF_WORLD_MAXというマクロで定義されています。

そこで、XYを1/10スケールである300にします。標高が強調されて地形がわかりやすくなり、面白みのある風景が出現しました。

マネキンを羊蹄山の山頂1898Mに配置し、標高が再現されていることが検証できました。
ALOS全球数値地表モデル (c)JAXA
http://www.eorc.jaxa.jp/ALOS/aw3d30/index_j.htm