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

RedBook

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

формат

CE

TE

GL_ALPHA

 

не определена

GL_LUMINANCE

 

не определена

GL_LUMINANCE_ALP

 

не определена

HA

 

 

 

GL_INTENSITY

 

не определена

GL_RGB

 

 

GL_RGBA

 

 

Замечание: Замещающая текстурная функция (GL_REPLACE) просто берет цвет, которым объект был бы нарисован без текстурирования (цвет фрагмента), отбрасывает его и замещает цветом текстуры. Функцию замещения следует использовать в случаях, когда на объект нужно наложить непрозрачную текстуру.

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

При модуляции (GL_MODULATE) цвет фрагмента модулируется содержимым текстурной карты. Если базовый формат – GL_LUMINANCE, GL_LUMINANCE_ALPHA или

GL_INTENSITY, цветовые величины умножаются на одинаковую величину, и цветовая карта модулирует между цветом фрагмента (если светлота или интенсивность равны 1) и черным цветом (если они равны 0). Для форматов RGB и RGBA каждый из компонентов входящего цвета умножается на соответствующую (и, возможно, разную для разных компонентов) величину в карте текстуры. Если присутствует альфа, ото умножается на альфа фрагмента. Модуляция хороша для использования с освещением,

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

Текстурная функция наложения это единственная функция, которая использует цвет, задаваемый переменной состояния GL_TEXTURE_ENV_COLOR. Величина светлоты, интенсивности или цвета в каком-то смысле используется в качестве значения альфа для наложения GL_TEXTURE_ENV_COLOR на цвет фрагмента.

9.4.5.1Наложение зеркального цвета после текстурирования

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

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

результате зеркальный блик на освещенном и текстурированном объекте получается более четким.

9.4.6Назначение координат текстуры

Когда вы рисуете текстурированную сцену, вы должны предоставить для каждой вершины и объектные, и текстурные координаты. Объектные координаты после преобразований определяют место, где будет нарисована каждая вершина. Координаты текстуры задают, какой из тэкселей текстурной карты назначается этой вершине. Точно

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

Координаты текстуры могут включать в себя 1, 2, 3 или 4 элемента. Обычно на них ссылаются как на координаты s, t, r и q, чтобы отделить от объектных координат (x, y, z, w) и координат вычислителей (u, v). Для одномерных текстур используется только координата s; для двумерных используются s и t; для трехмерных s, t и r. Координате q, как и объектной координате w, обычно присваивается значение 1. Она может быть использована для создания одномерных координат. Команда для передачи координат текстуры glTexCoord*() похожа на glVertex*(), glColor*() и glNormal*() она

имеет те же вариации и используется таким же образом между парами glBegin() и glEnd(). Обычно величины координат текстуры ранжируются от 0 до 1, однако им можно присваивать значения и вне этого диапазона.

void glTexCoord{1234}{sifd} (TYPE coords); void glTexCoord{1234}{sifd}v (TYPE *coords);

Устанавливает текущие координаты текстуры (s, t, r, q). Последующие обращения к

команде glVertex*() ассоциируют с передаваемыми вершинами текущие координаты текстуры. При использовании команды glTexCoord1*() координата sустанавливается в передаваемую величину, t и r устанавливаются в 0, а qв 1. При использовании glTexCoord3*() q устанавливается в 1, в s, t и r в передаваемые значения. Все 4 координаты вы можете задать с помощью команды glTexCoord4*(). Используйте нужный суффикс (s, i, f или d) и соответствующее значение для TYPE (GLshort, GLint, GLfloat или GLdouble), чтобы задать тип данных для координат. Вы можете передавать координаты индивидуально или воспользоваться векторной версией команды, чтобы передать их в виде указателя на массив, который их содержит. До того, как будет выполнено наложение текстуры, текстурные координаты умножаются на текстурную матрицу размерности 4x4. Обратите внимание на то, что целые координаты интерпретируются непосредственно, а не отображаются на диапазон [-1; 1] как координаты нормалей.

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

9.4.7 Вычисление правильных координат текстуры

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

простейшем случае вы накладываете прямоугольную текстуру на прямоугольную же модель например, если ваша текстура представляет собой отсканированное изображение каменной стены, а полигон, на который она должна быть наложена прямоугольная стена здания. Предположим, что и стена и текстура имеют квадратную форму, и вы хотите наложить всю текстуру на всю стену. В порядке против часовой стрелки координаты текстуры будут (0,0), (1,0), (1,1), (1,0). Когда вы рисуете стену, просто передайте эти текстурные координаты в то же время, когда передаете координаты вершин в порядке против часовой стрелки.

Теперь предположим, что высота стены равна 2/3 ее ширины, а текстура по-прежнему квадратная. Чтобы избежать искажения текстуры, вам нужно наложить на стену только ее часть, сохранением пропорций изображения. Предположим, что для этого вы решили использовать нижние 2/3 изображения текстуры. В этом случае при передаче вершин в порядке против часовой стрелки используйте следующие координаты текстуры – (0,0), (1, 0), (1, 2/3), (0, 2/3).

В качестве более сложного примера, предположим, что вы хотите нарисовать тонкую консервную банку и наложить на нее текстуру с изображением этикетки. Чтобы это сделать, вы покупаете консервную банку, отделяете этикетку и сканируете ее. Предположим, что она имеет 4 единицы в высоту и 12 в ширину, что соответствует

пропорции размера 3 к 1. Поскольку текстуры должны иметь пропорции к 1, вы можете либо не использовать верхнюю треть текстуры, либо, скопировав, присоединить к левому (правому) краю текстуры ее часть с правого (левого) края шириной 4 единицы. Предположим, вы решили не использовать верхнюю треть. Пусть банка представляет собой цилиндр, аппроксимированный 30 полигонами по 4 единицы высотой (что составляет высоту банки) и шириной 12/30 (что составляет 1/30 длины окружности банки). Для каждого из аппроксимирующих прямоугольников вы можете использовать следующие координаты текстуры:

1:

(0,0)

(1/30,0)

(1/30,2/3)

(0,2/3)

2:

(1/30,0)

(2/30,0)

(2/30,2/3)

(1/30,2/3)

3:

(2/30,0)

(3/30,0)

(3/30,2/3)

(2/30,2/3)

...

 

 

 

 

30:

(29/30,0)

(1,0)

(1,2/3)

(29/30, 2/3)

 

 

 

 

 

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

Если вы не озабочены искажением текстуры, часто довольно просто найти приемлемое решение. Например, рассмотрим сферу, чьи координаты заданы в форме

, где и . Прямоугольная карта

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

Рисунок 9-11. Искажение текстурной карты

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

полигонами или криволинейные поверхности большое значение имеет артистический компонент.

9.4.8 Повторение и подтягивание текстуры

Вы можете задавать текстурные координаты за пределами диапазона [0,1], в результате чего текстура будет повторена или подтянута. В режиме повторения, если у вас есть большая плоскость, текстурные координаты на которой варьируются от 0.0 до 10.0 в обоих направления, вы получите 100 копий текстуры, расположенных на экране вплотную друг к другу (по аналогии с паркетом или кусками линолеума). В процессе повторения целые части текстурных координат игнорируются, и копии заполняют поверхность. Для большинства приложений, использующих повторение текстуры, тэксели в верхнем и нижнем рядах текстуры должны совпадать, то же касается и левого и правого столбца.

Другой возможность является подтягивание текстурных координат: любые величины больше 1.0 устанавливаются равными 1.0, любые величины меньше 0.0 устанавливаются в 0.0. Подтягивание полезно для приложений, в которых требуется, чтобы одна копия текстуры покрывала большую площадь. Если текстурные координаты поверхности варьируются от 0.0 до 10.0 в обоих направлениях, появится только одна копия текстуры в левом нижнем углу поверхности.

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

Если вы выбрали GL_LINEAR в качестве метода фильтрации, для наложения текстуры используется взвешенная комбинация цветовых данных из массива 2x2 (для двумерных текстур). Если присутствует граница или цвет границы, то текстура и этот цвет используются вместе следующим образом:

В режиме прикрепления GL_REPEAT граница всегда игнорируется. Массив взвешенных тэкселей размерности 2x2 прикрепляется к противоположному краю текстуры. Таким образом, тэксели на правом краю усредняются с теми, что находятся на левом. То же касается тэкселей на верхнем и нижнем краях.

В режиме крепления GL_CLAMP тэксели на границе (или тэксели цвета GL_TEXTURE_BORDER_COLOR) используются в массиве взвешенных тэкселей 2x2.

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

Заметьте, что если вы используете подтягивание, вы можете избежать воздействия текстуры на остаток поверхности. Чтобы добиться этого, используйте альфа равное 0 для тэкселей на краях текстуры (или на границе). Функция текстурирования GL_DECAL непосредственно использует альфа при вычислениях. Если вы используете другую текстурную функцию, вам, возможно, понадобиться использовать цветовое наложение.

Чтобы оценить эффекты разных режимов крепления текстуры, мы должны установить текстурные координаты за пределами диапазона [0.0, 1.0]. Начнем с рассмотрения примера 9-1, модифицировав код таким образом, чтобы при наложении текстуры на квадраты ее координаты изменялись от 0.0 до 3.0.

glBegin (GL_QUADS);

glTexCoord2f (0.0,0.0); glVertex3f(-2.0,-1.0,0.0); glTexCoord2f (0.0,3.0); glVertex3f(-2.0,1.0,0.0); glTexCoord2f (3.0,3.0); glVertex3f(0.0,1.0,0.0); glTexCoord2f (3.0,0.0); glVertex3f(0.0,-1.0,0.0);

glTexCoord2f (0.0,0.0); glVertex3f(1.0,-1.0,0.0); glTexCoord2f (0.0,3.0); glVertex3f(1.0,1.0,0.0); glTexCoord2f (3.0,3.0); glVertex3f(2.41421,1.0, -1.41421); glTexCoord2f (3.0,0.0); glVertex3f(2.41421,-1.0, 2.41421); glEnd();

Результат работы этого кода в режиме прикрепления GL_REPEAT показан на рисунке 9- 12.

Рисунок 9-12. Повторение текстуры

В этом случае текстура повторяется в направлении s, и в направлении t, поскольку в тексте присутствуют два вызова:

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);

Если в каждом из направлений использовать GL_CLAMP вместо GL_REPEAT, вы получите нечто похожее на рисунок 9-13.

Рисунок 9-13. Подтягивание текстуры

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

Рисунок 9-14. Повторение и подтягивание текстуры

Теперь вы изучили все аргументы команды glTexParameter*(). Они перечислены в следующей таблице.

void glTexParameter{if} (GLenum target, GLenum pname, TYPE param); void glTexParameter{if}v (GLenum target, GLenum pname, TYPE *param);

Устанавливает различные параметры, управляющие тем, как обрабатывается текстура в процессе наложения на фрагмент или сохранения в текстурном объекте. Аргумент target может принимать значения GL_TEXTURE_1D, GL_TEXTURE_2D или

GL_TEXTURE_3D, индицируя размерность текстур, параметр которых изменяется. Возможные значения для pname и param перечислены в таблице 9-5. Вы можете

использовать векторную версию команды для установки параметра GL_TEXTURE_BORDER_COLOR или задавать индивидуальные значения других параметров с помощью невекторной версии. Если значения передаются как целые, они преобразуются в формат с плавающей точкой согласно таблице 4-1; они также приводятся к диапазону [0, 1].

Таблица 9-5. Параметры, устанавливаемые glTexParameter*()

Параметр

Возможные значения

GL_TEXTURE_WRAP_S

GL_CLAMP, GL_REPEAT, GL_CLAMP_TO_EDGE

GL_TEXTURE_WRAP_T

GL_CLAMP, GL_REPEAT, GL_CLAMP_TO_EDGE

GL_TEXTURE_WRAP_R

GL_CLAMP, GL_REPEAT, GL_CLAMP_TO_EDGE

GL_TEXTURE_MAG_FILTER

GL_NEAREST, GL_LINEAR

 

GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST,

GL_TEXTURE_MIN_FILTER

GL_NEAREST_MIPMAP_LINEAR,GL_LINEAR_MIPMAP_NEAREST,

 

GL_LINEAR_MIPMAP_LINEAR

 

 

GL_TEXTURE_BORDER_COLOR

любые 4 величины в диапазоне [0.0, 1,0]

GL_TEXTURE_PRIORITY

[0.0, 1.0] для текущего текстурного объекта

GL_TEXTURE_MIN_LOD

любое число с плавающей точкой

GL_TEXTURE_MAX_LOD

любое число с плавающей точкой

GL_TEXTURE_BASE_LEVEL

любое число с плавающей точкой

GL_TEXTURE_MAX_LEVEL

любое число с плавающей точкой

 

 

9.5 Автоматическое генерирование текстурных координат

Вы можете использовать текстурирование для создания контуров ваших моделей или для имитации отражения от окружающих предметов на блестящих поверхностях. Чтобы добиться этих результатов, позвольте OpenGL автоматически генерировать для вас координаты текстуры вместо того, чтобы задавать их непосредственно командой glTexCoord*(). Для автоматического генерирования текстурных координат используйте команду glTexGen*().

void glTexGen{ifd} (GLenum coord, GLenum pname, TYPE param); void glTexGen{ifd}v (GLenum coord, GLenum pname, TYPE *param);

Задает функцию для автоматического вычисления текстурных координат. Первый аргумент coordможет принимать значения GL_S, GL_T, GL_R или GL_Q, указывая на то, какая из координат: s, t, r или q должна быть вычислена. Аргумент pname может принимать значения GL_TEXTURE_GEN_MODE, GL_OBJECT_PLANE, GL_EYE_PLANE, GL_SPHERE_MAP. Если задано значение GL_TEXTURE_GEN_MODE, param должен быть целым числом (или указателем на целое число, если используется векторная версия команды), которое равно GL_OBJECT_LINEAR, GL_EYE_LINEAR или GL_SPHERE_MAP. Эти символические константы указывают на то, какая функция должна использоваться для вычисления координат текстуры. Со всеми остальными возможными значениями для pname, param должен представлять собой указатель на массив величин (в векторной версии команды), задавая параметры функции вычисления текстурных координат.

Различные методы генерирования текстурных координат имеют различное назначение. Использование плоскости в объектных координатах лучше всего применять, если изображение текстуры должно оставаться фиксированным на движущемся объекте. Таким образом, GL_OBJECT_LINEAR может использоваться для наложения текстуры дерева на крышку стола. Использование плоскости в видовых координатах (GL_EYE_LINEAR) лучше всего использовать для создания динамических контурных линий на движущихся объектах. GL_EYE_LINEAR может быть использована специалистами по геодезии, работающими с нефтью и газом. По мере того как скважина уходит глубже в землю, она может быть нарисована разными цветами, чтобы показать слои камня на разных глубинах. GL_SPHERE_MAP главным образом используется для создания наложения окружающей обстановки (environmental mapping).

9.5.1 Создание контуров

Когда заданы GL_TEXTURE_GEN_MODE и GL_OBJECT_LINEAR, функция вычисления текстурных координат это линейная комбинация объектных координат вершины

:

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

Величины передаются в аргументе param команды glTexGen*v() при pname, установленным в GL_OBJECT_PLANE. При правильно нормализованных

функция дает дистанцию от вершины до плоскости. Например, если , а

, функция дает дистанцию между вершиной и плоскостью x=0. Дистанция положительна на одной стороне плоскости, отрицательна на другой и равна 0, если вершина лежит в этой плоскости.

В самом начале в примере 9-8 на чайнике с равными пропусками рисуются контурные линии; линии показывают дистанцию от плоскости x=0. Коэффициенты для плоскости x=0 находятся в массиве:

GLfloat xequalzero[]={1.0,0.0,0.0,0.0};

В данном случае вычисляется только 1 величина (дистанция от плоскости), что позволяет наложить одномерную текстуру. Текстура полностью зеленая, однако, через равные промежутки времени на ней помещены красные маркеры. Поскольку чайник как бы стоит на плоскости xy, все контуры перпендикулярны его основанию. Изображение нарисованное программой показано на рисунке 9-15.

Рисунок 9-15. Красные контуры параллельны плоскости x=0

В этом же примере нажатие на клавишу ‘s’ изменяет параметры плоскости:

GLfloat stanted[]={1.0,1.0,1.0,0.0};

Теперь красные контуры параллельны плоскости x+y+z=0. Соответствующее изображение показано на рисунке 9-16. Чтобы восстановить уравнение, соответствующее плоскости x=0, нажмите клавишу ‘x’.

Рисунок 9-16. Красные контуры параллельны плоскости x+y+z=0

Пример 9-8. Автоматическое генерирование координат текстуры: файл texgen.cpp

#include <glut.h>

#define stripeImageWidth 32

GLubyte stripeImage[4*stripeImageWidth];

GLuint texName;

void makeStripeImage()

{

int j;

for(j=0;j<stripeImageWidth;j++)

{

stripeImage[4*j]=(GLubyte) ((j<=4) ? 255 : 0); stripeImage[4*j+1]=(GLubyte) ((j>4) ? 255 : 0); stripeImage[4*j+2]=(GLubyte) 0; stripeImage[4*j+3]=(GLubyte) 255;

}

}

GLfloat xequalzero[]={1.0,0.0,0.0,0.0};

GLfloat slanted[]={1.0,1.0,1.0,0.0};

GLfloat *currentCoeff;

GLenum currentPlane;

GLint currentGenMode;

void init()

{

glClearColor(0.0,0.0,0.0,0.0); glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH);

makeStripeImage(); glPixelStorei(GL_UNPACK_ALIGNMENT,1);

glGenTextures(1,&texName); glBindTexture(GL_TEXTURE_1D,texName);

glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

glTexImage1D(GL_TEXTURE_1D,0,GL_RGBA,stripeImageWidth,0, GL_RGBA,GL_UNSIGNED_BYTE,stripeImage);

glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);

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

glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_1D); glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); glFrontFace(GL_CW); glCullFace(GL_BACK); glMaterialf(GL_FRONT,GL_SHININESS,64.0);

}

void display()

{

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glPushMatrix();

glRotatef(45.0,0.0,0.0,1.0); glBindTexture(GL_TEXTURE_1D,texName); glutSolidTeapot(2.0);

glPopMatrix();

glFlush();

}

void reshape(int w, int h)

{

glViewport(0,0,(GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity();

if (w<=h) glOrtho(-3.5,3.5,-3.5*(GLfloat)h/(GLfloat)w, 3.5*(GLfloat)h/(GLfloat)w,-3.5,3.5);

else glOrtho(-3.5*(GLfloat)w/(GLfloat)h,

3.5*(GLfloat)w/(GLfloat)h,-3.5,3.5,-3.5,3.5); glMatrixMode(GL_MODELVIEW); glLoadIdentity();

}

void keyboard(unsigned char key,int x, int y)

{

switch(key)

{

case 'e': case 'E':

currentGenMode=GL_EYE_LINEAR; currentPlane=GL_EYE_PLANE; glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,currentGenMode);

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