c# - 无论如何要加快这个功能?

标签 c# xna

我在 XNA 中有一个体素(我的世界风格)引擎,世界被分成 block ,当一个立方体被修改时,我通过扫描所有立方体并检查面是否可见来重新创建顶点缓冲区。这通常以很好的速度运行,但是当立方体以某种方式排列时(这样顶点缓冲区会大很多)它可以接管一个帧来生成新的 block 。在最糟糕的配置(显示最多的顶点)中,它最多可能需要 100 毫秒。代码的以下部分代表 100 次中的大约 80-90 毫秒,当 block 更新时它运行了 131,072 次,在最坏的可能配置中它创建了 32,768 个立方体,而在所有其他运行中它创建了 0 个顶点。

我也在使用 i5 2500k,所以这在旧系统上可能真的很糟糕。

无论如何我都想不出提高速度的方法,而且我对编程还很陌生,所以我想我会把它贴在这里寻求一些建议?谢谢。

public void GenerateCubeGeometryAtPosition(int x, int y, int z, byte id)
{
    //We check if there's a cube in the six directions around the cube
    //if there's no cube ot the cube is transparent we add the vertices to the vertex list
    //if the cube is on the outside of the chunk we check the cube in the chunk next to it assuming it's loaded

    //if we have to build part of the cube we make a new vertex
    //first 3 bytes in the vertex are the position relative to the chunk
    //4th byte is for normals, we check it in the shader to figure out the normal
    //the next 2 bytes in the properties are for the texture positons on the texture atlas
    //last 2 bytes are for other properties of the vertex like light/shade etc

    //Check up and down
    if (y > YSize - 2)
    {
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, z, 0f), GlobalWorld.Blocks[id].VertexPropertiesTop[0]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y + 1, z, 0f), GlobalWorld.Blocks[id].VertexPropertiesTop[1]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, 1 + z, 0f), GlobalWorld.Blocks[id].VertexPropertiesTop[2]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y + 1, 1 + z, 0f), GlobalWorld.Blocks[id].VertexPropertiesTop[3]));
    }
    else if (Blocks[x, y + 1, z] == 0 || GlobalWorld.Blocks[Blocks[x, y + 1, z]].Transparent)
    {
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, z, 0f), GlobalWorld.Blocks[id].VertexPropertiesTop[0]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y + 1, z, 0f), GlobalWorld.Blocks[id].VertexPropertiesTop[1]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, 1 + z, 0f), GlobalWorld.Blocks[id].VertexPropertiesTop[2]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y + 1, 1 + z, 0f), GlobalWorld.Blocks[id].VertexPropertiesTop[3]));

    }
    if (y != 0 && (Blocks[x, y - 1, z] == 0 || GlobalWorld.Blocks[Blocks[x, y - 1, z]].Transparent))
    {
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, z, 1f), GlobalWorld.Blocks[id].VertexPropertiesBottom[0]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, 1 + z, 1f), GlobalWorld.Blocks[id].VertexPropertiesBottom[1]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, z, 1f), GlobalWorld.Blocks[id].VertexPropertiesBottom[2]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, 1 + z, 1f), GlobalWorld.Blocks[id].VertexPropertiesBottom[3]));
    }

    //check Right and Left of the cube and the adjacent chunk at the edges
    if (x == 0)
    {
        if (this.RightChunk != -1 && (GlobalWorld.LoadedChunks[this.RightChunk].Blocks[XSize - 1, y, z] == 0 || GlobalWorld.Blocks[GlobalWorld.LoadedChunks[this.RightChunk].Blocks[XSize - 1, y, z]].Transparent))
        {
            ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, z, 3f), GlobalWorld.Blocks[id].VertexPropertiesRight[0]));
            ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, z, 3f), GlobalWorld.Blocks[id].VertexPropertiesRight[1]));
            ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, 1 + z, 3f), GlobalWorld.Blocks[id].VertexPropertiesRight[2]));
            ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, 1 + z, 3f), GlobalWorld.Blocks[id].VertexPropertiesRight[3]));
        }
    }
    else if (Blocks[x - 1, y, z] == 0 || GlobalWorld.Blocks[Blocks[x - 1, y, z]].Transparent)
    {
        //right
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, z, 3f), GlobalWorld.Blocks[id].VertexPropertiesRight[0]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, z, 3f), GlobalWorld.Blocks[id].VertexPropertiesRight[1]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, 1 + z, 3f), GlobalWorld.Blocks[id].VertexPropertiesRight[2]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, 1 + z, 3f), GlobalWorld.Blocks[id].VertexPropertiesRight[3]));
    }
    if (x > XSize - 2)
    {
        if (this.LeftChunk != -1 && (GlobalWorld.LoadedChunks[this.LeftChunk].Blocks[0, y, z] == 0 || GlobalWorld.Blocks[GlobalWorld.LoadedChunks[this.LeftChunk].Blocks[0, y, z]].Transparent))
        {
            ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, z, 2f), GlobalWorld.Blocks[id].VertexPropertiesLeft[0]));
            ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, 1 + z, 2f), GlobalWorld.Blocks[id].VertexPropertiesLeft[1]));
            ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, 1 + y, z, 2f), GlobalWorld.Blocks[id].VertexPropertiesLeft[2]));
            ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, 1 + y, 1 + z, 2f), GlobalWorld.Blocks[id].VertexPropertiesLeft[3]));
        }
    }
    else if (Blocks[x + 1, y, z] == 0 || GlobalWorld.Blocks[Blocks[x + 1, y, z]].Transparent)
    {
        //left
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, z, 2f), GlobalWorld.Blocks[id].VertexPropertiesLeft[0]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, 1 + z, 2f), GlobalWorld.Blocks[id].VertexPropertiesLeft[1]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, 1 + y, z, 2f), GlobalWorld.Blocks[id].VertexPropertiesLeft[2]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, 1 + y, 1 + z, 2f), GlobalWorld.Blocks[id].VertexPropertiesLeft[3]));
    }

    //check Back and Front of the cube and the adjacent chunk at the edges
    if (z == 0)
    {
        if (this.BackChunk != -1 && (GlobalWorld.LoadedChunks[this.BackChunk].Blocks[x, y, ZSize - 1] == 0 || GlobalWorld.Blocks[GlobalWorld.LoadedChunks[this.BackChunk].Blocks[x, y, ZSize - 1]].Transparent))
        {
            ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, z, 5f), GlobalWorld.Blocks[id].VertexPropertiesBack[0]));
            ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, z, 5f), GlobalWorld.Blocks[id].VertexPropertiesBack[1]));
            ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, z, 5f), GlobalWorld.Blocks[id].VertexPropertiesBack[2]));
            ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y + 1, z, 5f), GlobalWorld.Blocks[id].VertexPropertiesBack[3]));
        }
    }
    else if (Blocks[x, y, z - 1] == 0 || GlobalWorld.Blocks[Blocks[x, y, z - 1]].Transparent)
    {
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, z, 5f), GlobalWorld.Blocks[id].VertexPropertiesBack[0]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, z, 5f), GlobalWorld.Blocks[id].VertexPropertiesBack[1]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, z, 5f), GlobalWorld.Blocks[id].VertexPropertiesBack[2]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y + 1, z, 5f), GlobalWorld.Blocks[id].VertexPropertiesBack[3]));
    }
    if (z > ZSize - 2)
    {
        if (this.ForwardChunk != -1 && (GlobalWorld.LoadedChunks[this.ForwardChunk].Blocks[x, y, 0] == 0 || GlobalWorld.Blocks[GlobalWorld.LoadedChunks[this.ForwardChunk].Blocks[x, y, 0]].Transparent))
        {
            ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, 1 + z, 4f), GlobalWorld.Blocks[id].VertexPropertiesFront[0]));
            ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, 1 + z, 4f), GlobalWorld.Blocks[id].VertexPropertiesFront[1]));
            ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, 1 + z, 4f), GlobalWorld.Blocks[id].VertexPropertiesFront[2]));
            ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y + 1, 1 + z, 4f), GlobalWorld.Blocks[id].VertexPropertiesFront[3]));
        }
    }
    else if (Blocks[x, y, z + 1] == 0 || GlobalWorld.Blocks[Blocks[x, y, z + 1]].Transparent)
    {
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, 1 + z, 4f), GlobalWorld.Blocks[id].VertexPropertiesFront[0]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, 1 + z, 4f), GlobalWorld.Blocks[id].VertexPropertiesFront[1]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, 1 + z, 4f), GlobalWorld.Blocks[id].VertexPropertiesFront[2]));
        ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y + 1, 1 + z, 4f), GlobalWorld.Blocks[id].VertexPropertiesFront[3]));
    }
}

最佳答案

我没有看到这段代码运行缓慢的任何明显原因。如果小的代码更改似乎无法为您提供必要的加速,我会尝试不同的实现。

如果我没理解错的话,当一个 block 发生变化时,您会为整个 64x64x32(= 131072) block block 重建顶点缓冲区。假设 block 中的 block 一次只更改几个,拥有一个包含所有立方体在预定位置的所有边的持久顶点缓冲区可能会快得多。当一个立方体面的状态发生变化时,您只需更改顶点缓冲区中的四个值,而不是从头开始创建整个顶点缓冲区。

例如,您可以在从 GetCubeFaceStartIndex(5, 6, 7, CubeFaceType.Top) 开始的四个连续顶点缓冲区索引处让立方体顶面的四个顶点位于 (5, 6, 7)

enum CubeFaceType { Top, Bottom, Left, Right, Front, Back }

int GetCubeFaceStartIndex(int x, int y, int z, CubeFaceType face)
{
    return 4 * ((int)cubeFace + 6 * (x + CHUNK_WIDTH * (y + CHUNK_HEIGHT * z));
}

要删除一个面(当删除 block 时),您可以将四个顶点设置为相同的值,例如新的 VertexPositionNormalSmall(Vector4.Zero,DummyProperties)。请注意,顶点共享相同位置的三角形在屏幕上是不可见的。

如果您需要添加一个面或更改它的属性,您可以像以前一样做,只是直接在由立方体和面的位置确定的索引处进行。

这个实现当然需要更大的顶点缓冲区。如果您的 block 大小为 64x64x32 立方体,则顶点缓冲区需要 64*64*64*6*4 = 3145728 个顶点长,这可能不切实际。可能需要减小块的大小。

关于c# - 无论如何要加快这个功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10538931/

相关文章:

c# - Farseer 3.3 检查未启用的物体是否会在启用时发生碰撞(生成)

c# - 存在哪些基于 XNA 的 3D 地形和物理库?

c# - 阻止音频文件重复 XNA

c# - 单元测试中的序列化异常

c# - ASP.net 获取数据库日期列的最大日期 如何避免日期列中的空值 C# 我的代码附后

c# - 在 ASP.Net Core MVC 中读取 JSON post 数据

c# - XNA 弹出文本对话框

.net - 使用 .NET 的跨平台图形 3D

c# - 以MVC形式动态添加元素

c# - 如何从 MailItem 获取特定于任务的属性