На предыдущих уроках мы узнали много нового об устройстве освещения в OpenGL. Рассмотрели такие технологии, как:
различные типы источников света.
На этом уроке мы объединим все ранее полученные знания, создав полностью освещенную сцену с 6 активными источниками света. Один источник направленного света будет имитировать солнечный свет, 4 других — отдельные точечные источники света, расставленные по всей сцене, и еще 1 — фонарик, который мы также добавим в нашу сцену.
Использование нескольких источников света
Чтобы использовать в сцене несколько источников света, необходимо вычисления освещения инкапсулировать в функции GLSL. Причина этого заключается в том, что вычисление освещения с несколькими типами света, каждый из которых требует отдельного выполнения различных действий, приведет к быстрому захламлению кода. Если мы будем осуществлять все эти операции только внутри функции main(), то у нас возникнут проблемы с пониманием принципов работы нашего алгоритма освещения (да и всей программы в целом).
Функции в GLSL очень похожи на функции в языке С++. У нас есть имя функции, возвращаемый тип, и нам нужно в верхней части файла кода объявить прототип функции, если она не была объявлена до функции main(). Мы создадим несколько различных функций для каждого из типов света: направленного, точечного и прожектора.
При реализации использования в сцене нескольких источников света обычно рассуждают следующим образом: у нас есть один цветовой вектор, который описывает выходной цвет фрагмента. Для каждого источника вклад его света в конечный цвет фрагмента добавляется к упомянутому выходному цветовому вектору. Таким образом, каждый свет в сцене будет вычислять свое индивидуальное воздействие на цвет фрагмента и вносить его в конечный выходной цвет. Общая структура кода должна выглядеть примерно следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
out vec4 FragColor; void main() { // Определяем выходное значение цвета vec3 output = vec3(0.0); // Добавляем к нему направленный свет output += someFunctionToCalculateDirectionalLight(); // Проделываем то же самое для всех точечных источников света for(int i = 0; i < nr_of_point_lights; i++) output += someFunctionToCalculatePointLight(); // А также добавляем другие источники света (например, прожекторы) output += someFunctionToCalculateSpotLight(); FragColor = vec4(output, 1.0); } |
Фактический код, в зависимости от реализации, скорее всего, будет отличаться, но общая структура останется прежней. Мы определяем несколько функций, которые вычисляют результирующий цвет, учитывая воздействия каждого источника света, и добавляют его к выходному цветовому вектору. Если, например, два источника света находятся близко к фрагменту, то их совокупный вклад приведет к более яркому освещению фрагмента по сравнению с фрагментом, освещаемым одним источником света.
Направленный свет
Во фрагментном шейдере нам необходимо определить функцию, которая вычисляет вклад направленного света для соответствующего фрагмента: функция, которая принимает несколько параметров и возвращает вычисленный цвет направленного освещения.
Сначала нам нужно определить минимальный набор необходимых переменных источника направленного света. Местом их хранения будет структура под названием DirLight
, которую мы собираемся использовать в качестве uniform-переменной. Переменные данной структуры должны быть вам уже знакомы по предыдущему уроку:
1 2 3 4 5 6 7 8 |
struct DirLight { vec3 direction; vec3 ambient; vec3 diffuse; vec3 specular; }; uniform DirLight dirLight; |
Затем мы передаем uniform-переменную dirLight
в функцию со следующим прототипом:
1 |
vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir); |
Примечание: Точно так же, как и в языках C/С++, когда мы хотим вызвать функцию (в данном случае, внутри функции main()), строка с определением функции должна предшествовать строке её вызова. Но в нашем случае мы бы предпочли определить функции после основной функции main(). Поэтому, чтобы сохранить выполнение вышеописанного требования, мы объявляем прототипы функций где-то выше основной функции main().
Вы можете видеть, что функция в качестве своих параметров использует структуру DirLight
и два вектора, необходимых ей для своих вычислений. Если вы успешно завершили предыдущий урок, то содержание данной функции не должно вас удивлять:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir) { vec3 lightDir = normalize(-light.direction); // Рассеянное затенение float diff = max(dot(normal, lightDir), 0.0); // Отраженное затенение vec3 reflectDir = reflect(-lightDir, normal); float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); // Комбинируем результаты vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords)); vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords)); vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords)); return (ambient + diffuse + specular); } |
Фактически, мы скопировали код из предыдущего урока и использовали векторы, переданные нам в качестве аргументов функции, для вычисления вектора вклада направленного света. Результирующие внешний, рассеянный и отраженный световые вклады затем возвращаются в виде единого цветового вектора.
Точечный свет
Подобно направленному свету, нам также необходимо определить функцию, которая вычисляет вклад точечного света в освещенность заданного фрагмента, включая затухание его освещенности. Так же, как и с направленным светом, мы определяем структуру, которая содержит все необходимые переменные точечного света:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
struct PointLight { vec3 position; float constant; float linear; float quadratic; vec3 ambient; vec3 diffuse; vec3 specular; }; #define NR_POINT_LIGHTS 4 uniform PointLight pointLights[NR_POINT_LIGHTS]; |
Как вы можете видеть, мы использовали директиву препроцессора в GLSL, чтобы определить количество точечных источников света, которые будут присутствовать в нашей сцене. Затем мы используем константу NR_POINT_LIGHTS
для создания массива структур PointLight
. Массивы в GLSL так же, как и массивы в языке C++, могут быть созданы с помощью двух квадратных скобок. Сейчас у нас есть 4 структуры PointLight
, которые нужно заполнить данными.
Прототип функции точечного света выглядит следующим образом:
1 |
vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir); |
Функция в качестве аргументов принимает все необходимые ей данные и возвращает vec3, представляющий вклад, который вносит выбранный источник точечного света в цвет фрагмента. Опять же, использование «высокоинтеллектуальной» технологии copy/paste приводит нас к следующему результату:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir) { vec3 lightDir = normalize(light.position - fragPos); // Рассеянное затенение float diff = max(dot(normal, lightDir), 0.0); // Отраженное затенение vec3 reflectDir = reflect(-lightDir, normal); float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); // Затухание float distance = length(light.position - fragPos); float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); // Комбинируем результаты vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords)); vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords)); vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords)); ambient *= attenuation; diffuse *= attenuation; specular *= attenuation; return (ambient + diffuse + specular); } |
Преимуществом абстрагирования данного функционала в отдельную функцию является то, что мы можем легко вычислить освещение для нескольких точечных источников света без необходимости дублировать код. В функции main() мы просто создаем цикл, который перебирает массив источников точечного света, вызывая при этом функцию CalcPointLight() для каждого точечного источника света.
Складываем всё вместе
Теперь, когда мы определили функцию для направленных источников света и функцию для точечных источников света, мы можем объединить всё это в функции main():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
void main() { // Свойства vec3 norm = normalize(Normal); vec3 viewDir = normalize(viewPos - FragPos); // Этап №1: Направленное освещение vec3 result = CalcDirLight(dirLight, norm, viewDir); // Этап №2: Точечные источники света for(int i = 0; i < NR_POINT_LIGHTS; i++) result += CalcPointLight(pointLights[i], norm, FragPos, viewDir); // Этап №3: Прожектор // result += CalcSpotLight(spotLight, norm, FragPos, viewDir); FragColor = vec4(result, 1.0); } |
В результирующий выходной цвет фрагмента будет добавляться вклад каждого типа света до тех пор, пока не будут обработаны все источники света. Результирующий цвет содержит цветовое воздействие всех источников света сцены вместе взятых. Мы оставляем для читателя реализацию функции CalcSpotLight() в качестве упражнения.
Примечание: В этом подходе есть много повторяющихся вычислений, распределенных по функциям, относящимся к различным типам света (например, вычисление вектора отражения, рассеянных и отраженных членов и сэмплирование текстур материала), поэтому здесь есть что оптимизировать 😉
Задание uniform-значений для структуры направленного света не должно быть слишком непривычным, но вам может быть интересно, как установить uniform-значения точечных источников света, поскольку uniform-переменная точечного света на самом деле представляет собой массив структур точечного света. Это отличается от того, что мы обсуждали ранее.
К счастью для нас, данный вопрос легко решается. Установка uniform-значений массива структур работает точно так же, как и установка uniform-значений отдельно взятой структуры, хотя на этот раз при запросе местоположения uniform-переменной мы также должны указать соответствующий индекс:
1 |
lightingShader.setFloat("pointLights[0].constant", 1.0f); |
Здесь мы при помощи индекса 0
выбираем первую структуру PointLight
в массиве pointLights
и извлекаем её внутреннюю переменную constant
, устанавливая ей значение 1.0
.
Давайте не будем забывать, что нам также нужно определить вектор положения для каждого из 4 точечных источников света, поэтому предлагаю немного расставить их по сцене. Мы определим еще один массив glm::vec3
, содержащий координаты позиций точечных источников света:
1 2 3 4 5 6 |
glm::vec3 pointLightPositions[] = { glm::vec3( 0.7f, 0.2f, 2.0f), glm::vec3( 2.3f, -3.3f, -4.0f), glm::vec3(-4.0f, 2.0f, -12.0f), glm::vec3( 0.0f, 0.0f, -3.0f) }; |
Затем, при помощи нужного индекса, выбираем соответствующую структуру PointLight
из массива pointLights
и устанавливаем её атрибут position
, равным значению первой позиции из всех, которые мы только что определили. Также теперь вместо одного (как было раньше) обязательно отрисуйте 4 световых куба. Для этого просто создайте другую матрицу модели для каждого из световых объектов (точно так же, как мы это сделали с контейнерами).
Если к этому еще добавить использование фонарика, то результат комбинирования всех источников света будет выглядеть следующим образом:
(вдали)
(вблизи)
GitHub / Урок №15. Множественные источники света — Исходный код
Как вы можете видеть, где-то в небе присутствует какая-то форма глобального освещения (например, солнце), у нас есть 4 источника света, разбросанных по всей сцене, и фонарик, который виден с точки зрения наблюдателя. Выглядит довольно аккуратно, не так ли?
На вышеприведенном изображении показаны все источники света со свойствами света, установленными по умолчанию, которые мы использовали на предыдущих уроках, но если вы поиграетесь с этими значениями, то сможете получить довольно интересные результаты. Художники и дизайнеры уровней обычно настраивают все эти переменные освещения в отдельном большом редакторе, чтобы убедиться, что освещение соответствует окружению. Используя наше простое окружение, вы уже можете создать некоторые довольно интересные визуальные эффекты, просто изменив атрибуты источников света:
Мы также изменили цвет фона, чтобы вы могли лучше рассмотреть эффект от разного типа освещения. Вы можете видеть, что, просто регулируя некоторые параметры освещения, появляется возможность создавать совершенно другую обстановку.
К настоящему времени вы уже должны иметь довольно хорошее представление о программировании освещения в OpenGL. Теперь, обладая такими знаниями, нам представляется возможность реализовать интересное и визуально насыщенное окружение и необычную обстановку. Попробуйте поиграть со всеми различными значениями освещения, чтобы создать свое собственное окружение.
Упражнения
Попробуйте, изменив значения атрибутов света, воссоздать различные типы обстановок, похожие на обстановки, присутствующие на последнем изображении.
Ответ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
// == ============================================================================================== // Пустыня // == ============================================================================================== glClearColor(0.75f, 0.52f, 0.3f, 1.0f); [...] glm::vec3 pointLightColors[] = { glm::vec3(1.0f, 0.6f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(1.0f, 1.0, 0.0), glm::vec3(0.2f, 0.2f, 1.0f) }; [...] // Направленный свет glUniform3f(glGetUniformLocation(lightingShader.Program, "dirLight.direction"), -0.2f, -1.0f, -0.3f); glUniform3f(glGetUniformLocation(lightingShader.Program, "dirLight.ambient"), 0.3f, 0.24f, 0.14f); glUniform3f(glGetUniformLocation(lightingShader.Program, "dirLight.diffuse"), 0.7f, 0.42f, 0.26f); glUniform3f(glGetUniformLocation(lightingShader.Program, "dirLight.specular"), 0.5f, 0.5f, 0.5f); // Точечный свет №1 glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[0].position"), pointLightPositions[0].x, pointLightPositions[0].y, pointLightPositions[0].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[0].ambient"), pointLightColors[0].x * 0.1, pointLightColors[0].y * 0.1, pointLightColors[0].z * 0.1); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[0].diffuse"), pointLightColors[0].x, pointLightColors[0].y, pointLightColors[0].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[0].specular"), pointLightColors[0].x, pointLightColors[0].y, pointLightColors[0].z); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[0].constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[0].linear"), 0.09); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[0].quadratic"), 0.032); // Точечный свет №2 glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[1].position"), pointLightPositions[1].x, pointLightPositions[1].y, pointLightPositions[1].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[1].ambient"), pointLightColors[1].x * 0.1, pointLightColors[1].y * 0.1, pointLightColors[1].z * 0.1); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[1].diffuse"), pointLightColors[1].x, pointLightColors[1].y, pointLightColors[1].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[1].specular"), pointLightColors[1].x, pointLightColors[1].y, pointLightColors[1].z); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[1].constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[1].linear"), 0.09); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[1].quadratic"), 0.032); // Точечный свет №3 glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[2].position"), pointLightPositions[2].x, pointLightPositions[2].y, pointLightPositions[2].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[2].ambient"), pointLightColors[2].x * 0.1, pointLightColors[2].y * 0.1, pointLightColors[2].z * 0.1); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[2].diffuse"), pointLightColors[2].x, pointLightColors[2].y, pointLightColors[2].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[2].specular") ,pointLightColors[2].x, pointLightColors[2].y, pointLightColors[2].z); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[2].constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[2].linear"), 0.09); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[2].quadratic"), 0.032); // Точечный свет №4 glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[3].position"), pointLightPositions[3].x, pointLightPositions[3].y, pointLightPositions[3].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[3].ambient"), pointLightColors[3].x * 0.1, pointLightColors[3].y * 0.1, pointLightColors[3].z * 0.1); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[3].diffuse"), pointLightColors[3].x, pointLightColors[3].y, pointLightColors[3].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[3].specular"), pointLightColors[3].x, pointLightColors[3].y, pointLightColors[3].z); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[3].constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[3].linear"), 0.09); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[3].quadratic"), 0.032); // Прожектор glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.position"), camera.Position.x, camera.Position.y, camera.Position.z); glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.direction"), camera.Front.x, camera.Front.y, camera.Front.z); glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.ambient"), 0.0f, 0.0f, 0.0f); glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.diffuse"), 0.8f, 0.8f, 0.0f); glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.specular"), 0.8f, 0.8f, 0.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.linear"), 0.09); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.quadratic"), 0.032); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.cutOff"), glm::cos(glm::radians(12.5f))); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.outerCutOff"), glm::cos(glm::radians(13.0f))); // == ============================================================================================== // Завод // == ============================================================================================== glClearColor(0.1f, 0.1f, 0.1f, 1.0f); [...] glm::vec3 pointLightColors[] = { glm::vec3(0.2f, 0.2f, 0.6f), glm::vec3(0.3f, 0.3f, 0.7f), glm::vec3(0.0f, 0.0f, 0.3f), glm::vec3(0.4f, 0.4f, 0.4f) }; [...] // Направленный свет glUniform3f(glGetUniformLocation(lightingShader.Program, "dirLight.direction"), -0.2f, -1.0f, -0.3f); glUniform3f(glGetUniformLocation(lightingShader.Program, "dirLight.ambient"), 0.05f, 0.05f, 0.1f); glUniform3f(glGetUniformLocation(lightingShader.Program, "dirLight.diffuse"), 0.2f, 0.2f, 0.7); glUniform3f(glGetUniformLocation(lightingShader.Program, "dirLight.specular"), 0.7f, 0.7f, 0.7f); // Точечный свет №1 glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[0].position"), pointLightPositions[0].x, pointLightPositions[0].y, pointLightPositions[0].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[0].ambient"), pointLightColors[0].x * 0.1, pointLightColors[0].y * 0.1, pointLightColors[0].z * 0.1); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[0].diffuse"), pointLightColors[0].x, pointLightColors[0].y, pointLightColors[0].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[0].specular"), pointLightColors[0].x, pointLightColors[0].y, pointLightColors[0].z); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[0].constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[0].linear"), 0.09); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[0].quadratic"), 0.032); // Точечный свет №2 glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[1].position"), pointLightPositions[1].x, pointLightPositions[1].y, pointLightPositions[1].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[1].ambient"), pointLightColors[1].x * 0.1, pointLightColors[1].y * 0.1, pointLightColors[1].z * 0.1); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[1].diffuse"), pointLightColors[1].x, pointLightColors[1].y, pointLightColors[1].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[1].specular"), pointLightColors[1].x, pointLightColors[1].y, pointLightColors[1].z); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[1].constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[1].linear"), 0.09); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[1].quadratic"), 0.032); // Точечный свет №3 glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[2].position"), pointLightPositions[2].x, pointLightPositions[2].y, pointLightPositions[2].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[2].ambient"), pointLightColors[2].x * 0.1, pointLightColors[2].y * 0.1, pointLightColors[2].z * 0.1); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[2].diffuse"), pointLightColors[2].x, pointLightColors[2].y, pointLightColors[2].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[2].specular") ,pointLightColors[2].x, pointLightColors[2].y, pointLightColors[2].z); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[2].constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[2].linear"), 0.09); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[2].quadratic"), 0.032); // Точечный свет №4 glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[3].position"), pointLightPositions[3].x, pointLightPositions[3].y, pointLightPositions[3].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[3].ambient"), pointLightColors[3].x * 0.1, pointLightColors[3].y * 0.1, pointLightColors[3].z * 0.1); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[3].diffuse"), pointLightColors[3].x, pointLightColors[3].y, pointLightColors[3].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[3].specular"), pointLightColors[3].x, pointLightColors[3].y, pointLightColors[3].z); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[3].constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[3].linear"), 0.09); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[3].quadratic"), 0.032); // Прожектор glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.position"), camera.Position.x, camera.Position.y, camera.Position.z); glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.direction"), camera.Front.x, camera.Front.y, camera.Front.z); glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.ambient"), 0.0f, 0.0f, 0.0f); glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.diffuse"), 1.0f, 1.0f, 1.0f); glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.specular"), 1.0f, 1.0f, 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.linear"), 0.009); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.quadratic"), 0.0032); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.cutOff"), glm::cos(glm::radians(10.0f))); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.outerCutOff"), glm::cos(glm::radians(12.5f))); // == ============================================================================================== // Хоррор // == ============================================================================================== glClearColor(0.0f, 0.0f, 0.0f, 1.0f); [...] glm::vec3 pointLightColors[] = { glm::vec3(0.1f, 0.1f, 0.1f), glm::vec3(0.1f, 0.1f, 0.1f), glm::vec3(0.1f, 0.1f, 0.1f), glm::vec3(0.3f, 0.1f, 0.1f) }; [...] // Направленный свет glUniform3f(glGetUniformLocation(lightingShader.Program, "dirLight.direction"), -0.2f, -1.0f, -0.3f); glUniform3f(glGetUniformLocation(lightingShader.Program, "dirLight.ambient"), 0.0f, 0.0f, 0.0f); glUniform3f(glGetUniformLocation(lightingShader.Program, "dirLight.diffuse"), 0.05f, 0.05f, 0.05); glUniform3f(glGetUniformLocation(lightingShader.Program, "dirLight.specular"), 0.2f, 0.2f, 0.2f); // Точечный свет №1 glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[0].position"), pointLightPositions[0].x, pointLightPositions[0].y, pointLightPositions[0].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[0].ambient"), pointLightColors[0].x * 0.1, pointLightColors[0].y * 0.1, pointLightColors[0].z * 0.1); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[0].diffuse"), pointLightColors[0].x, pointLightColors[0].y, pointLightColors[0].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[0].specular"), pointLightColors[0].x, pointLightColors[0].y, pointLightColors[0].z); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[0].constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[0].linear"), 0.14); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[0].quadratic"), 0.07); // Точечный свет №2 glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[1].position"), pointLightPositions[1].x, pointLightPositions[1].y, pointLightPositions[1].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[1].ambient"), pointLightColors[1].x * 0.1, pointLightColors[1].y * 0.1, pointLightColors[1].z * 0.1); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[1].diffuse"), pointLightColors[1].x, pointLightColors[1].y, pointLightColors[1].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[1].specular"), pointLightColors[1].x, pointLightColors[1].y, pointLightColors[1].z); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[1].constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[1].linear"), 0.14); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[1].quadratic"), 0.07); // Точечный свет №3 glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[2].position"), pointLightPositions[2].x, pointLightPositions[2].y, pointLightPositions[2].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[2].ambient"), pointLightColors[2].x * 0.1, pointLightColors[2].y * 0.1, pointLightColors[2].z * 0.1); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[2].diffuse"), pointLightColors[2].x, pointLightColors[2].y, pointLightColors[2].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[2].specular") ,pointLightColors[2].x, pointLightColors[2].y, pointLightColors[2].z); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[2].constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[2].linear"), 0.22); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[2].quadratic"), 0.20); // Точечный свет №4 glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[3].position"), pointLightPositions[3].x, pointLightPositions[3].y, pointLightPositions[3].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[3].ambient"), pointLightColors[3].x * 0.1, pointLightColors[3].y * 0.1, pointLightColors[3].z * 0.1); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[3].diffuse"), pointLightColors[3].x, pointLightColors[3].y, pointLightColors[3].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[3].specular"), pointLightColors[3].x, pointLightColors[3].y, pointLightColors[3].z); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[3].constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[3].linear"), 0.14); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[3].quadratic"), 0.07); // Прожектор glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.position"), camera.Position.x, camera.Position.y, camera.Position.z); glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.direction"), camera.Front.x, camera.Front.y, camera.Front.z); glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.ambient"), 0.0f, 0.0f, 0.0f); glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.diffuse"), 1.0f, 1.0f, 1.0f); glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.specular"), 1.0f, 1.0f, 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.linear"), 0.09); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.quadratic"), 0.032); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.cutOff"), glm::cos(glm::radians(10.0f))); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.outerCutOff"), glm::cos(glm::radians(15.0f))); // == ============================================================================================== // Биохимическая лаборатория // == ============================================================================================== glClearColor(0.9f, 0.9f, 0.9f, 1.0f); [...] glm::vec3 pointLightColors[] = { glm::vec3(0.4f, 0.7f, 0.1f), glm::vec3(0.4f, 0.7f, 0.1f), glm::vec3(0.4f, 0.7f, 0.1f), glm::vec3(0.4f, 0.7f, 0.1f) }; [...] // Направленный свет glUniform3f(glGetUniformLocation(lightingShader.Program, "dirLight.direction"), -0.2f, -1.0f, -0.3f); glUniform3f(glGetUniformLocation(lightingShader.Program, "dirLight.ambient"), 0.5f, 0.5f, 0.5f); glUniform3f(glGetUniformLocation(lightingShader.Program, "dirLight.diffuse"), 1.0f, 1.0f, 1.0f); glUniform3f(glGetUniformLocation(lightingShader.Program, "dirLight.specular"), 1.0f, 1.0f, 1.0f); // Точечный свет №1 glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[0].position"), pointLightPositions[0].x, pointLightPositions[0].y, pointLightPositions[0].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[0].ambient"), pointLightColors[0].x * 0.1, pointLightColors[0].y * 0.1, pointLightColors[0].z * 0.1); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[0].diffuse"), pointLightColors[0].x, pointLightColors[0].y, pointLightColors[0].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[0].specular"), pointLightColors[0].x, pointLightColors[0].y, pointLightColors[0].z); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[0].constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[0].linear"), 0.07); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[0].quadratic"), 0.017); // Точечный свет №2 glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[1].position"), pointLightPositions[1].x, pointLightPositions[1].y, pointLightPositions[1].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[1].ambient"), pointLightColors[1].x * 0.1, pointLightColors[1].y * 0.1, pointLightColors[1].z * 0.1); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[1].diffuse"), pointLightColors[1].x, pointLightColors[1].y, pointLightColors[1].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[1].specular"), pointLightColors[1].x, pointLightColors[1].y, pointLightColors[1].z); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[1].constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[1].linear"), 0.07); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[1].quadratic"), 0.017); // Точечный свет №3 glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[2].position"), pointLightPositions[2].x, pointLightPositions[2].y, pointLightPositions[2].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[2].ambient"), pointLightColors[2].x * 0.1, pointLightColors[2].y * 0.1, pointLightColors[2].z * 0.1); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[2].diffuse"), pointLightColors[2].x, pointLightColors[2].y, pointLightColors[2].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[2].specular") ,pointLightColors[2].x, pointLightColors[2].y, pointLightColors[2].z); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[2].constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[2].linear"), 0.07); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[2].quadratic"), 0.017); // Точечный свет №4 glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[3].position"), pointLightPositions[3].x, pointLightPositions[3].y, pointLightPositions[3].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[3].ambient"), pointLightColors[3].x * 0.1, pointLightColors[3].y * 0.1, pointLightColors[3].z * 0.1); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[3].diffuse"), pointLightColors[3].x, pointLightColors[3].y, pointLightColors[3].z); glUniform3f(glGetUniformLocation(lightingShader.Program, "pointLights[3].specular"), pointLightColors[3].x, pointLightColors[3].y, pointLightColors[3].z); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[3].constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[3].linear"), 0.07); glUniform1f(glGetUniformLocation(lightingShader.Program, "pointLights[3].quadratic"), 0.017); // Прожектор glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.position"), camera.Position.x, camera.Position.y, camera.Position.z); glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.direction"), camera.Front.x, camera.Front.y, camera.Front.z); glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.ambient"), 0.0f, 0.0f, 0.0f); glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.diffuse"), 0.0f, 1.0f, 0.0f); glUniform3f(glGetUniformLocation(lightingShader.Program, "spotLight.specular"), 0.0f, 1.0f, 0.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.constant"), 1.0f); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.linear"), 0.07); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.quadratic"), 0.017); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.cutOff"), glm::cos(glm::radians(7.0f))); glUniform1f(glGetUniformLocation(lightingShader.Program, "spotLight.outerCutOff"), glm::cos(glm::radians(10.0f))); |
Спасибо большое за уроки!
Но возникла довольно серьезная проблема, как и вопрос. Что делать то когда свет проходит сквозь стены? точнее сквозь все полигоны. Как я понимаю он вообще не учитывает это для простоты.
Но для меня это серьезное упущение и никак не могу найти решение этой проблемы.
Все же не очень если в одной комнате источник света есть и он просто сквозь стены проходит или например на одной и той же модельке при таком освещении видно как свет проходит сквозь эту же модельку и освещает те области, которые ну явно никак не должна.
Это уже дальше в 32м уроке будет изучение теней.
Отличное заключение! Спасибо, Дмитрий.
Признаюсь, получилось не сразу. Оказалось просто поспешил сразу «слепить» точечные источники в цикл, не подумав про изменение названия строковой uniform переменной в цикле.
Решение: