我在 XNA 中有一个纹理立方体,它是从在线教程中获取的。唯一的问题是,每次我渲染许多这些立方体时,它都会滞后。一位朋友告诉我,我可以将用于立方体的矢量数量减少到 8 个(每个角一个),并使用索引来创建立方体的三角形。所以我尝试这样做,但是,我承认我真的不知道如何做,特别是当它要求纹理的 Vector2 时。
我为图形设备启用了背面剔除。
我查看了 Riemer 的教程,但它们对我没有帮助。我是一个视觉学习者,阅读关于顶点和索引的长篇文章并不像观看带有解释的 YouTube 视频那样诱人。请有人告诉我该怎么做:
- 在渲染更多立方体时提高我的游戏性能。
- 渲染具有多个纹理的立方体。
- 将立方体“组合”成一个“块”,以减少每个立方体绘制的顶点数。
我的立方体根据我指定的 ID 从纹理贴图中抓取纹理,这很好用。我使用了一个名为“在 Windows Phone 7 上使用 XNA 中的顶点构造、绘制和纹理立方体”的教程;谷歌搜索显示了我用来创建多维数据集的大部分代码。
我已经浪费了一天中的大部分时间,茫然地盯着我的脑袋,并产生了头疼的想法。这个概念很简单,但实现起来很困难(至少对我来说)。
编辑:我已成功将矢量数量减少到 8 个,并绘制了立方体。但是,我无法为每个向量绘制纹理,因此会划伤这个想法。我对这种方法的替代方法是使用颜色而不是纹理,但这还不是我想要诉诸的东西。仅使用 8 个向量绘制每个立方体仍然会导致相同数量的延迟……所以现在,我已经回到使用 36 个向量来将纹理保持在应有的位置。我仍然想做上面列出的三件事。
编辑 2:根据要求,我的渲染代码如下所示。我使用以下方法将纹理传递给其构造函数中的每个立方体:
public Block(Vector3 position, int BlockID)
{
Position = position;
Texture = Assets.GetBlockTexture(@"Textures/terrain", BlockID);
Size = new Vector3(1, 1, 1);
}
Assets.GetBlockTexture 基本上根据传递给它的块 ID 从更大的 256x256 纹理贴图中返回特定的 16x16“块”纹理(是的,非常像 Minecraft 1.4 之前的版本)
在我的游戏中,Draw 方法如下:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
var s = new DepthStencilState {DepthBufferEnable = true};
spriteBatch.Begin(SpriteSortMode.Texture, BlendState.AlphaBlend, SamplerState.PointClamp, s, RasterizerState.CullCounterClockwise);
foreach (var block in blocks) block.Draw(GraphicsDevice, camera, effect);
spriteBatch.End();
base.Draw(gameTime);
}
它调用每个块的 Draw 方法:
public void Draw(GraphicsDevice device, Camera camera, BasicEffect effect)
{
effect = new BasicEffect(device)
{
TextureEnabled = true,
Texture = Texture,
View = camera.View,
Projection = camera.Projection,
World = Matrix.Identity
};
effect.EnableDefaultLighting();
foreach (var pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
Render(device);
}
}
然后调用块的 Render 方法:
public void Render(GraphicsDevice graphicsDevice)
{
if (!isConstructed) ConstructBlock();
using (var buffer = new VertexBuffer(graphicsDevice, VertexPositionNormalTexture.VertexDeclaration, NUMVERTICES, BufferUsage.WriteOnly))
{
buffer.SetData(vertices);
graphicsDevice.SetVertexBuffer(buffer);
}
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, NUMTRIANGLES);
}
ConstructBlock 方法使用正确的纹理坐标创建 36 个顶点:
private void ConstructBlock()
{
vertices = new VertexPositionNormalTexture[NUMVERTICES];
// Calculate the position of the vertices on the top face.
var topLeftFront = Position + new Vector3(-1.0f, 1.0f, -1.0f) * Size;
var topLeftBack = Position + new Vector3(-1.0f, 1.0f, 1.0f) * Size;
var topRightFront = Position + new Vector3(1.0f, 1.0f, -1.0f) * Size;
var topRightBack = Position + new Vector3(1.0f, 1.0f, 1.0f) * Size;
// Calculate the position of the vertices on the bottom face.
var btmLeftFront = Position + new Vector3(-1.0f, -1.0f, -1.0f) * Size;
var btmLeftBack = Position + new Vector3(-1.0f, -1.0f, 1.0f) * Size;
var btmRightFront = Position + new Vector3(1.0f, -1.0f, -1.0f) * Size;
var btmRightBack = Position + new Vector3(1.0f, -1.0f, 1.0f) * Size;
// Normal vectors for each face (needed for lighting / display)
var normalFront = new Vector3(0.0f, 0.0f, 1.0f) * Size;
var normalBack = new Vector3(0.0f, 0.0f, -1.0f) * Size;
var normalTop = new Vector3(0.0f, 1.0f, 0.0f) * Size;
var normalBottom = new Vector3(0.0f, -1.0f, 0.0f) * Size;
var normalLeft = new Vector3(-1.0f, 0.0f, 0.0f) * Size;
var normalRight = new Vector3(1.0f, 0.0f, 0.0f) * Size;
//UV texture coordinates
var textureTopLeft = new Vector2(1.0f * Size.X, 0.0f * Size.Y);
var textureTopRight = new Vector2(0.0f * Size.X, 0.0f * Size.Y);
var textureBottomLeft = new Vector2(1.0f * Size.X, 1.0f * Size.Y);
var textureBottomRight = new Vector2(0.0f * Size.X, 1.0f * Size.Y);
//FRONT face.
vertices[0] = new VertexPositionNormalTexture(topLeftFront, normalFront, textureTopLeft);
vertices[1] = new VertexPositionNormalTexture(btmLeftFront, normalFront, textureBottomLeft);
vertices[2] = new VertexPositionNormalTexture(topRightFront, normalFront, textureTopRight);
vertices[3] = new VertexPositionNormalTexture(btmLeftFront, normalFront, textureBottomLeft);
vertices[4] = new VertexPositionNormalTexture(btmRightFront, normalFront, textureBottomRight);
vertices[5] = new VertexPositionNormalTexture(topRightFront, normalFront, textureTopRight);
//BACK face.
vertices[6] = new VertexPositionNormalTexture(topLeftBack, normalBack, textureTopRight);
vertices[7] = new VertexPositionNormalTexture(topRightBack, normalBack, textureTopLeft);
vertices[8] = new VertexPositionNormalTexture(btmLeftBack, normalBack, textureBottomRight);
vertices[9] = new VertexPositionNormalTexture(btmLeftBack, normalBack, textureBottomRight);
vertices[10] = new VertexPositionNormalTexture(topRightBack, normalBack, textureTopLeft);
vertices[11] = new VertexPositionNormalTexture(btmRightBack, normalBack, textureBottomLeft);
//TOP face.
vertices[12] = new VertexPositionNormalTexture(topLeftFront, normalTop, textureBottomLeft);
vertices[13] = new VertexPositionNormalTexture(topRightBack, normalTop, textureTopRight);
vertices[14] = new VertexPositionNormalTexture(topLeftBack, normalTop, textureTopLeft);
vertices[15] = new VertexPositionNormalTexture(topLeftFront, normalTop, textureBottomLeft);
vertices[16] = new VertexPositionNormalTexture(topRightFront, normalTop, textureBottomRight);
vertices[17] = new VertexPositionNormalTexture(topRightBack, normalTop, textureTopRight);
//BOTTOM face.
vertices[18] = new VertexPositionNormalTexture(btmLeftFront, normalBottom, textureTopLeft);
vertices[19] = new VertexPositionNormalTexture(btmLeftBack, normalBottom, textureBottomLeft);
vertices[20] = new VertexPositionNormalTexture(btmRightBack, normalBottom, textureBottomRight);
vertices[21] = new VertexPositionNormalTexture(btmLeftFront, normalBottom, textureTopLeft);
vertices[22] = new VertexPositionNormalTexture(btmRightBack, normalBottom, textureBottomRight);
vertices[23] = new VertexPositionNormalTexture(btmRightFront, normalBottom, textureTopRight);
//LEFT face.
vertices[24] = new VertexPositionNormalTexture(topLeftFront, normalLeft, textureTopRight);
vertices[25] = new VertexPositionNormalTexture(btmLeftBack, normalLeft, textureBottomLeft);
vertices[26] = new VertexPositionNormalTexture(btmLeftFront, normalLeft, textureBottomRight);
vertices[27] = new VertexPositionNormalTexture(topLeftBack, normalLeft, textureTopLeft);
vertices[28] = new VertexPositionNormalTexture(btmLeftBack, normalLeft, textureBottomLeft);
vertices[29] = new VertexPositionNormalTexture(topLeftFront, normalLeft, textureTopRight);
//RIGHT face.
vertices[30] = new VertexPositionNormalTexture(topRightFront, normalRight, textureTopLeft);
vertices[31] = new VertexPositionNormalTexture(btmRightFront, normalRight, textureBottomLeft);
vertices[32] = new VertexPositionNormalTexture(btmRightBack, normalRight, textureBottomRight);
vertices[33] = new VertexPositionNormalTexture(topRightBack, normalRight, textureTopRight);
vertices[34] = new VertexPositionNormalTexture(topRightFront, normalRight, textureTopLeft);
vertices[35] = new VertexPositionNormalTexture(btmRightBack, normalRight, textureBottomRight);
isConstructed = true;
}
屏幕上只有 288 个三角形在 10 个块中渲染,但它的绘制速度却高达 1-3FPS。我知道问题不是我的显卡造成的,因为它可以毫无问题地玩许多 3D 游戏。
根据 Nico 的要求更新了代码:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
var s = new DepthStencilState {DepthBufferEnable = true};
spriteBatch.Begin(SpriteSortMode.Texture, BlendState.AlphaBlend, SamplerState.PointClamp, s, RasterizerState.CullCounterClockwise);
foreach (var block in blocks) block.Draw(camera, effect);
spriteBatch.DrawString(Content.Load<SpriteFont>("SpriteFont1"), "Number of triangles: " + triangles, new Vector2(10, 10), Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
块.cs:
private VertexPositionNormalTexture[] vertices;
private VertexBuffer buffer;
private GraphicsDevice device;
public Block(GraphicsDevice device, Vector3 position, int BlockID)
{
this.device = device;
Position = position;
Texture = Assets.GetBlockTexture(@"Textures/terrain", BlockID);
Size = new Vector3(1, 1, 1);
buffer = new VertexBuffer(device, VertexPositionNormalTexture.VertexDeclaration, NUMVERTICES, BufferUsage.WriteOnly);
}
public void Render()
{
if (!isConstructed) ConstructBlock();
buffer.SetData(vertices);
device.SetVertexBuffer(buffer);
device.DrawPrimitives(PrimitiveType.TriangleList, 0, NUMTRIANGLES);
}
public void Draw(Camera camera, BasicEffect effect)
{
effect = new BasicEffect(device)
{
TextureEnabled = true,
Texture = Texture,
View = camera.View,
Projection = camera.Projection,
World = Matrix.Identity,
PreferPerPixelLighting = false
};
effect.EnableDefaultLighting();
foreach (var pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
Render();
}
}
其余代码几乎相同。