10

私はしばらくの間それを書きたいと思っていました...大学のためのプロジェクトとして、私は(友人と)良い爆発と粒子効果を必要とするゲームを書きました。私たちはいくつかの問題に遭遇しましたが、それは非常にエレガントに解決しました(私は思います)、そして私は知識を共有したいと思います。

それでは、このチュートリアルを見つけました。JOGLでJavaを使用して実装するのに十分簡単に​​思えるパーティクル爆発効果を作成します。このチュートリアルをどの程度正確に実装したかについて答える前に、レンダリングがどのように行われるかを説明します。

Camera:は正規直交基底であり、基本的に3つの正規化された直交ベクトルと、カメラの位置を表す4番目のベクトルが含まれていることを意味します。レンダリングは以下を使用して行われますgluLookAt

glu.gluLookAt(cam.getPosition().getX(), cam.getPosition().getY(), cam.getPosition().getZ(), 
              cam.getZ_Vector().getX(), cam.getZ_Vector().getY(), cam.getZ_Vector().getZ(), 
              cam.getY_Vector().getX(), cam.getY_Vector().getY(), cam.getY_Vector().getZ());

カメラのzベクトルが実際にターゲットであり、yベクトルが「上」ベクトルであり、位置が...位置であるように。

それで(質問スタイルにすると)、良いパーティクル効果を実装する方法は?

PS:すべてのコードサンプルとゲーム内のスクリーンショット(回答と質問の両方)は、ここでホストされているゲームから取得されます:Astroid Shooter

4

1 に答える 1

22

それでは、最初にパーティクルの実装にアプローチする方法を見てみましょう。Sprite単一のパーティクルを表す抽象クラスがあります。

protected void draw(GLAutoDrawable gLDrawable) {
    // each sprite has a different blending function.
    changeBlendingFunc(gLDrawable);

    // getting the quad as an array of length 4, containing vectors
    Vector[] bb = getQuadBillboard();
    GL gl = gLDrawable.getGL();

    // getting the texture
    getTexture().bind();

    // getting the colors
    float[] rgba = getRGBA();
    gl.glColor4f(rgba[0],rgba[1],rgba[2],rgba[3]);

    //draw the sprite on the computed quad
    gl.glBegin(GL.GL_QUADS);
    gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3d(bb[0].x, bb[0].y, bb[0].z);
    gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3d(bb[1].x, bb[1].y, bb[1].z);
    gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3d(bb[2].x, bb[2].y, bb[2].z);
    gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3d(bb[3].x, bb[3].y, bb[3].z);
    gl.glEnd();
}

ここでは、ほとんどのメソッド呼び出しがかなり理解できますが、驚くことではありません。レンダリングは非常に簡単です。このdisplay方法では、最初にすべての不透明なオブジェクトを描画し、次にすべてのオブジェクトを取得してSprite並べ替え(カメラからの平方距離)、次に粒子を描画して、カメラから離れた場所に最初に描画します。しかし、ここでさらに詳しく調べなければならないのは、メソッドgetQuadBillboardです。各パーティクルは、次のように、カメラの位置に垂直な平面に「座る」必要があることを理解できます。 カメラスプライトに垂直 このような垂直平面を計算する方法は難しくありません。

  1. カメラの位置からパーティクルの位置をサブストラクチャして、平面に垂直なベクトルを取得し、それを正規化して、平面の法線として使用できるようにします。これで、平面は法線と位置によって厳密に定義されます。これは、現在の位置です(粒子の位置は、平面が通過する点です)。

  2. Y平面上のカメラのベクトルの投影を正規化することにより、クワッドの「高さ」を計算します。次の計算により、射影されたベクトルを取得できます。H = cam.Y - normal * (cam.Y dot normal)

  3. 計算により、クワッドの「幅」を作成しますW = H cross normal

  4. 4つのポイント/ベクトルを返します。{position+H+W,position+H-W,position-H-W,position-H+W}

しかし、すべてのスプライトがそのように機能するわけではなく、一部は垂直ではありません。たとえば、衝撃波リングスプライト、またはフライングスパーク/スモークトレイル: ここに画像の説明を入力してください 各スプライトは独自の「看板」を提供する必要がありました。ところで、スモークトレイルとフライングスプライトスパークの計算も少し困難でした。別の抽象クラスを作成しました。これを次のように呼びますLineSprite。ここでの説明はスキップします。ここでコードを確認できます:LineSprite

さて、この最初の試みは素晴らしかったが、予期しない問題があった。これが問題を説明するスクリーンショットです。 ここに画像の説明を入力してください ご覧のとおり、スプライトは互いに交差しているため、交差する2つのスプライトを見ると、1番目のスプライトの一部が2番目のスプライトの後ろにあり、別の部分が前にあります。 2番目のスプライト。これにより、交差点の線が表示される奇妙なレンダリングが発生しました。を無効glDepthMaskにしても、パーティクルをレンダリングすると、各スプライトで異なるブレンドが行われるため、結果には交差線が表示されることに注意してください。そのため、どういうわけかスプライトが交差しないようにする必要がありました。私たちが持っていたアイデアは本当にクールでした。

あなたはこれらすべての本当にクールな3Dストリートアートを知っていますか?これがその考えを強調する画像です:

ここに画像の説明を入力してください

このアイデアはゲームに実装できると考えたので、スプライトは互いに交差しません。これがアイデアを説明するための画像です:

ここに画像の説明を入力してください

基本的に、すべてのスプライトを平行な平面上に配置したため、交差は発生しませんでした。そして、それは同じままだったので、目に見えるデータには影響しませんでした。他のすべての角度からは、それは引き伸ばされたように見えますが、カメラの観点からは、それでも素晴らしく見えました。したがって、実装の場合:

クワッドビルボードを表す4つのベクトルとパーティクルの位置を取得する場合、元のクワッドビルボードを表す4つのベクトルの新しいセットを出力する必要があります。これを行う方法のアイデアは、ここでうまく説明されています:平面と線の交点。カメラの位置によって定義される「線」と、4つのベクトルのそれぞれがあります。カメラZベクトルを法線として使用できるため、平面とパーティクルの位置があります。また、スプライトを並べ替えるための比較関数に小さな変更が加えられます。これで、カメラの正規直交基底によって定義される同次行列を使用する必要があります。実際、計算は計算と同じくらい簡単です。cam.getZ_Vector().getX()*pos.getX() + cam.getZ_Vector().getY()*pos.getY() + cam.getZ_Vector().getZ()*pos.getZ();。もう1つ注意しなければならないのは、パーティクルがカメラの視野角から外れている場合、つまりカメラの後ろにある場合、パーティクルを表示したくないことです。特に、パーティクルの投影を計算したくない場合があります(可能性があります)。いくつかの非常に奇妙でサイケデリックスな効果をもたらします...)。あとは最終Spriteクラスを表示するだけです

結果は非常に良いです:

ここに画像の説明を入力してください

お役に立てば幸いです。この「記事」(またはゲーム:}についてコメントをお寄せください。探索、フォーク、使用が可能です...)

于 2012-09-16T12:24:43.163 に答える