忍者ブログ

Memeplexes

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

XNA4.0 複数のメッシュを一度のDrawで描画(ハードウェア・インスタンシング)

以前のこの記事のプログラムを、XNA4.0用に書きかえてみました。
たくさんの同じモデルを表示するときに役に立つ、ハードウェアインスタンシングです。

HardwareInstancing.fx
struct VertexPositionColor
{
	float4 Position : POSITION0;
	float4 Color : COLOR;
};

VertexPositionColor MyVertexShader(
	VertexPositionColor input,
	float3 position : POSITION1
	)
{
	input.Position.xyz += position;
	return input;
}

float4 MyPixelShader(float4 color : COLOR) : COLOR0
{
	return color;
}

technique HardwareInstancing
{
	pass Pass1
	{
		VertexShader = compile vs_3_0 MyVertexShader();
		PixelShader = compile ps_3_0 MyPixelShader();
	}
}




MyGame.cs
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;



class MyGame : Game
{
    VertexPositionColor[] vertices = new VertexPositionColor[]{
        new VertexPositionColor(new Vector3(-0.1f, 0.1f, 0), Color.Blue),
        new VertexPositionColor(new Vector3(0.1f, 0.1f, 0), Color.White),
        new VertexPositionColor(new Vector3(0.1f, -0.1f, 0), Color.Red)
    };

    Vector3[] instances = new Vector3[] {
        new Vector3(),
        new Vector3(0.1f, 0.1f, 0),
        new Vector3(0.2f, 0.2f, 0)
    };


    //Graphics Device Objects
    Effect effect;
    VertexBuffer triangleVertexBuffer;
    IndexBuffer indexBuffer;
    DynamicVertexBuffer instanceVertexBuffer;

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

    protected override void LoadContent()
    {
        effect = Content.Load<Effect>("HardwareInstancing");

        triangleVertexBuffer = new VertexBuffer(
            GraphicsDevice,
            VertexPositionColor.VertexDeclaration,
            vertices.Length,
            BufferUsage.WriteOnly
            );
        triangleVertexBuffer.SetData<VertexPositionColor>(vertices);


        var index = new int[] { 0, 1, 2 };
        indexBuffer = new IndexBuffer(
            GraphicsDevice,
            IndexElementSize.ThirtyTwoBits,
            index.Length, 
            BufferUsage.WriteOnly
            );
        indexBuffer.SetData<int>(index);


        instanceVertexBuffer = new DynamicVertexBuffer(
            GraphicsDevice, 
            new VertexDeclaration(
                new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 1)
            ),
            instances.Length,
            BufferUsage.WriteOnly);

        instanceVertexBuffer.SetData(instances);
    }

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

        GraphicsDevice.SetVertexBuffers(
            new VertexBufferBinding(triangleVertexBuffer, 0, 0),
            new VertexBufferBinding(instanceVertexBuffer, 0, 1)
            );
        GraphicsDevice.Indices = indexBuffer;

        instanceVertexBuffer.SetData(instances, 0, instances.Length, SetDataOptions.Discard);

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

            GraphicsDevice.DrawInstancedPrimitives(
                PrimitiveType.TriangleList,
                0,
                0,
                vertices.Length, 
                0,
                vertices.Length / 3,
                instances.Length
                );
        }
    }
}

xna4.0HardwareInstancing.jpg

拍手[1回]

PR