Implement sorting blending

This commit is contained in:
SeanOMik 2022-10-11 23:16:52 -04:00
parent 19d116ef65
commit 6944d0ac6d
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
17 changed files with 306 additions and 374 deletions

View File

@ -51,6 +51,8 @@ else()
target_link_libraries(simpleengine PUBLIC assimp)
endif()
# Link resources
target_link_libraries(simpleengine PUBLIC cmrc::base)
target_link_libraries(simpleengine PRIVATE simpleengine_resources)
# Include some dependencies' include directories

2
cmrc

@ -1 +1 @@
Subproject commit a64bea50c05594c8e7cf1f08e441bb9507742e2e
Subproject commit e386a629eb537d384811e598a3c96b9ca928f65e

View File

@ -9,17 +9,17 @@ target_sources(dev_testing PRIVATE ${source_list})
target_include_directories(dev_testing PUBLIC include)
# Embed shaders
file(GLOB_RECURSE shaders_list resources/shaders/*.glsl)
cmrc_add_resource_library(
resource_shaders
WHENCE resources/shaders
PREFIX shaders
${shaders_list}
)
#file(GLOB_RECURSE shaders_list resources/shaders/*.glsl)
#cmrc_add_resource_library(
# resource_shaders
# WHENCE resources/shaders
# PREFIX shaders
# ${shaders_list}
#)
# Link simpleengine
target_link_libraries(dev_testing PUBLIC simpleengine)
target_link_libraries(dev_testing PRIVATE resource_shaders)
#target_link_libraries(dev_testing PRIVATE resource_shaders)
# Set standard to C++20
set_target_properties(dev_testing PROPERTIES CXX_STANDARD 20 CXX_EXTENSIONS OFF)

View File

@ -1,46 +0,0 @@
#version 440
in vec3 vs_position;
in mat4 vs_transform;
in vec2 vs_texcoord;
in vec3 vs_normal;
in vec3 vs_to_light;
in vec3 vs_to_camera;
uniform bool texture_is_set;
uniform sampler2D vs_texture;
uniform vec3 light_color;
uniform float shine_damper;
uniform float reflectivity;
out vec4 fs_color;
void main() {
// Lighting
vec3 unit_normal = normalize(vs_normal);
vec3 unit_light_vector = normalize(vs_to_light);
float dot_prod = dot(unit_normal, unit_light_vector);
float brightness = max(dot_prod, 0.f);
vec3 diffuse = brightness * light_color;
// Specular lighting
// only do all this math is reflectivity is > 0
vec3 final_specular = vec3(0.f);
if (reflectivity > 0) {
vec3 unit_vector_to_camera = normalize(vs_to_camera);
vec3 light_direction = -unit_vector_to_camera;
vec3 reflected_light_dir = reflect(light_direction, unit_normal);
float specular_factor = dot(reflected_light_dir, unit_vector_to_camera);
specular_factor = max(specular_factor, 0.f);
float damped_specular = pow(specular_factor, shine_damper);
final_specular = damped_specular * reflectivity * light_color;
}
if (texture_is_set) {
//fs_color = vec4(0.5 * unit_normal + vec3(0.5), 1.f); // Visualize normals
fs_color = vec4(diffuse, 1.f) * texture(vs_texture, vs_texcoord) + vec4(final_specular, 1.f);
} else {
fs_color = vec4(diffuse, 1.f) + vec4(final_specular, 1.f);
}
}

View File

@ -1,31 +0,0 @@
#version 440
layout (location = 0) in vec3 vertex_position;
layout (location = 1) in vec2 vertex_texcoord;
layout (location = 2) in vec3 vertex_normal;
out vec3 vs_position;
out vec2 vs_texcoord;
out mat4 vs_transform;
out vec3 vs_normal;
out vec3 vs_to_light;
out vec3 vs_to_camera;
uniform mat4 transform_matrix;
uniform mat4 view_matrix;
uniform mat4 projection_matrix;
uniform vec3 light_position;
void main() {
vec4 world_pos = (transform_matrix * vec4(vertex_position, 1.f));
vs_position = world_pos.xyz;
vs_transform = transform_matrix;
vs_texcoord = vertex_texcoord;
gl_Position = projection_matrix * view_matrix * world_pos;
vs_normal = (transform_matrix * vec4(vertex_normal, 0.f)).xyz;
vs_to_light = light_position - world_pos.xyz;
vs_to_camera = (inverse(view_matrix) * vec4(0.f, 0.f, 0.f, 1.f)).xyz - world_pos.xyz;
}

View File

@ -31,9 +31,6 @@
#include <sstream>
#include <stdint.h>
#include <cmrc/cmrc.hpp>
CMRC_DECLARE(resource_shaders);
namespace se = simpleengine;
class FPSCounterEvent : public se::Event {
@ -61,141 +58,43 @@ public:
}
};
std::string read_resource_shader(const std::string &path) {
auto fs = cmrc::resource_shaders::get_filesystem();
cmrc::file vertex_file = fs.open(path);
return std::string(vertex_file.begin());
}
int main(int argc, char *argv[]) {
se::Game game(640, 480, "SimpleEngine 3D OpenGL - Developer Testing", GLFW_OPENGL_CORE_PROFILE, 4, 4, false);
/* se::gfx::Texture wall_texture("resources/wall.jpg");
se::gfx::Texture crate_texture("resources/container.jpg", true, true); */
// Load core shaders from SimpleEngine resources
se::gfx::shaders::Core3dShader core_shader;
auto white_texture = se::gfx::Texture::white_texture();
// white_texture.shine_damper = 10;
// white_texture.reflectivity = 1;
/* auto dragon = std::make_shared<se::objects_3d::Mesh>(game.get_window(), core_shader, white_texture,
"examples/dev_testing/resources/dragon.obj"); dragon->translate(0.f, -5.f, -15.f); game.add_event(dragon); */
/* auto cube = std::make_shared<se::objects_3d::Mesh>(game.get_window(), core_shader, white_texture,
"examples/dev_testing/resources/cube.obj"); cube->translate(0.f, -5.f, -15.f); game.add_event(cube);
se::gfx::Texture grass("examples/dev_testing/resources/grass.png");
auto terrain = std::make_shared<se::objects_3d::Terrain>(game.get_window(), core_shader, grass, 0, 0);
terrain->translate(0.f, -5.f, -15.f);
game.add_event(terrain); */
/* se::gfx::Texture stall_texture("examples/dev_testing/resources/stallTextureb.png");
auto stall = std::make_shared<se::objects_3d::Mesh>(game.get_window(), core_shader, stall_texture,
"examples/dev_testing/resources/stall.obj"); stall->translate(10.f, -5.f, 0.f); stall->rotate_y(90.f);
game.add_event(stall); */
/* std::vector<se::Vertex> square_vertices = {
{ se::Vectorf(0.5f, 0.5f, -1.f), glm::vec3(1.f, 0.f, 0.f), glm::vec2(0.f, 0.f) }, // top right
{ se::Vectorf(0.5f, -0.5f, -1.f), glm::vec3(0.f, 1.f, 0.f), glm::vec2(1.f, 0.f) }, // bottom right
{ se::Vectorf(-0.5f, -0.5f, -1.f), glm::vec3(0.f, 0.f, 1.f), glm::vec2(0.5f, 1.0f) }, // bottom left
{ se::Vectorf(-0.5f, 0.5f, -1.f), glm::vec3(.5f, 0.5f, 0.f), glm::vec2(0.5f, 1.0f) }, // top left
};
std::vector<GLuint> indicies = {
0, 1, 3,
1, 2, 3
};
auto square = std::make_shared<se::gfx::Model>(game.get_window(), core_shader, square_vertices, indicies);
square->translate(1.25f, 0.f, -1.f);
//square->rotate_y(90.f);
//square->scale(.75f);
game.add_event(square); */
/* se::gfx::Texture white_texture("examples/dev_testing/resources/white_texture.png");
auto cube = std::make_shared<se::objects_3d::Mesh>(game.get_window(), core_shader, white_texture,
"examples/dev_testing/resources/cube.obj"); cube->translate(-1.25f, 0.f, -1.f); game.add_event(cube); */
/* std::vector<se::Vertex> tri_vertices = {
{ se::Vectorf(-0.5f, -0.5f, -1.f), glm::vec3(1.f, 0.f, 0.f), glm::vec2(0.f, 0.f) }, // top right
{ se::Vectorf(0.5f, -0.5f, -1.f), glm::vec3(0.f, 1.f, 0.f), glm::vec2(1.f, 0.f) }, // bottom right
{ se::Vectorf(0.f, 0.5f, -1.f), glm::vec3(0.f, 0.f, 1.f), glm::vec2(0.5f, 1.0f) }, // bottom left
};
auto tri = std::make_shared<se::gfx::Model>(game.get_window(), core_shader, tri_vertices);
tri->translate(-1.25f, 0.f, -1.f);
tri->scale(.75f);
game.add_event(tri); */
std::vector<se::LitVertex> cube_vertices = {
{se::Vectorf(-1.f, -1.f, -1.f), glm::vec3(1.f, 0.f, 0.f), glm::vec2(0.f, 0.f)},
{se::Vectorf(1.f, -1.f, -1.f), glm::vec3(0.f, 1.f, 0.f), glm::vec2(1.f, 0.f)},
{se::Vectorf(1.f, 1.f, -1.f), glm::vec3(0.f, 0.f, 1.f), glm::vec2(2.f, 0.f)},
{se::Vectorf(-1.f, 1.f, -1.f), glm::vec3(1.f, 1.f, 0.f), glm::vec2(3.f, 0.f)},
{se::Vectorf(-1, -1, -1), glm::vec3(1.f, 1.f, 0.f), glm::vec2(4.f, 0.f)},
{se::Vectorf(-1, -1, 1), glm::vec3(1.f, 0.f, 0.f), glm::vec2(0.f, 1.f)},
{se::Vectorf(1, -1, 1), glm::vec3(0.f, 1.f, 0.f), glm::vec2(1.f, 1.f)},
{se::Vectorf(1, 1, 1), glm::vec3(0.f, 0.f, 1.f), glm::vec2(2.f, 1.f)},
{se::Vectorf(-1, 1, 1), glm::vec3(1.f, 1.f, 0.f), glm::vec2(3.f, 1.f)},
{se::Vectorf(-1, -1, 1), glm::vec3(1.f, 1.f, 0.f), glm::vec2(4.f, 1.f)},
{se::Vectorf(-1, 1, -1), glm::vec3(1.f, 0.f, 0.f), glm::vec2(0.f, -1.f)},
{se::Vectorf(1, 1, -1), glm::vec3(0.f, 1.f, 0.f), glm::vec2(1.f, -1.f)},
{se::Vectorf(-1, 1, 1), glm::vec3(1.f, 0.f, 0.f), glm::vec2(0.f, 2.f)},
{se::Vectorf(1, 1, 1), glm::vec3(0.f, 1.f, 0.f), glm::vec2(1.f, 2.f)},
};
std::vector<GLuint> cube_indicies = {0, 1, 5, 5, 1, 6, 1, 2, 6, 6, 2, 7, 2, 3, 7, 7, 3, 8,
3, 4, 8, 8, 4, 9, 10, 11, 0, 0, 11, 1, 5, 6, 12, 12, 6, 13};
auto camera = std::make_shared<se::Camera>(game.get_window(), core_shader, 70, glm::vec3(0, 0, 0));
game.add_event(camera);
// Create a renderer
auto renderer = std::make_shared<se::gfx::Renderer>(game.get_window(), core_shader);
auto renderer = std::make_shared<se::gfx::Renderer>(game.get_window(), core_shader, camera);
renderer->initialize();
game.add_renderable(renderer);
// Create a Scene and give it the renderer
auto scene = std::make_shared<se::Scene>(renderer);
game.add_event(scene);
se::ecs::Entity other_e = scene->create_entity();
other_e.add_component<se::ModelComponent>("examples/dev_testing/resources/transparent_window.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE | simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_TRANSPARENT);
auto &other_transform = other_e.add_component<se::TransformComponent>();
other_transform.translate(5.f, 0.5f, 1.f);
// Create an Entity in the Scene and add components to it.
se::ecs::Entity entity = scene->create_entity();
// entity.add_component<se::ModelComponent>("examples/dev_testing/resources/dragon.obj");
// entity.add_component<se::ModelComponent>("examples/dev_testing/resources/stall.obj");
// Backpack model required vertically flipped texture coords.
/* auto& model_comp =
entity.add_component<se::ModelComponent>("examples/dev_testing/resources/backpack/backpack.obj");
model_comp.model.vertically_flip_tex_coords(); */
// entity.add_component<se::ModelComponent>("examples/dev_testing/resources/viper/viper.obj");
// entity.add_component<se::ModelComponent>("examples/dev_testing/resources/halot/chief.fbx");
// entity.add_component<se::ModelComponent>("examples/dev_testing/resources/planks/planks.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE);
entity.add_component<se::ModelComponent>("examples/dev_testing/resources/bricks/bricks.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE);
//entity.add_component<se::ModelComponent>("examples/dev_testing/resources/bricks/bricks.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE);
entity.add_component<se::ModelComponent>("examples/dev_testing/resources/transparent_window.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE | simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_TRANSPARENT);
// entity.add_component<se::ModelComponent>("examples/dev_testing/resources/scientist/scientist.fbx");
// entity.add_component<se::ModelComponent>("examples/dev_testing/resources/paradigm/paradigm.fbx");
// entity.add_component<se::RotatingComponent>();
auto &transform_comp = entity.add_component<se::TransformComponent>();
transform_comp.translate(4.f, 0.f, 0.f);
// transform_comp.scale(0.05f);
// transform_comp.rotate_z(-90.f);
// transform_comp.rotate_y(-90.f);
// transform_comp.rotate_x(-90.f);
// Create the entity and add the model component to it.
/* auto entity = std::make_shared<simpleengine::Entity>();
entity->add_component<se::MeshComponent>(cube_vertices, cube_indicies, white_material, true);
entity->translate(3.5f, 0.f, 0.f); */
/* auto entity = std::make_shared<simpleengine::Entity>();
entity->add_component<se::ModelComponent>("examples/dev_testing/resources/dragon.obj");
entity->translate(12.f, -4.f, 0.f); */
auto camera = std::make_shared<se::Camera>(game.get_window(), core_shader, 70, glm::vec3(0, 0, 0));
game.add_event(camera);
se::ecs::Entity brick_e = scene->create_entity();
brick_e.add_component<se::ModelComponent>("examples/dev_testing/resources/bricks/bricks.fbx", simpleengine::gfx::ModelProcessingFlags::MdlProcFlag_CALCULATE_TANGENT_SPACE);
auto &brick_transf = brick_e.add_component<se::TransformComponent>();
brick_transf.translate(6.f, -0.5f, 1.f);
auto light = std::make_shared<se::gfx::Light>(core_shader, glm::vec3(0.f, 0.f, 0.f), glm::vec3(1.f, 1.f, 1.f));
game.add_event(light);

View File

@ -1,5 +1,6 @@
#pragma once
#include "rendering_type.h"
#include "texture.h"
#include <assimp/material.h>
@ -10,6 +11,9 @@
namespace simpleengine::gfx {
class Material {
public:
RenderingType rendering_type;
// TODO: Only one of each texture type.
std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> textures;
float ambient_strength;
@ -32,9 +36,9 @@ namespace simpleengine::gfx {
*/
float shine_factor;
Material(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> textures, float shine = 1.f, float specular_scalar = 1.f, float ambient_scalar = 1.f, float diffuse_scalar = 1.f) :
textures(textures), ambient_strength(ambient_scalar), diffuse_strength(diffuse_scalar), specular_strength(specular_scalar),
shine_factor(shine) {
Material(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> textures, RenderingType rendering_type, float shine = 1.f,
float specular_scalar = 1.f, float ambient_scalar = 1.f, float diffuse_scalar = 1.f) : textures(textures), rendering_type(rendering_type),
ambient_strength(ambient_scalar), diffuse_strength(diffuse_scalar), specular_strength(specular_scalar), shine_factor(shine) {
}
};

View File

@ -16,6 +16,7 @@ namespace simpleengine::gfx {
MdlProcFlag_FLIP_TEX_COORDS_VERTICALLY = 0b00000001,
MdlProcFlag_FLIP_TEX_COORDS_HORIZONTALLY = 0b00000010,
MdlProcFlag_CALCULATE_TANGENT_SPACE = 0b00000100,
MdlProcFlag_TRANSPARENT = 0b00001000,
};
/**
@ -40,7 +41,7 @@ namespace simpleengine::gfx {
gfx::Mesh process_mesh(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiMesh* mesh, const aiScene* scene);
std::unordered_map<aiTextureType, std::vector<Texture>> load_all_textures(aiMaterial* material);
std::vector<std::shared_ptr<Texture>> load_material_texture(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiMaterial* material, aiTextureType type, TextureFlags texture_color);
std::vector<std::shared_ptr<Texture>> load_material_texture(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiMaterial* material, aiTextureType type);
protected:
void post_process();
public:

View File

@ -1,36 +1,45 @@
#pragma once
#include "../camera.h"
#include "shader.h"
#include "simpleengine/gfx/mesh.h"
#include "../renderable.h"
#include "rendering_type.h"
#include <unordered_map>
#include <vector>
#include <queue>
#include <map>
namespace simpleengine::gfx {
class Mesh;
class RenderingJob {
public:
gfx::Mesh& rendering_mesh;
RenderingType rendering_type;
gfx::Mesh* rendering_mesh;
glm::mat4 transform_mat;
RenderingJob(gfx::Mesh& mesh, glm::mat4 position) : rendering_mesh(mesh), transform_mat(position) {
}
RenderingJob(RenderingType rendering_type, gfx::Mesh& mesh, glm::mat4 position);
};
class Renderer : public simpleengine::Renderable {
private:
GLFWwindow* window;
protected:
public:
std::queue<RenderingJob> transparent_render_queue;
std::queue<RenderingJob> other_render_queue;
std::queue<RenderingJob> rendering_queue;
gfx::Shader shader;
std::shared_ptr<Camera> camera;
Renderer(GLFWwindow* window, gfx::Shader shader);
Renderer(GLFWwindow* window, GLuint shader_program);
Renderer(GLFWwindow* window, gfx::Shader shader, std::shared_ptr<Camera> camera);
Renderer(GLFWwindow* window, GLuint shader_program, std::shared_ptr<Camera> camera);
void enable_debug();
virtual void sort_jobs();
virtual void queue_job(RenderingType rendering_type, gfx::Mesh& mesh, glm::mat4 position);
virtual void queue_job(RenderingJob job);
virtual void create_job_buffers(RenderingJob& job);
@ -40,5 +49,16 @@ namespace simpleengine::gfx {
virtual void update(const float& delta_time) override;
virtual void render() override;
/**
* @brief Renders a single job.
*
* @param job The job that will be rendered.
* @return true if the job was rendered successfully.
* @return false if there was an error when trying to render the job.
*/
virtual bool render_job(const RenderingJob& job);
virtual void render_job_queue(std::queue<RenderingJob>& queue);
virtual void render_job_queue(std::map<float, RenderingJob, std::greater<>>& queue);
};
}

View File

@ -0,0 +1,8 @@
#pragma once
namespace simpleengine::gfx {
enum RenderingType {
RendType_OPAQUE = 0,
RendType_TRANSPARENT = 1,
};
}

View File

@ -23,39 +23,29 @@ namespace simpleengine::gfx {
TexFlags_FLIP_VERTICALLY = 0b00000010,
TexFlags_FLIP_HORIZONTALLY = 0b00000100,
TexFlags_MIPMAP = 0b00001000,
TexFlags_NO_COLOR = 0b00010000,
/* TexFlags_NO_COLOR = 0b00010000,
TexFlags_RGB = 0b00100000,
TexFlags_RGBA = 0b01000000,
TexFlags_RGBA = 0b01000000, */
};
class Texture {
private:
unsigned char* img_data; // TODO Free this if its not used anymore
//unsigned char* img_data; // TODO Free this if its not used anymore
unsigned int texture_id;
unsigned int image_type_gl;
Texture() = default;
public:
/**
* @brief The default Texture flags not including the color.
*
* The default flags are `TexFlags_IMG_2D | TexFlags_MIPMAP`
*
* @see simpleengine::gfx::Texture::default_flags
*
*/
static constexpr int default_flags_no_color = TexFlags_IMG_2D | TexFlags_MIPMAP;
/**
* @brief The default Texture flags including the color.
*
* The default flags are `TexFlags_IMG_2D | TexFlags_MIPMAP | TexFlags_RGBA`
* The default flags are `TexFlags_IMG_2D | TexFlags_MIPMAP`
*
* @see simpleengine::gfx::Texture::default_flags_no_color
*
*/
static constexpr int default_flags = default_flags_no_color | TexFlags_RGBA;
static constexpr int default_flags = TexFlags_IMG_2D | TexFlags_MIPMAP;
int height;
int width;

View File

@ -47,8 +47,13 @@ out vec4 fs_color;
vec3 calculate_lighting();
void main() {
vec3 lighting = calculate_lighting();
// Skip completely transparent fragments.
/* vec4 diffuse = texture(u_material.diffuse, vs_texcoord);
if (diffuse.a < 0.1) {
discard;
} */
vec3 lighting = calculate_lighting();
fs_color = vec4(lighting, 1.f) * texture(u_material.diffuse, vs_texcoord);
}

View File

@ -48,9 +48,7 @@ simpleengine::Game::Game(int w, int h, const std::string& window_name, const int
}
void simpleengine::Game::enable_default_gl_options() const {
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
//glFrontFace(GL_CW);
update_enabled_vsync();

View File

@ -1,5 +1,6 @@
#include "gfx/model.h"
#include "gfx/material.h"
#include "gfx/rendering_type.h"
#include "gfx/texture.h"
#include "vector.h"
@ -107,11 +108,17 @@ namespace simpleengine::gfx {
}
}
// Get the rendering type
RenderingType rendering_type = RenderingType::RendType_OPAQUE;
if (model_processing_flags & ModelProcessingFlags::MdlProcFlag_TRANSPARENT) {
rendering_type = RenderingType::RendType_TRANSPARENT;
}
// Create a default material and white texture.
auto white_texture = gfx::Texture::white_texture();
std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> default_textures;
default_textures.emplace(white_texture.type, std::vector<std::shared_ptr<Texture>>{ std::make_shared<Texture>(white_texture) });
gfx::Material mat(default_textures);
gfx::Material mat(default_textures, rendering_type);
if (mesh->mMaterialIndex >= 0) {
std::cout << "TODO: Process model materials!" << std::endl;
@ -121,17 +128,17 @@ namespace simpleengine::gfx {
// Load Diffuse texture maps
aiTextureType loading_type = aiTextureType_DIFFUSE;
std::vector<std::shared_ptr<Texture>> diffuse_maps = load_material_texture(processed_textures, material, loading_type, TextureFlags::TexFlags_RGBA);
std::vector<std::shared_ptr<Texture>> diffuse_maps = load_material_texture(processed_textures, material, loading_type);
if (!diffuse_maps.empty()) textures.emplace(loading_type, diffuse_maps);
// Load specular texture maps
loading_type = aiTextureType_SPECULAR;
std::vector<std::shared_ptr<Texture>> spec_maps = load_material_texture(processed_textures, material, loading_type, TextureFlags::TexFlags_NO_COLOR);
std::vector<std::shared_ptr<Texture>> spec_maps = load_material_texture(processed_textures, material, loading_type);
if (!spec_maps.empty()) textures.emplace(loading_type, spec_maps);
// Load normals texture maps
loading_type = aiTextureType_NORMALS;
std::vector<std::shared_ptr<Texture>> normal_maps = load_material_texture(processed_textures, material, loading_type, TextureFlags::TexFlags_RGB);
std::vector<std::shared_ptr<Texture>> normal_maps = load_material_texture(processed_textures, material, loading_type);
if (!normal_maps.empty()) {
textures.emplace(loading_type, normal_maps);
@ -143,7 +150,7 @@ namespace simpleengine::gfx {
if (!textures.empty()) {
// TODO: Find a way to let the user set the scalars.
mat = Material(textures);
mat = Material(textures, rendering_type);
// Add `textures` into the `processed_textures` list.
for (const auto& pair : textures) {
@ -189,7 +196,7 @@ namespace simpleengine::gfx {
return {};
}
std::vector<std::shared_ptr<Texture>> Model::load_material_texture(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiMaterial* material, aiTextureType type, TextureFlags texture_color) {
std::vector<std::shared_ptr<Texture>> Model::load_material_texture(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiMaterial* material, aiTextureType type) {
std::vector<std::shared_ptr<Texture>> textures;
for (int i = 0; i < material->GetTextureCount(type); i++) {
@ -216,7 +223,7 @@ namespace simpleengine::gfx {
ss << model_directory << "/" << texture_path;
std::string full_path = ss.str();
Texture texture(full_path.c_str(), type, Texture::default_flags_no_color | texture_color);
Texture texture(full_path.c_str(), type);
texture.path = texture_path;
textures.emplace_back(std::make_shared<Texture>(texture));

View File

@ -9,25 +9,27 @@
#include <algorithm>
#include <assimp/material.h>
#include <functional>
#include <glm/geometric.hpp>
// TODO: Check if initialized before trying to do stuff
namespace simpleengine::gfx {
void create_mesh_buffers(simpleengine::gfx::Mesh& mesh);
void create_mesh_buffers(simpleengine::gfx::Mesh &mesh);
Renderer::Renderer(GLFWwindow* window, gfx::Shader shader): window(window), shader(shader) {
}
RenderingJob::RenderingJob(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 position)
: rendering_type(rendering_type), rendering_mesh(&mesh), transform_mat(position) {}
Renderer::Renderer(GLFWwindow* window, GLuint shader_program): Renderer(window,
gfx::Shader(shader_program)) {
Renderer::Renderer(GLFWwindow *window, gfx::Shader shader, std::shared_ptr<Camera> camera)
: window(window), shader(shader), camera(camera)/* , transparent_render_queue(CameraDistanceComparator(camera)) */ {}
}
Renderer::Renderer(GLFWwindow *window, GLuint shader_program, std::shared_ptr<Camera> camera)
: Renderer(window, gfx::Shader(shader_program), camera) {}
void debug_message_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
const GLchar *message, const void *userParam) {
void debug_message_callback(GLenum source, GLenum type, GLuint id, GLenum severity,
GLsizei length, const GLchar* message, const void* userParam) {
fprintf(stderr, "%s type = 0x%x, severity = 0x%x, message = %s\n",
(type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
type, severity, message);
(type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""), type, severity, message);
}
void Renderer::enable_debug() {
@ -35,24 +37,49 @@ namespace simpleengine::gfx {
glDebugMessageCallback(debug_message_callback, 0);
}
void Renderer::queue_job(RenderingJob job) {
RenderingJob& emplace = rendering_queue.emplace(job);
create_job_buffers(emplace);
void Renderer::sort_jobs() {
// Sort transparents
// std::sort()
}
void Renderer::create_job_buffers(RenderingJob& job) {
Mesh& rendering_mesh = job.rendering_mesh;
void Renderer::queue_job(RenderingType rendering_type, gfx::Mesh &mesh, glm::mat4 position) {
RenderingJob job(rendering_type, mesh, position);
if (!rendering_mesh.are_buffers_created) {
gfx::VBO& vbo = rendering_mesh.vbo;
gfx::VBO& ebo = rendering_mesh.ebo;
gfx::VAO& vao = rendering_mesh.vao;
this->queue_job(job);
}
void Renderer::queue_job(RenderingJob job) {
create_job_buffers(job);
switch (job.rendering_type) {
case RenderingType::RendType_TRANSPARENT: {
/* glm::vec3 pos = job.transform_mat[3];
float distance = glm::distance(pos, camera->position); */
this->transparent_render_queue.emplace(job);
break;
}
default:
this->other_render_queue.emplace(job);
break;
}
sort_jobs();
}
void Renderer::create_job_buffers(RenderingJob &job) {
Mesh *rendering_mesh = job.rendering_mesh;
if (!rendering_mesh->are_buffers_created) {
gfx::VBO &vbo = rendering_mesh->vbo;
gfx::VBO &ebo = rendering_mesh->ebo;
gfx::VAO &vao = rendering_mesh->vao;
vao.bind();
vbo.buffer(rendering_mesh.vertices.data(), 0, sizeof(LitVertex) * rendering_mesh.vertices.size());
vbo.buffer(rendering_mesh->vertices.data(), 0, sizeof(LitVertex) * rendering_mesh->vertices.size());
if (!rendering_mesh.indicies.empty()) {
ebo.buffer(rendering_mesh.indicies.data(), 0, rendering_mesh.indicies.size() * sizeof(GLuint));
if (!rendering_mesh->indicies.empty()) {
ebo.buffer(rendering_mesh->indicies.data(), 0, rendering_mesh->indicies.size() * sizeof(GLuint));
}
// Enable VAO attributes
@ -61,23 +88,29 @@ namespace simpleengine::gfx {
vao.enable_attrib(vbo, 2, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, normal), false);
vao.enable_attrib(vbo, 3, 2, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, tex_coord), false);
rendering_mesh.tangent_vbo.buffer(rendering_mesh.tangents.data(), 0, rendering_mesh.tangents.size() * sizeof(Vectorf));
vao.enable_attrib(rendering_mesh.tangent_vbo, 4, 3, GL_FLOAT, sizeof(Vectorf), 0, false);
rendering_mesh->tangent_vbo.buffer(rendering_mesh->tangents.data(), 0,
rendering_mesh->tangents.size() * sizeof(Vectorf));
vao.enable_attrib(rendering_mesh->tangent_vbo, 4, 3, GL_FLOAT, sizeof(Vectorf), 0, false);
vbo.unbind();
vao.unbind();
rendering_mesh.are_buffers_created = true;
rendering_mesh->are_buffers_created = true;
std::cout << "Created render job buffers" << std::endl;
}
}
void Renderer::update(const float& delta_time) {
}
void Renderer::update(const float &delta_time) {}
void Renderer::initialize() {
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
std::cout << "Base Renderer initialized" << std::endl;
}
@ -89,73 +122,112 @@ namespace simpleengine::gfx {
} */
}
void Renderer::render() {
bool Renderer::render_job(const RenderingJob &job) {
Mesh *mesh = job.rendering_mesh;
shader.set_uniform_matrix_4f("u_transform_matrix", job.transform_mat, false);
std::optional<Material> &material = mesh->material;
if (material.has_value()) {
shader.set_uniform_float("u_material.ambient_strength", material->ambient_strength, false);
shader.set_uniform_float("u_material.diffuse_strength", material->diffuse_strength, false);
shader.set_uniform_float("u_material.specular_strength", material->specular_strength, false);
shader.set_uniform_float("u_material.shine_factor", material->shine_factor, false);
// shader.set_uniform_float("u_material.reflect_factor", .1f, false);
auto diffuse_maps = material->textures.find(aiTextureType_DIFFUSE);
auto diffuse_map = diffuse_maps->second.front();
shader.set_uniform_int("u_material.diffuse", 0, false);
glActiveTexture(GL_TEXTURE0);
diffuse_map->bind();
// Apply the specular map if it exists
auto specular_maps = material->textures.find(aiTextureType_SPECULAR);
if (specular_maps != material->textures.end()) {
auto spec = specular_maps->second.front();
shader.set_uniform_int("u_material.has_specular_map", 1, false);
shader.set_uniform_int("u_material.specular_map", 1, false);
glActiveTexture(GL_TEXTURE1);
spec->bind();
} else {
shader.set_uniform_int("u_material.has_specular_map", 0, false);
}
// Apply the normal map if it exists
auto normal_maps = material->textures.find(aiTextureType_NORMALS);
if (normal_maps != material->textures.end()) {
auto normal = normal_maps->second.front();
shader.set_uniform_int("u_material.has_normal_map", 1, false);
shader.set_uniform_int("u_material.normal_map", 2, false);
glActiveTexture(GL_TEXTURE2);
normal->bind();
} else {
shader.set_uniform_int("u_material.has_normal_map", 0, false);
}
}
mesh->vao.bind();
if (mesh->indicies.empty()) {
glDrawArrays(GL_TRIANGLES, 0, mesh->vertices.size());
} else {
glDrawElements(GL_TRIANGLES, mesh->indicies.size(), GL_UNSIGNED_INT, 0);
}
return true;
}
void Renderer::render_job_queue(std::queue<RenderingJob> &rendering_queue) {
shader.use();
while (!rendering_queue.empty()) {
// Get the job from the queue, we'll remove it after we render.
RenderingJob& job = rendering_queue.front();
Mesh& mesh = job.rendering_mesh;
RenderingJob &job = rendering_queue.front();
shader.set_uniform_matrix_4f("u_transform_matrix", job.transform_mat, false);
bool res = this->render_job(job);
std::optional<Material>& material = mesh.material;
if (material.has_value()) {
shader.set_uniform_float("u_material.ambient_strength", material->ambient_strength, false);
shader.set_uniform_float("u_material.diffuse_strength", material->diffuse_strength, false);
shader.set_uniform_float("u_material.specular_strength", material->specular_strength, false);
shader.set_uniform_float("u_material.shine_factor", material->shine_factor, false);
//shader.set_uniform_float("u_material.reflect_factor", .1f, false);
auto diffuse_maps = material->textures.find(aiTextureType_DIFFUSE);
auto diffuse_map = diffuse_maps->second.front();
shader.set_uniform_int("u_material.diffuse", 0, false);
glActiveTexture(GL_TEXTURE0);
diffuse_map->bind();
// Apply the specular map if it exists
auto specular_maps = material->textures.find(aiTextureType_SPECULAR);
if (specular_maps != material->textures.end()) {
auto spec = specular_maps->second.front();
shader.set_uniform_int("u_material.has_specular_map", 1, false);
shader.set_uniform_int("u_material.specular_map", 1, false);
glActiveTexture(GL_TEXTURE1);
spec->bind();
} else {
shader.set_uniform_int("u_material.has_specular_map", 0, false);
}
// Apply the normal map if it exists
auto normal_maps = material->textures.find(aiTextureType_NORMALS);
if (normal_maps != material->textures.end()) {
auto normal = normal_maps->second.front();
shader.set_uniform_int("u_material.has_normal_map", 1, false);
shader.set_uniform_int("u_material.normal_map", 2, false);
glActiveTexture(GL_TEXTURE2);
normal->bind();
} else {
shader.set_uniform_int("u_material.has_normal_map", 0, false);
}
if (res) {
// Now we'll remove the job from the queue.
rendering_queue.pop();
}
mesh.vao.bind();
if (mesh.indicies.empty()) {
glDrawArrays(GL_TRIANGLES, 0, mesh.vertices.size());
} else {
glDrawElements(GL_TRIANGLES, mesh.indicies.size(), GL_UNSIGNED_INT, 0);
}
// Now we'll remove the job from the queue.
rendering_queue.pop();
}
shader.unuse();
}
}
void Renderer::render_job_queue(std::map<float, RenderingJob, std::greater<>>& rendering_queue) {
shader.use();
// Render each job then clear the queue
for (const auto& it : rendering_queue) {
this->render_job(it.second);
}
rendering_queue.clear();
shader.unuse();
}
void Renderer::render() {
// Render other (opaque) objects first
this->render_job_queue(other_render_queue);
// Render transparent objects
std::map<float, RenderingJob, std::greater<>> transparent_jobs;
while (!transparent_render_queue.empty()) {
RenderingJob& job = transparent_render_queue.front();
glm::vec3 pos = job.transform_mat[3];
float distance = glm::distance(pos, camera->position);
transparent_jobs.emplace(distance, job);
transparent_render_queue.pop();
}
this->render_job_queue(transparent_jobs);
}
} // namespace simpleengine::gfx

View File

@ -10,24 +10,6 @@ namespace simpleengine::gfx {
bool flip_vertically = flags & TextureFlags::TexFlags_FLIP_VERTICALLY;
bool mipmap = flags & TextureFlags::TexFlags_MIPMAP;
// Get the color channel type for opengl, and get
// the channel count for loading the texture with stb_image
int gl_color_channels;
int channel_count;
if (flags & TexFlags_RGBA) {
channel_count = 4;
gl_color_channels = GL_RGBA;
} else if (flags & TexFlags_RGB) {
channel_count = 3;
gl_color_channels = GL_RGB;
} else if (flags & TexFlags_NO_COLOR) {
channel_count = 1;
gl_color_channels = GL_RED;
} else {
std::cerr << "Texture color flag is missing!! Specify TexFlags_RGBA" << std::endl;
throw std::runtime_error("Texture color flag is missing!! Specify TexFlags_RGBA");
}
image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D;
glGenTextures(1, &texture_id);
@ -42,7 +24,7 @@ namespace simpleengine::gfx {
stbi_set_flip_vertically_on_load(flip_vertically);
img_data = stbi_load(path, &width, &height, &channels, channel_count);
unsigned char*img_data = stbi_load(path, &width, &height, &channels, 0);
if(!img_data) {
const char* failure = stbi_failure_reason();
std::cerr << "Failed to load texture! (" << failure << ")" << std::endl;
@ -50,13 +32,27 @@ namespace simpleengine::gfx {
}
std::cout << "Loaded image with a width of " << width << "px, a height of " << height << "px and " << channels << " channels" << std::endl;
glTexImage2D(image_type_gl, 0, gl_color_channels, width, height, 0, gl_color_channels, GL_UNSIGNED_BYTE, img_data);
// Get the color type
int color_format = 0;
if (channels == 1) {
color_format = GL_RED;
} else if (channels == 3) {
color_format = GL_RGB;
} else if (channels == 4) {
color_format = GL_RGBA;
} else {
std::cerr << "Unknown texture color format with " << channels << " channels!" << std::endl;
throw std::runtime_error("Unknown texture color format!");
}
glTexImage2D(image_type_gl, 0, color_format, width, height, 0, color_format, GL_UNSIGNED_BYTE, img_data);
if (mipmap) {
glGenerateMipmap(image_type_gl);
}
stbi_set_flip_vertically_on_load(false);
stbi_image_free(img_data);
unbind();
}
@ -66,24 +62,6 @@ namespace simpleengine::gfx {
bool flip_vertically = flags & TextureFlags::TexFlags_FLIP_VERTICALLY;
bool mipmap = flags & TextureFlags::TexFlags_MIPMAP;
// Get the color channel type for opengl, and get
// the channel count for loading the texture with stb_image
int gl_color_channels;
int channel_count;
if (flags & TexFlags_RGBA) {
channel_count = 4;
gl_color_channels = GL_RGBA;
} else if (flags & TexFlags_RGB) {
channel_count = 3;
gl_color_channels = GL_RGB;
} else if (flags & TexFlags_NO_COLOR) {
channel_count = 1;
gl_color_channels = GL_RED;
} else {
std::cerr << "Texture color flag is missing!! Specify TexFlags_RGBA" << std::endl;
throw std::runtime_error("Texture color flag is missing!! Specify TexFlags_RGBA");
}
image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D;
glGenTextures(1, &texture_id);
@ -98,7 +76,7 @@ namespace simpleengine::gfx {
stbi_set_flip_vertically_on_load(flip_vertically);
img_data = stbi_load_from_memory(buffer, buffer_length, &width, &height, &channels, channel_count);
unsigned char* img_data = stbi_load_from_memory(buffer, buffer_length, &width, &height, &channels, 0);
if(!img_data) {
const char* failure = stbi_failure_reason();
std::cerr << "Failed to load texture! (" << failure << ")" << std::endl;
@ -106,13 +84,27 @@ namespace simpleengine::gfx {
}
std::cout << "Loaded image with a width of " << width << "px, a height of " << height << "px and " << channels << " channels" << std::endl;
glTexImage2D(image_type_gl, 0, gl_color_channels, width, height, 0, gl_color_channels, GL_UNSIGNED_BYTE, img_data);
// Get the color type
int color_format = 0;
if (channels == 1) {
color_format = GL_RED;
} else if (channels == 3) {
color_format = GL_RGB;
} else if (channels == 4) {
color_format = GL_RGBA;
} else {
std::cerr << "Unknown texture color format with " << channels << " channels!" << std::endl;
throw std::runtime_error("Unknown texture color format!");
}
glTexImage2D(image_type_gl, 0, color_format, width, height, 0, color_format, GL_UNSIGNED_BYTE, img_data);
if (mipmap) {
glGenerateMipmap(image_type_gl);
}
stbi_set_flip_vertically_on_load(false);
stbi_image_free(img_data);
unbind();
}
@ -138,7 +130,6 @@ namespace simpleengine::gfx {
texture.height = height;
texture.channels = 4;
texture.type = aiTextureType::aiTextureType_DIFFUSE;
texture.img_data = data;
glGenTextures(1, &texture.texture_id);
texture.bind();
@ -148,10 +139,12 @@ namespace simpleengine::gfx {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture.img_data);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
texture.unbind();
free(data);
return texture;
}

View File

@ -19,12 +19,22 @@ namespace simpleengine {
// Is there a way these can be grouped?
registry.view<const TransformComponent, ModelComponent>().each([this](const TransformComponent& transform, ModelComponent& model_component) {
for (auto& mesh : model_component.model.meshes) {
renderer->queue_job(gfx::RenderingJob(mesh, transform.transform_matrix));
auto rendering_type = gfx::RenderingType::RendType_OPAQUE;
if (mesh.material) {
rendering_type = mesh.material->rendering_type;
}
renderer->queue_job(gfx::RenderingJob(rendering_type, mesh, transform.transform_matrix));
}
});
registry.view<const TransformComponent, MeshComponent>().each([this](const TransformComponent& transform, MeshComponent& mesh_component) {
renderer->queue_job(gfx::RenderingJob(mesh_component.mesh, transform.transform_matrix));
auto rendering_type = gfx::RenderingType::RendType_OPAQUE;
if (mesh_component.mesh.material) {
rendering_type = mesh_component.mesh.material->rendering_type;
}
renderer->queue_job(gfx::RenderingJob(rendering_type, mesh_component.mesh, transform.transform_matrix));
});
registry.view<TransformComponent, RotatingComponent>().each([this, &delta_time](TransformComponent& transform, RotatingComponent& rotating) {