Ранее я реализовал марширующие кубы / тетраэдры для рендеринга IsoSurface. Это работало ( YouTube ), но производительность была ужасной, так как я никогда не удосужился реализовать переменную Level of Detail, основанную на расстоянии просмотра (или даже удалив старые, отдаленные фрагменты).
Я решил пойти еще раз и сделать это правильно на этот раз. Я начал с создания 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 на основе положения камеры / усеченного конуса, пользовательских настроек и т. Д.
Итак ... Все это работает довольно хорошо. Используя простую сферу в качестве источника плотности и показывая все узлы:
И только листья
Тем не менее, есть несколько проблем:
- Я должен определить начальный ограничивающий объем (и чем он больше, тем больше обработки мне нужно сделать)
- В корне дерева я понятия не имею, насколько глубокими будут листья, поэтому моя нумерация LoD начинается с самого низкого качества (корень) и увеличивается с уменьшением фрагментов. Поскольку LoD теперь относительно начального объема, он не очень полезен, когда я хочу делать вещи с определенными размерами / качествами.
Я подумал о нескольких вариантах, но оба кажутся ошибочными:
- Сохраняйте коллекцию Octrees и добавляйте / удаляйте в зависимости от расстояния. Не могу понять, как мне было бы хорошо совмещаться… плюс мне нужен список известных пустых узлов, особенно если я хочу произвольные трехмерные поверхности (чтобы избежать повторного расчета пустых объемов)
- Добавьте родительский узел к текущему корню, затем добавьте семь братьев и сестер для исходного узла. Это будет работать и по требованию, но кажется, что сложно разумно сжиматься, когда игрок движется по ландшафту. Это также сделало бы номера LoD еще менее значимыми.
In [В пояснении к Q ниже] В настоящее время, если 2 физически смежных узла в дереве находятся в разных LOD, у меня есть некоторый код для приведения вершин так, что при создании сеток шва нет. Я могу сделать это, зная плотность для множества окружающих узлов. В сценарии, где у меня есть 2 независимых октода рядом, у меня не было бы легкого способа получить эту информацию, что привело бы к швам.
Какой оптимальный способ подойти к этому?