【问题标题】:Chunks loading and sort块加载和排序
【发布时间】:2014-09-13 12:51:40
【问题描述】:

我正在研究我的世界的克隆,我有 2 个块加载问题。

首先:确定要加载的块。

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

  1. 定义3d数组(数组)(大小:MAX_CHUNKS_X,MAX_CHUNKS_Y,MAX_CHUNKS_Z)
  2. 用 FALSE 填充 3d 数组
  3. 从区块列表传递时检查区块是否在视野范围内
  4. 如果在集合数组[chunk_x][chunk_y][chunk_z] = true;
  5. 通过列表后开始低音阵列
  6. 对于所有数组 [chunk_x][chunk_y][chunk_z] == false 在 chunk_x chunk_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() 蓝色 = 最接近 ChunksLoadList.begin()

我尝试使用

    ChunksLoadList.sort([&RootChunkLocation](SPendingToLoad& i,SPendingToLoad& j)
    {

        return i.DistanceToCamera < j.DistanceToCamera;
    }
    );

但是对于大视野范围,它会减慢速度... 我必须如何重写代码才能获得快速的波浪加载效果?

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

【问题讨论】:

  • 到相机的准确距离有多重要?和确切的顺序?所有的值都是浮动的吗?
  • Surt,到相机的距离只需要从最近到远的排序块。计算距离的函数只使用 sqrt() (x^2+y^2+z^2)
  • S32 是 int32_t 并且类型转换为 S32 的变量是浮点数?

标签: c++ algorithm voxel


【解决方案1】:

让我们先看看距离排序问题,如果你的 ChunksLoadList 是一个 std::list 而不是一个 std::vector 或 std::array(C++11) 你已经输掉了性能竞赛! Bjarne Stroustrup: Why you should avoid Linked Lists关注图!!!

如果您将其更改为 std::vector 后仍然太慢,您可以尝试“我刚刚发明的这种方法(TM)”!

最好的排序算法是这样的

O(C+K*N log log N) fastest?

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

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

但是对于这个问题有一个更好的算法!
洪水填充后跟插入排序,洪水填充在 O(N) 中产生一个几乎排序的列表,并且插入排序从 O(N) 中的部分有序列表中保护完全有序列表,总共 O(N) ...

O(C+K*N)

准备时间很长,每个元素很糟糕,但只有 N 次

variant of wikipedia

 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::dequeue

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

作为洪水填充,它无效,但作为距离的近似值。
如果您的要求得到满足,您可以停在这里。
如果您需要总排序,然后在 nearly sorted list O(N) 上运行插入排序,但随后您需要计算相机距离也。

可能的进一步优化:

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

【讨论】:

  • 嗯...估计的视距 528(16) 或 1040(32) 主要问题是 - 如何确定必须加载的下一个块(或单个块但离相机最近)。并且这个“下一个块”需要从相机到世界 9x9x9 视图的远测试结果进行排序:4 插入排序 - 您显示的 19 毫秒洪水填充算法 - 118 毫秒 std::sort(vector) - 世界 33x33x33 视图为 0.7 毫秒:16 插入排序-> 51771ms(不知道为什么)您显示的洪水填充算法:我弄错了,并且... bad_alloc =)但是在(9x9x9)上进行测试后...我认为甚至需要超过51771ms .. std::sort (向量) - 51ms
  • 插入排序只有在数据接近排序并且其中一个链接中显示的插入排序也不容易理解时才有效,即。如果你从那里实现它,你最好找到另一个实现:(
  • 将队列更改为 std::dequeue 在这两种情况下都有帮助吗?
  • 加载列表中的数据可以反转或接近排序
  • 我会对洪水填充代码的样子非常感兴趣,因为我想知道我是否在某个地方不够精确,或者这只是一个坏主意:)
猜你喜欢
  • 1970-01-01
  • 2012-01-17
  • 2018-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-23
  • 2016-10-14
  • 1970-01-01
相关资源
最近更新 更多