Add light components and systems
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
105
src/Light.cpp
105
src/Light.cpp
@@ -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;
|
||||
}
|
||||
98
src/Light.h
98
src/Light.h
@@ -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;
|
||||
};
|
||||
13
src/color.h
13
src/color.h
@@ -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
53
src/light.cpp
Normal 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 ®istry, 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
29
src/light.h
Normal 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 ®istry, Shader &shader);
|
||||
}
|
||||
@@ -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
37
src/transform.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "transform.h"
|
||||
#include "relationship.h"
|
||||
|
||||
void GlobalTransform::update(entt::registry ®istry)
|
||||
{
|
||||
// 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 =
|
||||
[®istry, &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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 ®istry);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user