improve lighting and use UBOs
This commit is contained in:
parent
3c6254ece3
commit
8ce253c0dc
10 changed files with 166 additions and 69 deletions
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ; }));
|
||||
|
|
63
src/main.cpp
63
src/main.cpp
|
@ -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);
|
||||
|
|
25
src/mesh.cpp
25
src/mesh.cpp
|
@ -20,14 +20,13 @@ 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);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -39,8 +38,7 @@ void Mesh::init()
|
|||
|
||||
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);
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue