【问题标题】:Need help using instancing in XNA 4.0在 XNA 4.0 中使用实例化需要帮助
【发布时间】:2012-03-29 16:00:41
【问题描述】:

我是来询问关于在 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)是对我来说有点太高级了。我认为他使用的是模型、网格和诸如此类的东西而不是顶点,所以我无法弄清楚哪一段代码实际上与我所追求的相关。

这就是我来找你的原因。如果有人能给我一个简单的(如果可能的话)教程或代码 sn-ps 解释如何在 XNA 4.0 中使用用顶点绘制的立方体(或任何图形)进行实例化,我将非常感激。

【问题讨论】:

    标签: visual-studio-2010 optimization xna xna-4.0


    【解决方案1】:

    这是我能想到的最简单的代码 sn-p。它是我几个月前编写的代码的改编版,用于显示一些立方体,就像您需要的一样,没有模型也没有花哨的东西。

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

    我在这个着色器旁边使用了THIS 纹理:

    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 文件夹中。

    在您的 Game1 中使用它就像调用一样简单:

    instancing = new Instancing();
    instancing.Initialize(this.GraphicsDevice);
    instancing.Load(Content);
    

    在你的 Draw 方法中:

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

    【讨论】:

      猜你喜欢
      • 2011-10-26
      • 1970-01-01
      • 1970-01-01
      • 2022-12-16
      • 1970-01-01
      • 2011-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多