Загрузка и сортировка кусков

0

Я работаю над клоном minecraft, и у меня есть 2 проблемы с загрузкой куска.

Сначала: Определите куски для загрузки.

я нашел один путь, он уродлив, но работает быстро для меня

  1. Определить 3d массив (массив) (размер: MAX_CHUNKS_X, MAX_CHUNKS_Y, MAX_CHUNKS_Z)
  2. Заполнить 3d-массив с FALSE
  3. Переходя от списка кусков, проверяя, есть ли внутри диапазона видения
  4. если внутри массива set [chunk_x] [chunk_y] [chunk_z] = true;
  5. После передачи списка начинается басинг массив
  6. Для всего массива [chunk_x] [chunk_y] [chunk_z] == false добавить в блок LoadingList в chunk_x chunk_y chunk_z

Другие способы менее уродливые и все еще быстрые?

Код:

     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() Синий = самый большой для ChunksLoadList. начать()

im попытаться использовать

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

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

Но это способ замедлить большие диапазоны видимости... Как я должен переписать код для быстрого эффекта волновой нагрузки?

Извините, ужасный английский, надеюсь, вы меня понимаете...

  • 0
    Насколько важно точное расстояние до камеры? а точный порядок? и все ли значения плавают?
  • 0
    Surt, расстояние до камеры нужно только для сортировки кусков от ближайшего к дальнему. Функция, которая вычисляет расстояние, не использует только sqrt () (x ^ 2 + y ^ 2 + z ^ 2)
Показать ещё 1 комментарий
Теги:
algorithm
voxel

1 ответ

0

Давайте сначала рассмотрим проблему сортировки по расстоянию, если ваш ChunksLoadList является std :: list, а не std :: vector или std :: array (С++ 11), вы уже потеряли гонку производительности! Bjarne Stroustrup: Почему вам следует избегать Linked Lists. Обратите внимание на график !!!

Если его все еще слишком медленно после того, как вы изменили его на 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 (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 = ~ 80000000 вокселов, вы действительно этого хотели? если вам нужна какая-то информация, у вас должен быть указатель или указатель, как минимум 4 байта, это удаляет кеш на большинстве систем.

Поскольку наводнение заполняет его неэффективным, а как приближение к расстоянию, оно есть.
Вы можете остановиться здесь, если ваши требования выполнены.
Если вам нужно полное упорядоченное задание, запустите сортировку в сортировке по почти отсортированному списку O (N), но тогда вам также нужно рассчитать расстояние между камерами.

Возможная дальнейшая оптимизация:

  • непрозрачные вокселы не добавляют соседей, которые также непрозрачны.
  • воздух (полностью прозрачный) не добавляется к списку камер, но должен быть там для заполнения, в случае наличия летающего острова.
  • 0
    Ну ... Расчетное расстояние просмотра 528 (16) или 1040 (32) Основная проблема - как определить следующие фрагменты (или один блок, но ближайший к камере), которые должны быть загружены. И эти «следующие куски» нужно отсортировать от камеры к дальним результатам испытаний для мира 9x9x9: 4 Вид сортировки - показанный вами алгоритм заполнения при наводнении 19 мс - 118ms std :: sort (vector) - 0,7 мс для мира 33x33x33 просмотр: 16 В диссертации sort -> 51771ms (не знаю почему) Алгоритм заполнения потока, который вы показываете: я делаю что-то неправильно и ... bad_alloc =) но после теста (9x9x9) ... я думаю, что нужно даже больше, чем 51771ms .. std :: sort (вектор) - 51мс
  • 0
    Сортировка вставок хороша только в том случае, если данные почти отсортированы, а сортировка вставок, показанная в одной из ссылок, также не так легко понять, т.е. если вы реализовали это оттуда, вам лучше найти другую реализацию :(
Показать ещё 7 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню