我来询问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中用顶点绘制的立方体(或任何图形)进行实例化,我将非常感激。
答案 0 :(得分:9)
这是我能提出的最简单的代码片段。它改编了几个月前制作的代码,用于展示一些立方体,就像你需要的那样,没有模特也没有什么花哨的。
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);