忍者ブログ

Memeplexes

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

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回]

PR