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

RedBook

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

glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST);

}

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

void display(void)

{

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

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,-0.5*(GLfloat)h/(GLfloat)w,0.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();

}

int main(int argc, char **argv)

{

glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(500,500); glutInitWindowPosition(100,100); glutCreateWindow("Rendering a Lit Sphere");

init();

glutDisplayFunc(display);

glutReshapeFunc(reshape);

glutMainLoop(); return 0;

}

Вызовы команд, связанных с освещением помещены в функцию init(). Эти вызовы коротко обсуждают в следующих параграфах и более детально позже в этой главе. Один из моментов, связанных с примером 5-1, который стоит отметить, заключается в том, что используется цветовой режим RGBA, а не индексный. OpenGL по-разному рассчитывает освещенность для этих двух режимах, и, вообще говоря, возможности освещения в индексном режиме весьма ограничены. Таким образом, если вам необходимо освещение, режим RGBAболее предпочтителен, и во всех примерах этой главы используется именно он.

5.3.1 Определение вектора нормали для каждой вершины каждого объекта

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

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

GL_RESCALE_NORMAL.

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

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

Замечание: Некоторые реализации OpenGL могут выполнять операцию GL_RESCALE_NORMAL не за счет простого масштабирования, а путем все той же полной нормализации (GL_NORMALIZE). Однако не существует способа выяснить так ли это в вашей реализации, и, в любом случае, вы не должны полагаться на это.

5.3.2 Создание, позиционирование и включение одного или более источников света

В примере 5-1 используется всего один источник белого света. Его местоположение задается вызовом команды glLightfv(). В этом примере для нулевого источника света (GL_LIGHT0) задается белый цвет для диффузного и зеркального отражения. Если вам требуется свет другого цвета, измените параметры glLight*().

Кроме того, вы можете добавить к вашей сцене как минимум 8 источников света различных цветов. (Конкретная реализация OpenGL может позволять и больше 8-ми источников.) По умолчанию цвет всех источников света кроме GL_LIGHT0 – черный. Вы можете располагать источники света везде, где только захотите, например, близко к сцене (как настольную лампу) или бесконечно далеко за ней (симулирую солнечный свет). Кроме того, вы можете управлять тем, испускает ли источник сфокусированный, узкий луч или более широкий. Помните, что каждый источник света требует дополнительных (и немалых) расчетов для отображения сцены, так что быстродействие вашего приложение зависит от количества источников.

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

5.3.3 Выбор модели освещения

Как вы можете ожидать, параметры модели освещения описываются командой glLightModel*(). В примере 5-1 единственным задаваемым параметром модели освещения является глобальное фоновое освещение. Модель освещения также позволяет указывать, где находится предполагаемое местоположение наблюдателя: бесконечно далеко или локально по отношению к сцене, и должны ли вычисления производиться по-разному для лицевых и обратных поверхностей объектов. В примере 5-1 используются значения по умолчанию для двух аспектов модели наблюдатель находится бесконечно далеко (режим «бесконечно удаленного наблюдателя») и одностороннее освещение. Использование режима «локального наблюдателя» заставляет производить намного больший объем сложных расчетов, так как OpenGL должна вычислить угол между точкой наблюдения и каждым объектом. В режиме «бесконечно удаленного наблюдателя», однако, этот угол игнорируется, и результат может быть несколько менее реалистичным. Далее, поскольку в примере 5-1 обратная поверхность сферы никогда не видна (она находится внутри сферы), достаточно одностороннего освещения.

5.3.4 Определение свойств материала для объектов сцены

Свойства материала объектов определяют, как он отражает свет и, таким образом, из какого реального материала он сделан (в зрительном восприятии). Поскольку

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

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

5.3.5 Несколько важных замечаний

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

5.4 Создание источников света

Источники света имеют несколько параметров, таких как цвет, позиция и направление. Следующие разделы объясняют, как контролировать эти свойства, на что будет похож результирующий источник света. Команда, используемая для указания всех параметров света это glLight*(). Она принимает три аргумента: идентификатор источника света, имя свойства и желаемое для него значение.

void glLight{if} (GLenum light, GLenum pname, TYPE param); void glLight{if}v (GLenum light, GLenum pname, TYPE *param);

Создает источник, задаваемый параметром light (который может принимать значения

GL_LIGHT0, GL_LIGHT1, ..., GL_LIGHT7). Задаваемая характеристика света определяется аргументом pname в виде константы (таблица 5-1). В параметре param задается значение или значения, в которые следует установить характеристику pname. Если используется векторная версия команды, param представляет собой вектор величин, а если невекторная, то param одно единственное значение. Невекторная версия команды может использоваться только для указания параметров, чье значение выражается одним числом.

Таблица 5-1. Значения по умолчанию для свойств источника света

Имена параметров

Значения по

Смысл

умолчанию

 

 

GL_AMBIENT

(0.0,0.0,0.0,1.0)

Интенсивность фонового света

 

(1.0,1.0,1.0,1.0)

Интенсивность диффузного света (значение по

GL_DIFFUSE

или

умолчанию для 0-го источника - белый свет, для

 

(0.0,0.0,0.0,1.0)

остальных - черный)

 

(1.0,1.0,1.0,1.0)

Интенсивность зеркального света (значение по

GL_SPECULAR

или

умолчанию для 0-го источника - белый свет, для

 

(0.0,0.0,0.0,1.0)

остальных - черный)

GL_POSITION

(0.0,0.0,1.0,0.0)

Положение источника света (x,y,z,w)

GL_SPOT_DIRECTION

(0.0,0.0,-1.0)

Направление света прожектора (x,y,z)

GL_SPOT_EXPONENT

0.0

Концентрация светового луча

GL_SPOT_CUTOFF

180.0

Угловая ширина светового луча

GL_CONSTANT_ATTENUATION

1.0

Постоянный фактор ослабления

GL_LINEAR_ATTENUATION

0.0

Линейный фактор ослабления

 

 

 

GL_QUADRATIC_ATTENUATION 0.0

Квадратичный фактор ослабления

 

 

Замечание: Значения по умолчанию для GL_DIFFUSEи GL_SPECULAR в таблице 5-1 различаются для GL_LIGHT0 и других источников света (GL_LIGHT1, GL_LIGHT2,

...). Для параметров GL_DIFFUSEи GL_SPECULAR источника света GL_LIGHT0

значение по умолчанию – (1.0, 1.0, 1.0, 1.0). Для других источников света значение тех же параметров по умолчанию – (0.0, 0.0, 0.0, 1.0).

В примере 5-2 показано, как использовать glLight*():

Пример 5-2. Указание цветов и позиции для источников света

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

GLfloat light_diffuse[]={1.0,1.0,1.0,1.0};

GLfloat light_specular[]={1.0,1.0,1.0,1.0};

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

glLightfv(GL_LIGHT0,GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0,GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0,GL_SPECULAR, light_specular); glLightfv(GL_LIGHT0,GL_POSITION, light_position);

Как вы можете видеть, для величин параметров определены массивы, и для установки этих параметров несколько раз вызывается команда glLightfv(). В этом примере первые три вызова glLightfv() являются избыточными, поскольку они используются для указания таких же значений параметров GL_AMBIENT, GL_DIFFUSE и GL_SPECULAR, какие установлены по умолчанию.

Замечание: Помните, что каждый источник света нужно включить командой glEnable().

Все параметры команды glLight*() и их возможные значения описываются в следующих разделах. Эти параметры взаимодействуют с параметрами модели освещения конкретной сцены и параметрами материала объектов.

5.4.1 Цвет

OpenGL позволяет вам ассоциировать с каждым источником света три различных параметра, связанных с цветом: GL_AMBIENT, GL_DIFFUSEи GL_SPECULAR. Параметр

GL_AMBIENT задает RGBA интенсивность фонового света, который каждый отдельный источник света добавляет к сцене. Как вы можете видеть в таблице 5-1, по умолчанию источник сета не добавляет к сцене фонового света, так как значение по умолчанию для GL_AMBIENT равно (0.0, 0.0, 0.0, 1.0). Именно эта величина была использована в примере 5-1. Если бы для того же источника света был задан синий фоновый свет,

GLfloat light_ambient[]={0.0,0.0,1.0,1.0}; glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);

то результат был бы таким, какой показан на рисунке 5-2.

Рисунок 5-2. Сфера, освещенная одним источником, добавляющим синий фоновый свет

Параметр GL_DIFFUSE наверное наиболее точно совпадает с тем, что вы привыкли называть «цветом света». Он определяет RGBA цвет диффузного света, который отдельный источник света добавляет к сцене. По умолчанию для GL_LIGHT0 параметр GL_DIFFUSE равен (1.0, 1.0, 1.0, 1.0), что соответствует яркому белому свету. Значение по умолчанию для всех остальных источников света (GL_LIGHT1, GL_LIGHT2, ..., GL_LIGHT7) равно (0.0, 0.0, 0.0, 0.0).

Параметр GL_AMBIENT влияет на цвет зеркального блика на объекте. В реальном мире

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

GL_SPECULAR в то же значение, что и GL_DIFFUSE. По умолчанию GL_SPECULAR равно (1.0, 1.0, 1.0, 1.0) для GL_LIGHT0 и (0.0, 0.0, 0.0, 0.0) для остальных источников.

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

5.4.2 Позиция и ослабление

Как было отмечено ранее, вы можете выбрать, следует ли считать источник света расположенным бесконечно далеко от сцены или близко к ней. На источники света первого типа ссылаются как на направленные (directional): эффект от бесконечно далекого расположения источника заключается в том, что все лучи его света могут считаться параллельными к моменту достижения объекта. Примером реального направленного источника света может служить солнце. Источники второго типа называются позиционными (positional), поскольку их точное положение на сцене определяет их эффект и, в частности, направление из которого идут лучи. Примером позиционного источника света является настольная лампа. Свет, используемый в примере 5-1, является направленным:

GLfloat light_position[]={1.0,1.0,1.0,0.0}; glLightfv(GL_LIGHT0, GL_POSITION, light_position);

Как видно, для параметра GL_POSITION вы задаете вектор из четырех величин (x, y, z, w). Если последняя величина w равна 0, соответствующий источник света считается направленным, и величины (x, y, z) определяют его направление. Это направление преобразуется видовой матрицей. По умолчанию параметру GL_POSITION соответствуют значения (0, 0, 1, 0), что задает свет, направленный вдоль отрицательного направления оси z. (Заметьте, что никто не запрещает вам создать свет, направленный в (0, 0, 0), однако такой свет не даст должного эффекта).

Если значение w не равно 0, свет является позиционным, и величины (x, y, z) задают его местоположение источника света в однородных объектных координатах. Это

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

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

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

,

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

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

По умолчанию равно 1.0, а и - 0.0, но вы можете задавать для этих коэффициентов другие значения:

glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 2.0); glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 1.0); glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.5);

Заметьте, что ослабляются и фоновая, и диффузная, и зеркальная интенсивности.

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

5.4.3 Прожектора

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

Рисунок 5-3. Параметр GL_SPOT_CUTOFF

Заметьте, что свет не излучается за ребрами конуса. По умолчанию, работа с прожекторами заблокирована, так как параметр GL_SPOT_CUTOFF равен 180.0. Эта величина означает, что свет излучается во всех направлениях (угол при вершине равен 360 градусам, что вообще не определяет конус). Значения для GL_SPOT_CUTOFF должны попадать в диапазон [0.0, 90.0] (значение также может быть равно специальной величине 180.0). Следующая строка устанавливает параметр

GL_SPOT_CUTOFF равным 45 градусам:

glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 45.0);

Вам также требуется задать направление прожектора, которое определяет центральную ось светового конуса:

GLfloat spot_direction[] = {-1.0, -1.0, 0.0}; glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);

Направление указывается в объектных координатах. По умолчанию направление – (0.0, 0.0, -1.0), так что если вы явно не изменяете параметр GL_SPOT_DIRECTION, источник света направлен вдоль отрицательного направления оси z. Также имейте в виду, что направление прожектора преобразуется видовой матрицей также, как если бы это был вектор нормали, и результат сохраняется в видовых координатах.

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

равен 0), чтобы управлять концентрацией света. Свет имеет самую высокую интенсивность в центре конуса. При движении от центра к ребрам он ослабляется с

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

5.4.4 Несколько источников света

Как было отмечено, у вас на сцене может быть как минимум восемь источников света (возможно больше, но это зависит от реализации OpenGL). Поскольку OpenGL проводит вычисления для того, чтобы определить, сколько света получает каждая вершина от каждого источника, увеличение источников слета весомо влияет на быстродействие. Константы, используемые для ссылки на 8 источников света это GL_LIGHT0, GL_LIGHT1, GL_LIGHT2, GL_LIGHT3 и так далее. В предыдущих обсуждениях параметры устанавливались для источника GL_LIGHT0. Если вам требуются дополнительные источники света, вы должны задать и их параметры. Также помните, что значения параметров по умолчанию не совпадают для GL_LIGHT0 и других источников. В примере 5-3 определяется белый ослабевающий прожектор:

Пример 5-3. Второй источник света

GLfloatlight_ambient[]={0.2,0.2,0.2,1.0};

GLfloat light_diffuse[]={1.0,1.0,1.0,1.0};

GLfloat light_specular[]={1.0,1.0,1.0,1.0};

GLfloat light_position[]={-2.0,2.0,1.0,1.0};

GLfloat spot_direction[]={-1.0,-1.0,0.0};

glLightfv(GL_LIGHT1,GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT1,GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT1,GL_SPECULAR, light_specular); glLightfv(GL_LIGHT1,GL_POSITION, light_position); glLightf(GL_LIGHT1,GL_CONSTANT_ATTENUATION, 1.5); glLightf(GL_LIGHT1,GL_LINEAR_ATTENUATION, 0.5); glLightf(GL_LIGHT1,GL_QUADRATIC_ATTENUATION, 0.2); glLightf(GL_LIGHT1,GL_SPOT_CUTOFF, 45.0); glLightfv(GL_LIGHT1,GL_SPOT_DIRECTION, spot_direction); glLightf(GL_LIGHT1,GL_SPOT_EXPONENT, 2.0);

glEnable(GL_LIGHT1);

Если эти строки добавить в пример 5-1, сфера будет освещена двумя источниками: одним направленным и одним прожектором.

5.4.5 Управление позицией и направлением источников света

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

Позиция источника света остается фиксированной

Источник света движется вокруг неподвижного объекта

Источник света движется вместе с точкой наблюдения

5.4.5.1Стационарный источник света

В простейшем случае, как в примере 5-1, положение источника света не изменяется. Чтобы добиться этого эффекта, вам следует устанавливать позицию источника света после всех используемых видовых и/или модельных преобразований. Пример 5-4 демонстрирует, как может выглядеть соответствующий объединенный код из init() и reshape().

Пример 5-4. Стационарный источник света

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

if (w<=h) glOrtho(-1.5,1.5,-0.5*(GLfloat)h/(GLfloat)w,0.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();

//далее функции init()

GLfloat light_position[]={1.0,1.0,1.0,0.0}; glLightfv(GL_LIGHT0,GL_POSITION,light_position);

Как вы видите, сначала устанавливается порт просмотра и проекционная матрица. Затем в видовую матрицу загружается единичная, и только после этого задается положение источника света. Поскольку используется единичная матрица, явно установленное положение источника света – (1.0, 1.0, 1.0) не изменяется умножением на него видовой матрицы. После этого, поскольку на тот момент ни позиция источника, ни видовая матрица не изменены, направление света остается прежним – (1.0, 1.0, 1.0).

5.4.5.2Независимо движущийся источник света

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

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

Пример 5-5. Независимое движение источника света

GLdouble spin; void display()

{

GLfloat light_position[]={0.0,0.0,1.5,1.0}; glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glPushMatrix();

gluLookAt(0.0,0.0,5.0,0.0,0.0,0.0,0.0,1.0,0.0);

glPushMatrix();

glRotated(spin,1.0,0.0,0.0); glLightfv(GL_LIGHT0,GL_POSITION,light_position);

glPopMatrix();

glutSolidTorus(0.275,0.85,8,15);

glPopMatrix();

glFlush();

}

spin это глобальная переменная, значение которой, вероятнее всего, определяется устройством ввода. Функция display() вызывает перерисовку сцены с источником света обращенным вокруг неподвижного торуса на spinградусов. Заметьте, что две

пары команд glPushMatrix() и glPopMatrix() изолируют видовые и модельные преобразования. Поскольку в примере 5-5 точка наблюдения остается неизменной,

текущая матрица проталкивается в стек и далее требуемое видовое преобразование задается командой gluLookAt(). Далее получившаяся матрица снова проталкивается в стек перед указанием преобразования поворота командой glRotate(). Затем задается положение источника света в новой повернутой системе координат, таким образом,

источник света оказывается повернутым относительно своего первоначального положения. (Помните, что позиция источника света сохраняется в видовых координатах, получающихся после преобразования видовой матрицей.) Торус рисуется после того, как матрица выталкивается из стека. Пример 5-6 представляет собой листинг программы, поворачивающей источник света вокруг неподвижного объекта. При нажатии левой кнопки мыши угол поворота источника света увеличивается на 30 градусов. Позиция источника света представлена маленьким неосвещенным проволочным кубом.

Пример 5-6. Перемещение источника света с помощью модельных преобразований:

файл movelight.cpp

#include <glut.h> int spin=0;

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

{

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

}

void display(void)

{

GLfloat position[]={0.0,0.0,1.5,1.0};

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glPushMatrix();

glTranslatef(0.0,0.0,-5.0); glPushMatrix();

glRotated((GLdouble)spin,1.0,0.0,0.0); glLightfv(GL_LIGHT0,GL_POSITION,position); glTranslated(0.0,0.0,1.5); glDisable(GL_LIGHTING); glColor3f(0.0,1.0,1.0);

glutWireCube(0.1); glEnable(GL_LIGHTING);

glPopMatrix();

glutSolidTorus(0.275,0.85,40,40);

glPopMatrix();

glutSwapBuffers();

}

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

{

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

gluPerspective(40.0,(GLfloat)w/(GLfloat)h,1.0,20.0); glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

void light_moving(void)

{

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