Compare commits
8 Commits
Author | SHA1 | Date |
---|---|---|
Ковалев Роман Евгеньевич | cfea1de4a0 | |
Ковалев Роман Евгеньевич | f5a90009c2 | |
Ковалев Роман Евгеньевич | 4f5c5ee0cb | |
Ковалев Роман Евгеньевич | 8455e85605 | |
Ковалев Роман Евгеньевич | e340265f5f | |
Ковалев Роман Евгеньевич | 254dbdd90e | |
Ковалев Роман Евгеньевич | ec44eebe2d | |
Ковалев Роман Евгеньевич | 5a727f94da |
|
@ -18,6 +18,7 @@ struct LightData
|
|||
alignas(16) glm::vec3 color; // Цвет
|
||||
alignas(16) glm::vec3 attenuation; // Радиус действия источника, линейный и квадратичный коэф. угасания
|
||||
alignas(16) glm::vec4 direction_angle; // Направление и половинный угол освещенности
|
||||
alignas(16) glm::mat4 vp[6]; // Матрицы проекции и трансформации в пространство источника
|
||||
};
|
||||
|
||||
// Источник света
|
||||
|
@ -30,6 +31,7 @@ class Light : public Node
|
|||
static Light& getNew(); // Возвращает ссылку на новый источник света
|
||||
void destroy(); // Уничтожает источник света
|
||||
|
||||
static int getCount(); // Возвращает количество источников
|
||||
const glm::vec3& c_color() const; // Константный доступ к цвету
|
||||
glm::vec3& e_color(); // Неконстантная ссылка для изменений цвета
|
||||
|
||||
|
@ -58,6 +60,7 @@ class Light : public Node
|
|||
void toData(); // Преобразует информацию об источнике в структуру LightData
|
||||
|
||||
virtual void recalcMatrices(); // Метод пересчета матрицы трансформации по необходимости, должен сбрасывать флаг changed
|
||||
void recalcVP(); // Пересчитывает по необходимости матрицу вида-проекции
|
||||
|
||||
static GLuint count; // количество используемых источников (должно быть <= MAX_LIGHTS)
|
||||
static LightData data[MAX_LIGHTS]; // Массив данных по источникам света
|
||||
|
|
|
@ -15,6 +15,7 @@ struct LightData
|
|||
vec3 color;
|
||||
vec3 attenuation;
|
||||
vec4 direction_angle;
|
||||
mat4 vp[6];
|
||||
};
|
||||
|
||||
layout(std140, binding = 2) uniform Light
|
||||
|
@ -37,6 +38,7 @@ uniform sampler2D gNormal;
|
|||
uniform sampler2D gDiffuseP;
|
||||
uniform sampler2D gAmbientSpecular;
|
||||
uniform sampler2DArray sunShadowDepth;
|
||||
uniform samplerCubeArray pointShadowDepth;
|
||||
|
||||
out vec4 color;
|
||||
|
||||
|
@ -63,8 +65,10 @@ void main()
|
|||
vec3 fragPosLightSpace; // Фрагмент в пространстве источника
|
||||
float shadowValue; // Значение затененности
|
||||
vec2 texelSize = 1.0 / textureSize(sunShadowDepth, 0).xy; // Размер текселя текстуры теней
|
||||
int x, y; // Счетчик для PCF
|
||||
int x, y, z; // Счетчик для PCF
|
||||
float pcfDepth; // Глубина PCF
|
||||
float cubemap_offset = 0.05f; // Отступ в текстурных координатах для PCF
|
||||
float cubemap_depth; // Дистанция между фрагментом и источником в диапазоне [0;1]
|
||||
|
||||
vec4 fragPosCamSpace = camera.view * vec4(fragPos, 1); // Фрагмент в пространстве камеры
|
||||
int cascade_index; // Индекс текущего каскада для вычисления теней
|
||||
|
@ -118,6 +122,30 @@ void main()
|
|||
// Цикл по источникам света
|
||||
int i;
|
||||
for (i = 0; i < light_f.count; i++)
|
||||
{
|
||||
// Обнулим значение тени
|
||||
shadowValue = 0;
|
||||
// Позиция фрагмента относительно источника
|
||||
fragPosLightSpace = fragPos - light_f.data[i].position;
|
||||
// Дистанция между фрагментом и источником в диапазоне [0;1]
|
||||
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);
|
||||
for(x = -1; x <= 1; ++x)
|
||||
{
|
||||
for(y = -1; y <= 1; ++y)
|
||||
{
|
||||
for(z = -1; z <= 1; ++z)
|
||||
{
|
||||
// Значение из кубической текстуры с учетом источника (i)
|
||||
pcfDepth = texture(pointShadowDepth, vec4(fragPosLightSpace + vec3(x, y, z)*cubemap_offset, i)).r;
|
||||
if(cubemap_depth > pcfDepth)
|
||||
shadowValue += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
shadowValue /= (27);
|
||||
if (shadowValue < 1.0)
|
||||
{
|
||||
// Данные об источнике относительно фрагмента
|
||||
L_vertex = light_f.data[i].position - fragPos;
|
||||
|
@ -154,8 +182,9 @@ void main()
|
|||
specular *= intensity;
|
||||
}
|
||||
|
||||
color += vec4(light_f.data[i].color*kd*diffuse * attenuation, 1)
|
||||
+ vec4(light_f.data[i].color*ks*specular * attenuation, 1);
|
||||
color += ( vec4(light_f.data[i].color*kd*diffuse * attenuation, 1)
|
||||
+ vec4(light_f.data[i].color*ks*specular * attenuation, 1) ) * (1.0 - shadowValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
#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;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#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,7 +98,15 @@ void Light::toData()
|
|||
{
|
||||
check_id(); // Проверка на работу с корректным индексом
|
||||
|
||||
// Если позиция изменилась
|
||||
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; // Цвет
|
||||
// Если радиус изменился
|
||||
if (data[index].attenuation.r != radius)
|
||||
|
@ -346,3 +354,22 @@ 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();
|
||||
first.e_color() = {1.0f, 0.0f, 0.0f}; // цвет
|
||||
first.e_position() = {0.3f, 0.1f, 0.5f}; // Позиция
|
||||
first.e_angle() = 70.0f;
|
||||
first.e_position() = {0.3f, 0.0f, 0.6f}; // Позиция
|
||||
first.e_angle() = 100.0f;
|
||||
Light& second = Light::getNew();
|
||||
second.e_color() = {0.0f, 0.0f, 1.0f}; // цвет
|
||||
second.e_position() = {-0.3f, -0.1f, 0.5f}; // Позиция
|
||||
second.e_position() = {-0.3f, 0.3f, 0.5f}; // Позиция
|
||||
|
||||
// Uniform-буферы
|
||||
UBO cameraUB(sizeof(CameraData), 0);
|
||||
|
@ -180,7 +180,7 @@ int main(void)
|
|||
lightShader.load(GL_VERTEX_SHADER, "shaders/quad.vert");
|
||||
lightShader.load(GL_FRAGMENT_SHADER, "shaders/lighting.frag");
|
||||
lightShader.link();
|
||||
const char* gtextures_shader_names[] = {"gPosition", "gNormal", "gDiffuseP", "gAmbientSpecular", "sunShadowDepth"};
|
||||
const char* gtextures_shader_names[] = {"gPosition", "gNormal", "gDiffuseP", "gAmbientSpecular", "sunShadowDepth", "pointShadowDepth"};
|
||||
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]);
|
||||
|
@ -222,6 +222,26 @@ int main(void)
|
|||
sunShadowShader.load(GL_FRAGMENT_SHADER, "shaders/empty.frag");
|
||||
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;
|
||||
|
||||
|
@ -254,8 +274,8 @@ int main(void)
|
|||
rectangle.e_scale() = glm::vec3(4);
|
||||
|
||||
// Параметры материала
|
||||
rectangle.material.ka = {0.4, 0.4, 0.4};
|
||||
rectangle.material.kd = {0.4, 0.4, 0.4};
|
||||
rectangle.material.ka = {0.2, 0.2, 0.2};
|
||||
rectangle.material.kd = {0.9, 0.9, 0.9};
|
||||
|
||||
// Шейдер для рисования отладочных лампочек
|
||||
ShaderProgram bulbShader;
|
||||
|
@ -363,6 +383,23 @@ int main(void)
|
|||
scene.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);
|
||||
// Активируем базовый буфер кадра
|
||||
|
@ -378,6 +415,7 @@ int main(void)
|
|||
gAmbientSpecular.use();
|
||||
// Подключаем текстуры теней
|
||||
sunShadowDepth.use();
|
||||
pointShadowDepth.use();
|
||||
// Рендерим прямоугольник с расчетом освещения
|
||||
quadModel.render();
|
||||
|
||||
|
|
Loading…
Reference in New Issue