Важным моментом является понятие соседа основания (
base neighbor) - это тот треугольник, который своим основанием прилежит к основанию рассматриваемого треугольника.
2.2.Деление треугольников
Теперь рассмотрим, по какому принципу происходит деление родительского
треугольника на дочерние. Чтобы узнать необходимо ли нам разбивать
треугольник, нужно определить насколько форма описываемвая
треугольником отличается от фактической высоты по HeightMap'е.
Рассмотрим треугольник. В качестве эталонной точки берется центральная
точка. Погрешность вычисляется по очень простой формуле:
погрешность=Abs((hLeft+hRight)/2-hCenter)
hLeft,hRight - это высота по карте высот в точках правого и левого вертекса.
hCenter - это высота по карте высот центральной точке
(hLeft+hRight)/2 - интерполированная высота над центральной точкой
Например, возьмем hLeft=15.0, hRight=25.0 и hCenter=23.0. По формуле погрешность равна Abs((15+25)/2-23)=Abs(20-23)=3. Чтобы определить является ли погрешность достаточной для деления, нам понадобится переменная, назовём её RoamMaxHeightError.
Её значение характеризует максимально допустимую разницу высот между
фактической и желаемой. Чем меньше её значение, тем больше ландшафт
будет соответствовать действительности и тем больше рисовать полигонов.
И наоборот чем больше её значение, тем грубее будет ландшафт и тем
меньше полигонов занимать. Если принять RoamMaxHeightError=5, то треугольник дальше разбиваться не будет, т.к. погрешность< RoamMaxHeightError (3<5). Если же принять значение RoamMaxHeightError=2,
то треугольник будет разбит, т.к. погрешность превышает максимально
допутимый уровень погрешности (3>2). Для примера покажу несколько
рендеров ландшафта 1024*1024 с разным значением RoamMaxHeightError. Высота ландшафта от -40.96 до 40.96.
Здесь наглядно видно преимущество метода: треугольники не тратятся на
отрисовку относительно плоских поверхностей, а более детально
обрабатывают выпуклые поверхности.
2.3.Бинарное дерево
Теперь разберемся, почему алгоритм основан на структуре "Бинарное
дерево треугольников". Как видно из предыдущей картинки каждый
треугольник имеет свой индивидуальный номер. Левому потомку
присваивается номер
(родитель<<1), а правому
(родитель<<1)+1.
Структура ландшафта в памяти компьютера представлена банком памяти, при
этом каждому треугольнику соответствует байт памяти, а его адрес
соответствует номеру треугольника. Значение байта представляет будет ли
делиться треугольник. Например, значение 1 обозначает, что текущий
треугольник будет разделен на два дочерних, а значение 0 что не будет.
Бинарное дерево даёт преимущество в том, что адрес каждого треугольника
очень легко вычислить, используя операции байтового сдвига. Сдвиг
вправо дает возможность найти родителя:
parent = Tri Shr 1
а сдвиг влево потомков:
LeftChild =Tri Shl 1
RightChild =(Tri Shl 1)+1;
Таким образом алгоритм построения ландшафта складывается из двух частей:
- Сначала мы рекурсивно обходим треугольники, проверяя погрешность высоты. Если погрешность превышает RoamMaxHeightError то
записываем в соответствующий байт в банке памяти 1 и проверяем
погрешность высоты для его потомков (для них аналогично). Если же
погрешность укладывается в RoamMaxHeightError то записываем в соответствующий байт 0 и переходим к следующему шагу.
- Теперь строим меш ландшафта по созданному нами дереву.
2.4.Diamond split
Однако даже в таком простом и наглядном алгоритме есть одна проблема. Давайте рассмотрим на примере:
У нас есть треугольник. Рассмотрим процесс его деления по шагам.
- Имеется треугольник 1. Определяем погрешность, допустим она больше
текущего RoamMaxHeightError. Поэтому разделяем его на два дочерних: 2 и
3
- Рассматриваем треугольники 2 и 3. Допустим погрешность в
треугольнике 3 не больше RoamMaxHeightError и поэтому дальше его не
делим. Теперь допустим, что погрешность в треугольнике 2 достаточна для
его деления на треугольники 4 и 5.
- Треугольник 3 не имеет потомков, его структура дальше не
просчитывается. Теперь рассматриваем треугольники 4 и 5. Допустим,
дальше треугольник 5 остается без изменений, а 4 делится на 8 и 9.
- В итоге мы имеем поверхность, состоящую из треугольников
3,5,8,9. Обратим внимание на стык треугольников 3, 8 и 9. Как видно 8 и
9 представляют участки с большей детализацией и 3 с меньшей. Из за
этого на поверхности ландшафта будут образовываться так называемые
трещины. Вот как они выглядят:
Описанная ситуация решается довольно просто. Помните, в описании
структур мы говорили и понятии "соседа основания "? Для того чтобы
устранить зазор в поверхности необходимо разделить и соседа основания.
В оригинальном документе два прилежащих основаниями треугольника
называют Diamond, из-за похожести его на алмаз или бриллиант. А
операция по их делению называется Split on a diamond, то есть его
разделение. После того как сосед основания будет разделен, алгоритм
переходит на его родителя и его соседа основания. И так до тех пор,
пока не встретятся уже оба разделенных треугольника.