XNA メモ – HLSLを使って画面の色を反転する方法

Posted: 2012年2月6日 カテゴリー: プログラミングメモ, XNA, XNAメモ
タグ:, , , , , , , , , ,

今回は、ピクセルシェーダを使用して画面の色(描画されている物の色)を反転させる方法をメモります(需要無い気がしますが・・・)。ちなみに、HLSLやピクセルシェーダについての解説はこのメモではしない予定です。

実装方法は、前に紹介したテクスチャアへの描画や、スクリーンショットをとる方法みたいにゲーム画面をレンダーターゲットに描画+保存し、その画像を描画する時にピクセルシェーダ内で画像の色を反転させます。前に紹介したテクスチャアの色を変える方法を使わないのは、あの処理はCPUでの処理なので、リアルタイムで行うと結構負担になる可能性があります。ですが、シェーダ内で処理すればGPU内で実行されるので、CPUへの負担は減ります。

 

実装方法ですが、まずレンダーターゲットを初期化します。

RenderTarget2D m_renderTarget;
m_renderTarget = new RenderTarget2D(GraphicsDevice,
graphics.PreferredBackBufferWidth,
graphics.PreferredBackBufferHeight,
false,
SurfaceFormat.Color,
DepthFormat.Depth16);

次に、レンダーターゲットにゲーム画面を描画し、保存した画像も描画します(Game1クラスのDraw()メソッド内で)。

GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.CornflowerBlue, 1.0f, 0);

GraphicsDevice.SetRenderTarget(m_renderTarget);
GraphicsDevice.Clear(Color.Transparent);

// ゲームの内用をテクスチャアに描画する
DrawContent();

GraphicsDevice.SetRenderTarget(null);

spriteBatch.Begin();
// 保存されているゲーム画面を描画する
spriteBatch.Draw(m_renderTarget, Vector2.Zero, Color.White);
spriteBatch.End();

下準備が出来たらエフェクトの実装です。まず、コンテントマネージャーに新しい.fxファイルを追加してください。追加したら、最初にsamplerを宣言してください。本来は中身も書くべきな気がしますが、今回は宣言だけにしときます。

sampler samplerState;

それが出来たら今度は、ピクセルシェーダに渡すパラメータの構造体を宣言します。今回必要なのは、テクスチャア座標だけなので、ソレだけを宣言します。

struct PS_INPUT
{
float2 TexCoord : TEXCOORD0;
};

次に、実際にピクセルの色を反転させる関数を実装します。行う処理は、パラメータから渡されたテクスチャア座標を使用し、現在のピクセルの色をゲーム画面のテクスチャアから取り出し、その色を反転させ、返すだけです。

float4 Negative(PS_INPUT p) : COLOR0
{
// テクスチャアから現在の座標の色を獲得する
float4 col = tex2D( samplerState, p.TextureCoord.xy );

// 色を反転する
col.rgb = 1 - col.rgb;

// 反転した色を返す
return col;
}

関数を実装したら、この処理を呼ぶtechniqueを作ります。

technique Flip
{
pass Pass0
{
PixelShader = compile ps_2_0 Negative();
}
}

これでエフェクトファイルの実装は終了です。後はゲーム内で使用するだけです。まず、エフェクトファイルを読み込みます。

Effect negativeEffect;
negativeEffect = Content.Load<Effect>("Negative");

次に、先ほど実装したレンダーターゲットの画像を描画する処理を変更し、上で読み込んだエフェクトを使用するようにします。そのためには、spriteBatch.Begin()メソッドの違うオーバーロード使用し、Effectクラスをパラメータの一つとして渡すことでspriteBatch.End()が呼ばれるまでの全ての描画に、先ほど作製したエフェクトを実行させる事が出来ます。後、エフェクトで使用するテクニックを設定しときます。

GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.CornflowerBlue, 1.0f, 0);

GraphicsDevice.SetRenderTarget(m_renderTarget);
GraphicsDevice.Clear(Color.Transparent);

DrawContent();

GraphicsDevice.SetRenderTarget(null);

negativeEffect.CurrentTechnique = negativeEffect.Techniques["Flip"];
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, SamplerState.PointWrap, DepthStencilState.Default, RasterizerState.CullNone, negativeEffect);
spriteBatch.Draw(m_renderTarget, Vector2.Zero, Color.White);
spriteBatch.End();

以上で終了です。もし画面の反転をon/off切り替えられるようにしたい場合は、描画を以下のように変更してください。

GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.CornflowerBlue, 1.0f, 0);

GraphicsDevice.SetRenderTarget(m_renderTarget);
GraphicsDevice.Clear(Color.Transparent);

DrawContent();

GraphicsDevice.SetRenderTarget(null);

if (isNegative)
{
negativeEffect.CurrentTechnique = negativeEffect.Techniques["Flip"];
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, SamplerState.PointWrap, DepthStencilState.Default, RasterizerState.CullNone, negativeEffect);
spriteBatch.Draw(m_renderTarget, Vector2.Zero, Color.White);
spriteBatch.End();
}
else
{
spriteBatch.Begin();
spriteBatch.Draw(m_renderTarget, Vector2.Zero, Color.White);
spriteBatch.End();
}

これでisNegativeを切り替えれば、簡単に切り替えられます。実装後はこんな感じになります。

 

コメント
  1. […] このメモでは、結構前のメモで紹介した色を反転させる処理を少しだけ変更し、画面の色を白黒に変える処理を紹介します。 […]

  2. […] 今回は、前回に引き続きHLSLを使って画面の色を反転する方法で紹介した処理を少しだけ変更し、違うエフェクトを作る方法を紹介します。 […]

  3. […] 今回は、前回に引き続きHLSLを使って画面の色を反転する方法で紹介した処理を少しだけ変更し、違うエフェクトを作る方法を紹介します。 […]

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中