Compare commits
No commits in common. "master" and "v0.1" have entirely different histories.
|
@ -18,7 +18,6 @@ struct LightData
|
||||||
alignas(16) glm::vec3 color; // Цвет
|
alignas(16) glm::vec3 color; // Цвет
|
||||||
alignas(16) glm::vec3 attenuation; // Радиус действия источника, линейный и квадратичный коэф. угасания
|
alignas(16) glm::vec3 attenuation; // Радиус действия источника, линейный и квадратичный коэф. угасания
|
||||||
alignas(16) glm::vec4 direction_angle; // Направление и половинный угол освещенности
|
alignas(16) glm::vec4 direction_angle; // Направление и половинный угол освещенности
|
||||||
alignas(16) glm::mat4 vp[6]; // Матрицы проекции и трансформации в пространство источника
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Источник света
|
// Источник света
|
||||||
|
@ -31,7 +30,6 @@ class Light : public Node
|
||||||
static Light& getNew(); // Возвращает ссылку на новый источник света
|
static Light& getNew(); // Возвращает ссылку на новый источник света
|
||||||
void destroy(); // Уничтожает источник света
|
void destroy(); // Уничтожает источник света
|
||||||
|
|
||||||
static int getCount(); // Возвращает количество источников
|
|
||||||
const glm::vec3& c_color() const; // Константный доступ к цвету
|
const glm::vec3& c_color() const; // Константный доступ к цвету
|
||||||
glm::vec3& e_color(); // Неконстантная ссылка для изменений цвета
|
glm::vec3& e_color(); // Неконстантная ссылка для изменений цвета
|
||||||
|
|
||||||
|
@ -60,7 +58,6 @@ class Light : public Node
|
||||||
void toData(); // Преобразует информацию об источнике в структуру LightData
|
void toData(); // Преобразует информацию об источнике в структуру LightData
|
||||||
|
|
||||||
virtual void recalcMatrices(); // Метод пересчета матрицы трансформации по необходимости, должен сбрасывать флаг changed
|
virtual void recalcMatrices(); // Метод пересчета матрицы трансформации по необходимости, должен сбрасывать флаг changed
|
||||||
void recalcVP(); // Пересчитывает по необходимости матрицу вида-проекции
|
|
||||||
|
|
||||||
static GLuint count; // количество используемых источников (должно быть <= MAX_LIGHTS)
|
static GLuint count; // количество используемых источников (должно быть <= MAX_LIGHTS)
|
||||||
static LightData data[MAX_LIGHTS]; // Массив данных по источникам света
|
static LightData data[MAX_LIGHTS]; // Массив данных по источникам света
|
||||||
|
|
|
@ -15,7 +15,6 @@ struct LightData
|
||||||
vec3 color;
|
vec3 color;
|
||||||
vec3 attenuation;
|
vec3 attenuation;
|
||||||
vec4 direction_angle;
|
vec4 direction_angle;
|
||||||
mat4 vp[6];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(std140, binding = 2) uniform Light
|
layout(std140, binding = 2) uniform Light
|
||||||
|
@ -38,7 +37,6 @@ uniform sampler2D gNormal;
|
||||||
uniform sampler2D gDiffuseP;
|
uniform sampler2D gDiffuseP;
|
||||||
uniform sampler2D gAmbientSpecular;
|
uniform sampler2D gAmbientSpecular;
|
||||||
uniform sampler2DArray sunShadowDepth;
|
uniform sampler2DArray sunShadowDepth;
|
||||||
uniform samplerCubeArray pointShadowDepth;
|
|
||||||
|
|
||||||
out vec4 color;
|
out vec4 color;
|
||||||
|
|
||||||
|
@ -65,10 +63,8 @@ void main()
|
||||||
vec3 fragPosLightSpace; // Фрагмент в пространстве источника
|
vec3 fragPosLightSpace; // Фрагмент в пространстве источника
|
||||||
float shadowValue; // Значение затененности
|
float shadowValue; // Значение затененности
|
||||||
vec2 texelSize = 1.0 / textureSize(sunShadowDepth, 0).xy; // Размер текселя текстуры теней
|
vec2 texelSize = 1.0 / textureSize(sunShadowDepth, 0).xy; // Размер текселя текстуры теней
|
||||||
int x, y, z; // Счетчик для PCF
|
int x, y; // Счетчик для PCF
|
||||||
float pcfDepth; // Глубина PCF
|
float pcfDepth; // Глубина PCF
|
||||||
float cubemap_offset = 0.05f; // Отступ в текстурных координатах для PCF
|
|
||||||
float cubemap_depth; // Дистанция между фрагментом и источником в диапазоне [0;1]
|
|
||||||
|
|
||||||
vec4 fragPosCamSpace = camera.view * vec4(fragPos, 1); // Фрагмент в пространстве камеры
|
vec4 fragPosCamSpace = camera.view * vec4(fragPos, 1); // Фрагмент в пространстве камеры
|
||||||
int cascade_index; // Индекс текущего каскада для вычисления теней
|
int cascade_index; // Индекс текущего каскада для вычисления теней
|
||||||
|
@ -123,68 +119,43 @@ void main()
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < light_f.count; i++)
|
for (i = 0; i < light_f.count; i++)
|
||||||
{
|
{
|
||||||
// Обнулим значение тени
|
// Данные об источнике относительно фрагмента
|
||||||
shadowValue = 0;
|
L_vertex = light_f.data[i].position - fragPos;
|
||||||
// Позиция фрагмента относительно источника
|
|
||||||
fragPosLightSpace = fragPos - light_f.data[i].position;
|
// Расстояние от поверхности до источника
|
||||||
// Дистанция между фрагментом и источником в диапазоне [0;1]
|
L_distance = length(L_vertex);
|
||||||
cubemap_depth = length(fragPosLightSpace) / light_f.data[i].attenuation.r;
|
|
||||||
// Сдвиг для решения проблемы акне
|
// Проверка на дистанцию
|
||||||
cubemap_depth -= max(0.05 * (1.0 - dot(N, light_f.data[i].direction_angle.xyz)), 0.005);
|
if (L_distance < light_f.data[i].attenuation.r)
|
||||||
for(x = -1; x <= 1; ++x)
|
|
||||||
{
|
{
|
||||||
for(y = -1; y <= 1; ++y)
|
// Нормирование вектора
|
||||||
|
L_vertex = normalize(L_vertex);
|
||||||
|
// арккосинус между вектором от поверхности к источнику и обратным направлением источника
|
||||||
|
acosA = degrees(acos(dot(-L_vertex, normalize(light_f.data[i].direction_angle.xyz))));
|
||||||
|
// Если угол меньше угла источника или угол источника минимален, то считаем освещенность
|
||||||
|
if(acosA <= light_f.data[i].direction_angle.a)
|
||||||
{
|
{
|
||||||
for(z = -1; z <= 1; ++z)
|
// Диффузная составляющая
|
||||||
|
diffuse = max(dot(L_vertex, N), 0.0); // скалярное произведение с отсеканием значений < 0
|
||||||
|
|
||||||
|
// Вектор половины пути
|
||||||
|
H = normalize(L_vertex + Cam_vertex);
|
||||||
|
// Зеркальная составляющая
|
||||||
|
specular = pow(max(dot(H, N), 0.0), p*4); // скалярное произведение с отсеканием значений < 0 в степени p
|
||||||
|
|
||||||
|
// Угасание с учетом расстояния
|
||||||
|
attenuation = 1 / (1 + light_f.data[i].attenuation[1] * L_distance + light_f.data[i].attenuation[2] * L_distance * L_distance);
|
||||||
|
|
||||||
|
// Если источник - прожектор, то добавим смягчение
|
||||||
|
if (light_f.data[i].direction_angle.a < 180)
|
||||||
{
|
{
|
||||||
// Значение из кубической текстуры с учетом источника (i)
|
intensity = clamp((light_f.data[i].direction_angle.a - acosA) / 5, 0.0, 1.0);
|
||||||
pcfDepth = texture(pointShadowDepth, vec4(fragPosLightSpace + vec3(x, y, z)*cubemap_offset, i)).r;
|
diffuse *= intensity;
|
||||||
if(cubemap_depth > pcfDepth)
|
specular *= intensity;
|
||||||
shadowValue += 1.0;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
shadowValue /= (27);
|
|
||||||
if (shadowValue < 1.0)
|
|
||||||
{
|
|
||||||
// Данные об источнике относительно фрагмента
|
|
||||||
L_vertex = light_f.data[i].position - fragPos;
|
|
||||||
|
|
||||||
// Расстояние от поверхности до источника
|
color += vec4(light_f.data[i].color*kd*diffuse * attenuation, 1)
|
||||||
L_distance = length(L_vertex);
|
+ vec4(light_f.data[i].color*ks*specular * attenuation, 1);
|
||||||
|
|
||||||
// Проверка на дистанцию
|
|
||||||
if (L_distance < light_f.data[i].attenuation.r)
|
|
||||||
{
|
|
||||||
// Нормирование вектора
|
|
||||||
L_vertex = normalize(L_vertex);
|
|
||||||
// арккосинус между вектором от поверхности к источнику и обратным направлением источника
|
|
||||||
acosA = degrees(acos(dot(-L_vertex, normalize(light_f.data[i].direction_angle.xyz))));
|
|
||||||
// Если угол меньше угла источника или угол источника минимален, то считаем освещенность
|
|
||||||
if(acosA <= light_f.data[i].direction_angle.a)
|
|
||||||
{
|
|
||||||
// Диффузная составляющая
|
|
||||||
diffuse = max(dot(L_vertex, N), 0.0); // скалярное произведение с отсеканием значений < 0
|
|
||||||
|
|
||||||
// Вектор половины пути
|
|
||||||
H = normalize(L_vertex + Cam_vertex);
|
|
||||||
// Зеркальная составляющая
|
|
||||||
specular = pow(max(dot(H, N), 0.0), p*4); // скалярное произведение с отсеканием значений < 0 в степени p
|
|
||||||
|
|
||||||
// Угасание с учетом расстояния
|
|
||||||
attenuation = 1 / (1 + light_f.data[i].attenuation[1] * L_distance + light_f.data[i].attenuation[2] * L_distance * L_distance);
|
|
||||||
|
|
||||||
// Если источник - прожектор, то добавим смягчение
|
|
||||||
if (light_f.data[i].direction_angle.a < 180)
|
|
||||||
{
|
|
||||||
intensity = clamp((light_f.data[i].direction_angle.a - acosA) / 5, 0.0, 1.0);
|
|
||||||
diffuse *= intensity;
|
|
||||||
specular *= intensity;
|
|
||||||
}
|
|
||||||
|
|
||||||
color += ( vec4(light_f.data[i].color*kd*diffuse * attenuation, 1)
|
|
||||||
+ vec4(light_f.data[i].color*ks*specular * attenuation, 1) ) * (1.0 - shadowValue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
#version 330 core
|
|
||||||
|
|
||||||
in vec4 FragPos;
|
|
||||||
in vec3 lightPos;
|
|
||||||
in float radius;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
// Расстояние между источником и фрагментом
|
|
||||||
float lightDistance = length(FragPos.xyz - lightPos);
|
|
||||||
|
|
||||||
// Приведение к диапазону [0;1]
|
|
||||||
lightDistance = lightDistance / radius;
|
|
||||||
|
|
||||||
// Замена значения глубины
|
|
||||||
gl_FragDepth = lightDistance;
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
#version 420 core
|
|
||||||
layout (triangles, invocations = 6) in; // здесь invocations соответствует числу сторон кубической карты теней
|
|
||||||
layout (triangle_strip, max_vertices=18) out; // здесь max_vertices = 3 вершины * 6 вызовов на стороны куба
|
|
||||||
|
|
||||||
struct LightData
|
|
||||||
{
|
|
||||||
vec3 position;
|
|
||||||
vec3 color;
|
|
||||||
vec3 attenuation;
|
|
||||||
vec4 direction_angle;
|
|
||||||
mat4 vp[6];
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(std140, binding = 2) uniform Light
|
|
||||||
{
|
|
||||||
LightData data[64];
|
|
||||||
int count;
|
|
||||||
} light_g;
|
|
||||||
|
|
||||||
uniform int light_i;
|
|
||||||
|
|
||||||
out vec4 FragPos;
|
|
||||||
out vec3 lightPos;
|
|
||||||
out float radius;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
for(int i = 0; i < 3; ++i)
|
|
||||||
{
|
|
||||||
FragPos = gl_in[i].gl_Position;
|
|
||||||
lightPos = light_g.data[light_i].position;
|
|
||||||
radius = light_g.data[light_i].attenuation.r;
|
|
||||||
gl_Position = light_g.data[light_i].vp[gl_InvocationID] * gl_in[i].gl_Position;
|
|
||||||
gl_Layer = gl_InvocationID + light_i*6;
|
|
||||||
EmitVertex();
|
|
||||||
}
|
|
||||||
EndPrimitive();
|
|
||||||
}
|
|
|
@ -98,15 +98,7 @@ void Light::toData()
|
||||||
{
|
{
|
||||||
check_id(); // Проверка на работу с корректным индексом
|
check_id(); // Проверка на работу с корректным индексом
|
||||||
|
|
||||||
// Если позиция изменилась
|
data[index].position = glm::vec3(result_transform[3]); // Позиция из матрицы трансформации
|
||||||
if (data[index].position.x != result_transform[3].x
|
|
||||||
|| data[index].position.y != result_transform[3].y
|
|
||||||
|| data[index].position.z != result_transform[3].z
|
|
||||||
)
|
|
||||||
{
|
|
||||||
data[index].position = glm::vec3(result_transform[3]); // Позиция из матрицы трансформации
|
|
||||||
recalcVP(); // Пересчет матрицы вида-проекции для расчета теней
|
|
||||||
}
|
|
||||||
data[index].color = color; // Цвет
|
data[index].color = color; // Цвет
|
||||||
// Если радиус изменился
|
// Если радиус изменился
|
||||||
if (data[index].attenuation.r != radius)
|
if (data[index].attenuation.r != radius)
|
||||||
|
@ -354,22 +346,3 @@ void Sun::recalcVP()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Пересчитывает по необходимости матрицу вида-проекции
|
|
||||||
void Light::recalcVP()
|
|
||||||
{
|
|
||||||
float near_plane = 0.1f;
|
|
||||||
glm::mat4 shadowProj = glm::perspective(glm::radians(90.0f), 1.0f, near_plane, radius);
|
|
||||||
data[index].vp[0] = shadowProj * glm::lookAt(position, position + glm::vec3( 1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f));
|
|
||||||
data[index].vp[1] = shadowProj * glm::lookAt(position, position + glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f));
|
|
||||||
data[index].vp[2] = shadowProj * glm::lookAt(position, position + glm::vec3( 0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
|
||||||
data[index].vp[3] = shadowProj * glm::lookAt(position, position + glm::vec3( 0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f));
|
|
||||||
data[index].vp[4] = shadowProj * glm::lookAt(position, position + glm::vec3( 0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f));
|
|
||||||
data[index].vp[5] = shadowProj * glm::lookAt(position, position + glm::vec3( 0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Возвращает количество источников
|
|
||||||
int Light::getCount()
|
|
||||||
{
|
|
||||||
return count;
|
|
||||||
}
|
|
50
src/main.cpp
50
src/main.cpp
|
@ -139,11 +139,11 @@ int main(void)
|
||||||
// Источники света
|
// Источники света
|
||||||
Light& first = Light::getNew();
|
Light& first = Light::getNew();
|
||||||
first.e_color() = {1.0f, 0.0f, 0.0f}; // цвет
|
first.e_color() = {1.0f, 0.0f, 0.0f}; // цвет
|
||||||
first.e_position() = {0.3f, 0.0f, 0.6f}; // Позиция
|
first.e_position() = {0.3f, 0.1f, 0.5f}; // Позиция
|
||||||
first.e_angle() = 100.0f;
|
first.e_angle() = 70.0f;
|
||||||
Light& second = Light::getNew();
|
Light& second = Light::getNew();
|
||||||
second.e_color() = {0.0f, 0.0f, 1.0f}; // цвет
|
second.e_color() = {0.0f, 0.0f, 1.0f}; // цвет
|
||||||
second.e_position() = {-0.3f, 0.3f, 0.5f}; // Позиция
|
second.e_position() = {-0.3f, -0.1f, 0.5f}; // Позиция
|
||||||
|
|
||||||
// Uniform-буферы
|
// Uniform-буферы
|
||||||
UBO cameraUB(sizeof(CameraData), 0);
|
UBO cameraUB(sizeof(CameraData), 0);
|
||||||
|
@ -180,7 +180,7 @@ int main(void)
|
||||||
lightShader.load(GL_VERTEX_SHADER, "shaders/quad.vert");
|
lightShader.load(GL_VERTEX_SHADER, "shaders/quad.vert");
|
||||||
lightShader.load(GL_FRAGMENT_SHADER, "shaders/lighting.frag");
|
lightShader.load(GL_FRAGMENT_SHADER, "shaders/lighting.frag");
|
||||||
lightShader.link();
|
lightShader.link();
|
||||||
const char* gtextures_shader_names[] = {"gPosition", "gNormal", "gDiffuseP", "gAmbientSpecular", "sunShadowDepth", "pointShadowDepth"};
|
const char* gtextures_shader_names[] = {"gPosition", "gNormal", "gDiffuseP", "gAmbientSpecular", "sunShadowDepth"};
|
||||||
lightShader.bindTextures(gtextures_shader_names, sizeof(gtextures_shader_names)/sizeof(const char*));
|
lightShader.bindTextures(gtextures_shader_names, sizeof(gtextures_shader_names)/sizeof(const char*));
|
||||||
// Загрузка данных о границах каскадов
|
// Загрузка данных о границах каскадов
|
||||||
glUniform1fv(lightShader.getUniformLoc("camera_cascade_distances"), CAMERA_CASCADE_COUNT, &camera_cascade_distances[1]);
|
glUniform1fv(lightShader.getUniformLoc("camera_cascade_distances"), CAMERA_CASCADE_COUNT, &camera_cascade_distances[1]);
|
||||||
|
@ -222,26 +222,6 @@ int main(void)
|
||||||
sunShadowShader.load(GL_FRAGMENT_SHADER, "shaders/empty.frag");
|
sunShadowShader.load(GL_FRAGMENT_SHADER, "shaders/empty.frag");
|
||||||
sunShadowShader.link();
|
sunShadowShader.link();
|
||||||
|
|
||||||
// Размер одной стороны кубической карты
|
|
||||||
const GLuint pointShadow_resolution = 500;
|
|
||||||
// Создадим буфер кадра для рендера теней от источников света
|
|
||||||
FBO pointShadowBuffer;
|
|
||||||
// Создадим текстуры для буфера кадра
|
|
||||||
TextureCubeArray pointShadowDepth(MAX_LIGHTS, pointShadow_resolution, pointShadow_resolution, GL_DEPTH_ATTACHMENT, 5, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT);
|
|
||||||
// Отключим работу с цветом
|
|
||||||
glDrawBuffer(GL_NONE);
|
|
||||||
glReadBuffer(GL_NONE);
|
|
||||||
// Активируем базовый буфер кадра
|
|
||||||
FBO::useDefault();
|
|
||||||
|
|
||||||
// Шейдер для расчета теней от точечных источников
|
|
||||||
ShaderProgram pointShadowShader;
|
|
||||||
// Загрузим шейдер
|
|
||||||
pointShadowShader.load(GL_VERTEX_SHADER, "shaders/sun_shadow.vert");
|
|
||||||
pointShadowShader.load(GL_GEOMETRY_SHADER, "shaders/point_shadow.geom");
|
|
||||||
pointShadowShader.load(GL_FRAGMENT_SHADER, "shaders/point_shadow.frag");
|
|
||||||
pointShadowShader.link();
|
|
||||||
|
|
||||||
// Модель прямоугольника
|
// Модель прямоугольника
|
||||||
Model rectangle;
|
Model rectangle;
|
||||||
|
|
||||||
|
@ -274,8 +254,8 @@ int main(void)
|
||||||
rectangle.e_scale() = glm::vec3(4);
|
rectangle.e_scale() = glm::vec3(4);
|
||||||
|
|
||||||
// Параметры материала
|
// Параметры материала
|
||||||
rectangle.material.ka = {0.2, 0.2, 0.2};
|
rectangle.material.ka = {0.4, 0.4, 0.4};
|
||||||
rectangle.material.kd = {0.9, 0.9, 0.9};
|
rectangle.material.kd = {0.4, 0.4, 0.4};
|
||||||
|
|
||||||
// Шейдер для рисования отладочных лампочек
|
// Шейдер для рисования отладочных лампочек
|
||||||
ShaderProgram bulbShader;
|
ShaderProgram bulbShader;
|
||||||
|
@ -383,23 +363,6 @@ int main(void)
|
||||||
scene.render(sunShadowShader, material_data);
|
scene.render(sunShadowShader, material_data);
|
||||||
rectangle.render(sunShadowShader, material_data);
|
rectangle.render(sunShadowShader, material_data);
|
||||||
|
|
||||||
// Изменим размер вывода для стороны кубической карты точечного источника
|
|
||||||
glViewport(0, 0, pointShadow_resolution, pointShadow_resolution);
|
|
||||||
// Активируем буфер кадра для теней от солнца
|
|
||||||
pointShadowBuffer.use();
|
|
||||||
// Подключим шейдер для расчета теней
|
|
||||||
pointShadowShader.use();
|
|
||||||
// Очистка буфера глубины
|
|
||||||
glClear(GL_DEPTH_BUFFER_BIT);
|
|
||||||
// Для каждого источника вызывается рендер сцены
|
|
||||||
for (int i = 0; i < Light::getCount(); i++)
|
|
||||||
{
|
|
||||||
glUniform1i(pointShadowShader.getUniformLoc("light_i"), i);
|
|
||||||
// Рендерим геометрию в буфер глубины
|
|
||||||
scene.render(pointShadowShader, material_data);
|
|
||||||
rectangle.render(pointShadowShader, material_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Изменим размер вывода для окна
|
// Изменим размер вывода для окна
|
||||||
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
|
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||||
// Активируем базовый буфер кадра
|
// Активируем базовый буфер кадра
|
||||||
|
@ -415,7 +378,6 @@ int main(void)
|
||||||
gAmbientSpecular.use();
|
gAmbientSpecular.use();
|
||||||
// Подключаем текстуры теней
|
// Подключаем текстуры теней
|
||||||
sunShadowDepth.use();
|
sunShadowDepth.use();
|
||||||
pointShadowDepth.use();
|
|
||||||
// Рендерим прямоугольник с расчетом освещения
|
// Рендерим прямоугольник с расчетом освещения
|
||||||
quadModel.render();
|
quadModel.render();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue