0

我在 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();
    }
}

其余代码几乎相同。

4

1 回答 1

1

我终于设法通过如此简单的解决方案克服了这个问题。

我在主游戏类中创建了一个 BasicEffect,它将传递给我的积木类。起初这不起作用,因为我不确定 BasicEffect 将如何工作,因此我不知道您可以在传递视图、投影和纹理时以不同的方式声明它。

所以,首先,我初始化了效果的基本修饰符:

effect = new BasicEffect(GraphicsDevice)
{
    TextureEnabled = true,
    World = Matrix.Identity,
    PreferPerPixelLighting = false
};

effect.EnableDefaultLighting();

在我的块的绘制方法中,在将效果传递给它之后,我做了以下事情:

effect.Texture = Texture;
effect.View = camera.View;
effect.Projection = camera.Projection;

所以不会每帧都创建一个新效果

于 2013-10-21T20:54:58.097 回答