私の実験についてコミュニティに伝えたいです。
私はいつも物理学を持つゲームが好きでした。 つまり、一部のプロセスはスクリプトによって制御されず、物理法則に従って時間とともに進化します。 このフローから、ゲームプレイの複雑さと予測不可能性が生じます。
多くの例がありますが、物理的な要素はさまざまなコンピューターゲームに微妙に浸透しています。 少なくとも任意のプラットフォーマーを取る:キャラクターの慣性、滑空、重力、高所からの落下によるダメージ、および武器からの反動があるとき、ゲームとはまったく異なる感覚。
または同じレース:人々を全速力で倒し、看板やゴミ箱に入れて、すぐに止まらず、地面に致命的に根ざした死んだ柱に衝突するのではなく、すべての方向に散らばることは何と喜びです。
または別の素晴らしい例は、ケルバル宇宙プログラムです。 物理学はすでにゲームプレイの直接のソースです。
または、たとえば、2D大砲のジャンル。 その魅力の一部は、破壊可能で活気のある土地に基づいています。 しかし、地球が直線的に崩壊するだけでなく、破裂した爆発から離れて現実的に振る舞うのであれば、どの程度良いでしょう。
物理的に現実的な焼けた地球のリメイクの限界まで、まさにそれをすることを長い間夢見ていた。 しかし、物理システムのモデリングに関する私のすべての実験は、信じられないほど遅いプロセッサーにかかっていました。 リアルタイムシミュレーションでは、数千個または2個の粒子が限界でした。
しかし、最近の「発見」は状況を変えました。 私たちは、ゲーミングアイロンの急速な発展の時代に生きています。 ハードウェアメーカーが高いfpsを維持しながら、ゲームメーカーがゲームのグラフィックコンポーネントの構築に最も熱心だったため、主にビデオカードが開発されました。 そして驚くべきことではありませんが、開発者がグラフィックシステム用のコードを記述する、つまりグラフィックコアで計算を実行する機能を追加するというNvidiaの決定。
私の意見では、この決定は静かな革命でした。 もちろん、ビデオカードがプロセッサよりも強力であることは知っていましたが、どの程度かはわかりませんでした。 平均的なゲーム用コンピューターでは、グラフィックスカードのパフォーマンスはCPUのパフォーマンスの50〜100倍です。
もちろん、タスクは十分に並列化される必要があり、このボーナスはどのアルゴリズムにも関係ありません。 しかし、数千の粒子のモデリングは完全に並列化されています。
これを実現して、物理学以外は何もスクリプト化されない完全に物理的なゲームを最終的に作成できることに気付きました。 ゲームは物理シミュレーションに相当します。
私は長い間Unityでゲームを作っていますが、このエンジンがComputeShaderクラスを実装し、プロジェクトでHLSL言語のシェーダーを使用できることを知ってうれしく思いました。 シェーダーを作成し、ComputeShaderインスタンスにリンクして、Updateでディスパッチするだけです。
GPUでの並列計算を理解するのは簡単ではありませんでした。 チュートリアルでは不十分であり、説明されている微妙な量はかなり限られています。 しかし、それほど大きな困難はありませんでした。HLSLの参照情報はmsdnでかなり豊富だったので、どういうわけか試行錯誤を繰り返して、詳細をマスターし、ゲームの作成を開始しました。
タスクは簡単でした。数万の相互作用する粒子をリアルタイムでシミュレートする必要があり、それらから独自の法則によってすでに生きている世界を構築することができました。
並列コンピューティングは陰湿なものです。 すべての計算を同じサイズの単純なブロックに減らして、各パーティクルに1つのストリームを持たせる必要がありました。 粒子相互作用の数学を極限まで単純化することにしました。 たとえば、積分器を使用せずに、現在のポイントで電界の大きさ(粒子の相互作用を記述)を測定し、それに基づいて粒子速度を変更するだけです。 シンプルさにより、すべてのスレッドが等しく高速に実行され、残りのスレッドが待機する必要のある重いスレッドがなくなります。
さらに、パーティクルと対話するとき、保護されたモードでデータを操作する必要がありました。これにより、パラレルストリームが同時の読み書きを認識し、混乱しないようにしました。 結局のところ、パーティクルが他の多数のパーティクルと同時に相互作用できる場合、それらのすべてが同時に速度を変更できるため、保護モードでこれを行う必要があります。 このための手段はHLSLで見つかりました。 確かに、InterlockedAdd()のような演算子はint値でのみ機能するため、精度を犠牲にしてビデオメモリに速度をint値として保存する必要がありました。
相互作用する粒子の巨大な配列も潜んでいます。 計算の複雑さを単純化する必要がありました
のようなものまで
これを実現するために、2次元の256x256グリッドを作成し、そのすべての要素で、すべてのステップですべての最も近いパーティクルへのリンクを維持しました。そのため、パーティクルの相互作用を計算するとき、各パーティクルは、いくつかの3x3グリッド要素内にあるパーティクルとのみ相互作用します。
ところで、なぜUnityに既に実装されている物理エンジンの代わりに、独自のエンジンを作成したのですか? 固体のシステムのモデリングに関連する幅広いタスクに適したユニバーサル物理エンジンは、相互作用する材料ポイントのシステムのモデリングにはあまり適していません。 私は仕様に合わせて最適化されたオリジナルのエンジンを好みました。 ユニット内の剛体で1000個のオブジェクトを作成する場合、fpsが大幅に低下することを確認できます。 私の場合、数万個のパーティクルが必要であり、ゼロから作成されたエンジンにより、優れたfpsで計算できます。
物理的相互作用の離散シミュレーションは、やはり潜んでいることです。 ステップが大きいほど、エラーが大きくなります。 粒子間の相互作用は、レナードジョーンズの力によって実現されます。つまり、粒子が互いに近づくと、反発力が12度まで増大します。 これにより、大きなステップに関連するエラーが大幅に強化されます。 単純に、物質が爆発すると、エネルギー保存の法則に違反します。
矛盾が生じます。迅速なリアルタイムシミュレーションが必要です。 しかし、ステップは非常に小さくする必要があります。 最初の実験と比較してステップを10分の1に減らし、各更新で10のシミュレーションサイクルを生成することで、この矛盾を解決しました()。 このソリューションの価格はパフォーマンスです。 そのため、パーティクルの数を大幅に減らす必要がありました。 しかし、それでもシステム全体の複雑な動作に十分な数が残っています。
まあ、物質の満足な振る舞いを得るために、数十のトリックが私によって実装されました。 たとえば、粒子間の原子価結合の類似物を導入しました。これは、隣接物間で運動量と粒子速度を分配します。 または、例えば、重力は地球の全容積に作用せず、粒子の上層のみに影響します。 しかし、物質の大きな塊が空中に舞い上がると、重力がそれらに完全に影響します。 これは、各ステップで重力マスクを作成し、計算で考慮することで実現されます。
そして、まだそのような微妙さはたくさんあります。私はこの特異性を深く掘り下げたくありません。 趣味モードで約4か月、並列計算と物理学のすべての問題を解決するのに時間がかかり、ある時点でゲームプレイのレベルに到達することができました。
最後に何が起こったのですか? その結果、ポケットタンク、スコーチドアース、ワームなどの「2D砲兵」というジャンルのゲームが完成しました。
ゲームプレイをより詳細に示した10分間の長いビデオを次に示します。
地球と建物がゼリーのように見えることに気付くかもしれません。 これはパフォーマンスのために修正されました。 ステップを減らして、粒子速度に対するフィールドの影響係数を強化できます。 しかし、私はゲームをあまり古くないビデオカードにとって負担にならないレベルに維持しようとしています。 384コアのGTX 750mカードでは、2万個のパーティクルを含むゲームが25 fpsで動作し、非常にプレイしやすくなっています。
客観的と主観的な2つの結論があります。
1.ビデオカードには非常に強力な機能があり、開発者がビデオカードを計算に使用することを妨げる、乗り越えられない技術的な障壁はありません。 これは、ゲームプロセスへの以前はアクセスできなかった(計算量が多いため)アプローチを実際に使用するために開かれる場合があります。
2.物理的に現実的なサンドボックスで遊ぶことから、非常に珍しい感覚が生じます。 そして、私の意見では、ゲームプレイ設計の分野における多くの予期しないアイデアがここに埋もれています。 また、グラフ上で光が収束しなかったため、ゲームプレイへの物理学の導入を開発者にもっと実験してもらいたいと思います。