153 lines
7.2 KiB
C++
153 lines
7.2 KiB
C++
#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));
|
||
}
|