Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
Ковалев Роман Евгеньевич | 7c0421c0ea | |
Ковалев Роман Евгеньевич | 6cdd1ef845 | |
Ковалев Роман Евгеньевич | 4785a46cca | |
Ковалев Роман Евгеньевич | 6d091e022d | |
Ковалев Роман Евгеньевич | a4a7df2073 | |
Ковалев Роман Евгеньевич | e977037c8a | |
Ковалев Роман Евгеньевич | 7ad56ddac4 |
|
@ -80,6 +80,8 @@ class RBO
|
|||
RBO(int w, int h, GLuint component = GL_DEPTH_COMPONENT); // Создает буфер рендера с заданными параметрами размеров и используемых компонент
|
||||
~RBO(); // Уничтожение буфера
|
||||
|
||||
void reallocate(int w, int h, GLuint component = GL_DEPTH_COMPONENT); // Изменяет размеры буфера рендера
|
||||
|
||||
GLuint getHandler(); // Возвращает дескриптор буфера рендера
|
||||
protected:
|
||||
GLuint handler; // Дескриптор
|
||||
|
|
|
@ -13,6 +13,7 @@ struct LightData
|
|||
{
|
||||
alignas(16) glm::vec3 position; // Позиция
|
||||
alignas(16) glm::vec3 color; // Цвет
|
||||
alignas(16) glm::vec3 attenuation; // Радиус действия источника, линейный и квадратичный коэф. угасания
|
||||
};
|
||||
|
||||
// Источник света
|
||||
|
@ -28,6 +29,9 @@ class Light : public Node
|
|||
const glm::vec3& c_color() const; // Константный доступ к цвету
|
||||
glm::vec3& e_color(); // Неконстантная ссылка для изменений цвета
|
||||
|
||||
const float& c_radius() const; // Константный доступ к радиусу
|
||||
float& e_radius(); // Неконстантная ссылка для изменений радиуса
|
||||
|
||||
static void render(ShaderProgram &shaderProgram, UBO &material_buffer); // Рисование отладочных лампочек
|
||||
private:
|
||||
Light(); // Конструктор без параметров
|
||||
|
@ -36,6 +40,7 @@ class Light : public Node
|
|||
virtual ~Light();
|
||||
|
||||
glm::vec3 color; // Цвет
|
||||
float radius; // Радиус действия источника
|
||||
|
||||
int index; // Индекс в массиве отправки (может не совпадать с lights) для дефрагментированного доступа
|
||||
static Light& findByIndex(GLuint index); // Возвращает ссылку на источник с нужным индексом
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
class Model genShpere(float radius, int sectorsCount, class Node* parent = NULL); // Генерирует сферу заданного радиуса с определенным количеством сегментов
|
||||
|
||||
// Класс узла сцены
|
||||
class Node
|
||||
{
|
||||
|
|
|
@ -23,6 +23,8 @@ class Texture
|
|||
|
||||
Texture& operator=(const Texture& other); // Оператор присваивания
|
||||
|
||||
void reallocate(GLuint width, GLuint height, GLuint texType = TEX_DIFFUSE, GLint internalformat = GL_RGBA, GLint format = GL_RGBA, GLenum dataType = GL_FLOAT); // Пересоздает текстуру для имеющегося дескриптора
|
||||
|
||||
void use(); // Привязка текстуры
|
||||
static void disable(GLuint type); // Отвязка текстуры по типу
|
||||
GLuint getType(); // Возвращает тип текстуры
|
||||
|
|
|
@ -13,6 +13,7 @@ struct LightData
|
|||
{
|
||||
vec3 position;
|
||||
vec3 color;
|
||||
vec3 attenuation;
|
||||
};
|
||||
|
||||
layout(std140, binding = 2) uniform Light
|
||||
|
@ -44,6 +45,8 @@ void main()
|
|||
float diffuse; // Диффузная составляющая
|
||||
vec3 H; // Вектор половины пути
|
||||
float specular; // Зеркальная составляющая
|
||||
float L_distance; // Расстояние от поверхности до источника
|
||||
float attenuation; // Коэф. угасания
|
||||
|
||||
// Фоновая освещенность
|
||||
color = vec4(ka, 1);
|
||||
|
@ -55,6 +58,12 @@ void main()
|
|||
// Данные об источнике относительно фрагмента
|
||||
L_vertex = light_f.data[i].position - fragPos;
|
||||
|
||||
// Расстояние от поверхности до источника
|
||||
L_distance = length(L_vertex);
|
||||
|
||||
// Проверка на дистанцию
|
||||
if (L_distance < light_f.data[i].attenuation.r)
|
||||
{
|
||||
// Нормирование вектора
|
||||
L_vertex = normalize(L_vertex);
|
||||
|
||||
|
@ -66,7 +75,11 @@ void main()
|
|||
// Зеркальная составляющая
|
||||
specular = pow(max(dot(H, N), 0.0), p*4); // скалярное произведение с отсеканием значений < 0 в степени p
|
||||
|
||||
color += vec4(light_f.data[i].color*kd*diffuse, 1)
|
||||
+ vec4(light_f.data[i].color*ks*specular, 1);
|
||||
// Угасание с учетом расстояния
|
||||
attenuation = 1 / (1 + light_f.data[i].attenuation[1] * L_distance + light_f.data[i].attenuation[2] * L_distance * L_distance);
|
||||
|
||||
color += vec4(light_f.data[i].color*kd*diffuse * attenuation, 1)
|
||||
+ vec4(light_f.data[i].color*ks*specular * attenuation, 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -189,6 +189,13 @@ RBO::~RBO()
|
|||
glDeleteRenderbuffers(1, &handler);
|
||||
}
|
||||
|
||||
// Изменяет размеры буфера рендера
|
||||
void RBO::reallocate(int w, int h, GLuint component)
|
||||
{
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, handler); // Привязка элементного буфера
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h);
|
||||
}
|
||||
|
||||
// Возвращает дескриптор буфера рендера
|
||||
GLuint RBO::getHandler()
|
||||
{
|
||||
|
|
|
@ -97,6 +97,13 @@ void Light::toData()
|
|||
|
||||
data[index].position = glm::vec3(result_transform[3]); // Позиция из матрицы трансформации
|
||||
data[index].color = color; // Цвет
|
||||
// Если радиус изменился
|
||||
if (data[index].attenuation.r != radius)
|
||||
{
|
||||
data[index].attenuation.r = radius; // Радиус действия источника
|
||||
data[index].attenuation[1] = 4.5/radius; // Линейный коэф. угасания
|
||||
data[index].attenuation[2] = 4 * data[index].attenuation[1] * data[index].attenuation[1]; // Квадратичный коэф. угасания
|
||||
}
|
||||
}
|
||||
|
||||
// Возвращает ссылку на новый источник света
|
||||
|
@ -143,7 +150,7 @@ Light& Light::findByIndex(GLuint index)
|
|||
}
|
||||
|
||||
// Конструктор без параметров
|
||||
Light::Light() : Node(), index(-1), uploadReq(false), color(1.0f)
|
||||
Light::Light() : Node(), index(-1), uploadReq(false), color(1.0f), radius(10.0f)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -157,6 +164,7 @@ Light& Light::operator=(const Light& other)
|
|||
index = other.index; // Переносим индекс
|
||||
uploadReq = other.uploadReq; // Необходимость загрузки
|
||||
color = other.color;
|
||||
radius = other.radius;
|
||||
|
||||
Node::operator=(other);
|
||||
}
|
||||
|
@ -173,16 +181,37 @@ void Light::render(ShaderProgram &shaderProgram, UBO &material_buffer)
|
|||
{
|
||||
// Загрузка модели лампочки при первом вызове функции
|
||||
static Scene bulb = loadOBJtoScene("../resources/models/bulb.obj", "../resources/models/", "../resources/textures/");
|
||||
static Model sphere = genShpere(1, 16, &bulb.root);
|
||||
|
||||
// Цикл по источникам света
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
// Сдвиг на позицию источника
|
||||
bulb.root.e_position() = data[i].position;
|
||||
sphere.e_scale() = glm::vec3(data[i].attenuation.r); // Масштабирование сферы
|
||||
// Задание цвета
|
||||
bulb.models.begin()->material.ka = data[i].color;
|
||||
bulb.models.begin()->material.ka = sphere.material.ka = data[i].color;
|
||||
|
||||
// Вызов отрисовки
|
||||
bulb.render(shaderProgram, material_buffer);
|
||||
|
||||
// Рисование сферы покрытия источника в режиме линий
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
sphere.render(shaderProgram, material_buffer);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
}
|
||||
|
||||
// Константный доступ к радиусу
|
||||
const float& Light::c_radius() const
|
||||
{
|
||||
return radius;
|
||||
}
|
||||
|
||||
// Неконстантная ссылка для изменений радиуса
|
||||
float& Light::e_radius()
|
||||
{
|
||||
uploadReq = true;
|
||||
|
||||
return radius;
|
||||
}
|
||||
|
|
|
@ -402,3 +402,77 @@ void Model::set_texture(Texture& texture)
|
|||
break;
|
||||
};
|
||||
}
|
||||
|
||||
// Генерирует сферу заданного радиуса с определенным количеством сегментов
|
||||
Model genShpere(float radius, int sectorsCount, Node* parent)
|
||||
{
|
||||
Model result(parent);
|
||||
|
||||
std::vector<glm::vec3> vertices;
|
||||
std::vector<glm::vec3> normals;
|
||||
std::vector<GLuint> indices;
|
||||
|
||||
float x, y, z, xy; // Позиция вершины
|
||||
float nx, ny, nz, lengthInv = 1.0f / radius; // Нормаль вершины
|
||||
float PI = 3.14159265;
|
||||
float sectorStep = PI / sectorsCount; // Шаг сектора
|
||||
float longAngle, latAngle; // Углы
|
||||
|
||||
for(int i = 0; i <= sectorsCount; ++i)
|
||||
{
|
||||
latAngle = PI / 2 - i * sectorStep; // Начиная с pi/2 до -pi/2
|
||||
xy = radius * cos(latAngle); // r * cos(lat)
|
||||
z = radius * sin(latAngle); // r * sin(lat)
|
||||
|
||||
// добавляем (sectorCount+1) вершин на сегмент
|
||||
// Последняя и первая вершины имеют одинаковые нормали и координаты
|
||||
for(int j = 0; j <= sectorsCount; ++j)
|
||||
{
|
||||
longAngle = j * 2 * sectorStep; // Начиная с 0 до 2*pi
|
||||
|
||||
// Положение вершины (x, y, z)
|
||||
x = xy * cos(longAngle); // r * cos(lat) * cos(long)
|
||||
y = xy * sin(longAngle); // r * cos(lat) * sin(long)
|
||||
vertices.push_back({x, y, z});
|
||||
|
||||
// Нормали (nx, ny, nz)
|
||||
nx = x * lengthInv;
|
||||
ny = y * lengthInv;
|
||||
nz = z * lengthInv;
|
||||
normals.push_back({nx, ny, nz});
|
||||
}
|
||||
}
|
||||
int k1, k2;
|
||||
for(int i = 0; i < sectorsCount; ++i)
|
||||
{
|
||||
k1 = i * (sectorsCount + 1); // начало текущего сегмента
|
||||
k2 = k1 + sectorsCount + 1; // начало следующего сегмента
|
||||
|
||||
for(int j = 0; j < sectorsCount; ++j, ++k1, ++k2)
|
||||
{
|
||||
// 2 треугольника на один сегмент
|
||||
// k1, k2, k1+1
|
||||
if(i != 0)
|
||||
{
|
||||
indices.push_back(k1);
|
||||
indices.push_back(k2);
|
||||
indices.push_back(k1 + 1);
|
||||
}
|
||||
|
||||
// k1+1, k2, k2+1
|
||||
if(i != (sectorsCount-1))
|
||||
{
|
||||
indices.push_back(k1 + 1);
|
||||
indices.push_back(k2);
|
||||
indices.push_back(k2 + 1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// Загрузка в модель
|
||||
result.load_verteces(&vertices[0], vertices.size());
|
||||
result.load_normals(&normals[0], normals.size());
|
||||
result.load_indices(&indices[0], indices.size());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -115,6 +115,13 @@ Texture::~Texture()
|
|||
}
|
||||
}
|
||||
|
||||
// Пересоздает текстуру для имеющегося дескриптора
|
||||
void Texture::reallocate(GLuint width, GLuint height, GLuint texType, GLint internalformat, GLint format, GLenum dataType)
|
||||
{
|
||||
use();
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, width, height, 0, format, dataType, NULL);
|
||||
}
|
||||
|
||||
// Привязка текстуры
|
||||
void Texture::use()
|
||||
{
|
||||
|
|
42
src/main.cpp
42
src/main.cpp
|
@ -9,14 +9,42 @@
|
|||
#include "Shader.h"
|
||||
#include "Lights.h"
|
||||
|
||||
#define WINDOW_WIDTH 800
|
||||
#define WINDOW_HEIGHT 600
|
||||
#define WINDOW_CAPTION "OPENGL notes on rekovalev.site"
|
||||
|
||||
// Указатели на текстуры для изменения размеров окна
|
||||
Texture* pgPosition = NULL;
|
||||
Texture* pgNormal = NULL;
|
||||
Texture* pgDiffuseP = NULL;
|
||||
Texture* pgAmbientSpecular = NULL;
|
||||
RBO* pgrbo = NULL;
|
||||
// Размеры окна
|
||||
int WINDOW_WIDTH = 800;
|
||||
int WINDOW_HEIGHT = 600;
|
||||
|
||||
// Функция-callback для изменения размеров буфера кадра в случае изменения размеров поверхности окна
|
||||
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
|
||||
{
|
||||
glViewport(0, 0, width, height);
|
||||
|
||||
// Изменение размеров текстур для G-буфера
|
||||
if (pgPosition)
|
||||
pgPosition->reallocate(width, height, 0, GL_RGB32F, GL_RGB);
|
||||
if (pgNormal)
|
||||
pgNormal->reallocate(width, height, 1, GL_RGB16F, GL_RGB);
|
||||
if (pgDiffuseP)
|
||||
pgDiffuseP->reallocate(width, height, 2, GL_RGBA16F);
|
||||
if (pgAmbientSpecular)
|
||||
pgAmbientSpecular->reallocate(width, height, 3);
|
||||
// И буфера глубины
|
||||
if (pgrbo)
|
||||
pgrbo->reallocate(width, height);
|
||||
|
||||
// Запомним новые размеры окна
|
||||
WINDOW_WIDTH = width;
|
||||
WINDOW_HEIGHT = height;
|
||||
|
||||
// Изменим параметры перспективной матрицы проекции для камеры
|
||||
Camera::current().setPerspective(CAMERA_FOVy, (float)width/height);
|
||||
}
|
||||
|
||||
bool firstMouse = true;
|
||||
|
@ -94,7 +122,6 @@ int main(void)
|
|||
const char* textures_base_shader_names[] = {"tex_diffuse", "tex_ambient", "tex_specular"};
|
||||
gShader.bindTextures(textures_base_shader_names, sizeof(textures_base_shader_names)/sizeof(const char*));
|
||||
|
||||
|
||||
// Загрузка сцены из obj файла
|
||||
Scene scene = loadOBJtoScene("../resources/models/blob.obj", "../resources/models/", "../resources/textures/");
|
||||
scene.root.e_scale() = glm::vec3(0.01);
|
||||
|
@ -124,7 +151,7 @@ int main(void)
|
|||
GLuint attachments[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 };
|
||||
FBO gbuffer(attachments, sizeof(attachments) / sizeof(GLuint));
|
||||
// Создадим текстуры для буфера кадра
|
||||
Texture gPosition(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT0, 0, GL_RGB16F, GL_RGB); // Позиция вершины
|
||||
Texture gPosition(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT0, 0, GL_RGB32F, GL_RGB); // Позиция вершины
|
||||
Texture gNormal(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT1, 1, GL_RGB16F, GL_RGB); // Нормали
|
||||
Texture gDiffuseP(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT2, 2, GL_RGBA16F); // Диффузная составляющая и коэф. глянцевости
|
||||
Texture gAmbientSpecular(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT3, 3); // Фоновая составляющая и один канал зеркальной
|
||||
|
@ -134,6 +161,13 @@ int main(void)
|
|||
// Активируем базовый буфер кадра
|
||||
FBO::useDefault();
|
||||
|
||||
// Сохраним указатели на текстуры для изменения размеров окна
|
||||
pgPosition = &gPosition;
|
||||
pgNormal = &gNormal;
|
||||
pgDiffuseP = &gDiffuseP;
|
||||
pgAmbientSpecular = &gAmbientSpecular;
|
||||
pgrbo = &grbo;
|
||||
|
||||
// Шейдер для расчета освещенности
|
||||
ShaderProgram lightShader;
|
||||
// Загрузка и компиляция шейдеров
|
||||
|
|
Loading…
Reference in New Issue