Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

RedBook

.pdf
Скачиваний:
20
Добавлен:
11.06.2015
Размер:
7.43 Mб
Скачать

glTexGenfv(GL_S,currentPlane,currentCoeff); glutPostRedisplay();

break; case 'o': case 'O':

currentGenMode=GL_OBJECT_LINEAR; currentPlane=GL_OBJECT_PLANE; glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,currentGenMode); glTexGenfv(GL_S,currentPlane,currentCoeff); glutPostRedisplay();

break; case 's': case 'S':

currentCoeff=slanted; glTexGenfv(GL_S,currentPlane,currentCoeff); glutPostRedisplay();

break; case 'x': case 'X':

currentCoeff=xequalzero; glTexGenfv(GL_S,currentPlane,currentCoeff); glutPostRedisplay();

break;

}

}

int main(int argc, char **argv)

{

glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(350,350); glutInitWindowPosition(100,100); glutCreateWindow("Automatic Texture-Coordinate Generation"); init();

glutDisplayFunc(display);

glutReshapeFunc(reshape);

glutKeyboardFunc(keyboard);

glutMainLoop(); return 0;

}

Вы можете включить автоматический расчет s-координат текстур, передав аргумент GL_TEXTURE_GEN_S команде glEnable(). Для автоматической генерации координат t, r или q нужно передать той же команде аргументы GL_TEXTURE_GEN_T, GL_TEXTURE_GEN_R или GL_TEXTURE_GEN_Q соответственно. Для выключения генерации координат текстуры используйте glDisable() с теми же аргументами.

Функция GL_OBJECT_LINEAR вычисляет координаты текстуры в координатной системе модели. В примере 9-8 изначально используется функция GL_OBJECT_LINEAR, и линии контура остаются перпендикулярными основанию чайника независимо от того, как поворачивается чайник, и с какой стороны на него смотрят. Однако, если нажать клавишу ‘e’ режим генерирования координат изменится с GL_OBJECT_LINEAR на GL_EYE_LINEAR, и координаты будут рассчитываться относительно видовой координатной системы. (Нажатие на клавишу ‘o’ восстанавливает режим GL_OBJECT_LINEAR.) Если в качестве плоскости определена x=0, то линии контура на чайнике будут параллельны плоскости yz относительно точки наблюдения, как

показано на рисунке 9-17. Говоря математически, вектор умножается на матрицу обратную к видовой для получения значений, используемых для вычисления дистанции до плоскости. Координаты текстуры генерируются следующей функцией:

сгенерированная координата = , где

.

В этом случае -- это видовые координаты вершины, а величины передаются в аргументе param команды glTexGen*v() при pname,

установленным в GL_EYE_PLANE. Величины вычисляют только один раз в момент их передачи glTexGen*v(), так что эта операция вовсе не так затратна с точки зрения вычислений, как кажется с первого взгляда.

Рисунок 9-17. Красные контуры параллельны плоскости yz в видовых координатах

Во всех приведенных примерах для создания контуров использовалась только одна сгенерированная координата. Однако координаты s, t и (если необходимо) r могут генерироваться независимо, отражая дистанцию между одной, двумя или тремя разными плоскостями. Если правильно построить двумерную или трехмерную текстурную карту, два или три набора контуров можно будет наблюдать одновременно.

В качестве дополнительного усложнения вы можете смешивать генерирующие функции. Например, вы можете вычислять sкоординату с помощью GL_OBJECT_LINEAR, а tс использованием GL_EYE_LINEAR.

9.5.2 Наложение изображения окружающихся предметов

Целью наложения окружающей обстановки является визуализация предмета, как будто он идеально блестящий и гладкий, и цвета на его поверхности это цвета окружающих его объектов, отраженные в глаз наблюдателя. Другими словами, если вы смотрите на идеально отполированный, идеально отражающий серебряный объект в комнате, вы видите на нем отражение стен, пола и других предметов в комнате. (Классическим примером этой техники является изображение киборга T1000 из фильма Терминатор 2.) Объекты, отражения которых вы видите, зависят от точки наблюдения и углов поверхности серебряного объекта. Чтобы производить наложение окружающей обстановки, все, что вам нужно сделать это создать подходящую карту текстуры, а затем заставить OpenGL автоматически сгенерировать для вас текстурные координаты.

Наложение окружающей обстановки (environmental mapping) – это аппроксимация, основанная на предположении о том, что элементы обстановки находятся далеко в сравнении с блестящим отражающим объектом то есть маленький объект находится в большой комнате. При таком предположении для нахождения цвета точки на поверхности нужно выпустить луч из глаза наблюдателя в точку поверхности, а затем отразить его от поверхности. Направление отраженного луча полностью определяет цвет, который нужно нарисовать в точке отражения. Кодирование цвета для каждого

направления на плоской текстурной карте эквивалентно помещению полированной сферы без изъянов в центр окружения и снятию с нее фотографии с помощью камеры, имеющей линзы с очень большой фокальной длиной и находящейся далеко от сферы. Говоря математически, линзы имеют бесконечно большую фокальную длину, а камера бесконечно удалена от сферы. Таким образом, кодирование покрывает циркулярный регион текстурной карты, находящийся вплотную к ее верхнему, нижнему, правому и левому краям. Величины вне этого круга не важны, поскольку при наложении обстановки доступ к ним никогда не осуществляется (они попросту не нужны).

Для получения абсолютно правильной карты обстановки, вам нужно раздобыть большую серебристую сферу, снять с нее фотографию в некоторой обстановке с помощью камеры, расположенной бесконечно далеко и имеющей линзы с бесконечно большой фокальной длиной, и отсканировать эту фотографию. Для получения

приблизительно верного результата вы можете использовать отсканированную фотографию обстановки, снятую камерой, имеющей линзы с очень большим углом (рыбий глаз).

После того, как вы создали текстуру, разработанную для наложения окружающей обстановки, вам нужно активизировать соответствующий алгоритм OpenGL. Этот алгоритм находит точку на поверхности сферы, которая находится там же, где и точка

на поверхности визуализируемого отражающего объекта и закрашивает точку объекта цветом, находящимся в соответствующей точке сферы.

Чтобы автоматически сгенерировать координаты текстуры для поддержки наложения окружающей обстановки, используйте в программе следующий код:

glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T);

Константа GL_SPHERE_MAP создает правильные текстурные координаты для наложения обстановки. Как показано выше, вам нужно установить этот режим в обоих направлениях (s и t). Однако вам не требуется задавать никаких параметров для функции, генерирующей координаты текстуры.

Функция GL_SPHERE_MAP генерирует координаты текстуры в несколько шагов:

1.Пусть u это вектор единичной длины направленный из начала координат к вершине (в видовых координатах).

2.Пусть nтекущий вектор нормали после преобразования в видовые координаты.

3.Пусть r это вектор отражения , вычисляемый как .

4.Затем вычисляет промежуточная величина .

5.Наконец, координаты текстуры s и t вычисляются следующим образом:

и .

Естественно, что с помощью описанной техники на блестящих объектах можно получать не только изображения окружающих предметов, а вообще всего, чего угодно. Единственное условие необходима сферическая карта текстуры. На рисунке 9-18 слева изображена одна из вариаций фрактала Мальденброда, а справа то же самое изображение, преобразованное к сферическому виду с помощью одного из графических редакторов. На рисунке 9-19 показан результат наложения этого изображения на чайник Юта.

Рисунок 9-18. Изображение, преобразованное в сферическую карту текстуры

Рисунок 9-19. Изображение множества Мальденброда на чайнике Юта

9.6 Дополнительные возможности

Дополнительно: В данном разделе описано, как использовать стек текстурных матриц (и связанную с ним координату q), а также мультитекстурирование. Эти техники считаются весьма сложными и не понадобятся для большинства приложений.

9.6.1 Стек текстурных матриц

Точно так же как координаты вашей модели преобразуются матрицами до завершения визуализации, текстурные координаты умножаются на матрицу 4x4 до того как происходит наложение. По умолчанию текстурная матрица представляет собой

единичную, следовательно, заданные или автоматически сгенерированные координаты остаются неизменными. Однако, модифицируя текстурную матрицу в процессе перерисовки объекта, вы можете заставить текстуру двигаться по поверхности объекта, поворачиваться вокруг нее, растягиваться и сжиматься или формировать любую комбинацию всего перечисленного. Вообще говоря, поскольку текстурная матрица это обычная матрица 4x4, можно добиться даже эффекта перспективы.

На самом деле текстурная матрица является верхней матрицей текстурного стека, который, как минимум, должен иметь глубину 2 матрицы. Все стандартные команды манипуляций с матрицами glPushMatrix(), glPopMatrix(), glMultMatrix(), glRotate*() и другие могут применяться к текстурным матрицам. Чтобы изменить текущую текстурную матрицу, установите режим матрицы в GL_TEXTURE следующим образом:

glMatrixMode(GL_TEXTURE); /* войти в режим текстурной матрицы */ glRotated(...);

/*...другие манипуляции с матрицей...*/ glMatrixMode(GL_MODELVIEW);

9.6.1.1 Координата q

Математика четвертой текстурной координаты q похожа на математику координаты w из четверки (x, y, z, w) объектных координат. Когда четверка текстурных координат (s, t, r, q) умножается на матрицу текстуры, результирующий вектор (s’, t’, r’, q’) интерпретируется как четверка однородных координат текстуры. Другими словами текстурная карта индексируется величинами s’/q’, t’/q’ и r’/q’.

Вы можете использовать qв случаях, когда требуется более одного проекционного или перспективного преобразования. Например, предположим, что вы хотите смоделировать прожектор с неравномерным лучом, который ярче ближе к центру или имеет не круглую форму из-за линз. Вы можете эмулировать сияние такого луча на плоской поверхности, создав текстурную карту, которая соответствует форме и интенсивности света, и спроецировав ее на нужную поверхность с использованием проекционного преобразования. Проектирование конуса света на поверхности сцены

требует перспективного преобразования (), поскольку свет может появляться на поверхностях, которые неперпендикулярны его источнику. Второе перспективное преобразование необходимо потому, что наблюдатель видит сцену с другой (но тоже перспективной) точки наблюдения.

Другой пример может возникнуть в ситуации, когда в качестве текстуры должна использовать фотография, сама имеющая перспективу. Как и в случае с источником света, результирующее изображение зависит от комбинации двух перспективных преобразований.

9.6.2 Мультитекстурирование

Во время стандартного текстурирования на полигон накладывается единственное изображение текстуры. В OpenGL версии 1.2 появилось мультитекстурирование,

которое позволяет накладывать на один и тот же полигон несколько текстур одну за одной.

Мультитекстурирование это опциональное расширение. Таким образом, несмотря на то, что оно было одобрено OpenGL Architecture Review Board (ARB – совет по рассмотрению архитектуры OpenGL), который является управляющим органом по всем вопросам, связанным с OpenGL, реализация OpenGL версии 1.2 не обязательно поддерживает мультитекстурирование.

Если ваша реализация поддерживает мультитекстурирование, у вас в распоряжении имеется серия текстурных блоков или модулей (texture units), каждый из которых

производит одну операцию текстурирования и передает свой результат в следующий текстурный блок. Так происходит до тех пор, пока все определенные текстурные блоки не завершат свои операции. Рисунок 9-20 показывает, как фрагмент претерпевает 4 текстурные операции по одной на каждый текстурный блок.

Рисунок 9-20. Конвейер мультитекстурирования

Мультитекстурирование позволяет применять усложненные техники визуализации, такие как световые эффекты, композиция и детализированные текстуры.

9.6.2.1 Мультитекстурирование по шагам

Для написания кода, использующего мультитекстурирование, нужно выполнить следующие шаги:

1.Проверьте, поддерживается ли расширение мультитекстурирования. Если оно не поддерживается, возможно, вам удастся достигнуть тех же результатов с помощью нескольких проходов визуализации. Чтобы выяснить какое количество текстурных блоков присутствует в вашей реализации, вызовите glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, ...). При наиболее плохом сценарии возвращенное число будет равно 1, что соответствует единственному текстурному блоку.

Замечание: Даже в случае, когда расширение поддерживается, в режиме отклика (feedback) результат мультитекстурирования не определен за пределами первого текстурного блока.

2.Установите нужное состояние текстурирования, включая изображение текстуры, фильтры, окружение, режим генерирования координат и матрицу, для каждого текстурного блока. Для смены текущего текстурного блока используйте команду glActiveTextureARB().

3.Задавая вершины, используйте glMultiTexCoord*ARB() чтобы задавать несколько наборов координат для разных текстур. В каждом текстурном блоке используется свой набор координат. Каждый набор текстурных координат будет использован в период текстурирования определенным текстурным блоком (в одном из нескольких проходов). Автоматическое генерирование координат и

передача координат в виде вершинного массива являются специальными случаями.

9.6.2.2 Настройка текстурных блоков

Мультитекстурирование предоставляет множественные текстурные блоки, которые производят дополнительные проходы по наложению текстуры. Каждый из текстурных блоков имеет одинаковые возможности и свое собственное состояние, включая:

изображение текстуры

параметры фильтрации

режимы наложения

стек текстурных матриц

функции автоматического генерирования текстурных координат

спецификацию вершинного массива (если она требуется).

Каждый текстурный блок комбинирует предыдущий цвет фрагмента со своим текстурным изображением в соответствии со своим состоянием. Результирующий цвет фрагмента поступает в следующий текстурный блок, если он активен.

Команда glActiveTextureARB() выбирает текущий модифицируемый текстурный блок, чтобы можно было изменять его состояние. После этого вызовы команд glTexImage*(), glTexParameter*(), glTexEnv*(), glTexGen*() и glBindTexture()

воздействуют только на текущий текстурный блок. Запрос значений переменных состояния текстурирования также возвращает значения из текущего текстурного блока,

также как запрос значений текущих координат текстуры и текущих растровых координат текстуры.

void glActiveTextureARB (GLenum texUnit);

Выбирает текстурный блок, который будет модифицироваться текстурными командами. texUnit это символическая константа в форме GL_TEXTUREi_ARB, где i должно иметь значение в диапазоне от 0 до k-1, где kмаксимальное число текстурных блоков.

Если вы используете объекты текстуры, вы можете связать текстуру с текущим текстурным блоком. Текущий текстурный блок будет иметь состояние, содержащееся в текстурном объекте (включая изображение текстуры).

Следующий пример кода в примере 9-9 имеет две части. В первой части создаются два обычных текстурных объекта (в предположении о том, что texelss0 и texels1 содержат изображения текстур). Во второй части два текстурных объекта используются для настройки двух текстурных блоков.

Пример 9-9. Инициализация текстурных блоков для мультитекстурирования

/* Создание обычных текстурных объектов */ GLuint texNames[2];

glGenTextures(2, texNames); glBindTexture(GL_TEXTURE_2D,texNames[0]); glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,32,32,0, GL_RGBA,GL_UNSIGNED_BYTE,texels0); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); glBindTexture(GL_TEXTURE_2D,texNames[1]); glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,16,16,0, GL_RGBA,GL_UNSIGNED_BYTE,texels1); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);

/* Использование 2 текстурных объектов для настройки 2 текстурных блоков, */ /* участвующих в мультитекстурировании */

glActiveTextureARB(GL_TEXTURE0_ARB); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,texNames[0]); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glMatrixMode(GL_TEXTURE);

glLoadIdentity();

glTranslatef(0.5,0.5,0.0);

glRotatef(45.0,0.0,0.0,1.0); glTranslatef(-0.5,-0.5,0.0); glMatrixMode(GL_MODELVIEW); glActiveTextureARB(GL_TEXTURE1_ARB); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,texNames[1]);

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

Результатом будет то, что текстурированный полигон при обработке будет визуализирован с использованием 2 текстурных блоков. В первом блоке накладывается текстура с изображением texels0, с фильтрацией GL_NEAREST, режимом присоединения GL_REPEAT, режимом наложения GL_REPLACE и поворачивающей текстурной матрицей. После завершения работы первого блока, уже текстурированный полигон направляется во второй блок текстуры (GL_TEXTURE1_ARB), где на него накладывается текстура с изображением texels1, режимом фильтрации GL_LINEAR, режимом присоединения GL_CLAMP_TO_EDGE, режимом наложения GL_MODULATE и текстурной матрицей по умолчанию.

Замечание: Операции по работе с группами атрибутов (с использованием команд glPushAttrib(), glPushClientAttrib(), glPopAttrib() или glPopClientAttrib())

сохраняют и восстанавливают состояние текстурирования для всех блоков текстуры (но не сохраняют стек текстурных матриц).

9.6.2.3 Указание вершин и их текстурных координат

При мультитекстурировании недостаточно задать один набор текстурных координат. Вам нужно иметь по одному набору для каждой вершины на каждый текстурный блок.

Вместо команды glTexCoord*() вы должны использовать команду glMultiTexCoord*ARB(), которая позволяет задать координаты текстуры и текстурный блок, к которому они относятся.

void glMultiTexCoord{1234}{sifd}ARB (GLenum texUnit, TYPE coords); void glMultiTexCoord{1234}{sifd}vARB (GLenum texUnit, TYPE *coords);

Устанавливает текстурные координаты (s, t, r, q) в значения, передаваемые в аргументе coords. Координаты будут использованы в текстурном блоке texUnit. Возможные значения для аргумента texUnitтакие же, как и в команде glActiveTextureARB().

В примере 9-10 треугольнику присваивается два набора текстурных координат, необходимых для мультитекстурирования с двумя активными текстурными блоками.

Пример 9-10. Указание вершин для мультитекстурирования

glBegin(GL_TRIANGLES); glMultiTexCoord2fARB(GL_TEXTURE0_ARB,0.0,0.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB,1.0,0.0); glVertex2f(0.0,0.0); glMultiTexCoord2fARB(GL_TEXTURE0_ARB,0.5,1.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB,0.5,0.0); glVertex2f(50.0,100.0); glMultiTexCoord2fARB(GL_TEXTURE0_ARB,1.0,0.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB,1.0,1.0); glVertex2f(100.0,0.0);

glEnd();

Замечание: Если вы используете мультитекстурирование и вызываете glTexCoord*(), вы устанавливаете значения координат для первого текстурного блока. Другими словами, использование glTexCoord*() эквивалентно использованию glMultiTexCoord*ARB(GL_TEXTURE0_ARB, ...).

В редких случаях, когда вы применяете мультитекстурирование к битовой карте или изображению, вам нужно ассоциировать несколько наборов текстурных координат с каждой позицией растра. То есть, вы должны вызвать glMultiTexCoord*ARB()

несколько раз, по одному на каждый активный текстурный блок для каждого вызова glRasterPos*(). (Поскольку для каждого изображения и битовой карты существует только одна позиция растра, может быть задано лишь по одному набору координат для каждого текстурного блока, что сильно ограничивает эстетические возможности.)

Если вы применяете мультитекстурирование и используете автоматическую генерацию текстурных координат, glActiveTextureARB() задает текстурный блок, на который воздействуют следующие команды:

glTexGen*(...);

glEnable(GL_TEXTURE_GEN_*);

glDisable(GL_TEXTURE_GEN_*);

Если вы применяете мультитекстурирование и передаете координаты текстуры в вершинном массиве, используйте команду glClientActiveTextureARB(), устанавливающую текстурный блок, для которого команда glTexCoordPointer() задает текстурные координаты.

void glCLientActiveTextureARB (GLenum texUnit);

Выбирает текстурный блок, для которого координаты текстуры задаются в вершинном массиве. texUnitэто символическая константа в форме GL_TEXTUREi_ARB, могущая принимать те же значения, что и в команде glActiveTextureARB().

Глава 10. Буфер кадра

Целью практически каждой графической программы является отображение изображений на экране. Экран представляет собой прямоугольный массив пикселей, каждый из которых способен отобразить миниатюрный квадрат цвета, соответствующий цвету точки изображения. После этапа растеризации (включая текстурирование и туман) данные все еще не являются пикселями они являются фрагментами. Каждый фрагмент имеет координаты, соответствующие пикселю, а также значения цвета и глубины. Далее каждый из фрагментов проходит через серию текстов и операций.

Если фрагмент переживает тесты и операции, он становится пикселем. Чтобы нарисовать пиксели, требуется знать какого они цвета. Эта информация сохраняется в цветовом буфере. Поскольку данные хранятся одинаково для каждого пикселя, хранилище всех пикселей и называется буфером. Разные буферы могут содержать различное количество информации на каждый пиксель, но внутри одного буфера на каждый пиксель приходится одинаковое количество информации. Буфер, который хранит по одному биту информации на каждый пиксель, называется битовой плоскостью.

Как показано на рисунке 10-1, нижний левый пиксель OpenGL– это пиксель (0, 0), что соответствует оконным координатам нижнего левого угла региона размером 1x1, занятого этим пикселем. Вообще пиксель с координатами (x, y) заполняет область, ограниченную слева x, справа x+1, снизу y, сверху y+1.

Рисунок 10-1. Область, занимаемая пикселем

Соседние файлы в предмете Компьютерная Графика