improve lighting and use UBOs

This commit is contained in:
hippoz 2023-09-02 02:39:46 +03:00
parent 3c6254ece3
commit 8ce253c0dc
Signed by: hippoz
GPG key ID: 56C4E02A85F2FBED
10 changed files with 166 additions and 69 deletions

View file

@ -8,6 +8,8 @@ glfw3_dep = dependency('glfw3')
assimp_dep = dependency('assimp')
incdir = include_directories(['src', 'src/vendor'])
cpp_args = ['-pedantic', '-Wall', '-Wextra']
executable(
'game',
'./src/common.cpp',
@ -20,5 +22,6 @@ executable(
'./src/main.cpp',
'./src/vendor/glad/glad.c',
include_directories : incdir,
dependencies : [glfw3_dep, assimp_dep]
dependencies : [glfw3_dep, assimp_dep],
cpp_args : cpp_args
)

View file

@ -1,9 +1,12 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout(std140, binding = 0) uniform Matrices
{
mat4 projection;
mat4 view;
};
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{

View file

@ -59,10 +59,10 @@ uniform PointLight pointLights[POINT_LIGHTS_COUNT];
vec3 ComputeDirectionalLight(DirectionalLight light, vec3 norm, vec3 viewDir)
{
vec3 lightDir = normalize(-light.direction);
vec3 reflectDir = reflect(-lightDir, norm);
vec3 halfwayDir = normalize(lightDir + viewDir);
float diff = max(dot(norm, lightDir), 0.0);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
float spec = pow(max(dot(norm, halfwayDir), 0.0), material.shininess);
vec3 ambient = light.ambient * vec3(texture(material.texture_diffuse1, TexCoords));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.texture_diffuse1, TexCoords));
@ -77,10 +77,10 @@ vec3 ComputePointLight(PointLight light, vec3 norm, vec3 viewDir, vec3 fragPos)
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
vec3 lightDir = normalize(light.position - fragPos);
vec3 reflectDir = reflect(-lightDir, norm);
vec3 halfwayDir = normalize(lightDir + viewDir);
float diff = max(dot(norm, lightDir), 0.0);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
float spec = pow(max(dot(norm, halfwayDir), 0.0), material.shininess);
vec3 ambient = light.ambient * vec3(texture(material.texture_diffuse1, TexCoords));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.texture_diffuse1, TexCoords));
@ -91,7 +91,7 @@ vec3 ComputePointLight(PointLight light, vec3 norm, vec3 viewDir, vec3 fragPos)
vec3 ComputeSpotLight(SpotLight light, vec3 norm, vec3 viewDir, vec3 fragPos) {
vec3 lightDir = normalize(light.position - fragPos);
vec3 reflectDir = reflect(-lightDir, norm);
vec3 halfwayDir = normalize(lightDir + viewDir);
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = light.cutOff - light.outerCutOff;
@ -101,7 +101,7 @@ vec3 ComputeSpotLight(SpotLight light, vec3 norm, vec3 viewDir, vec3 fragPos) {
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
float diff = max(dot(norm, lightDir), 0.0);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
float spec = pow(max(dot(norm, halfwayDir), 0.0), material.shininess);
vec3 ambient = light.ambient * vec3(texture(material.texture_diffuse1, TexCoords));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.texture_diffuse1, TexCoords));

View file

@ -7,9 +7,12 @@ out vec3 Normal;
out vec3 FragPos;
out vec2 TexCoords;
layout(std140, binding = 0) uniform Matrices
{
mat4 projection;
mat4 view;
};
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{

View file

@ -32,11 +32,11 @@ void Camera::process_mouse(double x, double y)
pitch = -89.0f;
double pitch_factor = cos(glm::radians(pitch));
front = (glm::vec3){
front = glm::vec3(
cos(glm::radians(yaw)) * pitch_factor,
sin(glm::radians(pitch)),
sin(glm::radians(yaw)) * pitch_factor
};
);
last_mouse_x = x;
last_mouse_y = y;

View file

@ -1,7 +1,7 @@
#include "scope_guard.hpp"
#define __$CONCAT(a,b) a ## b
#define _$CONCAT(a, b) __$CONCAT(a, b)
#define __MACRO_CONCAT(a, b) a ## b
#define __MACRO_CONCAT_EXPAND(a, b) __MACRO_CONCAT(a, b)
#define guard(M_fn) auto _$CONCAT(__defer__, __LINE__) = (sg::make_scope_guard((M_fn)));
#define defer(M_stmt) auto _$CONCAT(__defer__, __LINE__) = (sg::make_scope_guard([&](void) -> void { M_stmt ; }));
#define guard(M_fn) auto __MACRO_CONCAT_EXPAND(__defer__, __LINE__) = (sg::make_scope_guard((M_fn)));
#define defer(M_stmt) auto __MACRO_CONCAT_EXPAND(__defer__, __LINE__) = (sg::make_scope_guard([&](void) -> void { M_stmt ; }));

View file

@ -26,9 +26,20 @@
std::function<void(int width, int height)> framebuffer_size_callback = nullptr;
std::function<void(double x, double y)> cursor_position_callback = nullptr;
static const int samples = 4;
void GLAPIENTRY gl_message_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
{
(void)source;
(void)id;
(void)severity;
(void)length;
(void)userParam;
if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) {
return;
}
fprintf(stderr, "OPENGL MESSAGE: %s\n", message);
if (type == GL_DEBUG_TYPE_ERROR) {
fprintf(stderr, "exiting due to gl error above...\n");
@ -45,6 +56,9 @@ int main()
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
if (samples > 0) {
glfwWindowHint(GLFW_SAMPLES, samples);
}
GLFWwindow *window = glfwCreateWindow(800, 600, "gaming", NULL, NULL);
if (!window) {
@ -55,14 +69,16 @@ int main()
gladLoadGL();
glfwSwapInterval(0);
glfwSetFramebufferSizeCallback(window, [](GLFWwindow *_, int width, int height) {
glfwSetFramebufferSizeCallback(window, [](GLFWwindow *window, int width, int height) {
(void)window;
if (framebuffer_size_callback) {
framebuffer_size_callback(width, height);
}
});
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glfwSetCursorPosCallback(window, [](GLFWwindow *_, double x, double y) {
glfwSetCursorPosCallback(window, [](GLFWwindow *window, double x, double y) {
(void)window;
if (cursor_position_callback) {
cursor_position_callback(x, y);
}
@ -71,6 +87,9 @@ int main()
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_DEBUG_OUTPUT);
if (samples > 0) {
glEnable(GL_MULTISAMPLE);
}
glDebugMessageCallback(gl_message_callback, NULL);
glm::vec3 point_light_positions[] = {
@ -86,15 +105,6 @@ int main()
glm::mat4 projection = glm::mat4(1.0f);
Camera camera;
framebuffer_size_callback = [&projection](int width, int height) {
projection = glm::perspective(glm::radians(45.0f), (float)width / (float)height, 0.1f, 100.0f);
glViewport(0, 0, width, height);
};
cursor_position_callback = [&camera](double x, double y) {
camera.process_mouse(x, y);
};
std::vector<Mesh> meshes;
load_model_from_file(meshes, "./assets/model/backpack.obj");
@ -130,6 +140,29 @@ int main()
glBindVertexArray(0);
}
unsigned int matrices_ubo;
{
glGenBuffers(1, &matrices_ubo);
glBindBuffer(GL_UNIFORM_BUFFER, matrices_ubo);
glBufferData(GL_UNIFORM_BUFFER, 2 * sizeof(glm::mat4), NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glBindBufferRange(GL_UNIFORM_BUFFER, 0, matrices_ubo, 0, 2 * sizeof(glm::mat4));
}
framebuffer_size_callback = [&projection, matrices_ubo](int width, int height) {
projection = glm::perspective(glm::radians(45.0f), (float)width / (float)height, 0.1f, 100.0f);
glViewport(0, 0, width, height);
glBindBuffer(GL_UNIFORM_BUFFER, matrices_ubo);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4), &projection);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
};
cursor_position_callback = [&camera](double x, double y) {
camera.process_mouse(x, y);
};
float delta_time = 0.0f;
float last_frame_time = 0.0f;
@ -157,6 +190,10 @@ int main()
camera.movement(delta_time, Camera::MovementDown);
}
glBindBuffer(GL_UNIFORM_BUFFER, matrices_ubo);
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), &camera.view);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glClearColor(0.5, 0.5, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -165,11 +202,9 @@ int main()
{
glUseProgram(lit_program);
program_set(lit_program, "model", glm::scale(glm::translate(glm::mat4(1.0), glm::vec3(0.0, 0.0, 0.0)), glm::vec3(1.0, 1.0, 1.0)));
program_set(lit_program, "projection", projection);
program_set(lit_program, "view", camera.view);
program_set(lit_program, "viewPos", camera.position);
program_set(lit_program, "material.shininess", 32.0f);
program_set(lit_program, "material.shininess", 64.0f);
program_set(lit_program, "directionalLight.direction", -0.2f, -1.0f, -0.3f);
program_set(lit_program, "directionalLight.ambient", 0.05f, 0.05f, 0.05f);

View file

@ -20,27 +20,25 @@ void Mesh::init()
{
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vertices_vbo);
glGenBuffers(1, &indicies_ebo);
glBindVertexArray(vao);
{
glBindBuffer(GL_ARRAY_BUFFER, vertices_vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicies_ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicies.size() * sizeof(unsigned int), &indicies[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vertices_vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);
glGenBuffers(1, &indicies_ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicies_ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicies.size() * sizeof(unsigned int), &indicies[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, textureCoords));
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, textureCoords));
}
glBindVertexArray(0);
}
@ -54,10 +52,13 @@ void Mesh::draw(unsigned int program_id) const
glActiveTexture(GL_TEXTURE0 + i);
if (texture.type == "texture_diffuse") {
switch (texture.type) {
case Texture::TextureType::DIFFUSE:
program_set(program_id, ("material.texture_diffuse" + std::to_string(diffuse_number++)).c_str(), static_cast<int>(i));
} else if (texture.type == "texture_specular") {
break;
case Texture::TextureType::SPECULAR:
program_set(program_id, ("material.texture_specular" + std::to_string(specular_number++)).c_str(), static_cast<int>(i));
break;
}
glBindTexture(GL_TEXTURE_2D, texture.id);
@ -72,7 +73,7 @@ void Mesh::draw(unsigned int program_id) const
static std::unordered_map<std::string, Texture> file_path_to_loaded_texture_cache;
static void load_material_textures(std::vector<Texture> &out_textures, const aiMaterial *material, const aiTextureType texture_type, const char *type_name, const std::string &texture_root_directory)
static void load_material_textures(std::vector<Texture> &out_textures, const aiMaterial *material, const aiTextureType texture_type, Texture::TextureType type_name, const std::string &texture_root_directory)
{
unsigned int texture_count = aiGetMaterialTextureCount(material, texture_type);
@ -125,11 +126,9 @@ static void visit_node_process_mesh(const aiScene *scene, const aiMesh *mesh, co
}
}
if (mesh->mMaterialIndex >= 0) {
aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
load_material_textures(textures, material, aiTextureType_DIFFUSE, "texture_diffuse", *texture_root_directory);
load_material_textures(textures, material, aiTextureType_SPECULAR, "texture_specular", *texture_root_directory);
}
aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
load_material_textures(textures, material, aiTextureType_DIFFUSE, Texture::TextureType::DIFFUSE, *texture_root_directory);
load_material_textures(textures, material, aiTextureType_SPECULAR, Texture::TextureType::SPECULAR, *texture_root_directory);
}
static void visit_node(aiNode *node, const aiScene *scene, std::string *texture_root_directory, std::vector<Mesh> &out_meshes)
@ -161,5 +160,5 @@ void load_model_from_file(std::vector<Mesh> &out_meshes, const std::string &path
auto t2 = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> delta = t2 - t1;
printf("processed %ld meshes in %fms\n", out_meshes.size(), delta.count());
printf("load_model_from_file: processed %ld meshes (took %fms)\n", out_meshes.size(), delta.count());
}

View file

@ -12,15 +12,19 @@ struct Vertex {
};
struct Texture {
enum class TextureType {
DIFFUSE,
SPECULAR
};
unsigned int id;
std::string type;
TextureType type;
};
struct Mesh {
std::vector<Vertex> vertices;
std::vector<Texture> textures;
std::vector<unsigned int> indicies;
bool use_indicies = true;
unsigned int vao, vertices_vbo, indicies_ebo;

View file

@ -3,16 +3,24 @@
#include "common.hpp"
#include "vendor/glad/glad.h"
#include "vendor/stb_image.h"
#include <cassert>
#include <cerrno>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <future>
#include <iostream>
#include <vector>
struct LoadedImage {
unsigned char *data = NULL;
int width, height = 0;
};
unsigned int texture_from_file(const char *path)
{
printf("texture_from_file: load %s\n", path);
auto t1 = std::chrono::high_resolution_clock::now();
int x, y;
unsigned char *data = stbi_load(path, &x, &y, NULL, 4);
@ -37,27 +45,64 @@ unsigned int texture_from_file(const char *path)
glBindTexture(GL_TEXTURE_2D, 0);
auto t2 = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> delta = t2 - t1;
printf("texture_from_file: loaded %s (took %fms)\n", path, delta.count());
return texture;
}
unsigned int cubemap_from_files(std::vector<const char *> &faces)
{
auto t1 = std::chrono::high_resolution_clock::now();
assert(faces.size() == 6);
unsigned int thread_count = faces.size() / 2;
unsigned int images_per_thread = faces.size() / thread_count;
std::vector<LoadedImage> loaded_images(faces.size());
defer(
for (auto &image : loaded_images) {
free(image.data);
}
)
std::vector<std::thread> threads;
threads.reserve(thread_count);
for (unsigned int i = 0; i < thread_count; i++) {
unsigned int image_index = i * images_per_thread;
threads.push_back(
std::thread {
[](unsigned int images_per_thread, unsigned int image_index, std::vector<const char *> *faces, std::vector<LoadedImage> *images) {
for (unsigned int i = image_index; i < (image_index + images_per_thread); i++) {
LoadedImage *image = &images->at(i);
image->data = stbi_load(faces->at(i), &image->width, &image->height, NULL, 3);
}
},
images_per_thread,
image_index,
&faces,
&loaded_images
}
);
}
for (auto &task : threads) {
task.join();
}
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
int width, height = 0;
unsigned char *data = NULL;
for (unsigned int i = 0; i < faces.size(); i++) {
printf("cubemap_from_files: load %s\n", faces[i]);
data = stbi_load(faces[i], &width, &height, NULL, 3);
defer(stbi_image_free(data));
if (data) {
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
for (unsigned int i = 0; i < loaded_images.size(); i++) {
LoadedImage *image = &loaded_images[i];
if (image->data) {
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, image->width, image->height, 0, GL_RGB, GL_UNSIGNED_BYTE, image->data);
} else {
fprintf(stderr, "cubemap_from_files: failed to load file %s\n", faces[i]);
fprintf(stderr, "cubemap_from_files: file was not loaded: %s\n", faces[i]);
}
}
@ -67,5 +112,10 @@ unsigned int cubemap_from_files(std::vector<const char *> &faces)
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
auto t2 = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> delta = t2 - t1;
printf("cubemap_from_files: loaded %ld faces (took %fms)\n", faces.size(), delta.count());
return texture;
}