HTML5 / JavaScriptゲームでタイルを使用して滑らかな照明遷移を作成する


7

タイル置換を使用してHTML5 / JavaScriptゲームに照明効果を実装しようとしています。私が今持っているのは一種の動作ですが、光源が動き回るので、トランジションは十分に滑らか/自然に見えません。これが私が今いるところです:

  1. 現在、背景マップに明るい/シャドウスペクトルのPNGタイルシートが適用されています。最も暗いタイルから完全に透明になっています。デフォルトでは、最も暗いタイルが起動時にレベル全体に描画され、他のすべてのレイヤーなどをカバーします。
  2. 各タイルの位置を計算し、そのx座標とy座標を配列に格納するために、所定のタイルサイズ(40 x 40ピクセル)を使用しています。
  3. 次に、配列の各位置に透明な40 x 40ピクセルの「グリッドブロック」エンティティを生成します
  4. 次に、使用しているエンジン(ImpactJS)により、光源エンティティからこのグリッドブロックエンティティのすべてのインスタンスまでの距離を計算できます。
  5. 次に、それらの各グリッドブロックタイルの下のタイルを適切な透明度のタイルに置き換えることができます。

現在、マップ上に生成されるグリッドブロックエンティティの各インスタンスで、次のような計算を行っています。

var dist = this.distanceTo( ig.game.player );
var percentage = 100 * dist / 960;

if (percentage < 2) {
    // Spawns tile 64 of the shadow spectrum tilesheet at the specified position
    ig.game.backgroundMaps[2].setTile( this.pos.x, this.pos.y, 64 ); 
}       
else if (percentage < 4) {
    ig.game.backgroundMaps[2].setTile( this.pos.x, this.pos.y, 63 );
}
else if (percentage < 6) {
    ig.game.backgroundMaps[2].setTile( this.pos.x, this.pos.y, 62 );
}       
// etc...

問題は、私が言ったように、このタイプの計算では光源が非常に自然に見えるわけではないということです。タイルの切り替えがシャープすぎるように見えますが、理想的には、スペクトルタイルシートを使用してスムーズにフェードインおよびフェードアウトします(これを行うために管理している別のゲームからタイルシートをコピーしたので、タイルシェードの問題ではないことがわかります。他のゲームがそれをやっている方法)。おそらくパーセンテージを使用してタイルを切り替える方法は、スムーズな移行を可能にするような、より良い/より動的な近接フォーラムで置き換えることができると思いますか?ここでビジュアルを改善するために私ができること、または各タイルについて収集している情報との近接度を計算するより良い方法について、誰かが何かアイデアを持っているでしょうか?

(追記:スタックのオーバーフローから誰かの提案でこれを再投稿しています。重複については申し訳ありません!)


1
あなたが持っているものとあなたが持ちたいもののスクリーンショットを投稿できますか?
MichaelHouse

確かに、私は今夜スクリーンショットを投稿します。
スペクトル

1
スクリーンショットを追加するのを忘れました...
MichaelHouse

回答:


5

まず、この種の作業をHTML5で行ったことがないので、特定のプラットフォームをサポートできないことを残念に思います。したがって、言語にとらわれない方法でこれに対処するようにします。

タイルごとに光量を計算していると、スムーズな移行が得られないと思います。これは、フラットシェーディング、グーローシェーディング、フォンシェーディングの違いと似ています。

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

あなたがしていることは、フラットシェーディングに似ています。つまり、タイルごとに異なるライトを割り当て、上の画像に示されているように、タイル間のシャープな遷移をもたらします。

より良い結果を得るには、頂点ごとにライトを計算する必要があります(つまり、グーロー)。あなたのエンジンの機能が何であるかはわかりませんが、理想的なケースは、各タイルが四角形で、その頂点に直接アクセスできる場合です。次に、各頂点のライトからの距離を計算し、シェードカラーを頂点のすぐ内側に格納できます。最後に、レンダリングパイプラインは、タイルの表面全体の陰影の補間を自動的に処理し、より滑らかな外観(別名グローシェーディング)を実現します。

少しコストは高くなりますが、より良い結果を得るには、フラグメントシェーダー内でピクセルごと(つまりフォン)に基づいてライトを計算できます。あなたの例からそうであるように、サンプリングするライトが2、3個しかない場合、基本的なアプローチはうまく機能します。

最後に、非常にうまく機能する別の方法として、最初にすべてのライト(およびライトのみ)を個別のレンダーターゲットにレンダリングし、オプションで結果をぼかし、最後にシーンの残りの部分とブレンドする方法があります。これに関するいくつかのアイデアについては、この質問を確認してください。


最後の代替案は、HTML5 Canvasに適しているようです。ImpactJSが特にシェーダーと頂点を実装していない限り、他のものはCanvasに公開されません。
DMan、2012年

@DManそうです、キャンバスベースの場合、おそらくこれらの変更をサポートしていません。おそらくそれはWebGLエンジンだったのではないかと考えていましたが、その場合は簡単です。
David Gouveia

細かい対応ありがとうございました。今晩の最後の提案と、私が試みている他のいくつかのアイデアを調べます。
スペクトル

4

線形減衰のある照明のように見えます(光の強度は線形に低下しています)。逆二乗則を試してみてください。または、単純な指数関数的な減衰。

float maxLightDistance = 64;
float fallOff = 1.4f;
float intensity = Math.pow(distanceFromSource / maxLightDistance, fallOff);
int tileToUse = (int)intensity;
ig.game.backgroundMaps[2].setTile( this.pos.x, this.pos.y, tileToUse);

上記のコードはまた、if else ifあなたが行っている凶悪なことを取り除くのにも役立ちます。

基本的な指数関数的減衰だけを使用して、次のような結果が得られます(単一の光源の後でより良い画像を投稿できますが、現時点ではありません)。

溶岩からの光

また、Excelのようなプログラムはこのようなものに最適であることにも言及する必要があります。数式の変更をかなり迅速にテストしてグラフ化するか、条件付きルールを使用してセルの色を変更できます。


減衰式を変更しても、タイルの表面全体に光がスムーズに補間されないことに注意してください。各タイルには、次のタイルに到達したときに突然変化する単一の色があります。明るさの非常に小さな変化を使用すると、問題を隠して見栄えをよくすることができますが、それでもスムーズな移行ではありません。また、逆二乗則ではなく線形減衰(効果の最大半径と最小半径)の外観を優先するプロジェクトがあったため、減衰の選択は美学に大きく関係していると私は主張します。
David Gouveia

私の提案は、OPがすでに持っているものに基づいています。これは、レンダリングシステムを再作成する必要なく、簡単に試せるソリューションであることを意味しています。また、OPsメソッドが複数の色合いのタイルを隣り合わせに配置している場合、違いが生じる可能性があります。
MichaelHouse

@spectralbatしかし、私はそのif else if連鎖を取り除くことに断固として同意します。パーセンテージをタイルインデックスにマップするメソッドを作成しsetTile、Byte56の例のように、すべてのブランチを1回の呼び出しで置き換えます。
David Gouveia

もちろん、あなたが指摘したのは良いことです。特に、変更がどれほど単純かを考えると、OPが現在持っているものよりも良く見えるかもしれません。:) タイルのスムーズな移行の実際の問題とは何の関係もないと私は指摘しています。しかし、多分それはまさにOPが求めていたものであり、私は誤解したのは私だった。;-)
David Gouveia 2012年

ありがとう!これで私の元の問題が解決されない場合でも、見栄えをよくするために何かを試みます。これと今夜試してみた他のいくつかのオプションを紹介します。
スペクトル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.