Строительство и ремонт

Opengl освещение. Основы освещения в OpenGL

Произведения годов. Волошин Максимилиан. ДОБЛЕСТЬ ПОЭТА. 1. Править поэму, как текст заокеанской депеши: Сухость, ясность, нажим - начеку каждое слово.

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

Вытравить из словаря слова «Красота», «Вдохновенье» - Подлый жаргон рифмачей Поэту - понятья: Правда, конструкция, план, равносильность, cжатость и точность. В трезвом, тугом ремесле - вдохновенье и честь поэта: В глухонемом веществе заострять запредельную зоркость. Волошин М.А. Библиотека: Орловская областная научная универсальная публичная библиотека им. И.А. Бунина. - М., ; Избранные произведения: В 2-х т.

М., ; Красный дым: Повести. - М., ; Гладышев из разведроты: Повести. - М., ; Эшелон; Неизбежность: Романы. Много занимался переводами марийских и удмуртских поэтов. Время от времени пробовал свои силы также в прозе. Соч. Максимилиан Александрович Волошин () - один из крупнейших поэтов первой трети XX века. Это талантливый художник, многогранный лирик, прошедший путь от символистских, эзотерических стихотворений к гражданско-публицистической и научно-философской поэзии, через антропософские пристрастия - к «идеалу Града Божия».

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

Общаться с единомышленниками! Писать отзывы, участвовать в поэтических дуэлях и конкурсах! Присоединяйтесь к лучшему! Спасибо, что присоединились к Поэмбук! На вашу почту отправлено письмо с данными доступа к аккаунту!

Необходимо авторизоваться в течение 24 часов. В противном случае аккаунт будет удален! Зарегистрированные пользователи получают массу преимуществ: Публиковать стихи - реализовать свой талант! Создавать избранные коллекции авторов и стихов! Общаться с единомышленниками! Писать отзывы, участвовать в поэтических дуэлях и конкурсах!. Максимилиан Волошин. Описание. Максимилиан Александрович Волошин - один из крупнейших поэтов первой трети XX века.

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

Избранные произведения и письма. М. А. Волошин. Цена. руб. Максимилиан Александрович Волошин - один из крупнейших поэтов первой трети XX века. Это талантливый художник, многогранный лирик, прошедший путь от символистских, эзотерических стихотворений к гражданско-публицистической и научно-философской поэзии, через антропософские пристрастия - к "идеалу Града Божия".

Волошин М.А., Доблесть поэта: Избранные произведения и письма. серия: Новая библиотека русской классики: обязательный экземпляр Парад, г., стр., Описание книги. Максимилиан Александрович Волошин () - один из крупнейших поэтов первой трети XX века. Это талантливый художник, многогранный лирик, прошедший путь от символистских, эзотерических стихотворений к гражданско-публицистической и научно-философской поэзии, через антропософские пристрастия - к «идеалу Града Божия».

Categories Post navigation

Вэтомурокемыбудемучитьсяосвещатьизатенятьнаши3дмодели.Вотсписоктого,чтомыизучим:

  • Каксделатьтак,чтобыобъектбылярчекогданаходитсяближекисточникусвета.
  • Каксделатьотблескикогдамывидимотраженныйсветнапредмете(specular lighting )
  • Как сделать, чтобы объект был немного затененный, когда свет падает не прямо на объект(diffuse lighting)
  • Подсветка сцены(ambient lighting)
  • Тени. Эта тема заслуживает отдельного урока(или уроков, если даже не книг).
  • Зеркальное отражение(например, вода)
  • Подповерхностное рассеивание(например, как у воска)
  • Анизотропные материалы(окрашенный металл, например)
  • Затенение основанное на физических процессах, чтобы имитировать реальность еще лучше.
  • Преграждениесвета(Ambient Occlusion есличто-топреграждаетсвет,тостановитсятемнее)
  • Отражение цвета(красный ковер будет делать белый потолок слегка слегка красноватым)
  • Прозрачность
  • Глобальное освещение(в принципе все что мы указали выше можно назвать этим термином)

Другими словами, самое простое освещение и затенение.

Нормали

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

Нормали Треугольников

Нормаль к плоскости — это единичный вектор который направлен перпендикулярно к этой плоскости.

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

Вот псевдокод вычисления нормали:

треугольник(v1, v2, v3)
сторона1 = v2-v1
сторона2 = v3-v1
треугольник.нормаль = вектПроизведение(сторона1, сторона2).нормализировать()

Вершинная Нормаль

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

вершина v1, v2, v3, ....
треугольник tr1, tr2, tr3 // они все используют вершину v1
v1.нормаль = нормализовать(tr1.нормаль + tr2.нормаль + tr3.нормаль)

Использование нормалей вершин в OpenGL

Использовать нормали в OpenGL очень просто. Нормаль — это просто атрибут вершины, точно так же, как и позиция, цвет или UV координаты...Тоесть ничего нового учить не придется...даже наша простенькая функция loadOBJ уже загружает нормали.

GLuint normalbuffer;
glGenBuffers(1, &normalbuffer);

glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), &normals, GL_STATIC_DRAW);

// Третий атрибутный буфер: нормали
glEnableVertexAttribArray(2);

glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glVertexAttribPointer(
2, // атрибут
3, // размер
GL_FLOAT, // тип
GL_FALSE, // нормализованный ли?
0, // шаг
(void*)0 // смещение в буфере
);

И этого достаточно чтобы начать:


Диффузное освещение

Важность нормали к поверхности

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

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


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


//
//
float cosTheta = dot(n,l);

В этом коде «n» - это нормаль, а «l» - единичный вектор который идет от поверхности к источнику света(а не наоборот, хотя это может показатьсянепонятным)

Будьте внимательны со знаком

Иногда наша формула будет не работать. Например, когда свет будет находиться за треугольником, n и l будут противоположны, поэтому n.l будет отрицательным. И в итоге у нас будет какой-то отрицательный цвет, и в итоге какой-то бред. Поэтому мы приведем все отрицательный числа к 0 с помощью функции clamp.

// Косинус угла между нормалью и направлением света
// 1 — если свет перпендикулярен к треугольнику
// 0 — если свет параллелен к треугольнику
// 0 — если свет позади треугольника
float cosTheta = clamp(dot(n,l), 0,1);
color = LightColor * cosTheta;

Цвет материала

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



Мы можем промоделировать это простым умножением:

color = MaterialDiffuseColor * LightColor * cosTheta;

Моделирование света

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

С таким источником света, уровень освещения поверхности будет зависеть от расстояния до источника света: чем дальше, тем темнее. Эта зависимости рассчитывается так:

color = MaterialDiffuseColor * LightColor * cosTheta / (distance*distance);

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

color = MaterialDiffuseColor * LightColor * LightPower * cosTheta / (distance*distance);

Объединяем все вместе

Чтобы этот код работал нам нужен определенный набор параметров(цвета и мощности) и немного дополнительного кода.

MaterialDiffuseColor — мы можем взять прямо из текстуры.

LightColor и LightPower нужно будет выставить в шейдере с помощью GLSL uniform.

CosTheta будет зависеть от векторов n и l. Его можно вычислять для любого из пространств, угол будет одним и тем же. Мы будем использовать пространство камеры, так как тут очень просто посчитать положение светового источника:

// Нормаль фрагмента в пространстве камеры
vec3 n = normalize(Normal_cameraspace);
// Направление света(от фрагмента к источнику света
vec3 l = normalize(LightDirection_cameraspace);

Normal _cameraspace и LightDirection _ cameraspace подсчитываются в вершинном шейдере и передаются во фрагментный для дальнейшей обработки:

// Позиция вершины в пространстве камеры:МВП * положение
gl_Position = MVP * vec4(vertexPosition_modelspace,1);
// Положение вершины в мировом пространстве: M * положение
Position_worldspace = (M * vec4(vertexPosition_modelspace,1)).xyz;
// Вектор который идет от вершины камере в пространстве камеры
// В пространстве камеры, камера находится по положению (0,0,0)
vec 3 vertexPosition _ cameraspace = ( V * M * vec 4( vertexPosition _ modelspace ,1)). xyz ;
EyeDirection_cameraspace = vec3(0,0,0) - vertexPosition_cameraspace;
// Вектор который идет от вершины к источнику света в пространстве камеры.
//Матрица M пропущена, так как она в в этом пространстве единичная.
vec3 LightPosition_cameraspace = (V * vec4(LightPosition_worldspace,1)).xyz;
LightDirection_cameraspace = LightPosition_cameraspace +
EyeDirection_cameraspace;
// Нормаль вершины в пространстве камеры
Normal_cameraspace = (V * M * vec4(vertexNormal_modelspace,0)).xyz; // Будет работать лишь в том случае , когда матрица модели не изменяет её размер .

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

Обязательно попробуйте!!!

M и V – это матрицы Модели и Вида, которые передаются в шейдер точно так же, как и наша старая добрая MVP.

Время испытаний

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

Результат

Только лишь с одной диффузной компонентой у нас получается вот такая вот картинка(простите меня за некрасивые текстуры).



Вроде бы как получше, чем было раньше, но многого еще не хватает. Особенно заметна проблема с неосвещенными частями. Затылок нашей дорогой мартышки Сюзанны полностью черный(мы ведь использовали clamp()).

Окружающее освещение(ambient lighting)

Окружающее освещение – это чистой воды читерство.

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

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

vec3 MaterialAmbientColor = vec3(0.1,0.1,0.1) * MaterialDiffuseColor;
color =
// Окружающее освещение : симулируем непрямое освещение
MaterialAmbientColor +
// Диффузное : " цвет " самого объекта
MaterialDiffuseColor * LightColor * LightPower * cosTheta /
(distance*distance);

Результат

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



Отраженный свет(Specular light)

Часть света которая отражается, в основном отражается в сторону отраженного луча к поверхности.



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

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


// вектор взгляда(в сторону камеры)
vec3 E = normalize(EyeDirection_cameraspace);
//Направление в котором треугольник отражает свет
vec 3 R = reflect (- l , n );
// Косинус угла между вектором взгляда и вектором отражения обрезанный до нуля если нужно
// - Смотрим прям на отражение -> 1
// -Смотрим куда-то в другую сторону -> < 1
float cosAlpha = clamp(dot(E,R), 0,1);
color =
// Окружающее освещение:симулируем непрямое освещение
MaterialAmbientColor +
// Диффузное : " цвет " самого объекта
MaterialDiffuseColor * LightColor * LightPower * cosTheta /
(distance*distance) ;
// Отраженное: отраженные отблески, как зеркало
MaterialSpecularColor * LightColor * LightPower * pow(cosAlpha,5) /

В следующем уроке мы будем разбирать, как можно ускорить рендеринг нашего VBO.

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

Свойства материала

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

void glMaterial (GLenum face, GLenum pname, GLtype param)
void glMaterialv (GLenum face, GLenum pname, GLtype *params)

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

GL_AMBIENT параметр params должен содержать четыре целых или вещественных значения цветов RGBA, которые определяют рассеянный цвет материала (цвет материала в тени).

Значение по умолчанию: (0.2, 0.2, 0.2, 1.0).

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

Значение по умолчанию:(0.8, 0.8, 0.8, 1.0).

GL_SPECULAR параметр params должен содержать четыре целых или вещественных значения цветов RGBA, которые определяют цвет зеркального отражения материала.

GL_SHININESS параметр params должен содержать одно целое или вещественное значение в диапазоне от 0 до 128, которое определяет степень зеркального отражения материала.

Значение по умолчанию: 0.

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

Значение по умолчанию: (0.0, 0.0, 0.0, 1.0).

GL_AMBIENT_AND_DIFFUSE эквивалентно двум вызовам команды glMaterial…() со значением pname GL_AMBIENT и GL_DIFFUSE и одинаковыми значениями params.

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

Параметр face определяет тип граней, для которых задается этот материал и может принимать значения GL_FRONT, GL_BACK или GL_FRONT_AND_BACK.

Если в сцене материалы объектов различаются лишь одним параметром, рекомендуется сначала установить нужный режим, вызвав glEnable() c параметром GL_COLOR_MATERIAL, а затем использовать команду

void glColorMaterial (GLenum face, GLenum pname)

где параметр face имеет аналогичный смысл, а параметр pname может принимать все перечисленные значения. После этого, значения выбранного с помощью pname свойства материала для конкретного объекта (или вершины) устанавливается вызовом команды glColor…(), что позволяет избежать вызовов более ресурсоемкой команды glMaterial…() и повышает эффективность программы.

Добавить в сцену источник света можно с помощью команд

void glLight (GLenum light, GLenum pname, GLfloat param)
void glLight (GLenum light, GLenum pname, GLfloat *params)

Параметр light однозначно определяет источник,и выбирается из набора специальных символических имен вида GL_LIGHTi, где i должно лежать в диапазоне от 0 до GL_MAX_LIGHT, которое не превосходит восьми.

Оставшиеся два параметра имеют аналогичный смысл, что и в команде glMaterial…(). Рассмотрим их назначение (вначале описываются параметры для первой команды, затем для второй):

GL_SPOT_EXPONENT параметр param должен содержать целое или вещественное число от 0 до 128, задающее распределение интенсивности света. Этот параметр описывает уровень сфокусированности источника света.

Значение по умолчанию: 0 (рассеянный свет).

GL_SPOT_CUTOFF параметр param должен содержать целое или вещественное число между 0 и 90 или равное 180, которое определяет максимальный угол разброса света. Значение этого параметра есть половина угла в вершине конусовидного светового потока, создаваемого источником.

Значение по умолчанию: 180 (рассеянный свет).

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

Значение по умолчанию: (0.0, 0.0, 0.0, 1.0).

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

GL_SPECULAR параметр params должен содержать четыре целых или вещественных значения цветов RGBA, которые определяют цвет зеркального отражения.

Значение по умолчанию: (1.0, 1.0, 1.0, 1.0)для LIGHT0 и (0.0, 0.0, 0.0, 1.0) для остальных.

GL_POSITION параметр params должен содержать четыре целых или вещественных, которые определяют положение источника света. Если значение компоненты w равно 0.0, то источник считается бесконечно удаленным и при расчете освещенности учитывается только направление на точку (x,y,z), в противном случае считается, что источник расположен в точке (x,y,z,w).

Значение по умолчанию: (0.0, 0.0, 1.0, 0.0).

GL_SPOT_DIRECTION параметр params должен содержать четыре целых или вещественных числа, которые определяют направление света.

Значение по умолчанию: (0.0, 0.0, -1.0, 1.0).

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

Для использования освещения сначала надо установить соответствующий режим вызовом команды glEnable (GL_LIGHTNING), а затем включить нужный источник командой glEnable(GL_LIGHTn).

Модель освещения

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

Для задания глобальных параметров освещения используются команды

void glLightModel (GLenum pname, GLenum param)
void glLightModelv (GLenum pname, const GLtype *params)

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

GL_LIGHT_MODEL_LOCAL_VIEWER параметр param должен быть булевским и задает положение наблюдателя. Если он равен FALSE, то направление обзора считается параллельным оси -z, вне зависимости от положения в видовыx координатах. Если же он равен TRUE, то наблюдатель находится в начале видовой системы координат. Это может улучшить качество освещения, но усложняет его расчет.

Значение по умолчанию: FALSE.

GL_LIGHT_MODEL_TWO_SIDE параметр param должен быть булевским и управляет режимом расчета освещенности как для лицевых, так и для обратных граней. Если он равен FALSE, то освещенность рассчитывается только для лицевых граней. Если же он равен TRUE, расчет проводится и для обратных граней. Значение по умолчанию: FALSE.

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

Значение по умолчанию:(0.2, 0.2, 0.2,1.0).

Освещение какого-либо пространства - это процесс, благодаря которому это пространство наполняется светом и все находящиеся в нём предметы делаются видимыми.
Освещение любого объекта зависит от двух факторов:

  • Первый - это материал, из которого сделан объект.
  • Второй - это свет, которым он освещен.

В зависимости от реализации OpenGL на сцене могут присутствовать восемь и более источников света.По умолчанию освещение отключено. Включить нулевой источник света можно командой:

  • glEnable(GL_LIGHT0);

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

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

Для управления свойствами источника света используются команды glLight*:

  • glLightf(GLenum light, GLenum pname, GLfloat param);
    glLightfv(GLenum light, GLenum pname, const GLfloat *param);

Параметр light указывает OpenGL для какого источника света задаются параметры. Команда glLightf используется для задания скалярных параметров, а glLightfv используется для задания векторных характеристик источников света.

Сначала рассмотрим функцию, которая устанавливает базовые настройки. Когда вы разрешили освещение, то вы можете уже устанавливать фоновую освещенность. По умолчанию, значение фоновой освещенности равно (0.2, 0.2, 0.2, 1). Создайте новый проект, скопируйте туда шаблонный файл и отключите освещение. Вы с трудом сможете различить сферу на экране. С помощью функции glLightModel вы можете установить фоновое освещение. Если вы повысите его до (1,1,1,1), т.е. до максимума, то включать источники света вам не понадобится. Вы их действия просто не заметите, т.к. объект уже максимально освещен. И получится, что вы как бы отключили освещение. В общем, добавьте в main вызов следующей функции:

  • float ambient = {0.5, 0.5, 0.5, 1};
    ...
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);

Попробуйте изменить параметры и посмотрите на результат.

Материал
Материал может рассеивать, отражать и излучать свет. Свойства материала устанавливаются при помощи функции

  • glMaterialfv(GLenum face, GLenum pname, GLtype* params)

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

  • GL_BACK задняя грань
    GL_FONT передняя грань
    GL_FRONT_AND_BACK обе грани

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

  • GL_AMBIENT рассеянный свет
    GL_DIFFUSE тоже рассеянный свет
    GL_SPECULAR отраженный свет
    GL_EMISSION излучаемый свет
    GL_SHININESS степень отраженного света
    GL_AMBIENT_AND_DIFFUSE оба рассеянных света

Цвет задается в виде массива из четырех элементов - RGBA. В случае GL_SHININESS params указывает на число типа float, которое должно быть в диапазоне от 0 до 128.
Вам надо всего лишь модифицировать функцию display.

  • void CALLBACK display(void)
    {
    GLUquadricObj *quadObj;
    GLfloat front_color = {0,1,0,1};
    GLfloat back_color = {0,0,1,1};
    quadObj = gluNewQuadric();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, front_color);
    glMaterialfv(GL_BACK, GL_DIFFUSE, back_color);
    glPushMatrix();
    glRotated(110, -1,1,0);
    gluCylinder(quadObj, 1, 0.5, 2, 10, 10);
    glPopMatrix();
    gluDeleteQuadric(quadObj);
    auxSwapBuffers();
    }

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

  • glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);

Источники направленного света
Источника света такого типа находится в бесконечности и свет от него распространяется в заданном направлении. Идеально подходит для создания равномерного освещения. Хорошим примером источника направленного света может служить Солнце. У источника направленного света, кроме компонент излучения, можно задать только направление.

  • GL_POSITION (0.0, 0.0, 1.0, 0.0) //(x, y, z, w) направление источника направленного света

Первые три компоненты (x, y, z) задают вектор направления, а компонента w всегда равна нулю (иначе источник превратится в точечный).

Функции затухания
Это функция изменения интенсивности освещения(интенсивность света не убывает с расстоянием) , используется вместе с точечным освещением

  • GL_POSITION(0.0, 0.0, 1.0, 0.0)//позиция источника света (по умолчанию источник света направленный)
  • GL_CONSTANT_ATTENUATION 1.0 //постоянная k_const в функции затухания f(d)
  • GL_LINEAR_ATTENUATION 0.0 //коэффициент k_linear при линейном члене в функции затухания f(d)
  • GL_QUADRATIC_ATTENUATION 0.0 //коэффициент k_quadratic при квадрате расстояния в функции затухания f(d)

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

  • GL_SPOT_DIRECTION (0.0, 0.0, -1.0) //(x, y, z) - направление прожектора (ось ограничивающего конуса)
  • GL_SPOT_CUTOFF 180.0 //угол между осью и стороной конуса (он же половина угла при вершине)
  • GL_SPOT_EXPONENT 0.0 //экспонента убывания интенсивности

Тени
Тени напрямую не поддерживаются библиотекой OpenGL, поэтому их нужно разбирать отдельно.

В этом уроке мы научимся создавать вершинное освещение.
Исходные файлы main.cpp, main.h, init.h взяты из урока "Начало - инициализация".

Обьявим глобальную переменную позиции света в файле main.h :

extern float g_LightPosition[ 4 ] ; // Позиция источника света

Итак, в первую очередь нам нужно инициализировать освещение.
Сделаем мы это в файле init.cpp :

// Сразу переходим к функции InitializeOpenGL().
// В конец функции, перед закрывающейся скобкой, дописываем новый код.

// Лучше всего устанавливать цвет пространства в цвет "темноты" - отсутствия освещения.
// Так как мы будем использовать белый как цвет освещения, установим цвет
// пространства в черный:

glClearColor(0 , 0 , 0 , 1 ) ;

// Ниже создадим два массива цветов. Первый, ambience - цвет "рассеянного света", когда
// на полигон не падает прямое освещение. Если мы не установим этот цвет, не освещенные полигоны
// будут совершенно черными, и мы их не увидим. Цвет освещения мы сделаем белый, а рассеянный
// свет установим в половину этого значения.
// Второй массив, diffuse, это цвет направленного света. Мы выбрали белый. Первые три
// цифры массивы - R,G,B, последняя - значение альфа. Пока что не беспокойтесь о нём.
// Для рассеянного света выберем глубоко серый цвет, для дифузного - среднее между
// белым и черным.

float ambience[ 4 ] = { 0.3f , 0.3f , 0.3f , 1.0 } ; // Цвет мирового света
float diffuse[ 4 ] = { 0.5f , 0.5f , 0.5f , 1.0 } ; // Цвет позиционного света

// Чтобы установить мировое освещене, нужно передать OpenGL наши массивы.
// OpenGL даёт нам возможность использовать несколько источников света. Общее количество
// источников зависит от переменной GL_MAX_LIGHTS. Для первого используемого источника будем
// использовать дефайн OpenGL GL_LIGHT0. После указания используемого источника передаём
// OpenGL флаг говорящий, что мы устанавливаем значение ambience, и массив ambience-цветов.
// Точно то же делаем с diffuse и GL_DIFFUSE.

// Устанавливаем цвет рассеянного цвета (без направленного света)
glLightfv( GL_LIGHT0, GL_AMBIENT, ambience ) ;
// И диффузный цвет (цвет света)
glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse ) ;

// Далее нам нужно установить позицию источника света. У нас может быть много простых
// источников в разных местах, но в этом уроке будет использоваться только один.
// Для последующих источников нужно использовать GL_LIGHT1, GL_LIGHT2, GL_LIGHT3 и т.д...
// Мы сможем изменять позицию источника клавишами "+" и "-". Позиция по умолчанию - (0,1,0,1).
// Это расположит источник прямо над центральной пирамидой. Последнее значение в массиве
// g_LightPosition сообщает OpenGL, нужен ли нам ПОЗИЦИОННЫЙ или НАПРАВЛЕННЫЙ свет.
// Если значение = 1, цвет будет позиционным, иначе он будет направлен от камеры.
// Если мы установим направленный свет, он будет освещать всё "по дороге" от нашего "глаза".
// Если же свет будет позиционным, он "повиснет" в координатах x,y,z и будет освещать
// всё вокруг себя. Это то, что нам нужно, так что установим значение в единицу.

// После инициализации источника света нам нужно включить его:
glEnable( GL_LIGHT0 ) ;

// Но недостаточно включить один источник; кроме этого нужно включить само
// освещение в OpenGL:
glEnable(GL_LIGHTING) ;

// Следующая строка позволяет закрашивать полигоны цветом при включенном освещении:
glEnable(GL_COLOR_MATERIAL) ;

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

В init.cpp мы инициализировали освещение в функции InicializeOpenGL().

Теперь используем освещение в main.cpp

// В начале файла, после включения хидеров, добавим переменные:
float g_LightPosition[ 4 ] = { 0 , 1 , 0 , 1 } ; // Позиция источника света
float g_bLight = true ; // Включен ли свет

float rotY = 0.0f ; // Вращение по Y

// Напишем функцию, создающую пирамиду:
void CreatePyramid(float x, float y, float z, int width, int height)
{

GlBegin(GL_TRIANGLES) ;

// Ниже мы добавим что-то новое: НОРМАЛИ. Значение, насколько сильно нужно
// осветить конкретный полигон, OpenGL рассчитывает из его нормалей. Что такоей нормаль?
// Нормаль - это направление полигона. Вы заметите, что мы присваиваем заднему полигону
// нормаль (0,1,-1). Это значит, что полигон направлен в обратную сторону по оси Z (внутрь
// экрана). Запомните, нормали - это не координаты, а только направления.
// Функция glNormal3f() позволяют нам указать нормаль для вершин, переданных за ней.
// Сейчас мы напишем нормали вручную, но вы можете вернутся к урокам камеры, где есть
// ничто иное, как функция для рассчета нормалей.

// Задняя сторона
glNormal3f(0 , 1 , - 1 ) ; // Полигон направлен назад и вверх

// Передняя сторона
glNormal3f(0 , 1 , 1 ) ;
glColor3ub(255 , 0 , 0 ) ; glVertex3f(x, y + height, z) ;

// Левая сторона
glNormal3f(- 1 , 1 , 0 ) ;
glColor3ub(255 , 0 , 0 ) ; glVertex3f(x, y + height, z) ;
glColor3ub(255 , 0 , 255 ) ; glVertex3f(x - width, y - height, z + width) ;
glColor3ub(0 , 255 , 255 ) ; glVertex3f(x - width, y - height, z - width) ;

// Передняя правая сторона
glNormal3f(1 , 1 , 0 ) ;
glColor3ub(255 , 0 , 0 ) ; glVertex3f(x, y + height, z) ;
glColor3ub(255 , 0 , 255 ) ; glVertex3f(x + width, y - height, z - width) ;
glColor3ub(0 , 255 , 255 ) ; glVertex3f(x + width, y - height, z + width) ;

GlEnd() ;

// Теперь отрендерим дно пирамиды

GlBegin(GL_QUADS) ;

// Эти вершины образуют дно пирамиды
glNormal3f(0 , - 1 , 0 ) ;
glColor3ub(0 , 0 , 255 ) ; glVertex3f(x - width, y - height, z + width) ;
glColor3ub(0 , 0 , 255 ) ; glVertex3f(x + width, y - height, z + width) ;
glColor3ub(0 , 0 , 255 ) ; glVertex3f(x + width, y - height, z - width) ;
glColor3ub(0 , 0 , 255 ) ; glVertex3f(x - width, y - height, z - width) ;
glEnd() ;
}

//////////////////////////////////////////////////////////////////////////
// Внесём изменения в обработку клавиш, блок WM_KEYDOWN функции WinProc():

case WM_KEYDOWN:
switch (wParam)
{
// Ниже мы позволяем пользователю увеличивать и уменьшать позицию Y источника света
// клавишами "+" и "-". После изменения позиции необходимо сообщить об этом
// OpenGL вызовом glLightfv(). Мы передаём номер источника (GL_LIGHT0) и флаг
// GL_POSITION, плюс саму позицию.
// Нажатием "L" свет включается и выключается.

case VK_ESCAPE:
PostQuitMessage(0 ) ;
break ;

case VK_ADD: // Если нажата ПЛЮС
g_LightPosition[ 1 ] += 0.1f ; // Увеличиваем значение Y
// Убедимся, что не превысили 5
if (g_LightPosition[ 1 ] > 5 ) g_LightPosition[ 1 ] = 5 ;
break ;

case VK_SUBTRACT: // Если МИНУС
g_LightPosition[ 1 ] -= 0.1f ; // Уменьшим значение Y
// Убедиммся, что оно не меньше -5
if (g_LightPosition[ 1 ] < - 5 ) g_LightPosition[ 1 ] = - 5 ;
break ;

case "L" :

G_bLight = ! g_bLight; // Выключим свет

if (g_bLight) // Включим свет
glEnable(GL_LIGHTING) ;
else
glDisable(GL_LIGHTING) ; // Выключим свет
break ;
}
break ;

////////////////////////////////////////////////////////////////////////

// И, наконец, изменим функцию RenderScene():
void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ;
glLoadIdentity() ;

// Обновим позицию света ДО вызова glLookAt(), чтобы свет обновился
// корректно. Опустите функцию вниз, чтобы увидеть, что иначе случится.
// Если источник не двигается, вызывать эту функцию заново не нужно.
glLightfv( GL_LIGHT0, GL_POSITION, g_LightPosition ) ;

GluLookAt(0 , 0 , 6 , 0 , 0 , 0 , 0 , 1 , 0 ) ;

GlRotatef(rotY, 0.0f , 1.0f , 0.0f ) ; // Вращаем пирамиду вокруг оси Y

// Это создаёт 3д пирамиду в центре (0,0,0)
CreatePyramid(0 , 0 , 0 , 1 , 1 ) ;

// Создадим пирамиды вокруг:

CreatePyramid(3 , 0 , - 3 , 1 , 1 ) ;
CreatePyramid(- 3 , 0 , - 3 , 1 , 1 ) ;
CreatePyramid(0 , 0 , 5 , 1 , 1 ) ;

// Увеличиваем впращение.

RotY += 0.6f ;

SwapBuffers(g_hDC) ;
}

Итак, вот шаги, которые мы проделали:

1) Установили ambience-цвет мира:
glLightfv(GL_LIGHT0, GL_AMBIENT, ambienceArray);

2) Установили diffuse-цвет источника света:
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseArray);

3) Установили позицию источника света:
glLightfv(GL_LIGHT0, GL_POSITION, positionArray);

4) Включили источник света:
glEnable(GL_LIGHT0);

5) И освещение в OpenGL:
glEnable(GL_LIGHTING);