块加载和排序

Chunks loading and sort

本文关键字:排序 加载      更新时间:2023-10-16

我正在克隆minecraft,我有两个块加载问题。

第一:确定要加载的块。

我发现了一种方法,它很难看,但对我来说效果很快

  1. 定义三维数组(数组)(大小:MAX_CHUNKS_X、MAX_CHUKS_Y、MAX_CHUNKS_Z)
  2. 用FALSE填充三维数组
  3. 从块列表中传递时,检查块是否在视觉范围内
  4. 如果内部集合数组[chunk_x][chunk_y][chunk_6z]=true
  5. 通过列表后开始低音阵列
  6. 对于所有数组[chunk_x][chunk_y][chunk_6z]==false在chunk_xchunk_y chunk_z处添加到LoadingList块

另一种方法可以减少丑陋并保持快速?

代码:

     ChunksRenderList.clear();
    CChunk* Chunk = NULL;
    s32 RootChunk_X_Location = (floor(RenderCenter.x) / CHUNK_SIZE);
    s32 RootChunk_Y_Location = (floor(RenderCenter.y) / CHUNK_SIZE);
    s32 RootChunk_Z_Location = (floor(RenderCenter.z) / CHUNK_SIZE);
    if(RenderCenter.x < 0)
        RootChunk_X_Location--;
    if(RenderCenter.y < 0)
        RootChunk_Y_Location--;
    if(RenderCenter.z < 0)
        RootChunk_Z_Location--;
    core::vector3s RootChunkLocation(RootChunk_X_Location,RootChunk_Y_Location,RootChunk_Z_Location);
    u32 XZ_ArraySide = (RenderDistance_XZ*2)+1;
    u32 Y_ArraySide  = (RenderDistance_Y*2)+1;
    char array[XZ_ArraySide][Y_ArraySide][XZ_ArraySide];
    memset(array,0,(XZ_ArraySide*XZ_ArraySide*Y_ArraySide));
    for(auto it = Chunks.begin(); it != Chunks.end(); it++)
    {
        Chunk = (it->second);
        if(Chunk->Locked)
            continue;
        if(Chunk->KeepAliveCounter <= 0)
        {
            ChunksUnloadList.push_back(Chunk);
            continue;
        }
        else
        {
            Chunk->KeepAliveCounter -= WORLD_UPDATE_PERIOD;
            Chunk->DistanceToCamera = RenderCenter.distance_to(Chunk->ChunkAbsolutePosition);
        }
        if(Chunk->ChunkPosition.x >= (RootChunk_X_Location - (s32)RenderDistance_XZ) && Chunk->ChunkPosition.x <= (RootChunk_X_Location + (s32)RenderDistance_XZ))
            if(Chunk->ChunkPosition.y >= (RootChunk_Y_Location - (s32)RenderDistance_Y) && Chunk->ChunkPosition.y <= (RootChunk_Y_Location + (s32)RenderDistance_Y))
                if(Chunk->ChunkPosition.z >= (RootChunk_Z_Location - (s32)RenderDistance_XZ) && Chunk->ChunkPosition.z <= (RootChunk_Z_Location + (s32)RenderDistance_XZ))
                {
                    s32 PositionInMatrix_X = Chunk->ChunkPosition.x - (RootChunk_X_Location - (s32)RenderDistance_XZ);
                    s32 PositionInMatrix_Y = Chunk->ChunkPosition.y - (RootChunk_Y_Location - (s32)RenderDistance_Y);
                    s32 PositionInMatrix_Z = Chunk->ChunkPosition.z - (RootChunk_Z_Location - (s32)RenderDistance_XZ);
                    array[PositionInMatrix_X][PositionInMatrix_Y][PositionInMatrix_Z] = true;
                    Chunk->KeepAliveCounter = CHUNK_LIVE_TIME;
                }

        if(not Chunk->NeightboarsUpdated)
        {
            ChunksNeightboarUpdateList.push_back(Chunk);
        }
        if(not Chunk->ChunkUpdated)
        {
            ChunksRebuildList.push_back(Chunk);
        }
        if(not Chunk->Locked and Chunk->VisibleBlocks > 0)
        {
            ChunksRenderList.push_back(Chunk);
        }
    }
    for(u32 y = 0; y < Y_ArraySide; y++)
        for(u32 x = 0; x < XZ_ArraySide; x++)
            for(u32 z = 0; z < XZ_ArraySide; z++)
            {
                s32 ChunkPosition_X = (s32)x + (RootChunk_X_Location - (s32)RenderDistance_XZ);
                s32 ChunkPosition_Y = (s32)y + (RootChunk_Y_Location - (s32)RenderDistance_Y);
                s32 ChunkPosition_Z = (s32)z + (RootChunk_Z_Location - (s32)RenderDistance_XZ);
                if(array[x][y][z] == 0)
                {
   SPendingToLoad ToLoad;
                    ToLoad.Position.set(ChunkPosition_X,ChunkPosition_Y,ChunkPosition_Z);
                    ToLoad.DistanceToCamera = ToLoad.Position.distance_to_sqr(RootChunkLocation);
                    ChunksLoadList.push_back(ToLoad);
                }
            }

第二:如何对ChunksLoadList进行排序以使其像这张图片上的左边一样生效https://www.dropbox.com/s/owjfaaekcj2m23w/58f2e4c8.png?dl=0红色=最接近ChunksLoadList.begin()Blue=告别ChunksLoadList.begin()

我尝试使用

    ChunksLoadList.sort([&RootChunkLocation](SPendingToLoad& i,SPendingToLoad& j)
    {
        return i.DistanceToCamera < j.DistanceToCamera;
    }
    );

但它的方法是在大的视野范围内放慢速度。。。我必须如何重写代码才能获得快速加载效果?

对不起,我的英语很糟糕,我希望你能理解我…

让我们先来看看距离排序问题,如果您的ChunksLoadList是std::list,而不是std::vector或std::array(C++11),那么您已经输掉了性能竞赛!Bjarne Stroustrup:为什么你应该避免链表密切关注图表!!!

如果在你把它改成std::vector后它仍然太慢,你可以试试"我刚刚发明的这个方法(TM)"!

最好的排序算法类似

O(C+K*N log log N)最快?

具有可怕的C常数准备时间,每个元素可怕的K和非常好的N log log N

对于N->无穷大,这将是O(N log log N)

但是对于这个问题,有一个更好的算法
整体填充,然后是插入排序,整体填充在O(N)中生成一个几乎排序的列表,插入排序从O(N。。。

O(C+K*N)

有一个可怕的恒定准备时间,每个元素都很糟糕,但只有N倍

维基百科的变体

 Flood-fill (node, target-color, replacement-color): 
 If target-color is equal to replacement-color, return.
 Set Q to the empty queue. [must be std::vector or std::array or this will fail]
 Add camera node to the end of Q.
 While Q is not empty: 
     Set n equal to the *first* element of Q.
     Remove *first* element from Q.
     If the color of n is equal to target-color:
         Add n to the distance list as the next closed (this will be nearly correct)
         Set the color of n to replacement-color and mark "n" as processed.
         Add adjacent nodes to end of Q if they has not been processed yet. (x/y/z +1/-1)
 Return.

队列元素为x、y、z
使用std::出列

距离列表也必须是随机访问包含,从大小(viewdistance*2+1)^3开始完全分配,这可能很大
如果视图距离100是201^3=~8000000个体素,你真的想要这个吗?如果你需要一些信息,你必须有一些指针或索引,至少4个字节,这会破坏大多数系统的缓存。

作为洪水填充,它是无效的,但作为距离的近似值。
如果你的要求得到满足,你可以到此为止
如果您需要总排序,然后在几乎排序的列表O(N)上运行插入排序,但您还需要计算相机距离。

潜在的进一步优化:

  • 不透明体素不会添加同样不透明的邻居
  • 空气(完全透明)不会添加到相机列表中,但需要在那里填充,以防出现飞行岛