粒子でソフトエッジ領域を実装する方法


13

私のゲームはPhaserを使用して作成されていますが、質問自体はエンジンに依存しません。

私のゲームにはいくつかの環境があります。基本的に、プレイヤーキャラクターが移動して影響を受けるポリゴンエリアです。たとえば、氷、火、毒など。これらの領域のグラフィック要素は、色で塗りつぶされたポリゴン領域自体と、適切なタイプの粒子(この例では氷の破片)です。これは現在、私がこれを実装している方法です-タイルスプライトをパーティクルパターンで覆うポリゴンマスクで:

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

ハードエッジは悪いように見えます。次の2つのことを実行して改善したいと思います。1.多角形の塗りつぶし領域をソフトエッジにし、背景に溶け込ませます。2.いくつかの破片をポリゴン領域から出させて、それらが中央で切断されず、領域に直線がないようにする

例(モックアップ):

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

ポリゴンをぼかすことで1を達成できると思いますが、2でどうすればいいかわかりません。

これをどのように実装しますか?


2
それはすごいですね。あなたのゲームへのリンクをお願いできますか?:)
ashes999

@GameAlchemistこれはタイル画像ですi.imgur.com/y54CeQ9.png
OpherV

@ ashes999それはまだ進行中の作業です。リンクが
完成

白いオブジェクトを含む透明なPNGであることに注意してください。あなたは(ブラウザで画像を開くことが多い場合などのように)白い背景の上にそれを表示した場合、あなたは何も表示されません
OpherV

@OpherVそれは素晴らしいだろう。質問を編集してリンクを投稿してください。これはおそらく、このサイトで最も話題になっている方法です:)
ashes999

回答:


2

1.モックアップに近いものが必要な場合は、パーティクルを使用します(完全にブローされたパーティクルシステムである必要はありません)。

RenderTextureでポリゴンの形でパーティクルをレンダリングします。必ず粒子に添加剤のブレンドを使用してください。ポリゴンの内側のパーティクルは互いにスムーズにブレンドされ、外側のパーティクルは必要なソフトエッジを提供します。(エフェクトの例は、このyoutubeビデオで見ることができます:Additive Particles Video これで、RenderTextureがメイン画面にレンダリングされ、完了です。RenderTextureは、パーティクルが背景と混ざらないようにするために必要です。

三角形をパーティクルテクスチャに直接配置して、これがどのように機能するかを確認できます。それ以外の場合は、「パーティクルスープ」の上に別のレイヤーとしてレンダリングします。

このように見える更新されたjsfiddleで簡単なモックアップを作成しました。更新デモ されたデモはここで見つけることができます

2.各パーティクルには速度と原点があります。プレイヤーがポリゴンに触れると、プレイヤーの速度に比例して各パーティクルの速度が変化します。パーティクルがプレイヤーから離れるほど、プレイヤーの速度による影響は少なくなります。

粒子の速度を計算する式は次のようになります。

//player.velocity and particle.velocity are vectors 
//k is a factor to enhance or weaken the influence of players velocity
var distanceToPlayer = (player.position - particle.position).length();
particle.velocity = particle.velocity + ((k * player.velocity) + particle.velocity) * (1/distanceToPlayer);

パーティクルの位置を計算するには、これを更新メソッドに入れます:

var speedY = -(springConstant * (particle.position.y - particle.origin.y)) - (dampingFactor * particle.velocity.y);
var speedX = -(springConstant * (particle.position.x - particle.origin.x)) - (dampingFactor * particle.velocity.x);

particle.position.y = particle.position.y + speedY;
particle.position.x = particle.position.x + speedX;

particle.velocity.x = particle.velocity.x + speedX;
particle.velocity.y = particle.velocity.y + speedY;

これにより、プレイヤーが流体を攪拌したときに各パーティクルがその原点を中心に揺れる「流体」が得られます。springConstantは、パーティクルがその原点からどれだけ離れてスイングするかを変更し、dampingFactorは、パーティクルが静止する速度を変更します。ゲームで使用している1dシミュレーションの修正バージョン以降、コードを調整する必要がある場合があります。

デモがあります:デモ 流体が希望どおりに動作するまで、上部の3つの定数を微調整します。


それは#1を解決するための本当に興味深いアイデアです!私はそれが好きです。三角形の移動\間隔の実装をどのように提案しますか?
OpherV

1
質問2に答えるために元の投稿を編集しました。
ジルス

パーティクル効果の小さなデモを追加しました。少し調整するだけで目的の効果が得られると思います。
zilluss

私は最終的にあなたのソリューションを使用しました。それは私が達成しようとしていた効果に最も近いものです。ありがとう!しかし、1つの質問-あなたの例でどのように弾力性をクランプし、本当にわずかな動きでも粒子がそのような巨大な距離をジャンプしないようにしますか?
OpherV

dancingFactorとspringConstantをいじることができます。減衰が大きいと、粒子がより速く静止します。バネ定数が低いと、粒子の速度が低下します。残念ながら、どちらの値でも粒子のスープはより粘性があります。そのため、代わりに、プレイヤーがパーティクルに触れたときに、プレイヤーがパーティクルに追加する最大速度を次のようにクランプできます。particle.velocity.x = clamp(maxVelocity、-maxVelocity、particle.velocity.x +((playerInfluenceFactor * deltaVelocityX )+ particle.velocity.x)*(1 / distanceToPlayer)); クランプについては、stackoverflow.com
a / 11409944を

4

これらの2つのポイントに関する私の考え:

  1. シェーダーブラーを使用することもできますが、それは非常に高価になります。代わりに、中心の半透明から端で透明にフェードする三角形の追加の境界線を描画して、「ぼかし」をシミュレートします。私は私のゲームでそれをやったが、それはかなりうまく機能している。これが私のゲームの虹っぽいブースターのスクリーンショットです。

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

    外側の境界には勾配があります。私の状況では、境界線は内側の部分と同じ不透明度で始まりませんが、これらの不透明度を等しく設定すると、きれいなフェードが得られます。

  2. パーティクルシステムをプログラムし、パーティクルをポリゴンに追従させます。そうすることで、エッジで何が起こるか心配する必要がなくなります。パーティクルシステムのダイナミクスにより、パーティクルがポリゴン内にあり、均等に分布していることが確認されます。最も近いパーティクルが互いに押しやろうとすることもできますが、慣性を持たせて滑らかに見えるように、多くの「質量」で作成することができます。これを速くするためには、いくつかの可能性がありますが、大きな問題は、お互いのメカニズムをプッシュする時間の複雑さです。各パーティクルに他のすべてのパーティクルをプッシュさせると、システムに100個のパーティクルがある場合、O(n ^ 2)になりますが、これは良くありません。これを最適化する方法については、PixelJunkの次のプレゼンテーションを参照してください。http://fumufumu.q-games.com/gdc2010/shooterGDC.pdf

    より単純なアプローチは、パーティクルシステムを構築するときに、各パーティクルを3つまたは4つの他のパーティクルに接続することです。これで、すべてのパーティクルは、接続されている4つの他のパーティクルをプッシュするだけで済みます。ただし、このアプローチでは、パーティクルシステムの乱流が不可能になります。しかし、現在の状況では静的テクスチャを使用しているため、これは問題ではないようです。このアプローチは素晴らしいO(n)になります。


ありがとう!1.これを視覚化するのに苦労しています。ゲームでどのように見えるか動作するかのモックアップを投稿してください。2.面白い!その上で読み上げます
OpherV

画像をありがとう。チューブベースまたはラインベースのシェイプでどのように機能するかはわかりますが、ポリゴンではどのように機能しますか?両側から投影された三角形のグラデーションがうまく整列しないのではないでしょうか...?
OpherV

うまくフィットさせます。それがアイデアです。これには、数学や交差点の計算などが含まれます。境界線をさらに分割して、滑らかにすることもできます。可能性のトン。
マーティンコートー

3

あなたの投稿を読んだときに私が持っていたアイデアはこれでした:
•あなたがあなたの地域に使用するタイルのセットを構築します。
•タイルの解像度で小さな一時的なキャンバスにエリアポリゴンをレンダリングします(例:タイルが16X16の場合、(16X、16X)より低い解像度でレンダリングします)。
•その一時的なキャンバスを使用して、メインキャンバスにタイルをレンダリングするかどうかを決定します。
低解像度のキャンバスにポイントが設定されている場合、メインキャンバスに「ランダム」タイルを描画します。ポイントが設定ポイントのちょうど隣にある場合、メインキャンバス上でより低い不透明度で「ランダムな」タイルを描画します(トランジションを行うため)。

解像度を下げるとブロック効果が生じるのではないかと心配しましたが、20X20のタイルを使用しても、非常にきれいに見えます。

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

この手順は次のとおりです。ポリゴンを取得します。
ここに画像の説明を入力してください

タイルの解像度でポリゴンを描画しますここに画像の説明を入力してください(!!はい、それはモールの赤いものです)。

次に、低解像度キャンバスのimageDataを使用して、タイルまたはノートを描画するかどうかを決定します。
低解像度キャンバスにピクセルが設定されている場合、タイルを描画する必要があることを意味します。「ランダム」タイルインデックスを選択して、描画するタイルを選択します。そのランダムインデックスは、特定のエリア/タイルで常に同じでなければなりません。
ポイントが空であるが塗りつぶされたポイントの隣にある場合、タイルも描画しますが、不透明度は半分です。

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

それではタイルを描きましょう:

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

ポリゴンの場合、ポリゴンを数回描画して縮小し、描画ごとに不透明度を増やします(globalCompositeOperation 'lighter'も使用できます)。

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

すべてを追加すると、次のようになります。

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

フィドルはこちら:

http://jsfiddle.net/gamealchemist/T7b4Y/

これが役立つかどうか教えてください。


ソリューションについて詳しく説明し、コードを提供してくれてありがとう!「次に、低解像度のキャンバスのimageDataを使用して、タイルまたはノートを描画するかどうかを決定します」とはどういう意味ですか。小さな画像データをどのように使用して、大きな画像にどこをどのように描画するかを決定しますか?そして、この方法を使用して、三角形の重なりを回避して、モックアップと同様の間隔を実現するにはどうすればよいですか?
OpherV

私はそれが完全なブールテストであることを意味します:このタイルを埋める必要がありますか?trueまたはfalseは、imageData [(x + y * width)* 4]!= 0の低解像度テストのテストによって与えられます。つまり、== '低解像度キャンバスに何かを描画しましたかそのタイルの場所?次に、はいの場合、精巧な素数で埋められた数式(getRandomNumber)を使用して、(x、y)から「ランダムな」タイルインデックスに移動します。ポリゴンを適切に定義した場合、どのように重複するかわかりませんので、2番目の質問はありません。
GameAlchemist

1

ただのアイデア:

タイルでは、「ピース」の幅は最大で約80ピクセルです。2つのエリアを作成することをお勧めします。元のポリゴンを描画し、各エッジから約80ピクセルのモックアップを作成します。次に、タイルをより大きなポリゴンに描画します。

次に、内側のポリゴンの外側にピクセルがあり、内側のポリゴンと交差しないすべての「ピース」を塗りつぶして透明にします。

これは非常に高いレベルですが、あなたと共有すると思いました。ここで決定すべき多くの詳細があります。

以下を示す粗雑な画像:

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

内側の黒いポリゴンが元のポリゴンである場合、すべてのポリゴンを赤いドットで消去します。


ただし、タイルイメージに埋め込まれたピースと内部ポリゴンとの交差をどのように確認しますか?
OpherV

@OpherVうーん、ポイントXがポリゴン内にあるかどうかを判断できますか?外側のポリゴン内のすべてのピクセルをループし、白いピクセルごとにすべてのピクセルを塗りつぶし、内側/外側にあるかどうかを確認できます。しかし、これは特に効率的には聞こえませんが、何かを取得したら、最適化する方法を考えることができますか?
user46560

これはCPUで行われる後処理です。それ自体ではほとんど最適化できません。内側のポリゴンと外側のポリゴンが三角形のストリップで接続されている場合、アイデアはうまく機能します。OPは頂点属性情報を追加し、各頂点を内側または外側としてタグ付けできます。次に、頂点シェーダーで、不透明度/アルファを透明度の低い値から完全に不透明な値に線形補間できます。
テオドロン

@teodronこれは、私が答えで作ろうとしたポイントです。それは高レベルのアイデアであり、私は実際にはゲーム開発者ではありません。アイデアを思いつきました。
user46560

@ user46560ええ、しかしこの方法では、そのポリゴン間バンドにあるピクセルを計算する必要はまったくありません。GPUでもCPUでもありません。あなたが言うようにゲーム開発の方法に慣れていないので、あなたはあなたのアイデアのために+1に値します:)。
テオドロン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.