忍者ブログ

Memeplexes

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

[PR]

×

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


かんたんXNA4.0 その25 ブレンド関数

物を半透明にするアルファ・ブレンディングですが、
ブレンド関数を使うことによってもっと別のことも出来ます。

アルファ・ブレンディングとはもう少し一般的にいうと、
色を混ぜる(ブレンドする)ということです。
ある混ぜ方をすると物が半透明になりますが、
別の混ぜ方をすれば別の効果が得られます。

前回では2つの色は常に足されましたが、(変わったのは係数だけ)
これは逆に引いたり、あるいは最大値をとったり、
最小値をとったりするようにも変更できます。
(そのため、アルファは単なる不透明度ではない場合だってたくさんあり、
むしろそれがほとんどなのです。)


このような、混ぜ方の関数を設定するのが
BlendState.ColorBlendFunctionプロパティです。


public BlendFunction CoplorBlendFunction { get; set; }

これはMicrosoft.Xna.Framework.Graphics.BlendFunction列挙体を
セットまたはゲットします。

BlendFunction列挙体
メンバ名 説明
Add "最終的な色" = ("これから描画するポリゴンの色" × SourceBlend) + ("描画する前の色" × DestinationBlend)
Max "最終的な色" = max( ("これから描画するポリゴンの色" × SourceBlend), ("描画する前の色" × DestinationBlend) )
Min "最終的な色" = min( ("これから描画するポリゴンの色" × SourceBlend), ("描画する前の色" × DestinationBlend) )
ReverseSubtract "最終的な色" = ("描画する前の色" × DestinationBlend) - ("これから描画するポリゴンの色" × SourceBlend)
Subtract "最終的な色" = ("これから描画するポリゴンの色" × SourceBlend) - ("描画する前の色" × DestinationBlend)


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


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

    public Triangle(Vector3 p1, Vector3 p2, Vector3 p3, Color color)
    {
        vertices[0] = new VertexPositionColor(p1, color);
        vertices[1] = new VertexPositionColor(p2, color);
        vertices[2] = new VertexPositionColor(p3, color);
    }

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

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

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

class MyGame : Game
{
    GraphicsDeviceManager graphics;
    BasicEffect effect;

    Triangle redTriangle = new Triangle
    (
        new Vector3(1, 0.5f, -1),
        new Vector3(0, -1, -1),
        new Vector3(-1, 0.5f, -1),
        Color.Red
    );

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

    protected override void LoadContent()
    {
        effect = new BasicEffect(GraphicsDevice)
        {
            View = Matrix.CreateLookAt
            (
                new Vector3(0, 0, 3),  //カメラの位置
                new Vector3(0, 0, 0),   //カメラの見る点
                new Vector3(0, 1, 0)    //カメラの上向きベクトル
            ),
            Projection = Matrix.CreatePerspectiveFieldOfView
            (
                MathHelper.ToRadians(45),   //視野の角度。ここでは45°
                GraphicsDevice.Viewport.AspectRatio,//画面のアスペクト比(=横/縦)
                1,      //カメラからこれより近い物体は画面に映らない
                100     //カメラからこれより遠い物体は画面に映らない
            )
        };

        GraphicsDevice.BlendState = new BlendState
        {
            ColorSourceBlend = Blend.SourceAlpha,
            ColorDestinationBlend = Blend.One,
            ColorBlendFunction = BlendFunction.ReverseSubtract,
        };
    }

    protected override void UnloadContent()
    {
        effect.Dispose();
    }

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


        redTriangle.Draw(GraphicsDevice, effect);
    }
}

blendFunctionReverseSubtract.JPG
さて、赤い三角形を描画したはずなのに青っぽくなっています。
どういうことでしょう?

これは、背景の色から赤い成分が引かれたのです。

"最終的な色(0, 149, 237)" = (コーンフラワーブルー(100, 149, 237) × 1) - (赤(255, 0, 0) × 1)

デフォルトでは成分は足されるのですが、ここでは引かれています。
このように、BlendState.ColorBlendFunctionを使うと
詳しい色の混ぜ方を設定することが出来るのです。

拍手[0回]

PR

かんたんXNA4.0 その24 アルファ・ブレンディング

XNAでは物を半透明に描くことが出来ます。
ゼリーのように、後ろのものが透けて見えるのです。

これをアルファ・ブレンディングと言います。
不透明度(アルファ)を考慮する描画だからです。

ポリゴンをスライムのように透明にするには、
BlendState.ColorDestinationBlendプロパティを使います。

public Blend ColorDestinationBlend { get; set; }

Blend列挙体
メンバ名 説明
Zero × 0
One × 1
SourceColor × "これから描くポリゴンの色"

※正確には掛け算と言うより、「それぞれの色の要素が”これから書くポリゴンの色”の対応する色の要素倍される」です。

例えば、(1, 1, 1)と(0.1, 0.2, 0.3)なら(0.1, 0.2, 0.3)。
(0.1, 0.2, 0.3)と(0.1, 0.2, 0.3)なら(0.01, 0.04, 0.09)
InverseSourceColor × (白 - "これから描くポリゴンの色")
SourceAlpha × "これから描くポリゴンの不透明度"
InverseSourceAlpha × (1 - "これから描くポリゴンの不透明度")
DestinationAlpha × "背景の不透明度"
InverseDestinationAlpha × (1 - "背景の不透明度")
DestinationColor × 背景の色
InverseDestinationColor × (白 - "背景の色")
SourceAlphaSaturation × Min("これから描くポリゴンの不透明度", 1 - 描画前の不透明度)
BothInverseSourceAlpha これはDestinationBlendプロパティにセットする必要はありません。これをSourceBlendプロパティにセットするとDestinationBlendの中身は上書きされます(ただしプロパティの値には反映されず、Zeroのままですが)。

この値をセットすると、
最終的な色 =
描画前の色 × 描画するポリゴンの不透明度
+ 描画するポリゴンの色 × (1 - 描画するポリゴンの不透明度)

となります。
BlendFactor × "RenderState.BlendFactorプロパティにセットした色"
InverseBlendFactor × (白 - "RenderState.BlendFactorプロパティにセットした色")
ただしこのモードは、GraphicsDeviceCapabilitiesクラスでSourceBlendCapabilitiesプロパティかDestinationBlendCapabilitiesプロパティのSupportsBlendFactorプロパティ(こいつはgetだけでsetはできません)がtrueのときにしか使えません。


このプロパティは、ポリゴンをその上に描画する前の背景が
どの程度結果に影響するかを表します。
デフォルトではBlend.Zeroで全く影響されません。
つまり、背景は全く描画結果に現れないのです。(不透明に見えます)

"最終的な色" = "これから描画するポリゴンの色"

もし透明なポリゴンを描こうと思えば、
これを、例えばBlend.Oneに指定してやればいいでしょう。
そうすれば、

"最終的な色" = "描画する前の色" + "描画するポリゴンの色"

となり、半透明に見えます。
実際にはBlendState.Additiveで同じことができます。
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;


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

    public Triangle(Vector3 p1, Vector3 p2, Vector3 p3, Color color)
    {
        vertices[0] = new VertexPositionColor(p1, color);
        vertices[1] = new VertexPositionColor(p2, color);
        vertices[2] = new VertexPositionColor(p3, color);
    }

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

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

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

class MyGame : Game
{
    GraphicsDeviceManager graphics;
    BasicEffect effect;

    Triangle redTriangle = new Triangle
    (
        new Vector3(1, 0.5f, -1),
        new Vector3(0, -1, -1),
        new Vector3(-1, 0.5f, -1),
        Color.Red
    );

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

    }

    protected override void LoadContent()
    {
        effect = new BasicEffect(GraphicsDevice)
        {
            View = Matrix.CreateLookAt
            (
                new Vector3(0, 0, 3),  //カメラの位置
                new Vector3(0, 0, 0),   //カメラの見る点
                new Vector3(0, 1, 0)    //カメラの上向きベクトル
            ),
            Projection = Matrix.CreatePerspectiveFieldOfView
            (
                MathHelper.ToRadians(45),   //視野の角度。ここでは45°
                GraphicsDevice.Viewport.AspectRatio,//画面のアスペクト比(=横/縦)
                1,      //カメラからこれより近い物体は画面に映らない
                100     //カメラからこれより遠い物体は画面に映らない
            )
        };
    }

    protected override void UnloadContent()
    {
        effect.Dispose();
    }

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

        GraphicsDevice.BlendState = BlendState.Additive;
        redTriangle.Draw(GraphicsDevice, effect);
    }
}


destBlendOne.JPG
ここでは赤い三角形を描画しているのですが、
アルファ・ブレンディングの効果で半透明になり、
ピンクっぽくなっています。

背景のコーンフラワーブルーと赤が
加算されているのです。

さて、このサンプルプログラムはアルファ・ブレンディングを
銘打っておきながら不透明度(アルファ)を利用していません。
ただ単純にポリゴンの色を加算しているだけです。

サギです。

不透明値を変更しても実際に描画されるポリゴンの
色には変わりがないのですから!

ポリゴンの色の不透明度のデータを変更したら、
実際に描画される色も変更されて欲しいものです。

それに、この描画の仕方はゼリーやスライムというよりもむしろ
自分で光っている透明な物体、光るゼリーに近いのです。
(光るゼリーなんて見たことありませんが、
他に形容するのは難しいですからね)


アルファが本当に考慮されるアルファ・ブレンディングを行うには、
BlendState.ColorSourceBlendプロパティも使います。

public Blend ColorSourceBlend [ get; set; }

このプロパティは、これから描画するポリゴンの色が
どの程度最終的な色に反映されるかを表します。

デフォルトはBlend.Oneで、これから描くポリゴンの色が
100%反映されるようになっています。

実際には、BlendState.AlphaBlendを使うだけで構いません。
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;


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

    public Triangle(Vector3 p1, Vector3 p2, Vector3 p3, Color color)
    {
        vertices[0] = new VertexPositionColor(p1, color);
        vertices[1] = new VertexPositionColor(p2, color);
        vertices[2] = new VertexPositionColor(p3, color);
    }

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

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

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

class MyGame : Game
{
    GraphicsDeviceManager graphics;
    BasicEffect effect;

    Triangle redTriangle = new Triangle
    (
        new Vector3(1, 0.5f, -1),
        new Vector3(0, -1, -1),
        new Vector3(-1, 0.5f, -1),
        new Color(255, 0, 0, 250)
    );

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

    }

    protected override void LoadContent()
    {
        effect = new BasicEffect(GraphicsDevice)
        {
            View = Matrix.CreateLookAt
            (
                new Vector3(0, 0, 3),  //カメラの位置
                new Vector3(0, 0, 0),   //カメラの見る点
                new Vector3(0, 1, 0)    //カメラの上向きベクトル
            ),
            Projection = Matrix.CreatePerspectiveFieldOfView
            (
                MathHelper.ToRadians(45),   //視野の角度。ここでは45°
                GraphicsDevice.Viewport.AspectRatio,//画面のアスペクト比(=横/縦)
                1,      //カメラからこれより近い物体は画面に映らない
                100     //カメラからこれより遠い物体は画面に映らない
            )
        };

    }

    protected override void UnloadContent()
    {
        effect.Dispose();
    }

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

        GraphicsDevice.BlendState = BlendState.AlphaBlend;
        redTriangle.Draw(GraphicsDevice, effect);
    }
}
alpha20.JPG
このサンプルプログラムは、不透明度が255中20の
赤い三角形を描画しています。

「最終的に描画される色」 
        = 不透明度 × 「描画前の色」 + (1 - 不透明度)×「描画するポリゴンの色」


ぼんやりとしていますが、不透明度を上げていくと
徐々にはっきりしてきます。

alpha40.JPG40/255
alpha80.JPG80/255
alpha160.JPG160/255
alpha255.JPG255/255

不透明度が255の三角形は普通に描画したものと変わりません。
これが前のサンプルとは違うところです。

前のサンプルは背景と三角の色を単純に足していましたが、
このサンプルではポリゴンの色の不透明度が考慮慮されて足されます。

拍手[0回]


かんたんXNA4.0 その23 深度バッファ関数

さて、深度バッファとは物体の前後関係から
適切に描画するためのデータでした。

カメラからの距離がより小さいときには描画し、
より大きいときには描画しないのです。

こうすることによって近くにあるものは遠くにあるものを隠し、
遠くにあるものは近くにあるものに隠されるのです。

実はこの挙動は変更することが出来ます。
例えば全く逆、カメラからの距離がより大きいときには描画し、
より小さいときには描画しないということができます。

近くにあるものは遠くにあるものに隠れ、
遠くにあるものは近くにあるものを隠すことが可能となるのです!!
(そんなことをして何が楽しいのかは知りませんが)
こういった挙動はDepthStencilState.DepthBufferFunctionプロパティで
設定します。

public CompareFunction DepthBufferFunction { get; set; }

このプロパティで表される条件を満たしたときのみ描画し、
満たさないときは描画しません。
そしてデフォルトの条件は「より小さいとき」です。

このプロパティの型は
Microsoft.Xna.Framework.CompareFunction列挙体です。

メンバ名 説明
Always 常に描画
Equal ==
Greater >
GreaterEqual >=
Less <
LessEqual <=
Never 常に描画しない
NotEqual !=

デフォルトの値はLessEqualです。
カメラからの距離が「より小さいとき」、
つまりカメラに近いときは描画すると言うことです。
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;


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

    public Triangle(Vector3 p1, Vector3 p2, Vector3 p3, Color color)
    {
        vertices[0] = new VertexPositionColor(p1, color);
        vertices[1] = new VertexPositionColor(p2, color);
        vertices[2] = new VertexPositionColor(p3, color);
    }

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

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

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

class MyGame : Game
{
    GraphicsDeviceManager graphics;
    BasicEffect effect;

    Triangle blueTriangle = new Triangle
    (
        new Vector3(0, 1, 0),
        new Vector3(1, -0.5f, 0),
        new Vector3(-1, -0.5f, 0),
        Color.Blue
    );
    Triangle redTriangle = new Triangle
    (
        new Vector3(1, 0.5f, -1),
        new Vector3(0, -1, -1),
        new Vector3(-1, 0.5f, -1),
        Color.Red
    );

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

    }

    protected override void LoadContent()
    {
        effect = new BasicEffect(GraphicsDevice)
        {
            View = Matrix.CreateLookAt
            (
                new Vector3(0, 0, 3),  //カメラの位置
                new Vector3(0, 0, 0),   //カメラの見る点
                new Vector3(0, 1, 0)    //カメラの上向きベクトル
            ),
            Projection = Matrix.CreatePerspectiveFieldOfView
            (
                MathHelper.ToRadians(45),   //視野の角度。ここでは45°
                GraphicsDevice.Viewport.AspectRatio,//画面のアスペクト比(=横/縦)
                1,      //カメラからこれより近い物体は画面に映らない
                100     //カメラからこれより遠い物体は画面に映らない
            )
        };
        GraphicsDevice.DepthStencilState = new DepthStencilState
        {
            DepthBufferFunction = CompareFunction.GreaterEqual
        };
    }

    protected override void UnloadContent()
    {
        effect.Dispose();
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(
            ClearOptions.Target | ClearOptions.DepthBuffer, //色と深度バッファをクリア
            Color.CornflowerBlue,   //色の初期値
            0,  //深度バッファの初期値(一番近いところから始める)
            0   //ステンシルバッファの初期値
            );


        blueTriangle.Draw(GraphicsDevice, effect);
        redTriangle.Draw(GraphicsDevice, effect);
    }
}

depthBufferFunctionGreaterEqual.jpg
このサンプルプログラムは、奇妙なことに
「近くのものが遠くのものに隠される」ようになっています。

カメラからの距離が「大きいか等しい」ときのみ描画するようなっているのです。

実際にこれがなんの役に立つかはさっぱりわかりませんが
こういうのもあるということです。

拍手[0回]


かんたんXNA4.0 その22 深度バイアス

3DCGには"z-ファイティング"という現象があります。
カメラからの距離があまりにも同じような物体が2つあると、
深度バッファの計算が狂って(丸め誤差などが原因だそうです)
描画がおかしくなります。

zFighting2.jpg

zFighting.jpg


これは、同じ平面上に2つの三角形を重ねてクルクルと回転させて表示したものです。
なんだか縦にギザギザしているのがわかると思います。
これが"z-ファイティング"です。

これが問題になるのは、物が隠れて出来る"影(シャドウ)"を描画するときなどです。
戦闘機が太陽光をさえぎって地面に影を落とすとすると、
地面を表すポリゴンと影を表すポリゴンが重なることになります。
すると、このような変なギザギザが発生してしまうことがあるのです。

この問題を解決する方法のひとつとして、深度バイアスがあります。
深度が同じならプラスαの情報を使って
どっちのポリゴンが前か決めればいいのです。
例えばカメラからの距離が同じ2つの三角形があるとしましょう。
このままだとzファイティングが発生するのですが、
ここで片方の深度バイアスを0.1fに設定してやります。(デフォルトでは0)
そうすると、0.1の方がより奥にあると認識されて0の後ろに隠れるのです。
z-ファイティングになりません。

この深度バイアスをセットするには
RasterizerState.DepthBiasプロパティを使います。

public float DepthBias { get; set; }

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


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

    public Triangle(Vector3 p1, Vector3 p2, Vector3 p3, Color color)
    {
        vertices[0] = new VertexPositionColor(p1, color);
        vertices[1] = new VertexPositionColor(p2, color);
        vertices[2] = new VertexPositionColor(p3, color);
    }

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

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

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

class MyGame : Game
{
    GraphicsDeviceManager graphics;
    BasicEffect effect;

    Triangle blueTriangle = new Triangle
    (
        new Vector3(0, 1, 0),
        new Vector3(1, -0.5f, 0),
        new Vector3(-1, -0.5f, 0),
        Color.Blue
    );
    Triangle redTriangle = new Triangle
    (
        new Vector3(1, 0.5f, 0),
        new Vector3(0, -1, 0),
        new Vector3(-1, 0.5f, 0),
        Color.Red
    );
    RasterizerState depthBiasEnabled;

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

    }

    protected override void LoadContent()
    {
        effect = new BasicEffect(GraphicsDevice)
        {
            View = Matrix.CreateLookAt
            (
                new Vector3(0, 0, 3),  //カメラの位置
                new Vector3(0, 0, 0),   //カメラの見る点
                new Vector3(0, 1, 0)    //カメラの上向きベクトル
            ),
            Projection = Matrix.CreatePerspectiveFieldOfView
            (
                MathHelper.ToRadians(45),   //視野の角度。ここでは45°
                GraphicsDevice.Viewport.AspectRatio,//画面のアスペクト比(=横/縦)
                1,      //カメラからこれより近い物体は画面に映らない
                100     //カメラからこれより遠い物体は画面に映らない
            )
        };
        depthBiasEnabled = new RasterizerState
        {
            DepthBias = 0.1f,
            CullMode = CullMode.None 
        };
    }

    protected override void UnloadContent()
    {
        effect.Dispose();
    }

    protected override void Update(GameTime gameTime)
    {
        //(カメラではなく)三角形そのものを回転させる。
        effect.World *= Matrix.CreateRotationY(MathHelper.ToRadians(1));
    }

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

        
        GraphicsDevice.RasterizerState = RasterizerState.CullNone;
        blueTriangle.Draw(GraphicsDevice, effect);
        GraphicsDevice.RasterizerState = depthBiasEnabled;
        redTriangle.Draw(GraphicsDevice, effect);
    }
}
depthBias.jpg
深度バイアスをセットして、青い三角形を常に赤い三角形の上に描画するようにしました。
赤い三角形に深度バイアスをセットしたのでより遠くにあると認識されたようです。
カメラからの距離は同じですが、z-ファイティングにはなりません!


拍手[1回]


かんたんXNA4.0 その21 深度バッファへの書き込みの無効化

前回は深度バッファそのものを無効化しましたが、
深度バッファのチェックはそのままに、
書き込みだけを無効化することも出来ます。

書き込みを無効にすると、
深度バッファそのものを無効化したときのように
やはり奥の物が手前のものより前に描画されてしまいます。

深度が記録されなくなって、どの物体が手前に、
どの物体が奥にあるのかわからなくなるからです。

しかし使いようによっては変わったこともできます。
深度バッファそのものは有効なので
半透明のビームなどを描きたいときには
壁に隠れてかつ、ビーム同士では半透明で隠れない
といったことができます。

深度バッファへの書き込みを無効にするには
DepthStencilState.DepthRead
を使います。

public static readonly DepthStencilState DepthRead;

このオブジェクトをGraphicsDevice.DepthStencilStateにセットすると、
書き込みが無効になります。
デフォルトではもちろん書き込み有効です。

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;


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


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

    public Triangle(Vector3 p1, Vector3 p2, Vector3 p3, Color color)
    {
        vertices[0] = new VertexPositionColor(p1, color);
        vertices[1] = new VertexPositionColor(p2, color);
        vertices[2] = new VertexPositionColor(p3, color);
    }

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

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

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

class MyGame : Game
{
    GraphicsDeviceManager graphics;
    BasicEffect effect;

    Triangle blueTriangle = new Triangle
    (
        new Vector3(0, 1, 0),
        new Vector3(1, -0.5f, 0),
        new Vector3(-1, -0.5f, 0),
        Color.Blue
    );
    Triangle redTriangle = new Triangle
    (
        new Vector3(1, 0.5f, -1),
        new Vector3(0, -1, -1),
        new Vector3(-1, 0.5f, -1),
        Color.Red
    );

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

    }

    protected override void LoadContent()
    {
        effect = new BasicEffect(GraphicsDevice)
        {
            View = Matrix.CreateLookAt
            (
                new Vector3(0, 0, 3),  //カメラの位置
                new Vector3(0, 0, 0),   //カメラの見る点
                new Vector3(0, 1, 0)    //カメラの上向きベクトル
            ),
            Projection = Matrix.CreatePerspectiveFieldOfView
            (
                MathHelper.ToRadians(45),   //視野の角度。ここでは45°
                GraphicsDevice.Viewport.AspectRatio,//画面のアスペクト比(=横/縦)
                1,      //カメラからこれより近い物体は画面に映らない
                100     //カメラからこれより遠い物体は画面に映らない
            )
        };
    }

    protected override void UnloadContent()
    {
        effect.Dispose();
    }

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

        GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;

        blueTriangle.Draw(GraphicsDevice, effect);
        redTriangle.Draw(GraphicsDevice, effect);
    }
}

depthBufferWriteDisabled.jpg
ここでも、2つの三角形を描画しています。
手前に青い三角形、奥に赤い三角形があるのですが、
深度バッファへ書き込みがされていないので
ポリゴンが常に描画されてしまい、
赤い三角形が上に描画されてしまいます。

さて、これだけではDepthStencilState.None
との違いがわかりにくいですね。
そういうときには次のようにすると違いがわかります。
    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);

        GraphicsDevice.DepthStencilState = DepthStencilState.Default;
        blueTriangle.Draw(GraphicsDevice, effect);
        GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
        redTriangle.Draw(GraphicsDevice, effect);
    }

これは三角形を正常に描画します。
最後の赤い三角形の次にはもう描画するポリゴンがないので
深度バッファを書き込まなくても問題はないのです。



拍手[0回]