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

RedBook

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

5.6.5 Режим цвета материала

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

void glColorMaterial (GLenum face, GLenum mode);

Для граней, заданных аргументом face, заставляет свойство (или свойства) материала, заданное аргументом mode, все время принимать значение текущего цвета. При изменении текущего цвета (командой glColor*()) указанные свойства материала также незамедлительно меняются. Аргумент face может принимать значения GL_FRONT, GL_BACKили GL_FRONT_AND_BACK (такое значение аргумент имеет по умолчанию).

Аргумент mode может принимать значения GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_AMBIENT_AND_DIFFUSE (значение по умолчанию) или GL_EMISSION. В каждый момент времени активным является только один из режимов. glColorMaterial() не работает при использовании освещения в индексном режиме.

Отметьте, что glColorMaterial() задает две независимые величины: первая определяет, свойства материала какого типа или типов граней изменяются с изменением текущего цвета, а вторая какие именно свойства материала изменяются. Однако OpenGL не следит за разными значениями аргумента mode для разных типов граней!

Помимо вызова glColorMaterial() вам требуется вызвать glEnable() с аргументом GL_COLOR_MATERIAL. После этого во время рисования вы можете изменять текущий цвет командой glColor*() (а также по необходимости другие свойства материала командой glMaterial*()).

glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT, GL_DIFFUSE);

//Теперь glColor*() будет изменять диффузное отражение glColor3f(0.2,0.5,0.8);

//Здесь мы рисуем несколько объектов glColorMaterial(GL_FRONT, GL_SPECULAR);

//Теперь glColor*() изменяет не диффузное, //а зеркальное отражение glColor3f(0.9,0.0,0.2);

//Рисуем еще несколько объектов glDisable(GL_COLOR_MATERIAL);

Используйте glColorMaterial() в тех случаях, когда для множества вершин на сцене вам требуется изменять значение единственного параметра материала. Если вам нужно постоянно изменять более одного свойства используйте glMaterial*(). Когда функциональность команды glColorMaterial() вам не требуется, обязательно убедитесь, что вы выключили данный механизм командой glDisable(). Это позволит вам избежать свойств материала, изменяющихся «по неизвестным причинам», а также снизит затраты производительности. Быстродействие приложения при работе с механизмом glColorMaterial() зависит от реализации OpenGL. Некоторые реализации

могут оптимизировать обработку вершин для ускоренного изменения свойств материала на базе текущего цвета.

Пример 5-10 представляет собой интерактивную программу, использующую команду glColorMaterial() для изменения свойств материала. Нажатие на любую из трех кнопок мыши изменяет цвет диффузного отражения.

Пример 5-10. Использование glColorMaterial(): файл colormat.cpp

#include <glut.h>

GLfloat diffuseMaterial[4]={0.0,0.0,0.0,1.0};

//Инициализация void init(void)

{

GLfloat mat_specular[4]={1.0,1.0,1.0,1.0}; GLfloat light_position[4]={1.0,1.0,1.0,0.0};

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

glMaterialfv(GL_FRONT,GL_DIFFUSE,diffuseMaterial); glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular); glMaterialf(GL_FRONT,GL_SHININESS,25.0); glLightfv(GL_LIGHT0,GL_POSITION,light_position); glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0); glColorMaterial(GL_FRONT,GL_DIFFUSE); glEnable(GL_COLOR_MATERIAL);

}

//Отображение

void display(void)

{

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glutSolidSphere(1.0,20,16);

glutWireCube(1.0);

glFlush();

}

//Изменение размеров окна void reshape(int w, int h)

{

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

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

10.0,10.0); else

glOrtho(-1.5*(GLfloat)w/(GLfloat)h,1.5*(GLfloat)w/(GLfloat)h,-1.5,1.5,- 10.0,10.0);

glMatrixMode(GL_MODELVIEW); glLoadIdentity();

}

//Реакция на мышь

void mouse(int button,int state, int x, int y)

{

switch(button)

{

case GLUT_LEFT_BUTTON:

if (state==GLUT_DOWN) // Изменяем красный

{

diffuseMaterial[0]+=0.1;

if (diffuseMaterial[0] > 1.0) diffuseMaterial[0]=0.0; glColor4fv(diffuseMaterial);

glutPostRedisplay();

}

break;

case GLUT_MIDDLE_BUTTON:

if (state==GLUT_DOWN) // Изменяем зеленый

{

diffuseMaterial[1]+=0.1;

if (diffuseMaterial[1] > 1.0) diffuseMaterial[1]=0.0; glColor4fv(diffuseMaterial);

glutPostRedisplay();

}

break;

case GLUT_RIGHT_BUTTON:

if (state==GLUT_DOWN) // Изменяем синий

{

diffuseMaterial[2]+=0.1;

if (diffuseMaterial[2] > 1.0) diffuseMaterial[2]=0.0; glColor4fv(diffuseMaterial);

glutPostRedisplay();

}

break;

default:

break;

}

}

int main(int argc, char **argv)

{

glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(500,500); glutInitWindowPosition(100,100); glutCreateWindow("Using glColorMaterial()");

init();

glutDisplayFunc(display);

glutReshapeFunc(reshape);

glutMouseFunc(mouse);

glutMainLoop(); return 0;

}

5.7 Математика освещения

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

В следующих уравнениях математические расчеты производятся отдельно для R, G и B компонент цвета. Таким образом, если в уравнении складываются три величины, следует понимать, что R величины, G величины и B величины складываются отдельно,

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

. (Помните, что значение компонента A или альфа

компонента цвета вершины равно значению диффузного альфа компонента материала этой вершины.)

Цвет освещенной вершины вычисляется следующим образом:

цвет вершины = исходящий цвет материала вершины + глобальный фоновый цвет, умноженный на значение фонового свойства

материала вершины + фоновые, диффузные и зеркальные вклады всех источников света,

ослабленные должным образом.

После расчета освещенности цветовые величины масштабируются в диапазон [0, 1] (в режиме RGBA).

Имейте в виду, что при расчете освещенности OpenGL не принимает в расчет возможность того, что один объект может загораживать свет для другого, как следствие

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

5.7.1 Исходящий свет материала

Исходящий свет является простейшим для расчета. Его значение равно параметру GL_EMISSION материала вершины.

5.7.2 Масштабированный глобальный фоновый свет

Числовая величина этого света вычисляется путем перемножения глобального фонового света (определенного параметром GL_LIGHT_MODEL_AMBIENT) на значение фонового свойства материала GL_AMBIENT, определенного командой glMaterial*():

Каждая пара R, G и B величин для этих двух параметров перемножается независимо, формируя результирующий RGB цвет .

5.7.3 Вклады источников света

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

вклад =фактор ослабления * прожекторный эффект * (фоновый вклад + диффузный вклад + зеркальный вклад)

5.7.3.1Фактор ослабления

Фактор ослабления был описан ранее в этой главе.

,

где d - расстояние между позицией источника света и вершиной, - GL_CONSTANT_ATTENUATION (постоянный фактор ослабления), - GL_LINEAR_ATTENUATION (линейный фактор ослабления),

- GL_QUADRATIC_ATTENUATION (квадратичный фактор ослабления).

Если источник света является направленным, фактор ослабления равен 1.

5.7.3.2Прожекторный эффект

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

1, если источник не является прожектором (параметр GL_SPOT_CUTOFFравен

180.0);

0, если источник света является прожектором, но вершина лежит вне его конуса излучения;

, где

-- единичный

вектор из прожектора в вершину; -- направление прожектора (GL_SPOT_DIRECTION), предполагается, что источник света является прожектором и вершина лежит внутри его конуса излучения. Скалярное произведение векторов v и d меняется в соответствии с косинусом угла между ними; таким образом, объекты на линии освещения получают максимум освещенности, объекты вне этой линии получают меньше света в соответствии с косинусом угла.

Для определения того, лежит ли вершина внутри конуса излучения прожектора OpenGL

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

5.7.3.3Фоновый вклад

Фоновый вклад представляет собой фоновый цвет источника, умноженный на фоновое свойство материала вершины:

5.7.3.4Диффузный вклад

Необходимо принимать в расчет диффузный вклад источника света независимо от того, падает ли свет непосредственно на вершину или нет. Он вычисляется как:

, где

-- единичные вектор, указывающий из вершины в направлении положения источника света (GL_POSITION).

-- вектор нормали единичной длины в вершине.

5.7.3.5Зеркальный вклад

Зеркальный вклад зависит от того, падает ли свет непосредственно на вершину. Если

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

Вершинная нормаль единичной длины .

Сумма двух векторов единичной длины: вектора между вершиной и положением источника света (или направлением источника света) и вектора между вершиной

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

получаем .

Зеркальный показатель (GL_SHININESS).

Зеркальный цвет источника света ().

Зеркальное свойство материала ().

OpenGL использует следующее уравнение для расчета зеркального вклада источника света (с учетом приведенного выше описания):

.

Однако, если , зеркальный вклад равен 0.

5.7.4 Суммирование всех элементов

Ссылаясь на определения, данные в предыдущих разделах, мы можем записать полное уравнение освещенности, используемое OpenGL в следующем виде:

5.7.5 Отделение зеркального цвета

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

первичный цвет = исходящий свет материала вершины + глобальное фоновое освещение, умноженное на фоновое свойство материала вершины +

фоновые и диффузные вклады всех источников света, ослабленные соответствующим образом.

вторичный цвет = зеркальные вклады всех источников света, ослабленные соответствующим образом.

Следующие два уравнения применяются OpenGL для расчета первичного и вторичного цветов:

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

5.8 Освещение в индексном цветовом режиме

В индексном режиме параметры, задаваемые RGBAвеличинами, либо не имеют эффекта, либо интерпретируются особым образом. Поскольку в индексном режиме намного сложнее достигнуть определенных эффектов, связанных с освещением, следует использовать RGBAрежим везде, где это возможно. Вообще говоря, в индексном режиме используется всего три параметра в форме RGBA. Более конкретно, используются параметры источника света GL_DIFFUSEи GL_SPECULAR, а также

параметр материала GL_SHININESS. GL_DIFFUSEи GL_SPECULAR ( и ,

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

, где

R(x), G(x) и B(x) представляют соответственно красный, зеленый и синий компоненты цвета x. Весовые коэффициенты 0.30, 0.59 и 0.11 отражают степень восприятия компонентов цвета человеческим глазом ваши глаза наиболее чувствительных зеленому и наименее чувствительны к синему цвету.

Чтобы задать цвета материала в индексном режиме, используйте glMaterial*() со специальным параметром GL_COLOR_INDEXES:

GLufloat mat_colormap[]={16.0,47.0,79.0}; glMaterialfv(GL_FRONT, GL_COLOR_INDEXES, mat_colormap);

Три числа заданные для GL_COLOR_INDEXES задают соответственно цветовые индексы фонового, диффузного и зеркального цветов материала. Другими словами OpenGL считает цвет с индексом, заданным в первом числе (в данном случае 16.0) чистым фоновым цветом, цвет с индексом, заданным во втором числе (47.0) чистым диффузным цветом, а цвет с индексом, заданным в третьем числе (79.0) – чистым зеркальным цветом. (По умолчанию фоновый цвет имеет индекс 0.0, а диффузный и зеркальный цвета индекс 1.0. Отметьте, что команда glColorMaterial() не работает в индексном режиме.)

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

for (i=0;i<32;i++)

{

glutSetColor(16+i,1.0*(i/32.0),0.0,1.0*(i/32.0));

glutSetColor(48+i,1.0,1.0*(i/32.0),1.0);

}

Команда glutSetColor() библиотеки GLUT принимает 4 аргумента. Она ассоциирует индекс, задаваемый первым аргументом с тройкой RGB, задаваемой вторым, третьим и четвертым аргументами. При i=0 цветовой индекс 16 ассоциируется с черным RGBцветом (0, 0, 0). Цветовая карта плавно строится до диффузного цвета материала с индексом 47 (при i=31), которому соответствует фиолетовый RGB цвет (1.0, 0.0, 1.0).

Вторая команда внутри цикла строит карту между фиолетовым диффузным цветом и белым зеркальным цветом (1.0, 1.0, 1.0) в индексе 79.

5.8.1 Математика освещения в индексном режиме

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

Начнем с диффузного и зеркального элементов из RGBAуравнений. В диффузном

элементе заменим на , вычисленное в предыдущем разделе для индексного режима. Аналогично, для зеркального элемента, вместо

подставим из предыдущего раздела. (Ослабление,

прожекторный эффект и другие компоненты этих элементов вычисляются также как в RGBAрежиме.) Назовем эти модифицированные элементы d и s соответственно. Теперь,

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

результирующего цвета будет равен .

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

числом , где nколичество битов на цвет в индексном буфере.

Глава 6. Цветовое наложение, сглаживание, туман и смещение полигонов

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

6.1 Цветовое наложение

Вы уже видели значения альфа компонента в четверке RGBA, но до этого момента они игнорировались. Альфа значения задаются при использовании команды glColor*(), при указании очищающего цвета командой glClearColor(), а также при определении некоторых параметров освещения, например, свойств материала или интенсивности освещения. Пиксели на мониторе излучают красный, зеленый и синий свет, а его количество контролируется соответствующими значениями красного, зеленого и синего. Так каким же образом значение альфа влияет на то, что будет нарисовано в окне на экране?

При включенном механизме цветового наложения, значение альфа часто используется

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

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

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

6.1 Цветовое наложение

Вы уже видели значения альфа компонента в четверке RGBA, но до этого момента они игнорировались. Альфа значения задаются при использовании команды glColor*(), при указании очищающего цвета командой glClearColor(), а также при определении некоторых параметров освещения, например, свойств материала или интенсивности освещения. Пиксели на мониторе излучают красный, зеленый и синий свет, а его количество контролируется соответствующими значениями красного, зеленого и синего. Так каким же образом значение альфа влияет на то, что будет нарисовано в окне на экране?

При включенном механизме цветового наложения, значение альфа часто используется

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

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

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

Замечание: Альфа – величины не задаются в индексном цветовом режиме, как следствие, цветовое наложение в этом режиме недоступно.

Наиболее близкий к реальности способ осознания операций с цветовым наложением заключается в том, чтобы думать о RGB– тройке, как о цвете фрагмента, а об альфа величине как о степени его непрозрачности (цветовой плотности). Прозрачные и полупрозрачные поверхности имеют плотность ниже, чем непрозрачные и, таким образом, обладают меньшем значением альфа. Например, если вы рассматриваете объект через зеленое стекло, его цвет будет частично зеленым (от стекла) и частично цветом самого объекта. Процентное соотношение этих цветов зависит от того, насколько хорошо стекло пропускает свет. Если оно пропускает 80% поступающего на него света (то есть стекло цветовую имеет плотность равную 20%), то цвет, который вы увидите, будет состоять на 20% из цвета стекла и на 80% из цвета объекта за ним. Вы

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

6.1.1 Факторы источника и приемника

Во время цветового наложения цветовые величины входящего фрагмента (источника) комбинируются с цветовыми величинами соответствующего, сохраненного к текущему моменту пикселя (приемника) в два этапа. Сначала вы задаете, каким образом следует вычислять факторы источника и приемника. Эти факторы представляют собой четверки RGBA, которые умножаются на R, G, B и A величины источника и приемника соответственно. Затем соответствующие компоненты в двух наборах RGBA четверок комбинируются между собой. Чтобы показать этот процесс с математической точки

зрения, обозначим факторы источника и приемника соответственно и

, а цветовые компоненты источника и приемника обозначим нижним индексом s или d соответственно. Тогда результирующие цветовые величины после цветового наложения могут быть получены из следующего уравнения:

.

Каждый компонент этой четверки приводится к диапазону [0,1].

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

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

glEnable(GL_BLEND);

Для выключения наложения следует использовать команду glDisable() с аргументом GL_BLEND. Также обратите внимание, что использование констант GL_ONE (для источника) и GL_ZERO (для приемника) дает те же результаты, что и при выключенном цветовом наложении (именно эти значения установлены для факторов по умолчанию).

void glBlendFunc (GLenum sfactor, GLenum dfactor);

Управляет тем, как цветовые величины обрабатываемого фрагмента (источника) комбинируются с теми, которые уже сохранены в буфере кадра (приемника). Аргумент sfactor задает метод вычисления фактора наложения источника; аргумент dfactor -- метод вычисления фактора наложения приемника. Возможные значения этих параметров перечислены в таблице 6-1. Вычисляемые факторы наложения лежат в диапазоне [0,1]; после того, как цветовые величины источника и приемника комбинируются, они также приводятся к диапазону [0,1].

Замечание: В таблице 6-1 RGBA величины источника, приемника и константных цветов индицируются нижним индексом s, d или c соответственно. Вычитание четверок, означает покомпонентное вычитание одного их набора из другого.

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