無限の手続き型スターフィールドパターン
(特徴:視差スクロール)
基本的なレシピは次のとおりです。
- ランダムジェネレーターのシード(フレームごとに同じシード)
N個のランダムな点(X、Y)と「Z」値を生成します(たとえば、すべての点に対して0.5 ... 2)
すべてのポイントの位置を翻訳する:(X,Y) += scrollXY * Z
それは難しい部分です。ポイントごとにZ値が異なるため、異なる速度でスクロールします。これは「視差スクロール」と呼ばれ、驚くべき効果をもたらします。
ポイントをラップします(画面サイズを法として)。
フレームごとに同じシードを使用すると、ランダムなスターフィールドパターンが得られますが、フレームごとに永続的です(スクロール値によってのみ変更されます)。
楽しい事実
このアルゴリズムは簡単に変更できるため、N個すべての位置を実際にメモリに保存する必要はありません。必要なのは、ランダムなベース(X、Y)座標(および深さ)を提供し、定数値といくつかの星の数がシードされるジェネレーターだけです。
擬似コード:
for (int i=0; i<1000; ++i) {
RandomGenerator rnd;
rnd.seed(SomeConstantSeed + i*10293);
// determine i-th star's position
var basePosition = vec2(rnd.next(800), rnd.next(600));
var depth = rnd.next(0.5, 2);
// parallax scrolling and wrapping
var realPosition = basePosition + scrollXY * depth;
var wrappedPosition = realPosition modulo vec2(800, 600);
// these are our coordinates! let's draw
renderStar(wrappedPosition);
}
ここでは、すべての星がオンデマンドで生成され、フレーム間でその値をメモリに保持する必要はありません。フレームごとに同じ(ただしアニメーション化された)スターフィールドを生成するには、ランダムジェネレータシードが一定であるだけで十分です。
同じ手法を使用して、各星に異なるランダムな(ただし永続的な)色を割り当てることができます。
OpenGLを使用して効率的に実装する方法は?
最も簡単で効果的な方法は、頂点シェーダーでその場で位置を生成することです。
VBOでスタージオメトリを準備します。1つの頂点(ポイントスプライトの場合)、テクスチャ付きのクワッドなど、何でもかまいません。
を使用してレンダリングします。希望する星の数はglDrawArraysInstanced
どこですかprimcount
頂点シェーダーで、上記の擬似コードからループの本体を実装し、をに置き換えgl_InstanceID
ますi
。次に、上記のように、各頂点の入力XY画面位置(VSの属性変数)をスクロール値(変数として渡される)で変更しuniform vec2
ます。
いくつかの脚注:
- 頂点シェーダーにランダムジェネレーターが必要になります。1Dノイズテクスチャを使用して実装するか、こちらをご覧ください。
- 星のジオメトリが1ポイントより多い場合(つまり、ポイントスプライトではなくクワッドを使用する場合)、星の一部の頂点がラップされ、残りの頂点がラップされない状況を回避するために、画面のラップにさらに注意する必要があります。これはもう少しトリッキーですが、実行可能です。ポイントスプライトの使用は簡単です。