スプライトの周りにアウトラインを描く効率的な方法


21

私はXNAを使用してゲームをプログラムしており、スプライトで「選択された」効果を実現するためのさまざまな方法を試しています。私が抱えている問題は、スプライトバッチに描画される各クリック可能オブジェクトが複数のスプライトを使用して描画されることです(各オブジェクトは最大6つのスプライトで構成できます)。

Xピクセルのスプライトにアウトラインを追加する方法を教えていただければ幸いです(アウトラインの幅はピクセルのさまざまな数になります)。

前もって感謝します、

  • グレッグ。

回答:


20

これを実行する最も簡単な方法(パフォーマンスに本当に縛られていない限り、おそらく最良の方法です)は、スプライトのコピーを2つ持つことです。

  • 通常版
  • 「脂肪」、無着色バージョン-基本的に、オリジナルよりも「太い」スプライトX-manyピクセルの白色バージョン。

「ファット」バージョンを使用してオブジェクト全体を描画し、その上に通常バージョンを描画します。

「脂肪」バージョンを白にすることにより、SpriteBatchの組み込みのカラーティントを使用して、選択色を動的に変更できます。

「ファット」バージョンを生成するには、元のスプライトを自動的に取得し、アルファチャンネルを読み取り、元の画像の最大アルファチャンネルをサンプリングして新しいアルファチャンネルを作成できるContent Pipeline Extensionを作成することをお勧めします。設定RGB =(1,1,1)。

スプライトにはすべて、アウトラインを追加するのに十分な透明な境界線があることを確認する必要があります(コンテンツプロセッサでこれを確認し、必要に応じてスペースを空けることもできます)。

スプライトが数個しかない場合は、適切な画像エディター(GIMP、Photoshop)を使用して手動で実行できます:アルファチャンネルから選択、展開、選択からアルファ、カラーチャンネルを白で塗りつぶします。


4

最初に各オブジェクトを単一のスプライトに描画する必要があると思います。次に、スプ​​ライトのエッジを検出するためにシェーダーを作成し、エッジが見つかったところにピクセルを描画する必要があると思います。これを行うには、既にいくつかのシェーダーが存在している必要があり、使用または移植することができます。


11
この種のシェーダーは驚くほど書くのが面倒です、と聞いたことがあります(3Dゲームの1つで使用し、見苦しいエッジケースにぶつかりました)。考えたいことの1つは、(0、255、255、0)のような特定の色でアウトラインをスプライトテクスチャに直接エンコードし、スプライトが選択されたときにシェーダーにその色を変換させることです。その後、シェーダーは簡単な色の変更であり、アウトラインや必要な詳細をアーティストが高度に制御できます。

4

要件に応じて、スプライトのアウトラインをオンデマンドで作成することも効果的です。私はあなたのスプライトに透明性があり、単なる長方形ではなく不規則な形であると仮定しています(これではうまくいきますが、輪郭の長方形は些細なはずです)。

when selected:
   outline = new sprite canvas of appropriate size
   for sprite in object:
      # use larger numbers for thicker outlines
      for x in (-1, 0, 1) and y in (-1, 0, 1):
         render sprite mask into canvas at x,y with desired color

描画するたびにこれを行う必要はないことに注意してください(可能であれば)が、スプライトを切り替えるときに新しいアウトラインスプライトを作成するだけです。


はい、これも私が提案したかったものです。マスクされたスプライトを、元のスプライトの左、右、上、下に、既存のスプライトの下に1ピクセルずつレンダリングします。多くのゲームでは、この方法を使用して、レンダリングされたテキストの輪郭を描くか、4つの位置のうち2つだけでドロップシャドウを作成します。
カイ

1

最も単純なブルートフォースアプローチは、各スプライトの2つのコピーを作成することです。通常のコピーと強調表示されたコピーです。次に、強調表示されたらそれらを交換します。

メモリに余裕がある場合は、それ以上複雑にする必要はありません。さらに、アーティストは、強調表示されたときに外観を完全に制御できるため、アウトラインやその他の任意の操作を実行できます。


問題の一部は、OPが各オブジェクトを複数のスプライトで作成できると言っていることだと思います。したがって、アウトラインは、各コンポーネントスプライトの周りに別個のアウトラインを持つのではなく、結合されたオブジェクトのアウトラインでなければならないと思います。
クリス・ハウ

1
クリス、結合されたオブジェクトの輪郭である必要はなく、複数のスプライトで作成されたオブジェクトに対してはうまく機能します。wkerslakeが言ったことを正確に実行しますが、そのオブジェクトのすべての通常のスプライトの背後に強調表示されたスプライトを必ず描画してください。そのようにオブジェクトが何個のスプライトで構成されていても、ハイライトはそのオブジェクトの描画時間の2倍をわずかに超える時間しか使用しません。
AttackingHobo

1

スプライトごとに、ベーススプライトのアウトラインである別のスプライトもあります。アウトラインオブジェクトを描画するときは、ベーススプライトを描画し、結合レンダリングのマスクを作成してから、マスクを除くアウトラインスプライトを描画します。


2
なぜアウトラインスプライトを最初に描画し、それらの上に通常のスプライトを描画しないのですか?
クリス・ハウ

これを行わない1つの理由(またはChrisの提案)は、2倍のテクスチャメモリを使用するためです。もう1つの理由は、スプライトを変更するたびに2つのファイルを更新する必要があるため、アーティストのワークフローがくだらないことです。

2
ええ、理想的には、2つの実際のスプライトアセットはありません。スプライトにアルファテストを使用している場合は、アウトラインをスプライトに入れて、透明領域よりわずかに高いアルファを与えることができます。次に、アルファテストの参照値を制御することにより、アウトラインを表示するかどうかを制御できます。私が言っていたのは、スプライトの2つのバージョン(その2つのアセットまたは同じアセットの2つの状態)がある場合、まずアウトラインバージョンを描画し、次に通常バージョンを描画することです。この方法では、派手なシェーダーやマスクなどは必要ありません。
クリス・ハウ

1
クリスのアイデアにはメリットがあります。さらに、アセット/コンテンツパイプラインの一部として実行されるアウトラインスプライトのアルファを生成するツールを作成する場合、アーティストが2つのファイル(または同じアセット)を更新することを回避できます。テクスチャメモリは問題の場合もそうでない場合もありますが、独立したアウトラインスプライトは高度にDXT圧縮可能である必要があります。ビデオメモリ内の元のテクスチャのサイズの1/6であり、忠実度の損失はありません。
jpaver

1

トレードオフが異なるいくつかの異なるソリューション。

最も簡単:フラットカラーを複数回使用してオブジェクトをレンダリングし、位置(左、上、下、右などのオフセット)を揺らします。これにより、その上にレンダリングするもののアウトラインバージョンが作成されますが、パフォーマンスコストが発生します。多くの余分なレンダリングなしで太い境界線を考慮します。4xでは、1ピクセルまたは2ピクセルの境界線で問題ありません。

最速:テクスチャを前処理して、既に境界線が付いているコピー、または単に境界線であるコピー、またはシェーダーでカラー化できるフラットグレースケール8ビットマスクをコピーします。これはおそらくメモリを犠牲にして高速になります。

ベスト:私の意見ですが、オブジェクトの符号付き距離フィールド(SDF)表現を生成するのが最善の解決策となるでしょう。これらのテクスチャは、ソーステクスチャよりはるかに小さくても、有用なデータをキャプチャできます。基本的に、各ピクセルは、生成に使用したオブジェクトからの距離をエンコードします。このデータを手に入れると、グローからアウトラインまで、あらゆる種類のエフェクトを作成できます。境界線のサイズや色などが変更される可能性がありますが、依然として比較的安価なシェーダーであり、余分な描画は1つだけです。欠点は、ツーリングと前処理です。


0

効率がよくわかりませんが、一番簡単な方法は、最初に選択したい色でスプライトの大きなバージョンを描画することです。その上にスプライトを描画します。最初のスプライトのエッジのみが表示され、選択の効果が得られます。

編集:ただし、コメントからわかるように、これは良い考えではありません。


1
ただ、スプライトをスケールアップすることは、真のアウトライン与えるものではありません
イアン

2
私はそうは思わないが、それは簡単だろう。
共産主義のダック

2
たくさんのものは簡単ですが、問題を解決しないでください。あらゆる種類の興味深いシルエットを持つスプライトの場合、スケールアップにより絶対ゴミが生成されます。

スケールアップは、正方形または円形のオブジェクトにのみ適しています。形状が実際に幅広、高さ、または隙間がある場合、外観が非常に悪くなります。
AttackingHobo

3
スケールアップすると、何もしないよりも良い結果が得られ、「完璧」への道に沿った有用なステップにもなります。グラフィカルな結果は完璧ではありませんが、これが内部ツール用である場合、それで十分かもしれません。
ダッシュトムバン

0

私はスプライトを拡大することに同意します。最も簡単なルートであり、特にこの目的のために追加のスプライトを作成することなく、任意のスプライトの選択に適用できます。

  • すなわち、spriteOutline.Scale = spriteOriginal.Scale * 0.1f; spriteOutline.Color = new Color(255、0、0、255);

0

元のスプライトの色をアウトライン色に置き換えます(または必要に応じて色を付けます)。このフラットシェーディングまたは色付けされたスプライトを1ピクセルオフセットで4回レンダリングします。x、y =(-1、-1)、(+ 1、-1)、(+ 1、-1)、(-1、+ 1)、(+ 1 、+ 1)。オブジェクトを構成するすべてのスプライトについて繰り返します。

その後、元のスプライトを適切な順序で(0,0)にレンダリングします。

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