スプライトをサブピクセル単位でどのように移動しますか?


11

ピクセルはオンまたはオフです。スプライトを移動できる最小量は1ピクセルです。では、スプライトの動きをフレームあたり1ピクセルよりも遅くするにはどうすればよいでしょうか。

私が行った方法は、変数に速度を追加して、それが1(または-1)に達したかどうかをテストすることでした。もしそうなら、私はスプライトを動かして、次のように変数を0にリセットします:

update(dt):
    temp_dx += speed * dt
    temp_dy += speed * dt

    if (temp_dx > 1)
        move sprite
        reset temp_dx to 0
    if (tempy_dy > 1)
        move sprite
        reset temp_dy to 0

ばかげている感じがして、スプライトの動きがぎくしゃくしているので、この方法は嫌いでした。それでは、サブピクセルの動きをどのように実装しますか?


あなたができる唯一のことは、双一次フィルタリングです。
AturSams 2014年

フレームあたり1ピクセル未満しか移動しない場合、どのようにぎくしゃくするように見えますか?

回答:


17

いくつかのオプションがあります:

  1. あなたがするようにしてください。あなたはすでにそれが滑らかに見えないことを述べました。ただし、現在の方法にはいくつかの欠点があります。の場合x、以下を使用できます。

    tempx += speed * dt
    
    while (tempx > 0.5)
      move sprite to x+1
      tempx -= 1
    while (tempx < -0.5)
      move sprite to x-1
      tempx += 1

    これはもっと良いはずです。ifステートメントを0.5を使用するように切り替えました。0.5を渡すと、前の値よりも次の値に近づくからです。私はwhileループを使用して、タイムステップごとに1ピクセルを超える移動を可能にしました(これを行うのに最適な方法ではありませんが、コンパクトで読みやすいコードになります)。動きの遅いオブジェクトの場合、ピクセル配置の基本的な問題を扱っていないので、それでもまだびくびくしています。

  2. スプライトに複数のグラフィックスを用意し、サブピクセルオフセットに応じて異なるグラフィックスを使用します。唯一のxで平滑化サブピクセルを行うには、たとえば、あなたは、あなたのスプライト用のグラフィックを作成することができx+0.5、そして位置が間にある場合x+0.25x+0.75、あなたの元の代わりにこのスプライトを使用しています。より細かく配置したい場合は、より多くのサブピクセルグラフィックを作成します。あなたがこれを行う場合xと、yレンダリングのあなたの数が急速に間隔の数の二乗で数スケールとして、バルーンことができますの間隔は0.54つのレンダリングを必要とする、0.2516を必要とします。

  3. スーパーサンプル。これは、サブピクセル解像度で画像を作成するための遅延(そして潜在的に非常に高価)な方法です。基本的には、シーンをレンダリングする解像度を2倍(またはそれ以上)にし、実行時に縮小します。パフォーマンスがすぐに低下する可能性があるため、ここで注意することをお勧めします。これを行うそれほど積極的ではない方法は、スプライトをスーパーサンプリングし、実行時にそれをダウンスケールすることです。

  4. Zehelvionによって提案されているように、使用しているプラ​​ットフォームがすでにこれをサポートしている可能性があります。整数以外のx座標とy座標を指定できる場合は、テクスチャフィルタリングを変更するオプションがある場合があります。多くの場合、最近傍がデフォルトであり、これにより「ぎくしゃくした」動きが発生します。他のフィルタリング(線形/三次)は、はるかに滑らかな効果になります。

2. 3.と4.のどちらを選択するかは、グラフィックの実装方法によって異なります。グラフィックスのビットマップスタイルはプリレンダリングに適していますが、ベクタースタイルはスプライトスーパーサンプリングに適しています。システムがサポートしている場合は、4。が適切な方法です。


なぜ1のしきい値を0.5に置き換えるのですか?また、ステートメントをwhileループに移動した理由もわかりません。更新関数はティックごとに1回呼び出されます。
bzzr 2014年

1
良い質問-私はあなたのコメントに基づいて答えを明確にしました。
Jez 2014年

スーパーサンプリングは「レイジー」かもしれませんが、多くの場合、2倍または4倍のオーバーサンプリングのパフォーマンスコストは、特にレンダリングの他の側面を簡略化できる場合は特に問題になりません。
スーパーキャット2014年

大きな予算のゲームでは、グラフィック設定にアンチエイリアスとしてリストされているオプションとして、通常3が表示されます。
ケビン

1
@ケビン:あなたはおそらく実際にはしません。ほとんどのゲームはマルチサンプリングを使用しますが、多少異なります。他のバリアントも一般的に使用されており、たとえばカバレッジや深度サンプルが異なります。フラグメントシェーダーの実行コストのため、スーパーサンプリングはほとんど行われません。
イマレット2014年

14

多くの古いskoolゲームがこの問題を解決(または非表示)した1つの方法は、スプライトをアニメーション化することでした。

つまり、スプライトがフレームごとに1ピクセル未満しか移動しない場合(または、特にピクセル/フレーム比が3フレームで2ピクセルのように奇妙になる場合)、nを作成することでジャーキネスを隠すことができますこれらのnフレームにわたって、スプライトをk < nピクセルだけ移動するフレームアニメーションループ。

重要なのは、スプライトが常に各フレームで何らかの方法で移動する限り、スプライト全体が突然「ジャーク」する単一のフレームは決してないということです。


これを説明するために、古いビデオゲームから実際のスプライトを見つけることはできませんでした(たとえば、レミングスの掘り出しアニメーションの一部はそのようなものだったと思います)が、コンウェイのゲームオブライフの「グライダー」パターンがとても素敵なイラスト:

ここに画像の説明を入力してください
CC-By-SA 3.0ライセンスの下で使用されるKieff / Wikimedia Commonsによるアニメーション

ここでは、黒いピクセルの小さなブロックが右下を這っていくのがグライダーです。注意深く見ると、4つのアニメーションフレームを使用して1ピクセルを斜めにクロールしていることに気付くでしょう。しかし、これらのフレームはそれぞれのフレームで何らかの形で動くため、動きはぎくしゃくしていません(少なくとも、これ以上はありません)。とにかくそのフレームレートを見ると、何よりもぎくしゃくします。


2
これは、速度が固定されている場合、またはフレームあたり1/2ピクセル未満の場合、またはアニメーションが「大きく」、動きの変化を不明瞭にするのに十分な速さである場合、優れたアプローチです。
スーパーキャット2014年

これは良いアプローチですが、カメラがスプライトに追従しなければならない場合でも、スムーズに移動しないため問題が発生します。
Elden Abob 2014

6

スプライトの位置は浮動小数点数として保持され、表示の直前にのみ整数に丸められる必要があります。

スプライトを超解像度に維持し、表示する前にスプライトをダウンサンプリングすることもできます。スプライトを3倍のディスプレイ解像度に維持した場合、スプライトのサブピクセル位置に応じて、9つの異なる実際のスプライトができます。


3

ここでの唯一の実際の解決策は、双一次フィルタリングを使用することです。アイデアは、GPUに、重複している4つのスプライトピクセルに基づいて各ピクセルの値を計算させることです。これは一般的で効果的なテクニックです。スプライトをテクスチャとして2d-plain(掲示板)に配置するだけです。次に、GPUを使用してこれらのプレーンをレンダリングします。これはうまく機能しますが、狙った場合、多少ぼやけた結果が得られ、8ビットまたは16ビットの外観が失われることが予想されます。

長所:

すでに実装された、非常に高速なハードウェアベースのソリューション。

短所:

8ビット/ 16ビットの忠実度の喪失。


1

浮動小数点は、これを行う通常の方法です。特に、最終的にGLターゲットにレンダリングする場合で、ハードウェアが浮動小数点座標のシェーディングされたポリゴンに非常に満足している場合は特にそうです。

ただし、現在行っていることを行う別の方法がありますが、ぎくしゃくとはありません。固定小数点。画面のいずれかの軸に沿って4kピクセル未満であることはほぼ確実ですが、32ビットの位置の値は0〜4,294,967,295の値を表すことができます。したがって、固定された「2進小数点」を(小数点と同様に)中央に配置すると、サブピクセル解像度の別の16ビットで0〜65536のピクセル位置を表すことができます。次に、通常どおりに数値を追加できます。画面スペースに変換するとき、または2つの数値を乗算したときに、16ビットを右シフトして変換することを忘れないでください。

(私は、浮動小数点ユニットのないIntel 386を使用していた当時、16ビットの固定小数点で3Dエンジンを作成しました。フレームごとに200のPhongシェーディングポリゴンのブラインドスピードを達成しました。)


1

ここでの他の回答に加えて、ある程度ディザリングを使用できます。ディザリングとは、オブジェクトのピクセルのエッジの色を明るくしたり、暗くしたりすることで、背景に合わせてエッジを柔らかくすることです。たとえば、次のように近似する4ピクセルの四角形があるとします。

OO
OO

この1/2ピクセルを右に移動する場合、実際には何も移動しません。しかし、いくつかのディザリングを使用すると、動きの錯覚を少し作ることができます。Oを黒、oを灰色とみなして、次のようにします。

oOo
oOo

1フレームで

 OO
 OO

次に、次で。灰色のエッジを持つ実際の「正方形」は、実際には全体で3ピクセルかかりますが、黒より明るい灰色なので、小さく見えます。ただし、これをコーディングするのは難しい場合があります。また、現時点でこれを行うことについては、あまり意識していません。彼らが物事にディザリングを使い始めた頃には、解像度はすぐに良くなり、画像操作など以外にはそれほど必要はありませんでした。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.