気象効果の実珟。 降氎量





倩気の圱響を正しくシミュレヌトするタスクは、ゲヌム業界のたさに蚭立からほが䌞びおいたす。 倩気は私たちの生掻の䞍可欠な郚分です。぀たり、倩気の圱響のないゲヌムは完党ではありたせん。 これが、珍しいゲヌムが少なくずも非垞に原始的な倩気シミュレヌションなしで行う理由です。 タスクは非垞に叀いため、明らかに効率が䜎いにもかかわらず、珟圚も䜿甚され続けおいる倚くの叀い゜リュヌションがありたす。 そしお、通垞の霧ですべおが単玔な堎合、降氎量の実装は特定の困難を匕き起こしたす。



では、珟実の䞖界で雚や雪ずは䜕ですか



これらは、地球自䜓から雲たでの空間をほが均等に埋める数十億個の小さな粒子です。 無制限のコンピュヌティングリ゜ヌスがある堎合-降氎量をシミュレヌトするために行う必芁があるのは、堎所に均等に分散されたこの10億個の粒子を凊理するこずだけです。 しかし、私たちの蚈算胜力は非垞に限られおおり、地圢、物䜓、その他すべおを含たない堎所が降氎のみで構成される堎合に限り、リアルタむムで100䞇個の粒子でさえ蚈算できたす。 十億に぀いお䜕ず蚀えたすか。



この点で、降氎量を実装するプロセスでは、3぀の個別のタスクに盎面したす。



たず、これをどのように達成するかを怜蚎しおください。

単玔な結論に基づいお、パヌティクルの数を枛らしたす。オブザヌバヌは10億個のパヌティクル党䜓を芋るこずはありたせん。 圌は圌の埌ろに、あたりにもはるかに䞊䞋に粒子を芋たせん。 これにより、すでにパヌティクルの数が3〜4回削枛されたす。 しかし、2億は倚すぎたす。 ここで私たちの助けに少しのトリックが来たす。 実際には、粒子は非垞に小さく、実際にはすでに数メヌトルの距離で均䞀なベヌルに倉わりたす。 したがっお、「正盎に」、玄10メヌトルの距離で芳枬者の前にパヌティクルのみを描画する必芁がありたす。 これらの条件䞋での50,000個の粒子は、非垞に密な降雪の倖芳を䜜成するのに十分です。 珟実の䞖界では、粒子サむズはミリメヌトル単䜍で枬定されるこずを理解するこずも重芁です。 コンピュヌタシミュレヌションの堎合、粒子サむズを数センチメヌトルたで簡単に増やすこずができたす。 オブザヌバヌには、粒子を調べ、そのサむズを呚囲のオブゞェクトず比范する機䌚がありたせん。



以䞋は、次の蚭定の降雪のある堎所です。15メヌトル以内の粒子数25,000、粒子サむズ-10センチメヌトル、20〜100メヌトルの距離で密床80の癜い霧。







降氎が無効になっおいる同じ堎所を次に瀺したす。







粒子サむズが䞍自然に倧きいずいう事実にもかかわらず、これは芳察者によっお絶察に正垞であるず認識されたす-結局のずころ、圌は粒子たでの距離を掚定するこずができず、倧きな粒子は非垞に近いため倧きいず思われたす。 珟実にはそうではありたせんが。



2番目の重芁なタスクは、各パヌティクルの蚈算を最小限に抑えるこずです。 各フレヌム内の25,000個のパヌティクルでさえ、目に芋える負荷です。 したがっお、少しでも最適化が重芁です。 それで、思い出しおみたしょう私たちが玠盎にそれをずるならば、私たちは粒子に察しおどんな蚈算をする必芁があるのか​​



これらのパラメヌタは、正確なシミュレヌションに取り組んでいる堎合に非垞に重芁です。 ただし、ゲヌムでは、芖芚的コンポヌネントが重芁であり、物理シミュレヌションの粟床ではありたせん。 オブザヌバヌには特定の粒子の挙動を远跡する機䌚がないため、ランダム性ず正盎な蚈算を安党に取り陀くこずができたす。 粒子が倉曎せずにサむクルからサむクルぞ同じパスを通過しおも、オブザヌバヌはこれに気付かないでしょう。 別の24,999個のパヌティクルがパスに沿っお近くに移動したすルヌプしおいる堎合でも。

したがっお



ゞオメトリずの単玔化された亀差が垞に機胜するずは限らず、堎合によっおはアヌティファクトが䜜成されるこずもありたす。 芖芚的には、ボむドからの粒子の倖芳のように芋えたす。







パヌティクルは、家の䞊にあるポむント「A」でパスを開始し、ポむント「B」たで䞋降する限り、すべお正垞です。 圌女は幟䜕孊の䞊にいたす。 圌女が高さ「B」を越えるずすぐに、圌女は芋えなくなりたした。 屋根の䞋にありたす。 これは、ポむント「C」を通過するたで続きたす。 颚の圱響により、粒子は家の倖に移動し、ゞオメトリよりも高いこずが刀明したした。その結果、粒子は再び芋えるようになりたした。 芖芚的には、家の壁から粒子が「芋える」ように芋えたす。 これはかなり䞍快なアヌティファクトであり、存圚するこずを念頭に眮く必芁がありたす。 粒子ベクトルずゞオメトリの亀差を「正盎に」蚈算しようずするず、降氎システムの動䜜が非垞に遅くなる危険がありたす。 しかし、かなり単玔なヒントがありたす。颚による粒子の偏差に埓っお高さマップを倉曎したす。



この゜リュヌションの唯䞀の欠点は、颚が倉わったずきに暙高マップを再構築する必芁があるこずです。



Igrostroyは垞にアヌティファクトず速床の劥協点であり、このケヌスはそのような劥協案の䞀䟋にすぎたせん。 アヌティファクトは、颚速が高いほど顕著になりたす。



最適化の最埌の段階は、コンピュヌティングのGPUぞの移行です。 実際、前のステップの埌に特別な蚈算はありたせんでした。



XY座暙は、原点ず颚によっお远加されたオフセットから蚈算されたす。

XY = Start.xy +颚*時間;

Z座暙は、萜䞋速床の初期座暙から時間を匕いお蚈算されたす。

Z = Start.z-速床*時間

さお、最埌に-粒子の可芖性は、この点で埗られたZ座暙ずゞオメトリの高さを比范するこずで決定されたす。

IsVisible = MapHeightXY<Z



これら3぀の操䜜はすべお、GPUに簡単に転送できたす。 芳察者からの距離、照明の䜿甚、その他のささいなこずを考慮しお、透明床の蚈算もありたす。 しかし、それらはすでにGPUに適甚されおおり、明らかに、転送䞭に問題になるこずはありたせん。



䞊蚘のすべおの特定の実装の説明に進む前に、実装の別の重芁な偎面に぀いお詳しく説明する䟡倀がありたす。 ぀たり、䜜成したパヌティクルのブロックを䞖界のどこに描画するか、およびどのような圢状にするかを決定する際に。



実装時に最初に頭に浮かぶのは、円柱の䞀郚であり、芳察者の座暙ず錐台の面に沿ったセクションを䞭心ずしおいたす。







これは非垞に魅力的なオプションです。 結果ずしお生じる円柱の䞀郚内でのみ粒子を生成するため、芳察者が芋るゟヌンでのみ䜜業するこずができたす。 ぀たり、生成された50,000個のパヌティクルのほがすべおが画面に衚瀺されたす ずおも経枈的です しかし、芳察者にカメラを動かしたり回転させたりする胜力を䞎えるず、すべおが壊れたす。 粒子が錐台の内郚に残るためには、芳枬者ずずもに円柱を移動する必芁がありたす。 ぀たり、芳察者がどのように移動しお回転するかに関係なく、圌は垞に同じ粒子を芋たす これはダメです。 したがっお、別のオプションに焊点を圓おたす。退化した粒子がたくさんありたすが、カメラの回転ず移動は粒子システムの仕事を壊したせん。カメラを移動しお回転させるず、実際には同じ粒子ですが、新しい粒子を芋おいるように感じたす粒子。



アむデアは、キュヌブの圢のゟヌンで䜜業しおいるずいうこずです。 初期初期化䞭に、粒子は立方䜓の寞法に埓っおXoY平面にランダムに配眮されたす。



粒子座暙は、ブロックのサむズで䞖界の原点にある正方圢のピヌスを塗り぀ぶしたす。







黒い点は、そのたた粒子の座暙を瀺したす。 赀は同じ粒子で、ブロックのサむズによっおのみ盞殺されたす。 仕組み芳枬者の錐台がありたす。 キュヌブを取り、錐台に入れたす。 刻印の䞻な条件は3぀です。



1ナニットは回転したせん。 碑文は移動するこずによっおのみ実行されたす。

2オブザヌバヌの座暙はブロックに含たれおいる必芁がありたす。

3芳察者から錐台の䞡面ずブロックの偎面の亀点たでの距離は、できるだけ等しくする必芁がありたす。



錐台にブロックを刻んだ埌、次のような結果が埗られたす。







錐台は私たちのブロックよりもはるかに倧きいですが、問題ではありたせん。 粒子は、芳枬者からわずか数メヌトル離れおいる必芁がありたす。



内接ブロックの座暙を取埗したら、颚の適甚を考慮しお、各粒子のXY座暙を蚈算したす。 簡単にするために、この䟋では、颚がないため、粒子の座暙はXY座暙を倉曎しおいないず仮定したす。







内接ブロックに入るように、各パヌティクルを移動したす。 これを行うには、XずYのパヌティクルを移動したすが、スムヌズではなく、ブロックのサむズに等しいステップで移動したす。







粒子はそれぞれ単独ではなく、ブロック単䜍で移動するこずがわかりたす。 たずえば、ブロック「1」に入る粒子は、Xに沿っお2サむズ、Yに沿っお1サむズ移動したす。



したがっお、すべおの粒子は、グリッド䞊の倉䜍に応じお、投圱䞊のゟヌン内にありたす。

移動するず、オブザヌバヌはゟヌンを移動し、パヌティクルはそれぞれ新しい投圱に移動したす。

たずえば、オブザヌバヌが珟圚の䜍眮からXから右に移動するず、ブロック「4」ず「2」が枛少し、逆にブロック「3」ず「1」が増加したす。 巊偎のゟヌンから萜䞋する粒子は、右偎にゞャンプしたす。 その結果、移動するず、芳枬者はたすたす倚くの新しい粒子を芋たすが、実際にはこれらはゟヌンから萜ちた叀い粒子です。 回転の堎合ず同じ状況で、芳察者の䜍眮が倉わっおもゟヌンだけは倉わりたせんが、錐台の境界が倉わるためです。



実甚的な実装



すべおの堆積物粒子は1぀のDIPで描画されたす。 頂点バッファヌは静的に䞀床初期化され、倉曎されたせん。 各パヌティクルは1぀の頂点で衚され、ブロック内にランダムなXYがありたす。 ゞオメトリシェヌダヌは、䞊からパヌティクルを䜜成したす。 雪の䟋で䜜られたした。 雚の堎合は、球圢の看板ではなく、円筒圢のものを䜿甚する必芁がありたす。 そしお、それに応じお、粒子は正方圢ではなく、長方圢です。



すべおの粒子に察しおグロヌバルに次のデヌタが必芁です。

mat4 ModelViewProjectionMatrix; -座暙をモデル空間からカメラ空間に倉換し、スクリヌン平面に投圱するための投圱モデルビュヌマトリックス。

フロヌト時間; -秒単䜍のグロヌバル時間。

フロヌト速床; -粒子萜䞋率;

フロヌトトップ; -粒子が萜䞋し始める高さ;

フロヌト底; -粒子の萜䞋が止たる高さ。

float CircleTime; -粒子が最高点から最䜎点に移動する時間。

vec2颚; -颚速;

float TileSize; -ブロックサむズ。

vec2 Border; -ブロック座暙。 ブロックの巊䞊隅。 右䞋はBorder + vec2TileSize、TileSizeです。

float ParticleSize; -粒子サむズ;

sampler2Dテクスチャ。 -粒子のテクスチャ。



各パヌティクルの属性

vec2䜍眮; -䜍眮。 この倀はブロック内でランダムに蚭定されたす。 Z座暙が蚭定されおいないのは、 シェヌダヌ内で蚈算されたす。

float TimeShift; -0を基準ずした時間のパヌティクル倉䜍。倀はCircleTime内でランダムに蚭定されたす。



この倀をTimeに远加するず、パヌティクルのランダムな開始䜍眮が取埗されたす。

float SpeedScale; -0.9-1.1の範囲のランダムな倀。 このSpeedの倀を乗算するず、パヌティクルごずにわずかに異なる速床が埗られたす。

頂点シェヌダヌ



uniform mat4 ModelViewProjectionMatrix; uniform float Time; uniform float Speed; uniform float Top; uniform float Bottom; uniform float CircleTime; // (Top-Bottom)/Speed uniform vec2 Wind; uniform float TileSize; uniform vec2 Border; in vec2 Position; in float TimeShift; in float SpeedScale; out vec4 Position3D; void main(void) { float ParticleCircleTime = CircleTime / SpeedScale; float CurrentProgress = mod(Time + TimeShift, ParticleCircleTime); vec3 Pos = vec3(Position.xy + Wind*CurrentProgress , Top - Speed*SpeedScale*CurrentProgress); Pos.x = mod(Pos.x, TileSize); Pos.y = mod(Pos.y, TileSize); float c; c = floor(Border.x/TileSize); if (c*TileSize+Pos.x < Border.x) Pos.x = Pos.x + (c+1)*TileSize; else Pos.x = Pos.x + c*TileSize; c = floor(Border.y/TileSize); if (c*TileSize+Pos.y < Border.y) Pos.y = Pos.y + (c+1)*TileSize; else Pos.y = Pos.y + c*TileSize; Position3D = ModelViewProjectionMatrix * vec4(Pos,1.0); }
      
      





幟䜕孊的なシェヌダヌ



 layout(points) in; layout(triangle_strip, max_vertices=12) out; const vec3 up = vec3(0.0,1.0,0.0); const vec3 right = vec3(1.0,0.0,0.0); uniform vec2 ParticleSize; in vec4 Position3D []; out float TexCoordX; out float TexCoordY; void main(void) { vec3 u = up * vec3(ParticleSize.y); vec3 r = right * vec3(ParticleSize.x); vec3 p = Position3D[0].xyz; float w = Position3D[0].w; gl_Position = vec4 ( p - u - r, w ); TexCoordX = 0.0; TexCoordY = 1.0; EmitVertex (); gl_Position = vec4 ( p - u + r, w ); TexCoordX = 1.0; TexCoordY = 1.0; EmitVertex (); gl_Position = vec4 ( p + u + r, w ); TexCoordX = 1.0; TexCoordY = 0.0; EmitVertex (); EndPrimitive (); // 1st triangle gl_Position = vec4 ( p + u + r, w ); TexCoordX = 1.0; TexCoordY = 0.0; EmitVertex (); gl_Position = vec4 ( p + u - r, w ); TexCoordX = 0.0; TexCoordY = 0.0; EmitVertex (); gl_Position = vec4 ( p - u - r, w ); TexCoordX = 0.0; TexCoordY = 1.0; EmitVertex (); EndPrimitive (); // 2nd triangle }
      
      





フラグメントシェヌダヌ



 uniform sampler2D Texture; in float TexCoordX; in float TexCoordY; out vec4 color; void main(void) { color = texture(Texture, vec2(TexCoordX, TexCoordY)); }
      
      







䞎えられたシェヌダヌが䜕をするかを詳しく芋おみたしょう。

すべおの基本的な操䜜は、頂点シェヌダヌで実行されたす。 ゞオメトリシェヌダヌはポむントをボリュヌムパヌティクルにアンパックしたすが、フラグメントシェヌダヌは単にテクスチャを適甚したす。 コヌドが単玔であるため、ゞオメトリシェヌダヌずフラグメントシェヌダヌは考慮されたせん。



頂点シェヌダヌを考えおみたしょう

最初に行う必芁があるのは、パヌティクルが珟圚どの䜍眮にあるかを調べるこずです。 私たちの䜍眮は時間に結び぀いおいるため、時間を蚈算する必芁がありたす。 これは、2぀の操䜜で行われたす。



float ParticleCircleTime = CircleTime / SpeedScale;

float CurrentProgress = modTime + TimeShift、ParticleCircleTime;

最初の行は、特定の粒子のサむクルに合蚈サむクル時間を䞎えたす。 なぜなら サむクルは速床に䟝存し、SpeedScaleでは速床が異なるため、必芁なこずは、合蚈サむクル時間を速床係数で陀算するこずだけです。



2行目では、珟圚のグロヌバルパヌティクル時間を取埗し、1サむクルの時間で陀算し、CurrentProgressの陀算の残りを取埗したす。 これは、特定のパヌティクルの珟圚のサむクルの開始から経過した時間です。



次のステップは、経過時間に埓っお䜍眮を蚈算するこずです。 XYを蚈算するには、颚から受け取ったオフセットを開始䜍眮に远加する必芁がありたすZの堎合-萜䞋速床に時間を掛けたす。

vec3 Pos = vec3Position.xy + Wind * CurrentProgress、Top-Speed * SpeedScale * CurrentProgress;

粒子は颚によりブロックの倖を飛ぶ可胜性があるため、粒子をブロックに戻す必芁がありたす。

Pos.x = modPos.x、TileSize;

Pos.y = modPos.y、TileSize;

その結果、ブロック内の粒子の座暙を取埗したす。







ただし、原点ではなく、芳枬者の呚囲にパヌティクルが必芁です この点に関しお、粒子を錐台の呚りで説明したゟヌンに移動したす。



c = floorBorder.x / TileSize;

ifc * TileSize + Pos.x <Border.x

Pos.x = Pos.x +c + 1* TileSize;

他に

Pos.x = Pos.x + c * TileSize;



c = floorBorder.y / TileSize;

ifc * TileSize + Pos.y <Border.y

Pos.y = Pos.y +c + 1* TileSize;

他に

Pos.y = Pos.y + c * TileSize;





投圱された座暙はスクリヌンに投圱されたすPosition3D = ModelViewProjectionMatrix * vec4Pos、1.0;



次に、ゞオメトリシェヌダヌが頂点をパヌティクルにアンパックしたす。



䞊蚘のコヌドは、snowの最も単玔な実装です。 グロヌバルラむティング、点光源、ゞオメトリずの亀差点の远加-タスクは非垞に簡単で、自分で凊理できるず思いたす。 たた、粒子だけではシャワヌや降雪を䜜り出すのに十分ではないこずを忘れないでください。 粒子はあたり倚くありたせん。 この状況では、霧が助けになり、その助けを借りお雪や雚の芆いが䜜られたす。



泚

この蚘事は数幎前に未出版の本の䞀郚ずしお曞かれたした。

かなり倧芏暡なプロゞェクトで䜜業を完了した埌、振り返っおみるず、長幎の開発の間に、興味深い話題になる可胜性のあるタスクがあるこずがわかりたした。 その結果、本が登堎したした。 この本は2012幎に執筆および線集されたしたが、どこにも出版されおいたせん。 察象読者は明確ではありたせんでした。



今日、私はこの本のテキストに出䌚い、おそらくそれからいく぀かの章がHabrコミュニティにずっお興味があるず思いたした。



テストずしお、倩気効果の実装に関する章を公開したす。 コミュニティがこの蚘事を歓迎しおいる堎合は、あず数章を公開したす。



All Articles