traaret_i_Zx

advertisement
3.2. Алгоритм z-buffer
Объекты, которые мы имеем в нашей работе, нужно суметь корректно отобразить,
чтобы на мониторе мы увидели реалистичную и понятную картинку. Чтобы это сделать,
нам поможет метод визуализации поверхностей – алгоритм z-буфера, за авторством Э.
Кэтмула. Этот способ довольно прост и эффективен.



Логически метод работает так:
сначала перебираются пиксели, принадлежащие проекции поверхности
потом эти пиксели восстанавливаем по положению соответствующих пикселей на
самой поверхности
и, в итоге, записываем в видеопамять коды цветов тех точек, которые ближе к
наблюдателю
В этом методе мы используем z-координату, чтобы в конце концов узнать, какие
точки насколько отдалены от наблюдателя – отсюда и название метода.
ЭВМ должна определить какие z-координаты у каждой точки и отсортировать эти
координаты. Для этого нужно создать две матрицы:

во-первых, одна будет хранить z-координаты тех точек, которые к наблюдателю
самые ближайшие – видимые на экране. Это буфер глубины Z. Чтобы рассчитать
его объем, нужно умножить количество слов на объем слова. Количество
определяется размером окна вывода дисплея: ширина * высота, где ширина –
крайняя правая точка окна минус крайняя левая и плюс 1, а высота – крайняя
нижняя минус крайняя верхняя точка окна и плюс 1. А объем слова Nz будет
зависеть от того, сколько в нем будет разрядов. Их число определяется
количеством квантов, на которые мы разделим глубину Z, чем больше квантов –
тем точнее будет результат, и вычисляется разрядность так: 2^(Nz).

Вторая матрица – буфер, который хранит цвет каждой точки, окончательно
обреченной к выводу на дисплей. Такая матрица называется буфер кадра F. Объем
такого буфера – площадь окна вывода (рассчитывается как для предыдущего
буфера), умноженная на слово, содержащее информацию о цвете. Разрядность
такого слова NF зависит от количества квантов, на которые мы расслоили диапазон
цветов - 2^(NF). Чем больше квантов – тем больше цветов, но объемнее буфер.
Для наглядности и удобства к восприятию алгоритм работы z-буфера поясняется на
схеме (рис. 10).
Следует отметить, что все вычисления ведутся в экранной системе координат.
Необходимо составить список LP={Pk}, в который мы поместим данные обо всех
полигонах каждой поверхности. Для начала им можно присвоить элементам такого списка
случайные номера, к сортировке мы еще не подошли.
Перед тем, как начать обрабатывать полигоны, выполним инициализацию двух
буферов – глубины и кадра (рассмотренных выше), для этого положим в буфер кадра
картинку (в принципе, любую) – она будет видима при отсутствии перед ней объектов. В
буфер глубины занесем информацию о дальности этой картинки от наблюдателя. В
соответствии с названием, фон – картинка на заднем плане, поэтому располагаем его в
самой дальней от наблюдателя плоскости, в то место, дальше которого ни один объект,
который мы будем потом отображать, не сможет забраться. Часто такие координаты
устанавливаются в зависимости от того, какое максимальное число разрядной сетки
процессора ЭВМ (чтоб уж наверняка).
Визуализируем кадр. Для этого:



сначала выбираем из списка LP очередной полигон Pk.
Проецируем его на экран, отсекаем лишнее окном вывода (рис. 11а,б).
Получившаяся экранная проекция Pэ сканируется по точкам (рис. 11в).
Такой процесс называется растеризация. Иными словами – происходит разложение
в растр – в двухмерный массив пикселей, заполняющий контур проекции. Вообще,
пиксели для растеризации можно выбирать в любом порядке, но, в большинстве случаев,
растеризация идет слева направо по строчкам – от верхней до нижней. Таких растровых
алгоритмов придумано довольно много.
Из получившегося растра pэ = [i j 0] берутся пиксели по одному и для каждого из
них восстанавливается образ точки p = [x y z], по уравнению той самой поверхности, на
которой она лежит. Можно сказать, что из каждого экранного пикселя, которые мы
храним в массиве растра, в направлении объекта проводится вектор Hэ (специальный
служебный, для сканирования), который, когда пересечет поверхность грани, поможет
рассчитать до нее расстояние.
Рис. 10
Рис. 11
Вид вектора Hэ зависит от типа наблюдателя:


Если он дальний (рис. 11а), то будет фиксированным Hэ = S, таким образом он
соответствует заданной параллельной проекции;
В сцене с ближним наблюдателем в точке S (рис. 11б) вектор Hэ = S – pэ. Метод
расчета пересечения прямой c объектом выглядит так: r(Ѳ) = pэ + Hэ Ѳ и
определяется в зависимости от того, какая поверхность этот объект ограничивает;
В таком случае, для неявной модели f(p) = 0 необходимо решить скалярное
уравнение f(pэ +Hэ Ѳ) = 0 и сделать этот расчет относительно лучевого параметра Ѳ
(который дает нам точку p=r(Ѳ) ). Если для примера взять, допустим, плоскость, заданную
{o,N}, у которой НФ f(p) = (p-o)◦N, то после проведения расчетов получим p =
cross_line(pэ,Hэ,o,N);
Чтобы найти ту точку, в которой прямая будет пересекаться с параметрической
поверхностью p(t,τ), нужно решить векторное уравнение pэ + Нэ Ѳ = p(t,τ), из которого p
будет равна r(Ѳ).
Итак, у найденной точки p мы нашли дальность d по формуле di=|ci-S|. Теперь
необходимо проверить состояние (i,j)-го элемента (Zij) в нашем буфере глубины. Если d
получается меньше, чем Zij, то это значит, что точка p к наблюдателю располагается
ближе, чем известные точки (фон или ранее найденные точки) с такими же экранными
координатами [ i j]. В таком случае (нашли новую ближайшую точку), сохраним
состояние этой точки Zij = d в z-буфере. В свою очередь, в пиксель буфера экранного
кадра Fij запишем цветовой код c.
Вот так и получается, что из нескольких точек, нанизанных на (i,j)-ую
сканирующую прямую, наблюдатель увидит лишь самую ближайшую. В случае, если на
прямой не оказалось ни одной точки, то цвет пикселя останется фоновым.
Когда оба вышеописанных цикла наконец выполнятся, то что содержалось в итоге
в буфере кадра (цвета пикселей отображаемого окна) скопируется в окно вывода на экране
дисплея, начиная с верхней строчки и с самого левого пикселя в ней.
В итоге, главные преимущества алгоритма z-буфера – это простота и тот факт, что
поверхности можно обрабатывать в произвольном порядке. Это позволяет экономить
машинные ресурсы на специальную сортировку по глубине. Сложность вычислений в
результате будет линейно зависеть от количества объектов и площади экрана, которую
они своими проекциями покрывают. Если на нашей сцене объектов совсем немного и они
относительно простые (и особенно если доля фона на конечном изображении большая), то
метод z-буфера совершит свои дела довольно таки быстро.
По традиции, нужно перечислить недостатки описанного метода (куда же без них):
1) Большой объем памяти, который занимают два крупных буфера, тем больше, чем
больше графическое разрешении и площадь окна вывода. Соответственно, при большом
разрешении и крупном окне памяти требуется много.
2) Приходится совершать предварительную растровую развертку проекции поверхности, а
если эта самая поверхность непрямолинейна – задача становится сложнее.
3) Так как на экран поверхности выводятся в произвольном порядке, становится сложно
реализовать полупрозрачность.
А.Майерсо, широко известный в узких кругах, предложил способ нейтрализации
одного из недостатков - повышенного потребления памяти. Чтобы это потребление
уменьшить, по его словам, нужно сократить высоту буферов кадра и глубины до одной
строки экрана, то есть сделать значение высоты=1.
В результате получился метод построчного сканирования с z-буфером.
Получается, что однострочная развертка поверхности – это:


проекция на экране такой линии, которая образуется при сечении поверхности
плоскостью зрения П (которая проходит через крайние точки сканирующей строки
[left уэ],[right уэ])
точка S расположения ближнего наблюдателя (рис. 12,а).
Отметим, что плоскость зрения П почти всегда не ортогональна картинной плоскости.
В случае же наблюдателя, удаленного по вектору S, плоскость зрения проходит через
точку [left уэ] + S и, например, при S||z°, всегда ортогональна экрану (рис. 12,б).
Самое сложное – это расчет плоского сечения криволинейной поверхности, не
аппроксимированной полигональными гранями (рис. 12,а).
Рис. 12
Еще здесь приходится формировать множество точек, которые мы находим, когда
сканирующий луч (наш вспомогательный вектор Hэ) пересекается с кривой линией
сечения. Ведь только в результате сортировки получившегося массива мы сможем найти
ту самую заветную ближайшую к наблюдателю точку.
Вообще можно производить расчеты с помощью аналитических формул. Но такое
возможно только для узкого класса неплоских поверхностей и кривых линий, в основном,
квадратичного типа. Если же наши объекты не попадают в их компанию, придется
прибегать к услугам медленных численных методов решения нелинейных уравнений.
Плоская грань пересекается с плоскостью зрения по прямому отрезку, имеющему
не более одной точки пересечения с лучом, но все равно эти расчеты должны выполняться
в пространстве (рис. 12,б). Поэтому гораздо эффективнее будет сначала найти экранную
проекцию абриса поверхности или грани, а потом уже построчно решать на плоскости xэуэ
задачу внешнего отсечения горизонтального отрезка {[left уэ],[right уэ]} полученным
полигоном.
В результате, в сканирующей строке формируется список проекций отрезков
Ls={a1’b1’…an’bn’}. Далее начинается их попиксельная обработка с помощью Z- и Fбуферов строки (которые нужно предварительно инициализировать фоновыми
значениями глубины и цвета). Ну и когда, наконец, завершится перебор содержимого
списка Ls, буфер F отобразится в сканируемую строку.
Использование буфера трафарета.
По заданию необходимо сделать зеркало Т-образной формы (рис.20)
Рис. 20
Следовательно, нам необходимо решить задачу отсечения. Под отсечением будем
понимать процедуру обнаружения и исключения из дальнейшего анализа таких элементов
сцены, которые не попадут в область видимости наблюдателя. Для создания такой формы
зеркала (рис. 6) используется наложение двух полигонов справа и слева соответственно с
цветом фона поверх зеркала. Для решения задачи отсечения в данной работе будем
использовать буфер трафарета. Он позволяет не визуализировать заданные области. Далее
объясним, как мы использовали буфер трафарета, разобьем все действия на несколько
шагов. Использование буфера трафарета пошагово:
1) Очистка буфера трафарета (заполнение нулями)
2) Заполняем единицами буфер трафарета в тех местах, где будет в дальнейшем
нарисовано отражение наших деталей (основания и боковой части) (рис. 21)
Рис. 21
3) Далее визуализируем отражение изображения основания и боковой детали. Перед этим
задаем проверку трафарета так, чтобы тест выполнялся успешно, в случае если в буфере
трафарета находится единица (видно по рис. 21)
4) Таким образом, у нас изображается отображение деталей (основания и боковой части)
только так, где соответствующему пикселю в буфере трафарета стоит 1. Но у нас единицы
в буфере трафарета находятся там, где должно быть отражение деталей, и т.е. только в
нашем зеркале будет нарисовано отражение.
Download