
Операторные скобки glBegin / glEnd
void glBegin (GLenum mode); void glEnd (void); |
Параметр mode определяет тип примитива, который задается внутри и может принимать следующие значения:
GL_POINTS |
каждая вершина задает координаты некоторой точки. |
GL_LINES |
каждая отдельная пара вершин определяет отрезок; если задано нечетное число вершин, то последняя вершина игнорируется. |
GL_LINE_STRIP |
каждая следующая вершина задает отрезок вместе с предыдущей. |
GL_LINE_LOOP |
отличие от предыдущего примитива только в том, что последний отрезок определяется последней и первой вершиной, образуя замкнутую ломаную. |
GL_TRIANGLES |
каждая отдельная тройка вершин определяет треугольник; если задано не кратное трем число вершин, то последние вершины игнорируются. |
GL_TRIANGLE_STRIP |
каждая следующая вершина задает треугольник вместе с двумя предыдущими. |
GL_TRIANGLE_FAN |
треугольники задаются первой и каждой следующей парой вершин (пары не пересекаются). |
GL_QUADS |
каждая отдельная четверка вершин определяет четырехугольник; если задано не кратное четырем число вершин, то последние вершины игнорируются. |
GL_QUAD_STRIP |
четырехугольник с номером n определяется вершинами с номерами 2n-1, 2n, 2n+2, 2n+1. |
GL_POLYGON |
последовательно задаются вершины выпуклого многоугольника. |
Как правило, разные типы примитивов имеют различную скорость визуализации на разных платформах. Для увеличения производительности предпочтительнее использовать примитивы, требующие меньшее количество информации для передачи на сервер, такие как GL_TRIANGLE_STRIP, GL_QUAD_STRIP, GL_TRIAGLE_FAN.
Например, чтобы нарисовать сферу или цилиндр, надо сначала создать объект специального типа GLUquadricObj с помощью команды
GLUquadricObj* gluNewQuadric(void);
а затем вызвать соответствующую команду:
void gluSphere (GLUquadricObj * qobj, GLdouble radius,
GLint slices, GLint stacks)
void gluCylinder (GLUquadricObj * qobj,
GLdouble baseRadius,
GLdouble topRadius,
GLdouble height, GLint slices,
GLint stacks)
Проекции
В OpenGL существуют стандартные команды для задания ортографической (параллельной) и перспективной проекций. Первый тип проекции может быть задан командами
void glOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far) void gluOrtho2D (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top) |
Рис.
6 Ортографическая проекция
Первая команда создает матрицу проекции в усеченный объем видимости (параллелепипед видимости) в левосторонней системе координат. Параметры команды задают точки (left, bottom, znear) и (right, top, zfar), которые отвечают левому нижнему и правому верхнему углам окна вывода. Параметры near и far задают расстояние до ближней и дальней плоскостей отсечения по удалению от точки (0,0,0) и могут быть отрицательными.
Во второй команде, в отличие от первой, значения near и far устанавливаются равными –1 и 1 соответственно. Это удобно, если OpenGL используется для рисования двумерных объектов. В этом случае положение вершин можно задавать, используя команды glVertex2*()
Перспективная проекция определяется командой
void gluPerspective (GLdouble angley, GLdouble aspect, GLdouble znear, GLdouble zfar) |
которая задает усеченный конус видимости в левосторонней системе координат. Параметр angley определяет угол видимости в градусах по оси у и должен находиться в диапазоне от 0 до 180. Угол видимости вдоль оси x задается параметром aspect, который обычно задается как отношение сторон области вывода (как правило, размеров окна) Параметры zfar и znear задают расстояние от наблюдателя до плоскостей отсечения по глубине и должны быть положительными. Чем больше отношение zfar/znear, тем хуже в буфере глубины будут различаться расположенные рядом поверхности, так как по умолчанию в него будет записываться ‘сжатая’ глубина в диапазоне от 0 до 1 (см. п. 0.).
Рис. 7 Перспективная проекция
Прежде чем задавать матрицы проекций, не забудьте включить режим работы с нужной матрицей командой glMatrixMode(GL_PROJECTION) и сбросить текущую, вызвав glLoadIdentity().
Например:
/* ортографическая проекция */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, w, 0, h, -1.0, 1.0); |
А. Матрица вращения (rotation)
Б. Матрица растяжения (сжатия) (dilatation)
В. Матрица отражения (reflection)
Г. Матрица переноса (translation)
Матрица отражения
Матрица отражения относительно плоскости xy:
Матрица отражения относительно плоскости yz:
Матрица отражения относительно плоскости zx:
Название Число граней Г Число ребер Р Число вершин В
многогранника
Тетраэдр 4 6 4
Гексаэдр 6 12 8
Октаэдр 8 12 6
Додекаэдр 12 30 20
Икосаэдр 20 30 12
Г + В = Р + 2
Куб (гексаэдр) строится совсем несложно (рис. 13).
Покажем, как, используя куб, можно построить тетраэдр и октаэдр.
Для построения тетраэдра достаточно провести скрещивающиеся диагонали противоположных граней куба (рис. 14).
Свет точечного источника отражается от идеального рассеивателя по закону косинусов Ламберта:
, (1)
где
— интенсивность отраженного света;
—
интенсивность точечного источника
света;
—
коэффициент диффузного отражения
(постоянная величина, 0 ≤
≤ 1);
— угол между направлением на источник
света и (внешней) нормалью к поверхности
(рис. 1).
На
объекты реальных сцен падает еще и
рассеянный свет, соответствующий
отражению света от других объектов.
Поскольку точный расчет рассеянного
освещения требует значительных
вычислительных затрат, в компьютерной
графике при вычислении интенсивности
поступают так:
, (2)
где
— интенсивность рассеянного света;
— (постоянный) коэффициент диффузного
отражения рассеянного света, 0 ≤
≤ 1.
Интенсивность света, естественно, зависит от расстояния d от объекта до источника света. Для того чтобы учесть это, пользуются следующей моделью освещения:
, (3)
где
— произвольная постоянная.
Интенсивность зеркально отраженного света зависит от угла падения, длины волны и свойств вещества. Так как физические свойства зеркального отражения довольно сложны, то в простых моделях освещения обычно пользуются следующей эмпирической моделью (модель Фонга):
, (4)
где
— экспериментальная постоянная;
— угол между отраженным лучом и вектором
наблюдения:
— степень, аппроксимирующая пространственное
распределение света (рис. 2).
Объединяя последние две формулы, получаем модель освещения (функцию закраски), используемую для расчета интенсивности (или тона) точек поверхности объекта (или пикселов изображения):
. (5)
Функцию закраски, используя единичные векторы внешней нормали n, а также единичные векторы, определяющие направления: на источник (вектор l), отраженного луча (вектор r) и наблюдения (вектор s), можно записать в следующем виде:
. (6)
Замечание
Чтобы получить цветное изображение, необходимо найти функции закраски для каждого из
трех основных цветов — красного, зеленого и синего. Поскольку цвет зеркально отраженного
света определяется цветом падающего, то постоянная считается одинаковой для каждого
из этих цветов.
Если точечных источников света несколько, скажем m, то модель освещения определяется так
. (7)
Если
освещаемая поверхность в рассматриваемой
точке гладкая (имеет касательную
плоскость), то вектор внешней нормали
вычисляется непосредственно (рис. 3). В
случае многогранной поверхности векторы
внешних нормалей можно найти только
для ее граней. Что касается направлений
векторов внешних нормалей на ребрах и
в вершинах этой поверхности, то их
значения можно найти только приближенно.
Пусть, например, грани, сходящиеся в данной вершине, лежат в плоскостях, описываемых уравнениями
.
Можно считать, что нормальные векторы этих плоскостей
,
Закраска методом Гуро
Наиболее простым из таких методов является метод Гуро, который основывается на определении освещенности грани в ее вершинах с последующей билинейной интерполяцией получившихся величин на всю грань.
Обратимся
к рис. 10, на котором изображена выпуклая
четырехугольная грань. Предположим,
что интенсивности в ее вершинах
известны и равны соответственно
.
Пусть W — произвольная точка грани. Для определения интенсивности (освещенности) в этой точке проведем через нее горизонтальную прямую. Обозначим через U и V точки пересечения проведенной прямой с границей грани.
Будем считать, что интенсивность на отрезке UV изменяется линейно, то есть
,
г
де
.
Для определения интенсивности в точках U и V вновь воспользуемся линейной интерполяцией, также считая, что вдоль каждого из ребер границы интенсивность изменяется линейно.
Тогда интенсивность в точках U и V вычисляется по формулам
,
,
где
.
Метод Гуро обеспечивает непрерывное изменение интенсивности при переходе от одной грани к другой без разрывов и скачков.
Еще одним преимуществом этого метода является его инкрементальный характер: грань рисуется в виде набора горизонтальных отрезков, причем так, что интенсивность последующего пиксела отрезка отличается от интенсивности предыдущего на величину постоянную для данного отрезка. Кроме того, при переходе от отрезка к отрезку значения интенсивности в его концах также изменяются линейно.
Таким образом, процесс рисования грани слагается из следующих шагов:
проектирование вершин грани на экран;
отыскание интенсивностей в вершинах по формуле (3);
определение координат концов очередного отрезка и значений интенсивности в них линейной интерполяцией;
рисование отрезка с линейным изменением интенсивности между его концами.
Замечания:
При определении освещенности в вершине, естественно, встает вопрос о выборе нормали. Часто в качестве нормали в вершине выбирается нормированная сумма нормалей прилегающих граней
, где
— произвольные весовые коэффициенты.
Дефекты изображения, возникающие при закраске Гуро, частично объясняются те, что этот метод не обеспечивает гладкости изменения интенсивности.
Закраска методом Фонга
Как и описанный выше метод закраски Гуро, закраска Фонга при расчете интенсивности также опирается на интерполирование. Однако в отличие от метода Гуро здесь интерполируется не значение интенсивности по уже известным ее значениям в опорных точках, а значение вектора внешней нормали, которое затем используется для вычисления интенсивности пиксела. Поэтому закраска Фонга требует заметно болшего объема вычислений. Правда, при этом и изображение получается более близким к реалистическому (в частности, при закраске Фонга зеркальные блики выглядят довольно правдоподобно).
Метод Фонга заключается в построении для каждой точки вектора, играющего роль вектора внешней нормали, и использовании этого вектора для вычисления освещенности в рассматриваемой точке по формуле (5). При этом схема интерполяции, используемая при закраске Фонга, аналогична интерполяции в закраске Гуро.
Для
определение вектора «нормали»
в точке W
проводим через эту точку горизонтальную
прямую и, используя значения векторов
«нормалей»
и
в точках ее пересечения U
и V
с ребрами грани, получаем
,
где
,
а векторы внешних нормалей в точках U и V находятся, в свою очередь (также линейной интерполяцией), по векторам нормалей в концевых точках соответствующих ребер рассматриваемой многоугольной грани:
,
,
где
.
Нормирование вектора необходимо в следствие того, что в формулах (1)-(5) используется единичный вектор нормали.
Замечания:
Как и метод Гуро метод Фонга также в значительной степени носит инкрементальный характер.
Применяя метод Фонга, мы фактически строим на многогранной модели непрерывное поле единичных векторов, использование которого в качестве поля внешних нормалей обеспечивает гладкость получаемого изображения.
Ясно, что требования к качеству изображения напрямую связаны с точностью рассматриваемой модели и объемом соответствующих ей вычислений. Несомненным достоинством предложенных моделей закраски (Гуро и Фонга) является их сравнительная простота. Однако вследствие значительных упрощений получаемый результат не всегда оказывается удовлетворительным. Преодолевать этот барьер качества лучше всего путем использования более совершенных моделей и методов. Описанию именно таких методов и посвящены заключительные главы настоящей части.
Зеркальное отражение
Отраженный
луч падает в точку P
в направлении i
и отражается в направлении, задаваемом
вектором r,
определяемым следующим законом: вектор
r
лежит в той же плоскости, что и вектор
i
и единичный вектор внешней нормали к
поверхности n,
а угол падения
равен углу отражения
(рис. 2).
Будем
считать все векторы единичными. Тогда
из первого условия следует, что вектор
r
равен линейной комбинации векторов i
и n,
то есть
r=αi+βn. (1)
Так же = ,
то (-i, n) = cos = cos = (r, n).
Отсюда легко получается
r = i - 2(i, n)n. (2)
Несложно убедиться, что вектор, задаваемый соотношением (2), является единичным.
Диффузное отражение
Идеальное диффузное отражение описывается законом Ламберта, согласно которому падающий свет рассеивается во все стороны с одинаковой интенсивностью. Таким образом не существует однозначно определенного направления, в котором бы отражался падающий луч, все направления равноправны и освещенность точки пропорциональна только доле площади, видимой от источника, то есть (i, n).
Идеальное преломление
Луч,
падающий в точку P
в направлении вектора i,
преломляется внутрь второй среды в
направлении вектора t
(рис. 2). Преломление подчиняется закону
Снеллиуса, согласно которому векторы
i,
n
и t
лежат в одной плоскости и для углов
справедлива соотношение
. (3)
Найдем для вектора t явное выражение. Этот вектор можно представить в следующем виде:
r=αi+βn. (4)
Соотношение (3) можно переписать так:
,
где
. (5)
Тогда
или
. (6)
Так как
,
то
. (7)
Из условия нормировки вектора t имеем
. (8)
Вычитая это соотношение из равенства (7), имеем:
, (9)
откуда
.
Из
физических соображений следует, что
.
Второй параметр определяется из уравнения
, (10)
дискриминант которого равен
. (11)
Решение этого уравнения задается формулой
(12)
и, значит, вектор
(13)
где
. (14)
При
этом случай, когда выражение над корнем
отрицательно (
)
соответствует так называемому полному
внутреннему отражению, когда вся световая
энергия отражается от границы раздела
сред и преломления фактически не
происходит.
Диффузное преломление
Диффузное преломление полностью аналогично диффузному отражению, при этом преломленный луч идет по всем направлениям t : (t, n) < 0 с одинаковой интенсивностью.
Рассмотрим теперь распределение энергии при отражении и преломлении. Из курса физики известно, что доля отраженной энергии задается коэффициентами Френеля
. (15)
Существует другая форма записи этих соотношений:
, (16)
где
. (17)
Формула (15) верна для диэлектрических материалов.
Для проводников обычно используется следующая формула
, (18)
где
— индекс поглощения.
Ясно, что все рассмотренные примеры являются идеализациями. На самом деле нет ни идеальных зеркал, ни идеально гладких поверхностей.
На практике обычно считают, что поверхность состоит из множества случайно ориентированных плоских идеальных микрозеркал (микрограней), с заданным законом распределения (рис. 3).
Пусть
n
— нормаль к поверхности (ее средней
линии), h
— вектор нормали к микрограни и α
— угол между ними,
α = arccos(n, h).
Поверхность будем описывать с помощью функции D(α), задающей плотность распределения случайной величины α (для идеально гладкой поверхности функция D(α) совпадает с δ- функцией Дирака).
Существует несколько распространенных моделей для функции D(α):
Гауссовское распределение
, (19)
распределение Бекмена
. (20)
В этих моделях m характеризует степень неровности поверхности — чем меньше m, тем более гладкой является поверхность.
Рассмотрим отражение луча света, падающего в точку P вдоль направления, задаваемого вектором l. Пусть n — вектор внешней нормали к поверхности. Поскольку микрограни распределены случайным образом, то отраженный луч может уйти практически в любую сторону. Определим долю энергии, уходящей в заданном направлении v. Для того, чтобы луч отразился в этом направлении, необходимо,. Чтобы он попал на микрогрань, нормаль h к которой удовлетворяет соотношению
. (21)
Доля
энергии, которая отразится от микрограни,
определяется коэффициентом Френеля
,
где
.
Если поверхность состоит из множества микрограней, начинает сказываться затеняющее влияние соседних граней, которое обычно описывается с помощью следующей функции:
. (22)
В этом случае интересующая нас доля энергии задается формулой
. (23)
Совершенно аналогично рассматривается преломление света поверхностью, состоящей из микрозеркал.
С использованием соотношения (23) можно построить формулу, полностью описывающую энергию (и отраженную, и преломленную) в заданном направлении. Для этого необходимо выпустить лучи во все возможные стороны и вычислить приходящую оттуда энергию, то есть в качестве вектора l можно рассматривать любой единичный вектор. Ясно, что на практике это невозможно.
Поэтому желательно взять алгоритм, отслеживающий лишь конечное число направлений, вносящих в искомую величину наибольший вклад.
Основная модель трассировки лучей
Введем некоторые ограничения на рассматриваемую сцену:
будем рассматривать только точечные источники света;
при трассировании преломленного луча будем игнорировать зависимость его направления от длины волны;
будем считать освещенность объекта состоящей из диффузной и зеркальной частей (с заданными весами).
Для определения освещенности точки P определим сначала непосредственную освещенность этой точки от источников света (выпустив из нее лучи ко всем источникам).
Для определения вторичной освещенности выпустим их точки P один луч для отраженного направления и один луч для преломленного. Тем самым для определения освещенности точки необходимо будет отслеживать лишь небольшое количество лучей.
При этом неидеально зеркальные отражение лучей, идущих от других объектов, игнорируется.
Обычно для компенсации всех таких не учитываемых величин вводится так называемое фоновое освещение — равномерное освещение со всех сторон, которое ни от чего не зависит и не затеняется.
Тогда энергия, покидающая точку P в заданном направлении, задается следующей формулой:
, (24)
где
— интенсивность фонового освещения;
— интенсивность i-го
источника света;
— интенсивность, приходящая по отраженному
лучу;
— освещенность, приносимая преломленным
лучом;
— цвет в точке P;
— коэффициент фонового освещения;
— коэффициент диффузного освещения;
— коэффициент зеркального освещения;
— вклад преломленного луча;
— вектор внешней нормали в точке P;
— единичный вектор направления из
точки P
на i-ый
источник света;
— угол отражения (для отраженного луча);
— угол преломления;
—
расстояние, пройденное отраженным
лучом;
—
расстояние, пройденное преломленным
лучом;
—
коэффициент ослабления для отраженного
луча;
—
коэффициент ослабления для преломленного
луча.
К сожалению, эта модель, хотя и является достаточно физически корректной, слишком сложна для практического воплощения. Поэтому часто используются более простые модели, например модель Холла:
. (25)
Несмотря на то, что коэффициенты Френеля заметно влияют на степень реалистичности изображения, на практике их применяют очень редко. Дело в том, что их использование наталкивается на ряд серьезных препятствий, одним из которых является сложность вычисления, а другим — отсутствие точной информации о зависимости величин, входящих в состав формулы, от длины волны λ.
Существуют определенные методы интерполяции коэффициентов Френеля (например, линейная), которые в сочетании с табличным способом задания способны заметно ускорить процесс их вычисления, однако их рассмотрение выходит за рамки данной книги.
Далее будет рассматриваться модель Уиттеда:
. (26)
Замечание
Часто
вместо члена
используется
.