Add light components and systems

This commit is contained in:
2022-10-23 14:03:30 +02:00
parent a3b6c3b346
commit 71a86bdae2
10 changed files with 160 additions and 250 deletions

View File

@@ -2,7 +2,6 @@ add_library(fever_engine
main.cpp
Controller.cpp
Window.cpp
Light.cpp
scene.cpp
FrameBuffer.cpp
Helper.cpp
@@ -13,6 +12,8 @@ add_library(fever_engine
material.cpp
camera.cpp
shader.cpp
transform.cpp
light.cpp
)
target_compile_features(fever_engine PUBLIC cxx_std_20)

View File

@@ -1,9 +1,9 @@
#include "Controller.h"
#include "FrameBuffer.h"
#include "Helper.h"
#include "Light.h"
#include "Window.h"
#include "gltf_loader.h"
#include "light.h"
#include "render.h"
#include "shader.h"
#include "util/Log.h"
@@ -54,16 +54,6 @@ void Controller::run()
auto standard_material_shader =
m_shader_cache.load(shader_hash, Material::SHADER_NAME).first->second;
DirectionalLight directional_light(
DirectionalLight::Prototype("", glm::vec3(-0.2, -1.0, -0.3), glm::vec3(1.0f), 5.f),
standard_material_shader.handle().get());
directional_light.setActive(true);
PointLight point_light(
PointLight::Prototype("", "", glm::vec3(4.0, 1.0, 6.0), glm::vec3(1.0F), 3.0F),
standard_material_shader.handle().get());
point_light.setActive(true);
Log::logger().info("Startup complete. Enter game loop.");
// This is the game loop
@@ -92,6 +82,7 @@ void Controller::run()
m_postProcessFrameBuffer.bind();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Light::update_lights(m_scene->registry(), standard_material_shader);
Render::render(m_scene->registry());
Framebuffer::unbind();

View File

@@ -1,105 +0,0 @@
#include "Light.h"
#include "shader.h"
#include <string>
uint32_t Light::s_idCounter = 0;
Light::Light(const std::string &name, glm::vec3 color, float intensity, Shader *shader)
: m_shader(shader), m_intensity(intensity), m_lightColor(color * intensity)
{
m_id = s_idCounter++;
}
Light::~Light() = default;
glm::vec3 Light::getColor()
{
return m_lightColor;
}
void Light::setShader(Shader *shader)
{
this->m_shader = shader;
update();
}
void Light::setColor(glm::vec3 color)
{
m_lightColor = color * m_intensity;
update();
}
void Light::setIntensity(float intensity)
{
this->m_intensity = intensity;
}
void Light::setActive(bool active)
{
m_isActive = active;
update();
}
PointLight::PointLight(Prototype prototype, Shader *shader)
: Light(prototype.name, prototype.color, prototype.intensity, shader), m_position(prototype.position)
{
update();
}
void PointLight::update()
{
m_shader->bind();
m_shader->set_uniform((getStructMemberName() + "isActive").c_str(), m_isActive);
m_shader->set_uniform((getStructMemberName() + "position").c_str(), m_position);
m_shader->set_uniform((getStructMemberName() + "color").c_str(), m_lightColor);
m_shader->unbind();
}
std::string PointLight::getStructMemberName()
{
// id - 1 because id 0 is always the DirectionalLight!
std::string temp = "u_pointLight[" + std::to_string(m_id - 1) + "].";
return temp;
}
glm::vec3 PointLight::getPosition()
{
return m_position;
}
void PointLight::setPosition(glm::vec3 position)
{
this->m_position = position;
update();
}
DirectionalLight::DirectionalLight(Prototype prototype, Shader *shader)
: Light(prototype.name, prototype.color, prototype.intensity, shader), m_direction(prototype.direction)
{
update();
}
void DirectionalLight::update()
{
m_shader->bind();
m_shader->set_uniform("u_directionalLight.isActive", m_isActive);
m_shader->set_uniform("u_directionalLight.direction", m_direction);
m_shader->set_uniform("u_directionalLight.color", m_lightColor);
m_shader->unbind();
}
void DirectionalLight::setDirection(glm::vec3 direction)
{
this->m_direction = direction;
update();
}
glm::vec3 DirectionalLight::getDirection()
{
return m_direction;
}

View File

@@ -1,98 +0,0 @@
#pragma once
#include <glm/glm.hpp>
#include <string>
class Shader;
class Light
{
public:
struct Prototype
{
Prototype(const std::string &_name, const std::string &_parent, glm::vec3 _color, float _intensity)
: name(_name), parent(_parent), color(_color), intensity(_intensity)
{}
virtual ~Prototype() = default;
std::string name;
std::string parent;
glm::vec3 color;
float intensity;
};
Light(const std::string &name, glm::vec3 color, float intensity, Shader *shader);
virtual ~Light() = 0;
virtual void update() = 0;
void setActive(bool active);
void setColor(glm::vec3 color);
void setIntensity(float intensity);
void setShader(Shader *shader);
glm::vec3 getColor();
protected:
Shader *m_shader;
uint32_t m_id;
static uint32_t s_idCounter;
bool m_isActive = true;
float m_intensity;
// Color
glm::vec3 m_lightColor;
};
class PointLight : public Light
{
public:
struct Prototype : public Light::Prototype
{
Prototype(const std::string &_name, const std::string &_parent, glm::vec3 _position, glm::vec3 _color,
float _intensity)
: Light::Prototype(_name, _parent, _color, _intensity), position(_position)
{}
glm::vec3 position;
};
PointLight(Prototype prototype, Shader *shader);
~PointLight() override = default;
void setPosition(glm::vec3 position);
glm::vec3 getPosition();
private:
void update() override;
std::string getStructMemberName();
glm::vec3 m_position = glm::vec3(0.0f, 0.0f, 0.0f);
};
class DirectionalLight : public Light
{
public:
struct Prototype : public Light::Prototype
{
Prototype(const std::string &_name, glm::vec3 _direction, glm::vec3 _color, float _intensity)
: Light::Prototype(_name, "", _color, _intensity), direction(_direction)
{}
glm::vec3 direction;
};
DirectionalLight(Prototype prototype, Shader *shader);
~DirectionalLight() override = default;
void setDirection(glm::vec3 direction);
glm::vec3 getDirection();
private:
void update() override;
glm::vec3 m_direction;
};

View File

@@ -1,12 +1,25 @@
#pragma once
#include <glm/glm.hpp>
struct Color
{
double r{}, g{}, b{};
double a = 1.0;
bool linear = false;
[[nodiscard]] auto to_vec3() const -> glm::vec3 { return {r, g, b}; }
};
constexpr auto operator*(Color const &color, float value) -> Color
{
Color new_color = color;
new_color.r *= value;
new_color.g *= value;
new_color.b *= value;
return new_color;
}
namespace ColorConstant {
static constexpr Color WHITE{.r = 1.0, .g = 1.0, .b = 1.0};
static constexpr Color BLACK{.r = 0.0, .g = 0.0, .b = 0.0};

53
src/light.cpp Normal file
View File

@@ -0,0 +1,53 @@
#include "light.h"
#include "transform.h"
static auto light_active(float illuminance) -> bool
{
return std::abs(illuminance) >= std::numeric_limits<float>::epsilon();
}
static auto point_light_uniform_base(std::size_t n) -> std::string
{
return "u_pointLight[" + std::to_string(n) + "].";
}
void Light::update_lights(entt::registry &registry, Shader &shader)
{
shader.bind();
// Directional light
{
auto directional_lights_view =
registry.view<DirectionalLight const, GlobalTransform const>();
entt::entity entity = directional_lights_view.front();
auto [directional_light, global_transform] = directional_lights_view.get(entity);
glm::vec4 unit_vector{1.0, 0.0, 0.0, 0.0};
glm::vec3 direction = glm::vec3(global_transform.transform * unit_vector);
shader.set_uniform("u_directionalLight.isActive",
light_active(directional_light.illuminance));
shader.set_uniform("u_directionalLight.direction", direction);
shader.set_uniform("u_directionalLight.color",
(directional_light.color * directional_light.illuminance).to_vec3());
}
// Point lights
{
auto point_lights_view = registry.view<PointLight const, GlobalTransform const>();
std::size_t num = 0;
for (auto [entity, point_light, global_transform] : point_lights_view.each()) {
shader.set_uniform((point_light_uniform_base(num) + "isActive").c_str(),
light_active(point_light.intensity));
shader.set_uniform((point_light_uniform_base(num) + "position").c_str(),
global_transform.position());
shader.set_uniform((point_light_uniform_base(num) + "color").c_str(),
(point_light.color * point_light.intensity).to_vec3());
num++;
}
}
Shader::unbind();
}

29
src/light.h Normal file
View File

@@ -0,0 +1,29 @@
#pragma once
#include "color.h"
#include "shader.h"
#include <entt/entt.hpp>
#include <glm/glm.hpp>
struct PointLight
{
static constexpr glm::vec3 DEFAULT_POSITION{4.0, 1.0, 6.0};
static constexpr float DEFAULT_INTENSITY = 3.0;
Color color = ColorConstant::WHITE;
float intensity{};
};
struct DirectionalLight
{
static constexpr glm::vec3 DEFAULT_DIRECTION{-0.2, -1.0, -0.3};
static constexpr float DEFAULT_ILLUMINANCE = 5.0;
Color color = ColorConstant::WHITE;
float illuminance{};
};
namespace Light {
void update_lights(entt::registry &registry, Shader &shader);
}

View File

@@ -1,5 +1,6 @@
#include "scene.h"
#include "camera.h"
#include "light.h"
#include "mesh.h"
#include "name.h"
#include "relationship.h"
@@ -24,6 +25,25 @@ Scene::Scene(entt::registry registry) : m_registry(std::move(registry))
// Remove Material resource as it is no longer needed.
m_registry.erase<entt::resource<Material>>(entity);
}
// Spawn default lights
auto directional_light = m_registry.create();
m_registry.emplace<Name>(directional_light, "Directional Light");
m_registry.emplace<Transform>(
directional_light,
Transform{.orientation = glm::toQuat(
glm::lookAt({}, DirectionalLight::DEFAULT_DIRECTION, Camera::UP_VECTOR))});
m_registry.emplace<GlobalTransform>(directional_light, GlobalTransform{});
m_registry.emplace<DirectionalLight>(
directional_light, DirectionalLight{.illuminance = DirectionalLight::DEFAULT_ILLUMINANCE});
auto point_light = m_registry.create();
m_registry.emplace<Name>(point_light, "Point Light");
m_registry.emplace<Transform>(point_light,
Transform{.translation = PointLight::DEFAULT_POSITION});
m_registry.emplace<GlobalTransform>(point_light, GlobalTransform{});
m_registry.emplace<PointLight>(point_light,
PointLight{.intensity = PointLight::DEFAULT_INTENSITY});
}
void Scene::update(std::chrono::duration<float> delta,
@@ -32,41 +52,7 @@ void Scene::update(std::chrono::duration<float> delta,
float aspect_ratio,
bool cursor_catched)
{
{
// Update GlobalTransform components
// TODO: Only do this when the Transform changed.
auto root_transform_view =
m_registry.view<Transform const, GlobalTransform>(entt::exclude<Parent>);
auto transform_view = m_registry.view<Transform const, GlobalTransform, Parent const>();
for (auto [entity, transform, global_transform] : root_transform_view.each()) {
global_transform = transform;
auto parent_global_transform = global_transform;
if (auto *children = m_registry.try_get<Children>(entity)) {
for (auto child : children->children) {
std::function<void(entt::entity entity,
GlobalTransform parent_global_transform)>
transform_propagate = [this, &transform_propagate, &transform_view](
entt::entity entity,
GlobalTransform parent_global_transform) {
auto [transform, global_transform, parent] = transform_view.get(entity);
global_transform.transform = parent_global_transform.transform *
GlobalTransform(transform).transform;
if (auto *children = m_registry.try_get<Children>(entity)) {
for (auto child : children->children) {
transform_propagate(child, global_transform);
}
}
};
transform_propagate(child, parent_global_transform);
}
}
}
}
GlobalTransform::update(m_registry);
Camera::aspect_ratio_update(m_registry, aspect_ratio);
Camera::keyboard_movement(m_registry, key_input, delta);
if (cursor_catched) {

37
src/transform.cpp Normal file
View File

@@ -0,0 +1,37 @@
#include "transform.h"
#include "relationship.h"
void GlobalTransform::update(entt::registry &registry)
{
// Update GlobalTransform components
// TODO: Only do this when the Transform changed.
auto root_transform_view =
registry.view<Transform const, GlobalTransform>(entt::exclude<Parent>);
auto transform_view = registry.view<Transform const, GlobalTransform, Parent const>();
for (auto [entity, transform, global_transform] : root_transform_view.each()) {
global_transform = transform;
auto parent_global_transform = global_transform;
if (auto *children = registry.try_get<Children>(entity)) {
for (auto child : children->children) {
std::function<void(entt::entity entity, GlobalTransform parent_global_transform)>
transform_propagate =
[&registry, &transform_propagate, &transform_view](
entt::entity entity, GlobalTransform parent_global_transform) {
auto [transform, global_transform, parent] = transform_view.get(entity);
global_transform.transform = parent_global_transform.transform *
GlobalTransform(transform).transform;
if (auto *children = registry.try_get<Children>(entity)) {
for (auto child : children->children) {
transform_propagate(child, global_transform);
}
}
};
transform_propagate(child, parent_global_transform);
}
}
}
}

View File

@@ -1,5 +1,6 @@
#pragma once
#include <entt/entt.hpp>
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
@@ -33,4 +34,6 @@ struct GlobalTransform
glm::mat4 transform{};
[[nodiscard]] auto position() const -> glm::vec3 { return transform[3]; };
static void update(entt::registry &registry);
};