我正在研究“我的世界”的克隆,我有2个大块加载问题。
首先:确定要加载的块。
我找到了一种丑陋的方式但对我来说很快
另一种不那么丑陋但仍然很快的方法?
代码:
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 Red =离ChunksLoadList.begin()最近 Blue =最接近ChunksLoadList.begin()
我尝试使用
ChunksLoadList.sort([&RootChunkLocation](SPendingToLoad& i,SPendingToLoad& j)
{
return i.DistanceToCamera < j.DistanceToCamera;
}
);
但它可以减缓大视野范围...... 如何重写代码以获得快速波浪加载效果?
对不起我糟糕的英语,我希望你理解我......
答案 0 :(得分:0)
让我们首先看一下距离排序问题,如果你的ChunksLoadList
是std :: list而不是std :: vector或std :: array(C ++ 11)你已经失去了性能竞争! Bjarne Stroustrup: Why you should avoid Linked Lists密切关注图表!
如果你把它改成std :: vector后仍然太慢,你可以试试#34;我刚刚发明的这种方法(TM)&#34;!
最好的排序算法类似于
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次
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 = ~8000000体素,你真的想要这个吗?如果你需要一些信息,你必须有一些指针或索引,至少4个字节,这会在大多数系统上吹掉缓存。
作为洪水填充它不起作用,但作为距离的近似值 如果满足您的要求,您可以在这里停止 IF 你需要总排序然后在nearly sorted list O(N)上运行插入排序,但是你也需要计算相机距离。
潜在的进一步优化: