Матрицы OpenGL
При обсуждении команд glRotatef и glTransiatef мы уже обращали внимание на то, что их действие объясняется с позиций линейной алгебры Например, про команду glTransiatef в соответствующем файле справки говорится, что эта команда умножает текущую матрицу на матрицу переноса Аналогично glRotatef сводится к операции перемножения текущей матрицы на матрицу поворота Многие изученные нами команды, действие которых я объяснял по их функциональному смыслу, в действительности описываются с помощью базовых понятий раздела математики, изучающего вопросы, связанные с геометрическими операциями, например, такими, как проекция Надеюсь, отсутствие ссылок на линейную алгебру нисколько не помешало вам при изучении предыдущего материала Если я говорю, что команда glscale является командой масштабирования (и умалчиваю о том, что она сводится к операции перемножения матриц), то рассчитываю на то, что читателю данной информации будет вполне достаточно для успешного использования этой команды на практике
Я сознательно не включил в книгу изложение математических основ для всех подобных команд, поскольку замыслил ее прежде всего как практическое руководство по компьютерной графике Мне кажется, что многие читатели не очень хотели бы особо углубляться в дебри формул Это отнюдь не значит, что я пытаюсь принизить значение математической грамотности Просто мой опыт преподавания подсказывает, что очень многие программисты предпочитают руководства, делающие упор на практике К счастью, существует масса литературы по компьютерной графике, уделяющей много внимания математике, где подробно рассказывается об операциях перемножения матриц и прочих подобных вопросах Если вы все-таки испытаете необходимость в более основательной теоретической подготовке, найти подходящее пособие не составит большого труда. Однако и в нашей практической книжке без представления о некоторых специальных терминах не обойтись. Ограничимся самым необходимым.В OpenGL имеется несколько важных матриц Матрица модели ("modelview matrix") связана с координатами объектов Она используется для того, чтобы в пространстве построить картину как бы видимую глазу наблюдателя. Другая матрица, матрица проекций ("piojection matirx"), связана с построением проекций пространственных объектов на плоскость.Матрица проекций, имея координаты точки зрения, строит усеченные ("clip") координаты, по которым после операций, связанных с перспективой, вычисляются нормализованные координаты в системе координат устройства ("normalized device coordinates") После трансформаций, связанных с областью вывода, получаются оконные координаты.Координаты вершин в пространстве и на плоскости проекций четырехмерные, помимо обычных координат есть еще w-координата Поэтому матрица модели и матрица проекций имеют размерность 4x4. Перенос и поворот системы координат сводится к операции перемножения матриц, связанных с текущей системой координат, и матриц переноса и поворота Библиотека OpenGL располагает набором команд, связанных с этими операциями, а также имеет универсальную команду для перемножения матриц glMultMatrix При желании и наличии математической подготовки этой командой можно заменить команды переноса, поворота и ряд других Посмотрим, как это делается.
В проекте из подкаталога Ех14 команда начального переноса заменена командой glMultMatrix Для этого введен массив 4x4, хранящий матрицу переноса:
rat . Array [0. 3, 0. 3] of GLfloat,
Матрица переноса заполняется нулями, кроме элементов главной диагонали, которые должны быть единицами, и последней строки, содержащей вектор переноса В примере перемещение осуществляется только по оси Z:
mt [0, 0] := 1;
№ [1, 1] := 1;
№ [2, 2] := 1;
mt [3, 3] := 1;
mt [3, 2] := -8;
Стартовый сдвиг теперь осуществляется так:
glMultMatrixf (@mt);
Если надо вернуться к исходной позиции, текущая матрица заменяется матрицей с единицами по диагонали и равными нулю всеми остальными элементами, единичной матрицей Это и есть действие команды giLoadidentity Она является частным случаем более универсальной команды glLoadMatrix, предназначенной для замены текущей матрицы на заданную, ссылка на которую передается в качестве аргумента.
Без примера эти команды не усвоить, поэтому загляните в подкаталог Exl5 Массив mt аналогичен единичной матрице. Команда glLoadidentity отсутствует, вместо ее вызова используется явная загрузка единичной матрицы:
glLoadMatrixf (@mt);
После знакомства с матричными операциями становится яснее технический смысл команд glPushMatrix и glPopMatrix, запоминающих в стеке текущую матрицу и извлекающих ее оттуда. Такая последовательность манипуляций выполняется быстрее, чем вызов glLoadMatrix. To же самое можно сказать и по поводу glLoadidentity, т. e. единичная матрица загружается быстрее
командой glLoadidentity, чем glLoadMatrix.
Замечание
Чем реже вы пользуетесь командами манипулирования матрицами, тем быстрее будет работать программа Но учтите, что если на сцене присутствует не больше пары десятков объектов, все манипуляции с матрицами съедают один кадр из тысячи.
Узнать, какая сейчас установлена матрица, можно с помощью команды glGet. Во всех наших предыдущих примерах мы задавали параметры вида применительно к матрице, установленной по умолчанию Определим, какая это матрица.
Подкаталог Ex16содержит проект, который нам в этом поможет Обработчик Resize формы дополнен выводом в заголовке окна имени текущей матрицы:
var
wrk: GLUInt; begin
glGetIntegerv (GL_MATRIX_MODE, @wrk);
case wrk of
GL_MODELVIEW: Caption: = 'GL_MODELVIEW';
GL_PROJECTION: Caption: = 'GL_PROJECTION';
end;
Запустив проект, выясняем, что по умолчанию в OpenGL установлена матрица модели. Итак, во всех предыдущих примерах операции производились над матрицей модели. В любой момент мы можем выяснить значение этой матрицы. Проиллюстрируем примером - проектом из подкаталога Exl7. При создании формы массив 4x4 заполняется матрицей модели:
glGetFloatv (GL_MODELVIEW_MATRIX, @mt);
при выборе пункта меню появляется вспомогательное окно, в котором выводится текущая матрица модели (рис 3. 11).
Содержание раздела