忍者ブログ

Memeplexes

プログラミング、3DCGとその他いろいろについて

XNA爆発チュートリアル その8 フェードアウト

XNA爆発チュートリアル その7.5のつづきです。

最後に新しい機能を付け加えた「その7」では
頂点を増やしてより爆発っぽくなりました。
しかし、それぞれの爆炎は時間がたっても
消えたりはせず、不自然でした。

ここではさらに本物に近づけるため、炎をフェードアウトさせます。
頂点のアルファ・チャンネルを時間に従ってうまく制御すれば、
それらしく炎が消えてくれるはずです。
頂点シェーダ内でその頂点の色(アルファ・チャンネルを操作してある)を決め、
ピクセルシェーダでそいつを乗算するのです。

では具体的にどのようにアルファ・チャンネルを決めればいいのでしょうか?
Xna Creators Clubのサンプルでは、次のようにして決めていました。

まず、各頂点に対応する、ノーマライズされた年齢を求めて、
これをもとにαを決めます。

ノーマライズされた年齢 = 現実の年齢 / 現実の寿命

どういうことかというと、この年齢は、0~1の範囲内になっており、
たとえば現実に炎の寿命が2秒、現在の歳が1秒だとすると、0.5です。(1 / 2)
現実の寿命が4秒、現実の歳が1秒だとすると0.25です(1 / 4)。

この、ノーマライズされた年齢を元にαを決めます。
Particle 3Dサンプル(Xna Creators Club)のシェーダー、ParticleEffect.fxでは
次のような三次関数でαを求めています:

color.a *= normalizedAge * (1 - normalizedAge) * (1 - normalizedAge) * 6.7;

この式を使って獏炎のα・チャンネルを計算するとうまい具合に
爆発が消えていきます。
(一番最後にマジックナンバー6.7がかけられているのは、ある一定の時間がたつまでは炎がはっきり(α = 1で)映し出されるようにするためです。)
ただし!これはなにぶん三次関数なので、寿命が切れた後に呼び出すと、
また爆発が見えるようになります。
たとえば2秒で消えることを予定している爆発を、
2秒後も3秒後も描画し続けていると、
いったん消えたはずの爆発がまた画面に現れるのです。
このことに気をつけましょう。
(いやでも目に入ってきますが)


この変更はエフェクトファイルだけです。
float4x4 View;
float4x4 Projection;

float Time;

texture ExplosionTexture;

sampler explosionSampler = sampler_state
{
	Texture = <ExplosionTexture>;
};

struct ExplosionVertexShaderOutput
{
	float4 Position : POSITION;
	float4 Color : COLOR;
};

float4 ComputeColor(float normalizedAge)
{
	float4 color = 1;
	color.a *= normalizedAge * (1 - normalizedAge) * (1 - normalizedAge) * 6.7;
	return color;
}

ExplosionVertexShaderOutput ExplosionVertexShader(float4 velocity:COLOR)
{
	ExplosionVertexShaderOutput output;
	float4 worldPosition = float4(velocity.xyz * Time, 1);
	output.Position = mul(worldPosition, mul(View, Projection));
	output.Color = ComputeColor(Time / 2);
	return output;
}

float4 ExplosionPixelShader(
	float2 textureCoordinate:TEXCOORD,
	float4 color:COLOR
	):COLOR
{
	return tex2D(explosionSampler, textureCoordinate) * color;
}

technique ExplosionShaderTechnique
{
	pass P0
	{
		VertexShader = compile vs_2_0 ExplosionVertexShader();
		PixelShader = compile ps_2_0 ExplosionPixelShader();
	}
}

explosionTutorialFadingOut.jpg
(爆発はほとんどフェードアウトしてしまっていて、かすかにしか見えません)

これで実行すると、2秒でフェードアウトします。
(爆発の寿命を2秒に設定しているので、ノーマライズされた寿命はTime / 2です。)

しかしそのまま実行し続けていると、すぐにまた炎があらわれます。
これはα・チャンネルを計算している関数の性質によるもので、
しかたがありません。
爆発に寿命が来たら描画しないような仕掛けが必要でしょう。





拍手[0回]

PR