Compare commits

..

13 Commits
v0.1 ... master

Author SHA1 Message Date
Ковалев Роман Евгеньевич 754490b7a0 Меньший радиус полусферы 2024-03-01 09:58:04 +03:00
Ковалев Роман Евгеньевич 51bb5db495 Размытие SSAO 2024-03-01 09:58:04 +03:00
Ковалев Роман Евгеньевич 0d95b6364d Шейдер размытия SSAO 2024-03-01 09:38:33 +03:00
Ковалев Роман Евгеньевич 48e9973a48 Проверка диапазона 2024-03-01 09:38:33 +03:00
Ковалев Роман Евгеньевич 7735037ef7 Учет SSAO при расчетах освещения 2024-03-01 09:38:33 +03:00
Ковалев Роман Евгеньевич 3594f2e4b1 Вычисление SSAO 2024-03-01 09:38:33 +03:00
Ковалев Роман Евгеньевич 3dd8fe789c Шейдер для расчета SSAO 2024-03-01 09:38:33 +03:00
Ковалев Роман Евгеньевич 2040bf7941 Текстура шума 2024-03-01 09:38:33 +03:00
Ковалев Роман Евгеньевич 129dc529a8 Стандартные параметры SSAO 2024-03-01 09:38:33 +03:00
Ковалев Роман Евгеньевич 40628c901b Подключение текстуры SSAO к шейдеру освещения 2024-03-01 09:38:33 +03:00
Ковалев Роман Евгеньевич 8485ceb2e4 Генерация буфера 2024-03-01 09:38:33 +03:00
Ковалев Роман Евгеньевич 9dc496c4e8 Шейдер для вычисления SSAO 2024-03-01 09:38:33 +03:00
Ковалев Роман Евгеньевич c02cc081ab Данные для SSAO 2024-03-01 09:38:33 +03:00
5 changed files with 205 additions and 3 deletions

View File

@ -10,6 +10,8 @@
#define MAX_LIGHTS 64
// Стандартное направление источника без поворота
#define DEFAULT_LIGHT_DIRECTION glm::vec4(0.0f, 0.0f, 1.0f, 0.0f)
// Максимальное число образцов для SSAO
#define MAX_SSAO 64
// Точечный источник света
struct LightData
@ -93,4 +95,14 @@ class Sun
static bool uploadReq; // Необходимость загрузки в следствии изменений
};
// Данные для SSAO
struct SSAO_data
{
float radius = 0.05f;
float bias = 0.025f;
int size = MAX_SSAO;
alignas(16) glm::vec2 scale;
glm::vec3 samples[MAX_SSAO];
};
#endif // LIGHTS_H

View File

@ -39,6 +39,7 @@ uniform sampler2D gDiffuseP;
uniform sampler2D gAmbientSpecular;
uniform sampler2DArray sunShadowDepth;
uniform samplerCubeArray pointShadowDepth;
uniform sampler2D ssao;
out vec4 color;
@ -51,6 +52,7 @@ void main()
vec3 ka = texture(gAmbientSpecular, texCoord).rgb;
float ks = texture(gAmbientSpecular, texCoord).a;
float p = texture(gDiffuseP, texCoord).a;
float ssao_value = texture(ssao, texCoord).r;
// Переменные используемые в цикле:
vec3 L_vertex; // Данные об источнике относительно фрагмента
@ -79,7 +81,7 @@ void main()
break;
// Фоновая освещенность
color = vec4(ka, 1);
color = vec4(ka, 1) * ssao_value;
// Расчет солнца, если его цвет не черный
if (length(sun.color) > 0)

62
shaders/ssao.frag Normal file
View File

@ -0,0 +1,62 @@
#version 420 core
in vec2 texCoord;
out float occlusion;
uniform sampler2D gPosition;
uniform sampler2D gNormal;
uniform sampler2D noise;
layout(std140, binding = 0) uniform Camera
{
mat4 projection;
mat4 view;
vec3 position;
} camera;
layout(std140, binding = 3) uniform SSAO
{
float radius;
float bias;
int size;
vec2 scale;
vec3 samples[64];
} ssao;
void main()
{
// Получим информацию из текстур для данного фрагмента по текстурным координатам
vec3 fragPos = (camera.view * vec4(texture(gPosition, texCoord).xyz, 1)).xyz;
vec3 normal = normalize(texture(gNormal, texCoord).rgb);
vec3 randomVec = normalize(texture(noise, texCoord * ssao.scale).xyz);
// Расчет TBN матрицы
vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
vec3 bitangent = cross(normal, tangent);
mat3 TBN = mat3(tangent, bitangent, normal);
float sampleDepth; // Значение глубины образца выборки
vec3 samplePos; // Выборка, ориентированная в пространстве вида камеры
vec4 sampleCoord; // Выборка, преобразованная к текстурным координатам
float rangeCheck; // Проверка диапазона
// Проинициализируем значение счетчика и запустим цикл по выборкам
occlusion = 0;
for(int i = 0; i < ssao.size; i++)
{
samplePos = TBN * ssao.samples[i]; // в TBN-пространстве
samplePos = fragPos + samplePos * ssao.radius; // в пространстве вида камеры
sampleCoord = camera.projection * vec4(samplePos, 1.0);
sampleCoord.xyz /= sampleCoord.w; // Деление на значение перспективы
sampleCoord.xyz = sampleCoord.xyz * 0.5 + 0.5; // Трансформация в диапазон [0.0; 1.0]
// Получаем значение глубины по образцу выборки
sampleDepth = (camera.view * vec4(texture(gPosition, sampleCoord.xy).rgb, 1)).z;
rangeCheck = smoothstep(0.0, 1.0, ssao.radius / abs(fragPos.z - sampleDepth));
occlusion += (sampleDepth >= samplePos.z + ssao.bias ? 1.0 : 0.0) * rangeCheck;
}
occlusion = 1 - (occlusion / ssao.size);
}

23
shaders/ssaoBlur.frag Normal file
View File

@ -0,0 +1,23 @@
#version 330 core
in vec2 texCoord;
out float occlusion;
uniform sampler2D ssao;
void main()
{
vec2 texelSize = 1.0 / vec2(textureSize(ssao, 0));
vec2 offset;
occlusion = 0.0;
for (int x = -2; x < 2; x++)
{
for (int y = -2; y < 2; y++)
{
offset = vec2(x, y) * texelSize;
occlusion += texture(ssao, texCoord + offset).r;
}
}
occlusion = occlusion / (4.0 * 4.0);
}

View File

@ -4,6 +4,7 @@
#include <GLM/glm.hpp>
#include <iostream>
#include <random>
#include "Scene.h"
#include "Shader.h"
@ -17,6 +18,8 @@ Texture* pgNormal = NULL;
Texture* pgDiffuseP = NULL;
Texture* pgAmbientSpecular = NULL;
RBO* pgrbo = NULL;
Texture* pssaoTexture = NULL;
Texture* pssaoTexture_raw = NULL;
// Размеры окна
int WINDOW_WIDTH = 800;
int WINDOW_HEIGHT = 600;
@ -38,6 +41,11 @@ void framebuffer_size_callback(GLFWwindow* window, int width, int height)
// И буфера глубины
if (pgrbo)
pgrbo->reallocate(width, height);
// SSAO
if (pssaoTexture)
pssaoTexture->reallocate(width, height, 6, GL_RED, GL_RED);
if (pssaoTexture_raw)
pssaoTexture_raw->reallocate(width, height, 0, GL_RED, GL_RED);
// Запомним новые размеры окна
WINDOW_WIDTH = width;
@ -180,7 +188,8 @@ 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", "pointShadowDepth"};
// Привязка текстур
const char* gtextures_shader_names[] = {"gPosition", "gNormal", "gDiffuseP", "gAmbientSpecular", "sunShadowDepth", "pointShadowDepth", "ssao"};
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]);
@ -242,6 +251,73 @@ int main(void)
pointShadowShader.load(GL_FRAGMENT_SHADER, "shaders/point_shadow.frag");
pointShadowShader.link();
// Создадим буфер для вычисления SSAO
GLuint attachments_ssao[] = { GL_COLOR_ATTACHMENT0 };
FBO ssaoBuffer(attachments_ssao, sizeof(attachments_ssao) / sizeof(GLuint));
// Создадим текстуры для буфера кадра
Texture ssaoTexture_raw(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT0, 0, GL_RED, GL_RED);
pssaoTexture_raw = &ssaoTexture_raw;
// Активируем базовый буфер кадра
FBO::useDefault();
// Стандартные параметры SSAO
SSAO_data ssao_data;
// Расчет масштабирования текстуры шума
ssao_data.scale = {WINDOW_WIDTH/4,WINDOW_HEIGHT/4};
// Генерируем случайные векторы
std::uniform_real_distribution<GLfloat> randomFloats(0.0, 1.0); // Генерирует случайные вещественные числа в заданном диапазоне
std::default_random_engine generator;
glm::vec3 sample; // Выборка
for (int i = 0; i < ssao_data.size; i++)
{
sample = { randomFloats(generator) * 2.0 - 1.0
, randomFloats(generator) * 2.0 - 1.0
, randomFloats(generator)
};
sample = glm::normalize(sample);
sample *= randomFloats(generator);
// Отмасштабируем выборку
sample *= 0.1 + 0.9 * (i / (float)ssao_data.size) * (i / (float)ssao_data.size);
ssao_data.samples[i] = sample;
}
// Загрузка данных в uniform-буфер
UBO ssaoUB(&ssao_data, sizeof(SSAO_data), 4);
// Текстура шума
glm::vec3 noise_vecs[16];
for (int i = 0; i < 16; i++)
noise_vecs[i] = { randomFloats(generator) * 2.0 - 1.0
, randomFloats(generator) * 2.0 - 1.0
, 0.0f
};
Texture noiseTexture(4,4, noise_vecs, 2, GL_RGBA32F, GL_RGB);
// Шейдер для расчета SSAO
ShaderProgram ssaoShader;
// Загрузим шейдер
ssaoShader.load(GL_VERTEX_SHADER, "shaders/quad.vert");
ssaoShader.load(GL_FRAGMENT_SHADER, "shaders/ssao.frag");
ssaoShader.link();
// Текстуры, используемые в шейдере
const char* ssaoShader_names[] = {"gPosition", "gNormal", "noise"};
ssaoShader.bindTextures(ssaoShader_names, sizeof(ssaoShader_names)/sizeof(const char*));
// Создадим буфер для размытия SSAO
FBO ssaoBlurBuffer(attachments_ssao, sizeof(attachments_ssao) / sizeof(GLuint));
// Создадим текстуры для буфера кадра
Texture ssaoTexture(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT0, 6, GL_RED, GL_RED);
pssaoTexture = &ssaoTexture;
// Активируем базовый буфер кадра
FBO::useDefault();
// Шейдер для размытия SSAO
ShaderProgram ssaoBlurShader;
// Загрузим шейдер
ssaoBlurShader.load(GL_VERTEX_SHADER, "shaders/quad.vert");
ssaoBlurShader.load(GL_FRAGMENT_SHADER, "shaders/ssaoBlur.frag");
ssaoBlurShader.link();
// Модель прямоугольника
Model rectangle;
@ -371,6 +447,31 @@ int main(void)
scene.render(gShader, material_data);
rectangle.render(gShader, material_data);
// Активируем буфер SSAO
ssaoBuffer.use();
// Используем шейдер для расчета SSAO
ssaoShader.use();
// Очистка буфера цвета
glClear(GL_COLOR_BUFFER_BIT);
// Подключаем текстуры G-буфера
gPosition.use();
gNormal.use();
// Подключаем текстуру шума для SSAO
noiseTexture.use();
// Рендерим прямоугольник
quadModel.render();
// Активируем буфер размытия SSAO
ssaoBlurBuffer.use();
// Используем шейдер для размытия SSAO
ssaoBlurShader.use();
// Очистка буфера цвета
glClear(GL_COLOR_BUFFER_BIT);
// Подключаем текстуру сырого SSAO
ssaoTexture_raw.use();
// Рендерим прямоугольник
quadModel.render();
// Изменим размер вывода для тени
glViewport(0, 0, sunShadow_resolution, sunShadow_resolution);
// Активируем буфер кадра для теней от солнца
@ -416,6 +517,8 @@ int main(void)
// Подключаем текстуры теней
sunShadowDepth.use();
pointShadowDepth.use();
// Подключим текстуру SSAO
ssaoTexture.use();
// Рендерим прямоугольник с расчетом освещения
quadModel.render();