17/src/Lights.cpp
2023-07-12 22:25:05 +03:00

153 lines
7.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Lights.h"
#include <GLM/gtc/matrix_transform.hpp>
#include <GLM/ext/matrix_transform.hpp>
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));
}