Нужна помощь с использованием инстансинга в XNA 4.0 - PullRequest
5 голосов
/ 29 марта 2012

Я пришел, чтобы узнать об экземплярах в XNA

Я начинающий разработчик XNA, только недавно перешел от 2D к 3D играм.
Я пытаюсь нарисовать большое количество кубиков, сделанныхисключительно из вершин в коде.Как можно подозревать, рисование большого количества этих кубов вызывает на моем компьютере немало стресса.
Когда я искал способ повысить производительность, я столкнулся с термином «создание экземпляров».
Не зная, какв XNA 4.0 работает инстансинг, я искал учебное пособие, подходящее для кого-то моего уровня.
Однако, единственное учебное пособие, с которым я столкнулся (http://blogs.msdn.com/b/shawnhar/archive/2010/06/17/drawinstancedprimitives-in-xna-game-studio-4-0.aspx), для меня слишком продвинуто.модели, сетки и еще много чего, а не вершин, поэтому я не могу понять, какой фрагмент кода на самом деле имеет отношение к тому, что я ищу.

Вот почему я к вам обращаюсь. Если кто-то может дать мнеЯ был бы очень рад простому (если возможно) учебнику или фрагментам кода, объясняющим, как использовать создание экземпляров с кубами (или любыми фигурами), нарисованными вершинами в XNA 4.0.

1 Ответ

9 голосов
/ 10 апреля 2012

Это самый простой фрагмент кода, который я мог придумать.Это адаптация кода, который я сделал пару месяцев назад для отображения некоторых кубов, точно так же, как вам нужно, без моделей и ничего необычного.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;

namespace HardwareInstancing
{
    public class Instancing
    {
        Texture2D texture;
        Effect effect;

        VertexDeclaration instanceVertexDeclaration;

        VertexBuffer instanceBuffer;
        VertexBuffer geometryBuffer;
        IndexBuffer  indexBuffer;

        VertexBufferBinding[] bindings;
        InstanceInfo[] instances;

        struct InstanceInfo
        {
            public Vector4 World;
            public Vector2 AtlasCoordinate;
        };

        Int32 instanceCount = 10000;

        public void Initialize(GraphicsDevice device)
        {
            GenerateInstanceVertexDeclaration();
            GenerateGeometry(device);
            GenerateInstanceInformation(device, instanceCount);

            bindings = new VertexBufferBinding[2];
            bindings[0] = new VertexBufferBinding(geometryBuffer);
            bindings[1] = new VertexBufferBinding(instanceBuffer, 0, 1);
        }

        public void Load(ContentManager Content)
        {
            effect = Content.Load<Effect>("InstancingShader");
            texture = Content.Load<Texture2D>("default_256");
        }

        private void GenerateInstanceVertexDeclaration()
        {
            VertexElement[] instanceStreamElements = new VertexElement[2];

            instanceStreamElements[0] = 
                    new VertexElement(0, VertexElementFormat.Vector4, 
                        VertexElementUsage.Position, 1);

            instanceStreamElements[1] = 
                new VertexElement(sizeof(float) * 4, VertexElementFormat.Vector2,
                    VertexElementUsage.TextureCoordinate, 1);

            instanceVertexDeclaration = new VertexDeclaration(instanceStreamElements);
        }

        //This creates a cube!
        public void GenerateGeometry(GraphicsDevice device)
        {
            VertexPositionTexture[] vertices = new VertexPositionTexture[24];

            #region filling vertices
            vertices[0].Position = new Vector3(-1, 1, -1);
            vertices[0].TextureCoordinate = new Vector2(0, 0);
            vertices[1].Position = new Vector3(1, 1, -1);
            vertices[1].TextureCoordinate = new Vector2(1, 0);
            vertices[2].Position = new Vector3(-1, 1, 1);
            vertices[2].TextureCoordinate = new Vector2(0, 1);
            vertices[3].Position = new Vector3(1, 1, 1);
            vertices[3].TextureCoordinate = new Vector2(1, 1);

            vertices[4].Position = new Vector3(-1, -1, 1);
            vertices[4].TextureCoordinate = new Vector2(0, 0);
            vertices[5].Position = new Vector3(1, -1, 1);
            vertices[5].TextureCoordinate = new Vector2(1, 0);
            vertices[6].Position = new Vector3(-1, -1, -1);
            vertices[6].TextureCoordinate = new Vector2(0, 1);
            vertices[7].Position = new Vector3(1, -1, -1);
            vertices[7].TextureCoordinate = new Vector2(1, 1);

            vertices[8].Position = new Vector3(-1, 1, -1);
            vertices[8].TextureCoordinate = new Vector2(0, 0);
            vertices[9].Position = new Vector3(-1, 1, 1);
            vertices[9].TextureCoordinate = new Vector2(1, 0);
            vertices[10].Position = new Vector3(-1, -1, -1);
            vertices[10].TextureCoordinate = new Vector2(0, 1);
            vertices[11].Position = new Vector3(-1, -1, 1);
            vertices[11].TextureCoordinate = new Vector2(1, 1);

            vertices[12].Position = new Vector3(-1, 1, 1);
            vertices[12].TextureCoordinate = new Vector2(0, 0);
            vertices[13].Position = new Vector3(1, 1, 1);
            vertices[13].TextureCoordinate = new Vector2(1, 0);
            vertices[14].Position = new Vector3(-1, -1, 1);
            vertices[14].TextureCoordinate = new Vector2(0, 1);
            vertices[15].Position = new Vector3(1, -1, 1);
            vertices[15].TextureCoordinate = new Vector2(1, 1);

            vertices[16].Position = new Vector3(1, 1, 1);
            vertices[16].TextureCoordinate = new Vector2(0, 0);
            vertices[17].Position = new Vector3(1, 1, -1);
            vertices[17].TextureCoordinate = new Vector2(1, 0);
            vertices[18].Position = new Vector3(1, -1, 1);
            vertices[18].TextureCoordinate = new Vector2(0, 1);
            vertices[19].Position = new Vector3(1, -1, -1);
            vertices[19].TextureCoordinate = new Vector2(1, 1);

            vertices[20].Position = new Vector3(1, 1, -1);
            vertices[20].TextureCoordinate = new Vector2(0, 0);
            vertices[21].Position = new Vector3(-1, 1, -1);
            vertices[21].TextureCoordinate = new Vector2(1, 0);
            vertices[22].Position = new Vector3(1, -1, -1);
            vertices[22].TextureCoordinate = new Vector2(0, 1);
            vertices[23].Position = new Vector3(-1, -1, -1);
            vertices[23].TextureCoordinate = new Vector2(1, 1);
            #endregion

            geometryBuffer = new VertexBuffer(device, VertexPositionTexture.VertexDeclaration,
                                              24, BufferUsage.WriteOnly);
            geometryBuffer.SetData(vertices);

            #region filling indices

            int[] indices = new int [36];
            indices[0] = 0; indices[1] = 1; indices[2] = 2;
            indices[3] = 1; indices[4] = 3; indices[5] = 2;

            indices[6] = 4; indices[7] = 5; indices[8] = 6;
            indices[9] = 5; indices[10] = 7; indices[11] = 6;

            indices[12] = 8; indices[13] = 9; indices[14] = 10;
            indices[15] = 9; indices[16] = 11; indices[17] = 10;

            indices[18] = 12; indices[19] = 13; indices[20] = 14;
            indices[21] = 13; indices[22] = 15; indices[23] = 14;

            indices[24] = 16; indices[25] = 17; indices[26] = 18;
            indices[27] = 17; indices[28] = 19; indices[29] = 18;

            indices[30] = 20; indices[31] = 21; indices[32] = 22;
            indices[33] = 21; indices[34] = 23; indices[35] = 22;

            #endregion

            indexBuffer = new IndexBuffer(device, typeof(int), 36, BufferUsage.WriteOnly);
            indexBuffer.SetData(indices);
        }

        private void GenerateInstanceInformation(GraphicsDevice device, Int32 count)
        {
            instances = new InstanceInfo[count]; 
            Random rnd = new Random();

            for (int i = 0; i < count; i++)
            {
                //random position example
                instances[i].World = new Vector4(-rnd.Next(400), 
                                                 -rnd.Next(400), 
                                                 -rnd.Next(400), 1);

                instances[i].AtlasCoordinate = new Vector2(rnd.Next(0, 2), rnd.Next(0, 2));
            }

            instanceBuffer = new VertexBuffer(device, instanceVertexDeclaration, 
                                              count, BufferUsage.WriteOnly);
            instanceBuffer.SetData(instances);
        }

        //view and projection should come from your camera
        public void Draw(ref Matrix view, ref Matrix projection, GraphicsDevice device)
        {
            device.Clear(Color.CornflowerBlue);

            effect.CurrentTechnique = effect.Techniques["Instancing"];
            effect.Parameters["WVP"].SetValue(view * projection);
            effect.Parameters["cubeTexture"].SetValue(texture);

            device.Indices = indexBuffer;

            effect.CurrentTechnique.Passes[0].Apply();

            device.SetVertexBuffers(bindings);
            device.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, 24, 0, 12, instanceCount);
        }
    }
}

Я использовал ЭТО Текстура вместе с этим шейдером:

float4x4 WVP;
texture cubeTexture;

sampler TextureSampler = sampler_state
{
    texture = <cubeTexture>;
    mipfilter = LINEAR;
    minfilter = LINEAR;
    magfilter = LINEAR;
};

struct InstancingVSinput
{
    float4 Position : POSITION0;
    float2 TexCoord : TEXCOORD0;
};

struct InstancingVSoutput
{
    float4 Position : POSITION0;
    float2 TexCoord : TEXCOORD0;
};

InstancingVSoutput InstancingVS(InstancingVSinput input, float4 instanceTransform : POSITION1, 
                                float2 atlasCoord : TEXCOORD1)
{
    InstancingVSoutput output;

    float4 pos = input.Position + instanceTransform;
    pos = mul(pos, WVP);

    output.Position = pos;
    output.TexCoord = float2((input.TexCoord.x / 2.0f) + (1.0f / 2.0f * atlasCoord.x),
                             (input.TexCoord.y / 2.0f) + (1.0f / 2.0f * atlasCoord.y));
    return output;
}

float4 InstancingPS(InstancingVSoutput input) : COLOR0
{
    return tex2D(TextureSampler, input.TexCoord);
}

technique Instancing
{
    pass Pass0
    {
        VertexShader = compile vs_3_0 InstancingVS();
        PixelShader = compile ps_3_0 InstancingPS();
    }
}

, которая должна быть названа InstancingShader.fx и помещена в вашу папку Content.1012 *

и в вашем методе Draw:

instancing.Draw(ref camera.View, ref camera.Projection, GraphicsDevice);
...