WisdomSoft - for your serial experiences.

アルファ合成

グラフィックスデバイスの既定の設定ではピクセルは常に不透明で、新しいピクセルで古いピクセルを上書きします。頂点色やテクスチャのアルファ値を用いて合成する方法を解説します。

背景とプリミティブを合成する

プリミティブをラスタライズして出力されるピクセルは、頂点の色やテクスチャによって決定されます。例えば頂点の色には ARGB 形式の色を設定することができますが、既定の設定ではアルファ値を用いた合成は無効に設定されています。よって、アルファ値に関係なくプリミティブの描画は新しいピクセルの色で塗りつぶします。テクスチャの場合も同様で、透過色は黒と合成されます。プリミティブの色やテクスチャのアルファ値は、既存のピクセルと合成されることはありません。

描画するプリミティブをアルファ値に基づいて背景と合成するには、描画するグラフィックスデバイスを表す GraphicsDevice オブジェクトの BlendState プロパティを設定します。

GraphicsDevice クラス BlendState プロパティ
public BlendState BlendState { get; set; }

このプロパティには合成方法を表す BlendState オブジェクトを設定します。BlendState クラスについては「スプライトの重ね合わせ」で解説したとおりです。既定の設定では元のピクセルを新しいピクセルで上書きする不透明の組み込みの合成ステートオブジェクトが設定されています。このオブジェクトは BlendState クラスの Opaque フィールドから得られるオブジェクトと同じです。

BlendState クラス Opaque フィールド
public static readonly BlendState Opaque

このオブジェクトに代わって、アルファ合成を行う AlphaBlend フィールドから得られる組み込みの合成ステートオブジェクトを、上記の BlendState プロパティに設定することで、ピルセルのアルファ合成が可能になります。

コード1
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

public class TestGame : Game
{
    public static void Main(string[] args)
    {
        using (Game game = new TestGame()) game.Run();
    }

    private GraphicsDeviceManager graphicsDeviceManager;
    private VertexBuffer vertexBuffer;
    private IndexBuffer indexBuffer;
    private BasicEffect effect;
    private VertexPositionTexture[] vertices;
    private short[] indices;

    public TestGame()
    {
        graphicsDeviceManager = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }

    protected override void Initialize()
    {
        Vector3 pt1 = new Vector3(-0.5F, 0.8F, 0);
        Vector3 pt2 = new Vector3(0.5F, 0.8F, 0);
        Vector3 pt3 = new Vector3(-0.5F, -0.8F, 0);
        Vector3 pt4 = new Vector3(0.5F, -0.8F, 0);

        Vector2 uv1 = new Vector2(0, 0);
        Vector2 uv2 = new Vector2(1, 0);
        Vector2 uv3 = new Vector2(0, 1);
        Vector2 uv4 = new Vector2(1, 1);

        vertices = new VertexPositionTexture[] {
	        new VertexPositionTexture(pt1, uv1),
	        new VertexPositionTexture(pt2, uv2),
	        new VertexPositionTexture(pt3, uv3),
	        new VertexPositionTexture(pt4, uv4),
        };
        indices = new short[] { 0, 1, 2, 1, 3, 2 };

        base.Initialize();
    }

    protected override void LoadContent()
    {
        vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), vertices.Length, BufferUsage.None);
        vertexBuffer.SetData(vertices);
        GraphicsDevice.SetVertexBuffer(vertexBuffer);

        indexBuffer = new IndexBuffer(GraphicsDevice, IndexElementSize.SixteenBits, indices.Length, BufferUsage.None);
        indexBuffer.SetData(indices);
        GraphicsDevice.Indices = indexBuffer;

        effect = new BasicEffect(GraphicsDevice);
        effect.TextureEnabled = true;
        effect.Texture = Content.Load<Texture2D>("TestImage");

        GraphicsDevice.BlendState = BlendState.AlphaBlend;

        base.LoadContent();
    }

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

        foreach (EffectPass pass in effect.CurrentTechnique.Passes)
        {
            pass.Apply();
            GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertices.Length, 0, 2);
        }

        base.Draw(gameTime);
    }
}
実行結果
コード1 実行結果

コード1は背景が透明な透過 PNG をテクスチャとして読み込み、描画しています。「テクスチャ コード1」の実行結果と比べると、背景の透過ピクセルが正しく透明になっていることが確認できます。