diff --git a/include/Lights.h b/include/Lights.h index 569ef9d..3affac5 100644 --- a/include/Lights.h +++ b/include/Lights.h @@ -81,7 +81,10 @@ class Sun alignas(16) glm::vec3 direction; // Направление лучей источника alignas(16) glm::vec3 color; // Цвет + alignas(16) glm::mat4 vp; // Матрица вида-проекции источника + void recalcVP(); // Пересчитывает по необходимости матрицу вида-проекции + static Sun instance; // Экземпляр синглтона static bool uploadReq; // Необходимость загрузки в следствии изменений }; diff --git a/src/Lights.cpp b/src/Lights.cpp index 2a15b30..278a8cd 100644 --- a/src/Lights.cpp +++ b/src/Lights.cpp @@ -264,6 +264,8 @@ Sun& Sun::get() // Загрузка данных об источнике на шейдер void Sun::upload(UBO& sun_data) { + instance.recalcVP(); // Пересчет матрицы вида-проекции источника по необходимости (влияет на флаг uploadReq) + if (uploadReq) { sun_data.loadSub(&instance, sizeof(instance)); @@ -299,3 +301,42 @@ glm::vec3& Sun::e_color() return instance.color; } + +// Пересчитывает по необходимости матрицу вида-проекции +void Sun::recalcVP() +{ + std::pair camProjCoords = Camera::current().getProjCoords(); + + // Есть изменения по источнику или камере + if (uploadReq || camProjCoords.first) + { + uploadReq = true; // Требуется загрузка в следствии пересчета матрицы + + glm::vec3 mean = glm::vec3(0); // Среднее арифметическое + glm::vec4 max, min; // макс и мин координаты + glm::vec4 point; // Точка приведенная в пространство источника света + + // Найдем среднее арифметическое от точек для нахождения центра прямоугольника + for (int i = 0; i < 8; i++) + mean += glm::vec3(camProjCoords.second[i]); + mean /= 8; + // Используем среднее арифметическое для получения матрицы вида параллельного источника + glm::mat4 lightView = glm::lookAt(mean + glm::normalize(direction), mean, CAMERA_UP_VECTOR); + + // Примем первую точку как минимальную и максимальную (приведя в пространство вида источника) + min = max = lightView * camProjCoords.second[0]; + // Для оставшихся точек + for (int i = 1; i < 8; i++) + { + // Приведем в пространство вида источника + point = lightView * camProjCoords.second[i]; + max = glm::max(max, point); + min = glm::min(min, point); + } + + // Максимальное значение глубины + max.z = std::max(fabs(max.z), fabs(min.z)); + // На основании максимальных и минимальных координат создадим матрицу проекции источника + vp = glm::ortho(min.x, max.x, min.y, max.y, min.z, max.z) * lightView; + } +}