忍者ブログ

Memeplexes

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

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。


XNA爆発チュートリアル その6 動かす

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

前回でBasicEffectから、HLSLで書いたカスタムエフェクトへの移行が済んだので、今回からはさらにいろんなことが出来るようになります。

まずは爆発を動かしてみましょう。
中心から、周囲に「ぶわっ」っと広がっていくような感じです。

これをやるためにエフェクトファイルにTimeというグローバル変数を用意して、
その値にしたがってそれぞれの爆炎を頂点シェーダで動かしていくことにします。

ただ、これをやるためには頂点の構造体の
メンバに速度が含まれていなければならないのですが、
これはとりあえず位置の情報を流用することにします。
(臭う!コードの臭いです!でも訂正は後回しです)

ExplosionTest.cs
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;


public class ExplosionTest : Microsoft.Xna.Framework.Game
{
    private GraphicsDeviceManager graphics;

    private Effect effect;
    private VertexPositionColor[] vertices = {
        new VertexPositionColor(new Vector3(0, 0.1f, 0), Color.White),
        new VertexPositionColor(new Vector3(0.1f, 0, 0), Color.White),
        new VertexPositionColor(new Vector3(-0.1f, 0, 0), Color.White)
    };

    private ContentManager content;


    public ExplosionTest()
    {
        graphics = new GraphicsDeviceManager(this);
        content = new ContentManager(Services);
    }

    protected override void LoadGraphicsContent(bool loadAllContent)
    {
        if (loadAllContent)
        {
            effect = content.Load<Effect>("Content/ExplosionShader");
            effect.Parameters["ExplosionTexture"].SetValue(
                content.Load<Texture2D>("Content/explosion")
                );

            graphics.GraphicsDevice.VertexDeclaration = new VertexDeclaration(
                graphics.GraphicsDevice,
                VertexPositionColor.VertexElements
                );
        }
    }

    protected override void UnloadGraphicsContent(bool unloadAllContent)
    {
        if (unloadAllContent) { content.Unload(); }
    }

    protected override void Draw(GameTime gameTime)
    {
        graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

        graphics.GraphicsDevice.RenderState.PointSize = 50;
        graphics.GraphicsDevice.RenderState.PointSpriteEnable = true;

        graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;
        graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
        graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.One;

        effect.Parameters["Time"].SetValue(
            (float)gameTime.TotalGameTime.TotalSeconds
            );

        effect.Begin();

        foreach (EffectPass pass in effect.CurrentTechnique.Passes)
        {
            pass.Begin();

            graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(
                PrimitiveType.PointList,
                vertices,
                0,
                vertices.Length
                );

            pass.End();
        }

        effect.End();
    }
}

ExplosionShader.fx
float Time;

texture ExplosionTexture;

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

float4 ExplosionVertexShader(float4 position:POSITION):POSITION
{
	return float4(position.xyz * Time, 1);
}

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

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


("return position * Time;"ではなくて"return float4(position.xyz * Time, 1);"
なのはそうしないとうまくいかないからです。float4の最後は1でなくてはいけません。
この値をたとえば2にすると爆発の速さが1/2になってしまいます。
大きくすると速さが遅くなっていくのです。
逆に、小さくすると速くなります。
xyzを拡大し、wも拡大すると、ちょうど互いに影響を打ち消しあい、結局爆発は動かなくなります。
"return position * Time;"では動かないように見えるのです。)



explosionTutorialExpanding1.jpg
explosionTutorialExpanding2.jpg
explosionTutorialExpanding3.jpg
うまくいきました。
3つの爆炎が時間の経過とともに周りへ広がっていきます。

ここで気になるのは、変数名とその役割が一致していないことです。
どういうわけか、位置を表す変数に速度が入ってしまっています。
これはいただけません。
直すことにしましょう。

C#側で新しい頂点の構造体を用意して、そのメンバの名前をVelocity(速度)にします。
HLSL側での変更は変数名の変更だけで良いでしょう。(position → velocity)

VertexVelocity.cs
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;


struct VertexVelocity
{
    public Vector3 Velocity;

    public VertexVelocity(Vector3 velocity)
    {
        this.Velocity = velocity;
    }

    public static readonly VertexElement[] VertexElements = {
        new VertexElement(
            0,
            0,
            VertexElementFormat.Vector3,
            VertexElementMethod.Default,
            VertexElementUsage.Color,
            0)
    };
}

ExplosionTest.cs
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;


public class ExplosionTest : Game
{
    private GraphicsDeviceManager graphics;

    private Effect effect;
    private VertexVelocity[] vertices = {
        new VertexVelocity(new Vector3(0, 0.1f, 0)),
        new VertexVelocity(new Vector3(0.1f, 0, 0)),
        new VertexVelocity(new Vector3(-0.1f, 0, 0))
    };

    private ContentManager content;


    public ExplosionTest()
    {
        graphics = new GraphicsDeviceManager(this);
        content = new ContentManager(Services);
    }

    protected override void LoadGraphicsContent(bool loadAllContent)
    {
        if (loadAllContent)
        {
            effect = content.Load<Effect>("Content/ExplosionShader");
            effect.Parameters["ExplosionTexture"].SetValue(
                content.Load<Texture2D>("Content/explosion")
                );

            graphics.GraphicsDevice.VertexDeclaration = new VertexDeclaration(
                graphics.GraphicsDevice,
                VertexVelocity.VertexElements
                );
        }
    }

    protected override void UnloadGraphicsContent(bool unloadAllContent)
    {
        if (unloadAllContent) { content.Unload(); }
    }

    protected override void Draw(GameTime gameTime)
    {
        graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

        graphics.GraphicsDevice.RenderState.PointSize = 50;
        graphics.GraphicsDevice.RenderState.PointSpriteEnable = true;

        graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;
        graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
        graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.One;

        effect.Parameters["Time"].SetValue(
            (float)gameTime.TotalGameTime.TotalSeconds
            );

        effect.Begin();

        foreach (EffectPass pass in effect.CurrentTechnique.Passes)
        {
            pass.Begin();

            graphics.GraphicsDevice.DrawUserPrimitives<VertexVelocity>(
                PrimitiveType.PointList,
                vertices,
                0,
                vertices.Length
                );

            pass.End();
        }

        effect.End();
    }
}

ExplosionShader.fx
float Time;

texture ExplosionTexture;

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

float4 ExplosionVertexShader(float4 velocity:COLOR):POSITION
{
	return float4(velocity.xyz * Time, 1);
}

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

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


実行結果はさっきと同じです。
さっきと違うのは、その内部です。
変数の名前と目的をだいたい一致させました。

「だいたい」と言うのは、(名前ではないですが)
セマンティクスを一致させることが出来ず、(VELOCITYがないため)
しかたがなくCOLORを使ったのです。
でもまあ、「色 → 特色 → 頂点の特色 → ここでは速度」という風に、
連想ゲームでたどり着けないこともないので
ここはおおめに見ても良いかもしれませんね。


ともかく!これでうまくリファクタリング(?)できました。
いままで頂点の構造体にはVertexPositionColorを使っており、
使っていない、無駄なメンバ(Color)があったのです。
今、それが取り除かれ、本当に必要な速度だけをメンバに持つ、
VertexVelocity構造体が作られました。
これでさらなる変更を加えやすくなったはずです。

つまり、
爆発を表しているそれぞれの頂点をフェードアウトさせたり、
それぞれの爆炎を回転させたり、
その他いろいろな変更を加えやすくなり、
結果としてより簡単に本物の爆発に近づくことが出来るのです。
(というか、そうなる予定です。)

拍手[0回]

PR

XNA爆発チュートリアル その5 HLSLへ

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

前回までに、爆炎っぽいものをそれらしく表示することが出来ました。
しかしまだ本物には及びません。
本物の爆発は「ぶわっ」という感じに広がっていくものだからです。
今のところ爆炎は動きません。
サイズも変わりません。

こういった、ポイントのいろんな変化を行うには、
HLSLを使うべきでしょう。
BasicEffectとはおさらばです。
HLSLでエフェクトファイルを直接書くことによって、
より詳しく描画をコントロールすることが出来ます。


ただ……、より詳しく描画をコントロールすることが出来るのはいいのですが、
そのかわり代償として、やらなければならないことが多くなり、
面倒になったり、一時的に見た目が逆戻りする(お粗末になる)ことがあるでしょう。

やる気を保つためにも、見た目をあんまりお粗末にしないことが大切です。
ですから、この回が終わるころにはBasicEffectで
やったものに追いついておくべきでしょうね。

心構えはこのくらいにして、さっそくプロジェクトにエフェクトファイルを追加しましょう。
ExplosionShader.fxという名前で、Contentフォルダの中に作ることにします。
それをContentManagerから"Content/ExplosionShader"という風に読み込みます。
こうして出来たEffectはただのEffectなのでTextureプロパティは使えません。
この関連は削除することになるでしょう。

ExplosionTest.cs
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;


public class ExplosionTest : Microsoft.Xna.Framework.Game
{
    private GraphicsDeviceManager graphics;

    private Effect effect;
    private VertexPositionColor[] vertices = {
        new VertexPositionColor(new Vector3(0, 0.1f, 0), Color.White),
        new VertexPositionColor(new Vector3(0.1f, 0, 0), Color.White),
        new VertexPositionColor(new Vector3(-0.1f, 0, 0), Color.White)
    };

    private ContentManager content;


    public ExplosionTest()
    {
        graphics = new GraphicsDeviceManager(this);
        content = new ContentManager(Services);
    }

    protected override void LoadGraphicsContent(bool loadAllContent)
    {
        if (loadAllContent)
        {
            effect = content.Load<Effect>("Content/ExplosionShader");
            graphics.GraphicsDevice.VertexDeclaration = new VertexDeclaration(
                graphics.GraphicsDevice,
                VertexPositionColor.VertexElements
                );
        }
    }

    protected override void UnloadGraphicsContent(bool unloadAllContent)
    {
        if (unloadAllContent) { content.Unload(); }
    }

    protected override void Draw(GameTime gameTime)
    {
        graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

        graphics.GraphicsDevice.RenderState.PointSize = 50;
        graphics.GraphicsDevice.RenderState.PointSpriteEnable = true;

        graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;
        graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
        graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.One;

        effect.Begin();

        foreach (EffectPass pass in effect.CurrentTechnique.Passes)
        {
            pass.Begin();

            graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(
                PrimitiveType.PointList,
                vertices,
                0,
                vertices.Length
                );

            pass.End();
        }

        effect.End();
    }
}

HLSLで書いたエフェクトファイルは考えられる限りもっともシンプルなものにします。
頂点シェーダは何もしてませんし、ピクセルシェーダは常に白を返します。
もちろんこんなのですから、結果は炎から真っ白タイルに戻ることが予想できます。

ExplosionShader.fx
float4 ExplosionVertexShader(float4 position:POSITION):POSITION
{
	return position;
}

float4 ExplosionPixelShader():COLOR
{
	return 1;   //white
}

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

explosionTutorialHLSLSimplest.jpg

あいたたた……見た目がただの白タイルに戻ってしまいました。
わかっていたこととはいえ、これは精神的にきついですね。
今まで築き上げてきたものが失われる、いやーな気分です。
でもすぐに建て直しできるので、気を取り直していきましょう。

テクスチャ

ここで白タイルから爆炎に復活させるにはHLSLで
ポイントにテクスチャを貼るようにしなければなりません。

これは簡単で、ポイントスプライトを使っているときには
ピクセルシェーダに自動的にテクスチャ座標が引数として入ってくるので
それを元にピクセルシェーダの戻り値をだせばいいのです。

C#側ではまたさっきまでのようにテクスチャをロードして
エフェクトにセットするようにします。

ExplosionTest.cs
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;


public class ExplosionTest : Microsoft.Xna.Framework.Game
{
    private GraphicsDeviceManager graphics;

    private Effect effect;
    private VertexPositionColor[] vertices = {
        new VertexPositionColor(new Vector3(0, 0.1f, 0), Color.White),
        new VertexPositionColor(new Vector3(0.1f, 0, 0), Color.White),
        new VertexPositionColor(new Vector3(-0.1f, 0, 0), Color.White)
    };

    private ContentManager content;


    public ExplosionTest()
    {
        graphics = new GraphicsDeviceManager(this);
        content = new ContentManager(Services);
    }

    protected override void LoadGraphicsContent(bool loadAllContent)
    {
        if (loadAllContent)
        {
            effect = content.Load<Effect>("Content/ExplosionShader");
            effect.Parameters["ExplosionTexture"].SetValue(
                content.Load<Texture2D>("Content/explosion")
                );

            graphics.GraphicsDevice.VertexDeclaration = new VertexDeclaration(
                graphics.GraphicsDevice,
                VertexPositionColor.VertexElements
                );
        }
    }

    protected override void UnloadGraphicsContent(bool unloadAllContent)
    {
        if (unloadAllContent) { content.Unload(); }
    }

    protected override void Draw(GameTime gameTime)
    {
        graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

        graphics.GraphicsDevice.RenderState.PointSize = 50;
        graphics.GraphicsDevice.RenderState.PointSpriteEnable = true;

        graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;
        graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
        graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.One;

        effect.Begin();

        foreach (EffectPass pass in effect.CurrentTechnique.Passes)
        {
            pass.Begin();

            graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(
                PrimitiveType.PointList,
                vertices,
                0,
                vertices.Length
                );

            pass.End();
        }

        effect.End();
    }
}

ExplosionShader.fx
texture ExplosionTexture;

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

float4 ExplosionVertexShader(float4 position:POSITION):POSITION
{
	return position;
}

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

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


explosionTutorialHLSLTextured.jpg

復活できました。
めでたく、HLSLでBasicEffectを使っていたときと同じことが出来ました。
きちんと、白タイルではなく爆炎が表示されています。

「このまま白いタイルのままだったらどうしよう」
という恐怖があったのですが、安心しました。
これは気分としては「冤罪でつかまったけれど無事疑いが晴れた」
というのに似ている気がしますね!

さて、今回無事にBasicEffectからHLSLに移行できたので
次回からはいろいろなことが詳しく調節できるようになるはずです。
(BasicEffectは柔軟性に欠けるため、さらなる進歩は難しいのです)

たとえばそれぞれの爆炎を時間の経過とともに周囲に「ぶわっ」と広げたり、
フェードアウトさせたり、回転させたり、
遠近法のようにカメラからの距離によって大きさを調節したり、
いろいろなことが出来るようになり、
さらに本物の爆炎に近づくことが出来るのです。
(というか、そうなる予定です)

拍手[0回]


XNA爆発チュートリアル その4 透過

XNA爆発チュートリアル その3 テクスチャを貼るのつづきです。

前回は、爆発を構成する各ポイントにテクスチャが貼られたものの、
テクスチャの爆炎の周りが黒くて、
リアルさよりもシュールさがきわだってしまったようにも思えます。

これを本物に近づけるために、とりあえずこの黒いのを消してみましょう。

アルファ・ブレンディングで透過するのです。

さて、どのようにブレンドするべきでしょうか?
自分で考えるのがめんどうなのでParticle 3D Sampleのやりかたをまねることにします。
ExplosionParticleSystemはどうブレンドしているかというと・・・

SourceBlend = Blend.SourceAlpha;
DestinationBlend = Blend.One;


ですね。
つまり爆炎の色が、透過してるところは無視して、足されるわけです。
たしかにこれなら黒いところが透明になって、爆炎だけ見えるようになるでしょう。

「あれ?"explosion.png"の周りの色は黒なんだから
SourceBlendもBlend.Oneをセットしても同じなんじゃないの?」と思いながらも、
作業を先に進めることにします。
(後になって試してみましたが、やっぱり同じような結果になりました)

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;


public class ExplosionTest : Microsoft.Xna.Framework.Game
{
    private GraphicsDeviceManager graphics;

    private BasicEffect effect;
    private VertexPositionColor[] vertices = {
        new VertexPositionColor(new Vector3(0, 0.1f, 0), Color.White),
        new VertexPositionColor(new Vector3(0.1f, 0, 0), Color.White),
        new VertexPositionColor(new Vector3(-0.1f, 0, 0), Color.White)
    };

    private ContentManager content;


    public ExplosionTest()
    {
        graphics = new GraphicsDeviceManager(this);
        content = new ContentManager(Services);
    }

    protected override void LoadGraphicsContent(bool loadAllContent)
    {
        if (loadAllContent)
        {
            effect = new BasicEffect(graphics.GraphicsDevice, null);
            graphics.GraphicsDevice.VertexDeclaration = new VertexDeclaration(
                graphics.GraphicsDevice,
                VertexPositionColor.VertexElements
                );

            effect.Texture = content.Load<Texture2D>("Content/explosion");
            effect.TextureEnabled = true;
        }
    }

    protected override void UnloadGraphicsContent(bool unloadAllContent)
    {
        if (unloadAllContent) { content.Unload(); }
    }

    protected override void Draw(GameTime gameTime)
    {
        graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

        graphics.GraphicsDevice.RenderState.PointSize = 50;
        graphics.GraphicsDevice.RenderState.PointSpriteEnable = true;

        graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;
        graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
        graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.One;

        effect.Begin();

        foreach (EffectPass pass in effect.CurrentTechnique.Passes)
        {
            pass.Begin();

            graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(
                PrimitiveType.PointList,
                vertices,
                0,
                vertices.Length
                );

            pass.End();
        }

        effect.End();
    }
}

explosionTutorialPointAlphaBlended.jpg

うまくいきました!

爆炎の周りの黒いふちがなくなって、
きちんと爆炎のように見えています。
もはやテクスチャの貼られたタイルではありません!

ただ、黒いのが消えたのはアルファ・ブレンディングを使っているからですが、
これはもしかすると後になって問題を引き起こすかもしれません。

つまり、RenderState.AlphaBlendEnabledをtrueにしっぱなしで、
描画が終わっても元のfalseに戻していないため、
今後普通の透過しないモデル(敵キャラとか)を描画したくなったときに、
それまでも半透明になってしまって、全体として
描画がメチャクチャになってしまう危険性があるのです。
でもそれはそのときになってから考えることにしましょう(笑)


さて、今回の変更はプログラマにとっては小さな一歩ですが、見た目としては大きな飛躍です。
加えたのは数行だけですが、もうこの状態で頂点の位置をダブらせれば本物の爆発っぽく見えるでしょう。
もっとも時間がたつにつれ頂点が動いたりはしないのでそれでもやっぱり限界があるといえます。
進化の袋小路、大きな前進があったものの、これ以上何かをするのは難しいというわけです。

本物の爆発なら時間がたつにつれ、爆炎が周囲に広がって、フェードアウトしていくべきではないでしょうか?
しかしそれをどうやって実現すれば良いでしょう?
Game.Updateメソッド内で各頂点の位置データを動かすべきでしょうか?
それも良いかもしれませんが、もしかしたら後でVertexBufferを使うかもしれない可能性を考えると、
C#側での頻繁な更新は避けたいものです。
もうそろそろHLSLを使ったほうが良いかもしれません。
C#側の頂点は止まっていて、HLSLで書いたエフェクトファイル内で頂点を動かすのです。

HLSLを使えばいったん見た目は後退することになるでしょう。
しかしそれは一時的なことで、すぐに現在以上の見た目になるはずです。

HLSLによって、それぞれの爆炎が「ぶわっ」と動いたり、
フェードアウトしたり、
あるいは大きさが変わったり、
色々することによって、本物の爆発のようになるのです。
(というか、そうなる予定です。)


拍手[0回]


XNA爆発チュートリアル その3 テクスチャを貼る

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

前回は爆発と言いつつ白いタイルのようなものが3つ表示されるだけでした。
今度はこれに炎のテクスチャを貼ってみましょう。

これから貼り付けるテクスチャはXna Creators Clubの
Particle 3Dから拝借してきたexplosion.pngです。

ebd0a9be.png(explosion.png : Particle 3D Sampleより)

これを白い四角に貼り付ければ少しはましになるのではないでしょうか。

この"explosion.png"をプロジェクトに追加して、
クラスファイルとごっちゃになるのも嫌なので
Contentフォルダを作ってその中に入れましょう。
つまりアセット名は"Content/explosion"になるわけです。

ではこれをContentManagerから読み込み、
BasicEffect.Textureプロパティにセットして、
BasicEffect.TextureEnabledプロパティをtrueにします。
これでうまくいくはず・・・!

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;


public class ExplosionTest : Microsoft.Xna.Framework.Game
{
    private GraphicsDeviceManager graphics;

    private BasicEffect effect;
    private VertexPositionColor[] vertices = {
        new VertexPositionColor(new Vector3(0, 0.1f, 0), Color.White),
        new VertexPositionColor(new Vector3(0.1f, 0, 0), Color.White),
        new VertexPositionColor(new Vector3(-0.1f, 0, 0), Color.White)
    };

    private ContentManager content;


    public ExplosionTest()
    {
        graphics = new GraphicsDeviceManager(this);
        content = new ContentManager(Services);
    }

    protected override void LoadGraphicsContent(bool loadAllContent)
    {
        if (loadAllContent)
        {
            effect = new BasicEffect(graphics.GraphicsDevice, null);
            graphics.GraphicsDevice.VertexDeclaration = new VertexDeclaration(
                graphics.GraphicsDevice,
                VertexPositionColor.VertexElements
                );

            effect.Texture = content.Load<Texture2D>("Content/explosion");
            effect.TextureEnabled = true;
        }
    }

    protected override void UnloadGraphicsContent(bool unloadAllContent)
    {
        if (unloadAllContent) { content.Unload(); }
    }

    protected override void Draw(GameTime gameTime)
    {
        graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

        graphics.GraphicsDevice.RenderState.PointSize = 50;

        effect.Begin();

        foreach (EffectPass pass in effect.CurrentTechnique.Passes)
        {
            pass.Begin();

            graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(
                PrimitiveType.PointList,
                vertices,
                0,
                vertices.Length
                );

            pass.End();
        }

        effect.End();
    }
}

explosionTutorialTexturedPointFailed.jpg
はい失敗です。(イライラ)

四角の色が白でなくなってはいますが、
ここでやりたかったのはテクスチャを貼り付けることです。
四角の色を変えることではありません。

どうしてこういう失敗をしてしまったのかというと、
レンダーステートのPointSpriteEnabledプロパティをtrueにしていなかったからです。
このプロパティをtrueにすることによって初めて、
ポイントの上にテクスチャが表示されるようになります。
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;


public class ExplosionTest : Microsoft.Xna.Framework.Game
{
    private GraphicsDeviceManager graphics;

    private BasicEffect effect;
    private VertexPositionColor[] vertices = {
        new VertexPositionColor(new Vector3(0, 0.1f, 0), Color.White),
        new VertexPositionColor(new Vector3(0.1f, 0, 0), Color.White),
        new VertexPositionColor(new Vector3(-0.1f, 0, 0), Color.White)
    };

    private ContentManager content;


    public ExplosionTest()
    {
        graphics = new GraphicsDeviceManager(this);
        content = new ContentManager(Services);
    }

    protected override void LoadGraphicsContent(bool loadAllContent)
    {
        if (loadAllContent)
        {
            effect = new BasicEffect(graphics.GraphicsDevice, null);
            graphics.GraphicsDevice.VertexDeclaration = new VertexDeclaration(
                graphics.GraphicsDevice,
                VertexPositionColor.VertexElements
                );

            effect.Texture = content.Load<Texture2D>("Content/explosion");
            effect.TextureEnabled = true;
        }
    }

    protected override void UnloadGraphicsContent(bool unloadAllContent)
    {
        if (unloadAllContent) { content.Unload(); }
    }

    protected override void Draw(GameTime gameTime)
    {
        graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

        graphics.GraphicsDevice.RenderState.PointSize = 50;
        graphics.GraphicsDevice.RenderState.PointSpriteEnable = true;

        effect.Begin();

        foreach (EffectPass pass in effect.CurrentTechnique.Passes)
        {
            pass.Begin();

            graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(
                PrimitiveType.PointList,
                vertices,
                0,
                vertices.Length
                );

            pass.End();
        }

        effect.End();
    }
}

explosionTutorialPointTextured.jpg(クリックで写真を拡大)

うまくいきました。

たしかに"explosion.png"が貼られています。
四角形の中に爆炎っぽいものが表示されています。
周りが黒くて、とても爆発には見えないという嫌な事実は無視です。
これによってほんのちょっと、完成に近づいたといえるのではないでしょうか!

白いタイルがそれぞれ爆発の頂点のように動いたとしても
ゲームプレイヤーからは爆発には見えずに、「????」となるはずです。
だから、これはとても必要なことだったのです。

これからさらに透過処理して本物の爆炎っぽく見せたり、
それぞれの四角を時間の経過とともに「ぶわっ」と動かしたり、
四角の数自体をふやしたりすることによって、
本物の爆発に近づいていくのです。
(というか、そうなる予定です。)



拍手[0回]


XNA爆発チュートリアル その2

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

前回は大きさ1の点を表示するだけだったので、
こんどはこれを大きくしてみましょう。

点が周りに広がって動くだけでは
あまりリアルな爆発には見えないでしょうからね。
(もちろん現状ではまだ動いてすらいないのですが・・・)
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;


public class ExplosionTest : Microsoft.Xna.Framework.Game
{
    private GraphicsDeviceManager graphics;

    private BasicEffect effect;
    private VertexPositionColor[] vertices = {
        new VertexPositionColor(new Vector3(0, 0.1f, 0), Color.White),
        new VertexPositionColor(new Vector3(0.1f, 0, 0), Color.White),
        new VertexPositionColor(new Vector3(-0.1f, 0, 0), Color.White)
    };


    public ExplosionTest()
    {
        graphics = new GraphicsDeviceManager(this);
    }

    protected override void LoadGraphicsContent(bool loadAllContent)
    {
        if (loadAllContent)
        {
            effect = new BasicEffect(graphics.GraphicsDevice, null);
            graphics.GraphicsDevice.VertexDeclaration = new VertexDeclaration(
                graphics.GraphicsDevice,
                VertexPositionColor.VertexElements
                );
        }
    }

    protected override void Draw(GameTime gameTime)
    {
        graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

        graphics.GraphicsDevice.RenderState.PointSize = 50;

        effect.Begin();

        foreach (EffectPass pass in effect.CurrentTechnique.Passes)
        {
            pass.Begin();

            graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(
                PrimitiveType.PointList,
                vertices,
                0,
                vertices.Length
                );

            pass.End();
        }

        effect.End();
    }
}


explosionTutorialPointWithSize.jpg

点が大きくなりました!
スクリーン上のサイズが1から50に大きくなりました。

これで一歩前進です。
どこからどう見ても物が爆発しているようには見えませんが、
前進は前進です。

この白い四角い板みたいなのに爆炎のテクスチャが貼られ、
それぞれが動いたりいろんなことをされることによって
爆発っぽく見えるようになるのです。
(というか、そうなる予定です)

拍手[0回]