忍者ブログ

Memeplexes

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

かんたんXNA その26 アルファ・テスト

このページは古いです
最新版はこちら

XNAでは(やっぱりXNAに限ったことではありませんが)、
これから描画するピクセルの色のアルファの値によって
描画を制限することが出来ます。

たとえば、これからアルファが(255中)30以上の時しか
描画しない設定にすれば、色のアルファの値が20の三角形は
全く描画されなくなります。
アルファの値が40ならいつも通りに描画されます。
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;


class Triangle
{
    VertexPositionColor[] vertices = new VertexPositionColor[3];

    public Triangle(Vector3 p1, Vector3 p2, Vector3 p3)
    {
        vertices[0].Position = p1;
        vertices[1].Position = p2;
        vertices[2].Position = p3;
    }

    public Color Color
    {
        set
        {
            for (int i = 0; i < vertices.Length; i++)
            {
                vertices[i].Color = value;
            }
        }
    }

    public void Draw(GraphicsDevice graphicsDevice, BasicEffect effect)
    {
        graphicsDevice.VertexDeclaration = new VertexDeclaration(
            graphicsDevice,
            VertexPositionColor.VertexElements);
        effect.VertexColorEnabled = true;

        effect.Begin();

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

            graphicsDevice.DrawUserPrimitives<VertexPositionColor>(
                PrimitiveType.TriangleList,
                vertices,
                0,
                1
                );

            pass.End();
        }

        effect.End();
    }
}

class MyGame : Game
{
    GraphicsDeviceManager graphics;
    BasicEffect basicEffect;

    Triangle redTriangle = new Triangle(
        new Vector3(1, 0.5f, 0),
        new Vector3(0, -1, 0),
        new Vector3(-1, 0.5f, 0)
        );
    Triangle blueTriangle = new Triangle(
        new Vector3(0, 1, -1),
        new Vector3(1, -0.5f, -1),
        new Vector3(-1, -0.5f, -1)
        );
    byte alpha;

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

    protected override void LoadGraphicsContent(bool loadAllContent)
    {
        if (loadAllContent)
        {
            basicEffect = new BasicEffect(graphics.GraphicsDevice, null);
            basicEffect.View = Matrix.CreateLookAt(
                new Vector3(0, 0, 3),
                new Vector3(0, 0, 0),
                new Vector3(0, 1, 0)
                );
            basicEffect.Projection = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.ToRadians(45),
                Window.ClientBounds.Width / (float)Window.ClientBounds.Height,
                1, 100
                );
        }
    }

    protected override void Update(GameTime gameTime)
    {
        alpha++;
        Window.Title = "Alpha: " + alpha;
    }

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

        graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;
        graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
        graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
        
        graphics.GraphicsDevice.RenderState.AlphaTestEnable = true;
        graphics.GraphicsDevice.RenderState.AlphaFunction = CompareFunction.Greater;
        graphics.GraphicsDevice.RenderState.ReferenceAlpha = 30;

        redTriangle.Color = new Color(255, 0, 0, alpha);
        redTriangle.Draw(graphics.GraphicsDevice, basicEffect);

        graphics.GraphicsDevice.RenderState.AlphaBlendEnable = false;

        blueTriangle.Color = Color.Blue;
        blueTriangle.Draw(graphics.GraphicsDevice, basicEffect);
    }
}


alpha19.JPGアルファ:19
alpha57.JPGアルファ:57
alpha217.JPGアルファ:217

このサンプルでは、手前に赤い三角形を、奥に青い三角形を描画しています。
手前の赤い三角形はアルファの値が時間によって増えていきます。
最初は0から始まって、255まで行きます。

普通に考えれば、赤い三角形は最初から描画されそうですが、
そうはなりません。

アルファ・テストによってアルファが30より大きいときしか、
赤い三角形は描画されないのです。

そのため、最初の方は赤い三角形が全く描画されず、
青い三角形の全体が描画されます。
(全く描画されないため、深度バッファも変わりません。)

もしアルファ・テストがなかったら、深度バッファが書き込まれてしまうため、
たとえアルファの値が0だったとしても、青い三角形は一部しか描画されません。
alpha0.JPG※赤い三角形を描画した時に(実際にはアルファが0なので見えません)深度バッファが新しく書き込まれるため、遠いところにある青い三角形はその部分が描画されなくなってしまいます。


アルファ・テストを有効にするにはまず
RenderState.AlphaTestEnableプロパティを使います。

public bool AlphaTestEnable { get; set; }

これをtrueにすると、アルファ・テストが有効になります。

しかしそれだけではまだ普通に描画されます。
実際にアルファによって描画を制限するには
どういうときに描画をパスするかの条件を表すRenderState.AlphaFunctionと、
その条件にどんな値を使うかを表すRenderState.ReferenceAlpha
使わなければなりません。

public CompareFunction AlphaFunction { get; set; }
public int ReferenceAlpha { get; set; }


AlphaFunctionの型は深度バッファ関数の時に
使ったCompareFunctionです。
ReferenceAlphaプロパティで設定した値を基準にして、
描画するか、それとも描画しないかを決定します。
ここに入れる値によっては、サンプルとは逆に、
アルファが大きい時に描画しないというのも可能です。

ReferenceAlphaはAlphaFunctionにセットした関数によって
使われる値です。
この値が具体的に何を表すかはAlphaFunctionの中身によります。
この値よりアルファが大きい時に描画するのかもしれませんし、
小さい時に描画するのかもしれません。
あるいはこの値と同じ時に描画するのかもしれませんし、
この値と違う時に描画するのかもしれません。

この2つのプロパティを使うことによって、
描画するかしないかを柔軟にコントロールできるのです。

拍手[0回]

PR