Побудова Окрем для генерації місцевості


9

Раніше я реалізовував маршируючі кубики / тетраедри для візуалізації IsoSurface. Це спрацювало ( YouTube ), але продуктивність була жахливою, оскільки я ніколи не замислювався над тим, щоб реалізувати змінний рівень деталізації на основі відстані перегляду (або навіть видалення старих віддалених фрагментів).

Я вирішив ще раз поїхати і зробити це належним чином цього разу. Я почав зі створення OctreeNode, який працює так, коли Build()викликається.

  • Якщо шматок занадто малий для будівництва, повертайтеся негайно.
  • Опрацюйте, якщо поверхня проходить через об'єм цього шматка.
  • Якщо так, то вирішуємо, чи хочемо ми підняти LOD (оскільки камера закрита)
  • Якщо так, то нерестуйте 8 дітей і викликайте той самий процес на них
  • Якщо ні, побудуйте сітку за допомогою розмірів поточного вузла

Деякі псевдокоди:

OctNode Build() {
    if(this.ChunkSize < minChunkSize) {
        return null;
    }
    densityRange = densitySource¹.GetDensityRange(this.bounds);
    if(densityRange.min < surface < densityRange.max) {
        if(loDProvider.DesiredLod(bounds > currentLoD) {
            for(i 1 to 8) {
                if(children[i] == null) {
                    children[i] = new OctNode(...)
                }
                children[i] = children[i].Build();
            }
        } else {
            BuildMesh();
        }
        return this;
    }
}

¹ Окрім повернення щільності в точці, джерело щільності може визначити можливий діапазон щільності для заданого об'єму.

² Постачальник LoD приймає обмежувальне поле і повертає максимум бажаного LoD залежно від положення камери / фрустуму, налаштувань користувача тощо ...

Отже ... Це все працює досить добре. Використання простої сфери як джерела щільності та показ усіх вузлів:

Повний указ

І просто листя:

Octree показує лише листя

Однак є кілька питань:

  • Я повинен визначити початковий обмежувальний об'єм (і чим він більший, тим більше мені потрібно обробити)
  • У корені дерева я не знаю, наскільки глибокими будуть листя, тому моя нумерація LoD починається з найнижчої якості (корінь) і збільшується, коли шматки стають меншими. Оскільки LoD зараз відносно початкового обсягу, він не дуже корисний, коли я хочу робити речі за певними розмірами / якостями.

Я продумав кілька варіантів, але обидва здаються недоліками:

  • Підтримуйте колекцію Octrees та додайте / видаляйте залежно від відстані. Не можу зрозуміти, як я добре перетинаюсь¹, плюс мені знадобиться список відомих порожніх вузлів, особливо якщо я хочу довільні тривимірні поверхні (щоб уникнути повторного обчислення порожніх томів повторно)
  • Додайте батьківський вузол до поточного кореня, а потім додайте сім побратимів для вихідного вузла. Це спрацювало б і на вимогу, але здається складним розумне скорочення вниз, коли гравець рухається по пейзажу. Це також зробить номери LoD ще менш значущими.

¹ [У поясненні до Q нижче] В даний час, якщо два фізично суміжних вузла на дереві знаходяться на різних LOD, у мене є який-небудь код, щоб примусити верти, щоб у них не було шва при створенні сітки. Я можу це зробити, знаючи щільність для кількох оточуючих вузлів. У випадку, коли у мене є 2 незалежних октриси поруч, я не мав би простого способу отримати цю інформацію, що призвело до появи швів.

Який оптимальний спосіб підійти до цього?

Відповіді:


1

Я не впевнений, що відповідаю на точне запитання, тому я збираюся відповідати по сегментах, і сміливо відповідайте у коментарях, якщо є непорозуміння щодо деталей конкретного питання.

Я повинен визначити початковий обмежувальний об'єм (і чим він більший, тим більше мені потрібно обробити)

Здається, це не так. Оскільки octree збільшує зернистість експоненціально, додавання кількох рівнів у верхній частині повинно бути дуже невеликим чистим збільшенням ефективності.

У корені дерева я не знаю, наскільки глибокими будуть листя, тому моя нумерація LoD починається з найнижчої якості (корінь) і збільшується, коли шматки стають меншими. Оскільки LoD зараз відносно початкового обсягу, він не дуже корисний, коли я хочу робити речі за певними розмірами / якостями.

Якщо ви зафіксували кореневу протокол до якогось "достатньо великого значення", то "LoD відносно початкового обсягу" не повинно бути проблемою. І як було сказано вище, я не думаю, що додатковий рівень у верхній частині вплине на загальну ефективність.

Підтримуйте колекцію Octrees та додайте / видаляйте залежно від відстані. Не можу зрозуміти, як я б добре обміняв сітку, плюс мені знадобиться список відомих порожніх вузлів, особливо якщо я хочу довільні тривимірні поверхні (щоб уникнути повторного обчислення порожніх томів повторно)

Як я розумію, пропоноване рішення стосується зниження LoD при відсуванні від раніше деталізованої області. Я вважаю, що він повинен виглядати дуже схоже на кодовий шлях, що збільшується:

if (loDProvider.DesiredLod(bounds) <(is a lot less than)< currentLoD) { 
    for(i = 1 to 8) { 
        children[i].Destroy();
    }
    BuildMesh();
}

Тоді ви не витрачаєте занадто багато часу на перевірку віддалених вузлів, тому що можете покластися на те, що, поки далеко, не так вже й багато "активних" вузлів, оскільки всі вузли з більшою роздільною здатністю будуть видалені.


Якщо припустити, що невеликі вузли мають масштабний характер, це означало б потенційно десятки, якщо не сотні рівнів, коли я подорожую по континенту

Я думаю, що логарифмічна шкала октрису робить це все ще можливим. Якщо ваш найвищий рівень шириною 1 000 000 000 000 м (це було б у 25 разів ширше, ніж реальна Земля, а 625 разів більша площа поверхні), а ваші шматочки найнижчого рівня - 10 см поперек, це 32 рівні в октрисі, що, ймовірно, досить керований. Якщо ви хотіли, щоб планета була в 100 разів ширшою за Землю (і з 10000 разів більшою площею поверхні), це лише додаткові 3-4 рівні у вашому октре. У цей момент гравцеві знадобиться сотні років, щоб ходити по всьому світу, і якщо ви використовуєте наївну математику з плаваючою точкою, світ буде накопичувати помилки точності.

Підтримуйте колекцію Octrees та додайте / видаляйте залежно від відстані. Не можу зрозуміти, як я добре перетинаюсь¹, плюс мені знадобиться список відомих порожніх вузлів, особливо якщо я хочу довільні тривимірні поверхні (щоб уникнути повторного обчислення порожніх томів повторно)

Хіба це принципово не рівнозначно октару, що має широкий мільярд км, але зберігає список покажчиків на кожен, скажімо, блок на 1 км? Тоді "мережа через" просто покладається на вузли розміром 2 км. Збереження локальної посилання на кожен "великий блок" середнього рівня також не дозволяє вам повторювати вузли верхнього рівня, якщо ви переживаєте за "можливо десятки додаткових рівнів октриси"


Дякую за відповідь. Я не можу просто вибрати величезний початковий об'єм, оскільки моя місцевість нескінченна (це моя мета). Перегляньте відео, щоб отримати уявлення. Як таке, моє дерево вузлів просто стає все вище. Якщо припустити, що невеликі вузли мають масштабний характер, це означало б потенційно десятки, якщо не сотні рівнів, коли я подорожую по континенту. Re: Повідомлення впоперек, дозвольте додати ще кілька деталей до питання [Готово]
Основні

що стосується гравця, "мільярд миль" досить близький до "нескінченності". Для відповіді додано більше аргументів для фіксованого початкового тома.
Джиммі

Я досі непереконаний. Чому мають 30+ шарів відомої марної обробки? Це не елегантно, не кажучи вже про ефективне. Я вважаю, що вам потрібно пройтись, але ми просто говоримо про генерацію місцевості. Ніщо не говорить про те, що я повинен зосереджуватись на походженні, а також, що літати з великою швидкістю неможливо (хоча я б не змішувався з такою швидкістю!). FWIW Я використовую парні внутрішньо, щоб уникнути цієї проблеми з точністю.
Основні
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.