#include "Lights.h" #include #include void genShpere(Model& model, float radius, int sectorsCount); // Model.cpp // Статическое поле для модели лампочки GrouptedModel Bulb::bulb_model; // Конструктор с координатами, цветом и радиусом Bulb::Bulb(const glm::vec3 &pos, const glm::vec3 &c, float r, float a, const glm::vec3 &dir) { // Если отладочная модель не загружена - загрузим if (!bulb_model.parts.size()) { bulb_model = loadOBJtoGroupted("../resources/models/bulb.obj", "../resources/models/", "../resources/textures/"); Model radius_sphere; // Сгенерируем и загрузим меш сферы genShpere(radius_sphere, 1, 16); bulb_model.parts.insert(bulb_model.parts.begin(), radius_sphere); } // Сохраним данные о параметрах источника: position = pos; color = c; radius = r; K[0] = 4.5/radius; K[1] = 4 * K[0] * K[0]; angle = a; direction = dir; } // Отрисовка отладочной лампы и сферы void Bulb::render(ShaderProgram &shaderProgram, UBO &material_buffer) { // Расположение uniform-переменных GLuint model_uniform = shaderProgram.getUniformLoc("model"); GLuint angle_uniform = shaderProgram.getUniformLoc("angle"); GLuint direction_uniform = shaderProgram.getUniformLoc("direction"); // Загрузим направление glUniform3fv(direction_uniform, 1, &direction[0]); // Зададим параметры материала сфере действия bulb_model.parts[0].material.ka = color; bulb_model.parts[0].position = position; bulb_model.parts[0].scale = {radius, radius, radius}; // Угол для сферы (рисуем направленный конус) glUniform1f(angle_uniform, angle); // Рисование сферы покрытия источника в режиме линий glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); bulb_model.parts[0].render(shaderProgram, material_buffer); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // Угол для лампочки = 180 (рисуем целую модель) glUniform1f(angle_uniform, 180); // Зададим параметры материала сфере действия // Зададим цвет для колбы (первая в составе модели) bulb_model.parts[1].material.ka = color; for (int i = 1; i < bulb_model.parts.size(); i++) { bulb_model.parts[i].position = position; bulb_model.parts[i].render(shaderProgram, material_buffer); } } // Задание радиуса и расчет коэф. угасания void Bulb::setRadius(float r) { radius = r; K[0] = 4.5/radius; K[1] = 4 * K[0] * K[0]; } // Конструктор направленного источника с параметрами направления и цвета Sun::Sun(const glm::vec3 &dir, const glm::vec3 &c) : direction(dir), color(c) { } // Загрузка данных об источнике на шейдер void Sun::upload(ShaderProgram &shaderProgram) { GLuint direction_uniform = shaderProgram.getUniformLoc("Sun_direction"); GLuint color_uniform = shaderProgram.getUniformLoc("Sun_color"); // Загрузим данные glUniform3fv(direction_uniform, 1, &direction[0]); glUniform3fv(color_uniform, 1, &color[0]); } // Загружает матрицу проекции и трансформации в пространство источника void Sun::pov(ShaderProgram &shaderProgram, Camera camera) { // Точки по краям проекции камеры const glm::vec4 (*projCoords)[8] = camera.getProjCoords(); glm::vec3 mean; // Среднее арифметическое glm::vec4 max, min; // макс и мин координаты glm::vec4 point; // Точка приведенная в пространство источника света glm::mat4 lightView; // Матрица вида для вычисляемого каскада glm::mat4 results[CAMERA_CASCADE_COUNT]; // Результат вычисления каждого каскада for (int cascade = 0; cascade < CAMERA_CASCADE_COUNT; cascade++) { mean = glm::vec3(0); // Найдем среднее арифметическое от точек для нахождения центра прямоугольника for (int i = 0; i < 8; i++) mean += glm::vec3(projCoords[cascade][i]); mean /= 8; // Используем среднее арифметическое для получения матрицы вида параллельного источника lightView = glm::lookAt(mean + glm::normalize(direction), mean, CAMERA_UP_VECTOR); // Примем первую точку как минимальную и максимальную (приведя в пространство вида источника) min = max = lightView * projCoords[cascade][0]; // Для оставшихся точек for (int i = 1; i < 8; i++) { // Приведем в пространство вида источника point = lightView * projCoords[cascade][i]; max = glm::max(max, point); min = glm::min(min, point); } // Максимальное значение глубины max.z = std::max(fabs(max.z), fabs(min.z)); // На основании максимальных и минимальных координат создадим матрицу проекции источника results[cascade] = glm::ortho(min.x, max.x, min.y, max.y, min.z, max.z) * lightView; } // Загрузим данные о матрице проекции на выбранный шейдер GLuint lightVP_uniform = shaderProgram.getUniformLoc("Sun_VP"); glUniformMatrix4fv(lightVP_uniform, CAMERA_CASCADE_COUNT, GL_FALSE, &results[0][0][0]); } // Пересчитывает матрицы проекции и трансформации в пространство источника void Bulb::recalc_pov() { float near_plane = 0.1f; glm::mat4 shadowProj = glm::perspective(glm::radians(90.0f), 1.0f, near_plane, radius); vp[0] = shadowProj * glm::lookAt(position, position + glm::vec3( 1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)); vp[1] = shadowProj * glm::lookAt(position, position + glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)); vp[2] = shadowProj * glm::lookAt(position, position + glm::vec3( 0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); vp[3] = shadowProj * glm::lookAt(position, position + glm::vec3( 0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)); vp[4] = shadowProj * glm::lookAt(position, position + glm::vec3( 0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)); vp[5] = shadowProj * glm::lookAt(position, position + glm::vec3( 0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)); }