忍者ブログ

Memeplexes

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

かんたんXNA4.0 その20 深度バッファ

3Dグラフィックスでは、奥にある物体は手前にある物体に
隠されなければなりません。

例えば、壁の向こうに敵がいる場合、敵は壁に隠れて見えません。
(当たり前です!)

XNAではこのことを特に気にする必要はありません。
ふつうに描画するだけで自動的に奥のものが隠れてくれます。

depthBufferEnabled.jpg
(奥に赤い三角形、手前に青い三角形があります。
奥の三角形は手前の三角形に隠れています。)


これは内部で深度バッファというものを使っているからです。
深度バッファというのは色のデータと共に各ピクセルごとに
存在するデータのことで、
今一番手前の物体のカメラからの距離を表しています。
(もっともこれは相対的な値で、0.0から1.0までです)

もし今描画しようとしている物体の距離が深度バッファのものより遠ければ
(つまり今描画しようとしている物体が隠れてしまうのなら)
描画しないことにしています。
もし今から描画する方が近いのなら、描画して、
深度バッファを今描いたものに更新します。

このように深度バッファを使うことによって適切な描画が出来るのですが、
特殊な効果を狙ってあえて深度バッファを使わないようにすることが可能です。

これにはGraphicsDevice.DepthStencilStateプロパティを使って設定します。

public DepthStencilState DepthStancilState { get; set; }

これを使うと、深度バッファを有効にしたり無効にしたり出来ます。
デフォルトはもちろん有効です。

using System;
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;
    VertexPositionNormalTexture[] vertices;

    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);

    }

    Vector3 getPosition(int index, int count)
    {
        return new Vector3(
            (float)Math.Sin(2 * Math.PI * index / count),
            0,
            (float)Math.Cos(2 * Math.PI * index / count)
            );
    }

    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.None;

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


depthBufferDisabled.jpg
ここでは、2つの三角形を描画しています。
手前にあるのが青い三角形
奥にあるのが赤い三角形です。

しかし、深度バッファを無効にしたため、
隠れて見えないはずの赤い三角形が
青い三角形の上に描画されています。

まず青い三角形を描画し、その後赤い三角形を描画したため、
赤い三角形で上書きされてしまうのです。
(もし深度バッファが有効なら、赤い三角形を後から描いてもきちんと隠れてくれます!)


 

拍手[0回]

PR