feat: light improvements

This commit is contained in:
2025-10-18 17:34:15 +02:00
parent 8b8ad35d01
commit fa9076b834
5 changed files with 57 additions and 45 deletions

View File

@ -23,6 +23,7 @@ private:
unsigned int shadowMap; unsigned int shadowMap;
unsigned int fbo; unsigned int fbo;
glm::mat4 lightSpace; glm::mat4 lightSpace;
int shadowRes{1024};
}; };
#endif // COMPONENTS_LIGHT_H_ #endif // COMPONENTS_LIGHT_H_

View File

@ -6,6 +6,7 @@
#include "engine/renderer/shader.h" #include "engine/renderer/shader.h"
#include "engine/export.h" #include "engine/export.h"
#include "engine/components/light.h"
// TODO: make static or singleton // TODO: make static or singleton
class ENGINE_API Renderer { class ENGINE_API Renderer {
@ -21,6 +22,7 @@ private:
void ApplyLights(Shader &shader); void ApplyLights(Shader &shader);
void UpdateView(); void UpdateView();
void RenderScene(Shader &shader); void RenderScene(Shader &shader);
void EnsureShadowResources(light& l);
private: private:
Shader m_shader; Shader m_shader;
Shader m_depthShader; Shader m_depthShader;

View File

@ -86,6 +86,32 @@ void Renderer::ApplyLights(Shader &shader) {
} }
} }
void Renderer::EnsureShadowResources(light& l) {
if (l.fbo != 0 && l.shadowMap != 0) return; // already created
glGenFramebuffers(1, &l.fbo);
glGenTextures(1, &l.shadowMap);
glBindTexture(GL_TEXTURE_2D, l.shadowMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24,
l.shadowRes, l.shadowRes, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
// NEAREST is fine to start; switch to LINEAR + PCF later if you want
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
const float borderColor[] = {1.f, 1.f, 1.f, 1.f};
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glBindFramebuffer(GL_FRAMEBUFFER, l.fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, l.shadowMap, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void Renderer::UpdateView() { void Renderer::UpdateView() {
auto cam = m_registry.view<transform, camera>().back(); auto cam = m_registry.view<transform, camera>().back();
auto camTransform = m_registry.get<transform>(cam); auto camTransform = m_registry.get<transform>(cam);
@ -165,81 +191,64 @@ void Renderer::RenderScene(Shader &shader) {
} }
void Renderer::GenerateShadowMaps() { void Renderer::GenerateShadowMaps() {
const unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;
m_depthShader.use(); m_depthShader.use();
auto lights = m_registry.view<light>(); auto lights = m_registry.view<light>();
for (auto [lEntt, l] : lights.each()) { for (auto [_, l] : lights.each()) {
// TODO: support other light types when ready // TODO: support other light types when ready
if (l.type != light::LightType::DIRECTIONAL) return; if (l.type != light::LightType::DIRECTIONAL) continue;
EnsureShadowResources(l);
glGenFramebuffers(1, &l.fbo);
glGenTextures(1, &l.shadowMap);
glBindTexture(GL_TEXTURE_2D, l.shadowMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24,
SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
float borderColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glBindFramebuffer(GL_FRAMEBUFFER, l.fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, l.shadowMap, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
} }
void Renderer::Render() { void Renderer::Render() {
const unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;
m_depthShader.use(); m_depthShader.use();
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
auto lights = m_registry.view<light, transform>(); auto lights = m_registry.view<light, transform>();
for (auto [lEntt, l, t] : lights.each()) { for (auto [_, l, t] : lights.each()) {
// TODO: support other light types when ready // TODO: support other light types when ready
if (l.type != light::LightType::DIRECTIONAL) return; if (l.type != light::LightType::DIRECTIONAL) continue;
glClearColor(0x18/255.0f, 0x18/255.0f, 0x18/255.0f, 1.0f); EnsureShadowResources(l);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float near_plane = 0.1f, far_plane = 50.0f; float near_plane = 0.1f, far_plane = 20.0f;
glm::vec3 target = glm::vec3(0.0f, 0.5f, 0.0f); glm::vec3 target = glm::vec3(0.0f, 0.5f, 0.0f);
glm::mat4 lightView = glm::lookAt(t.position, target, glm::vec3(0.0f, 1.0f, 0.0f)); glm::mat4 lightView = glm::lookAt(t.position, target, glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 lightProjection = glm::ortho(-6.0f, 6.0f, -6.0f, 6.0f, 1.0f, 20.0f); glm::mat4 lightProjection = glm::ortho(-6.0f, 6.0f, -6.0f, 6.0f, near_plane, far_plane);
glm::mat4 lightSpaceMatrix = lightProjection * lightView; glm::mat4 lightSpaceMatrix = lightProjection * lightView;
m_depthShader.setMat4("u_lightSpace", lightSpaceMatrix); m_depthShader.setMat4("u_lightSpace", lightSpaceMatrix);
l.lightSpace = lightSpaceMatrix; l.lightSpace = lightSpaceMatrix;
glCullFace(GL_FRONT); glViewport(0, 0, l.shadowRes, l.shadowRes);
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glBindFramebuffer(GL_FRAMEBUFFER, l.fbo); glBindFramebuffer(GL_FRAMEBUFFER, l.fbo);
glClear(GL_DEPTH_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT);
RenderScene(m_depthShader);
// Optional: further stabilize acne
// glEnable(GL_POLYGON_OFFSET_FILL);
// glPolygonOffset(2.0f, 4.0f);
RenderScene(m_depthShader);
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
glCullFace(GL_BACK);
} }
// actual rendering glCullFace(GL_BACK);
// ---- MAIN PASS -----
glViewport(0, 0, Window::GetWidth(), Window::GetHeight()); glViewport(0, 0, Window::GetWidth(), Window::GetHeight());
glClearColor(0x18/255.0f, 0x18/255.0f, 0x18/255.0f, 1); glClearColor(0x18/255.0f, 0x18/255.0f, 0x18/255.0f, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_shader.use(); m_shader.use();
ApplyLights(m_shader); ApplyLights(m_shader);
UpdateView(); UpdateView();
RenderScene(m_shader); RenderScene(m_shader);
} }

View File

@ -196,10 +196,9 @@ void Object::LoadMaterials(const std::filesystem::path& filename) {
while (len > 0 && (texPath[len - 1] == ' ' || texPath[len - 1] == '\t')) while (len > 0 && (texPath[len - 1] == ' ' || texPath[len - 1] == '\t'))
texPath[--len] = '\0'; texPath[--len] = '\0';
std::filesystem::path fullPath = filename; std::filesystem::path texturePath = filename.parent_path() / texPath;
std::filesystem::path texturePath = fullPath.parent_path() / texPath;
currentMaterial->SetDiffuseTexture(Texture::LoadFile(texturePath)); currentMaterial->SetDiffuseTexture(Texture::LoadFile(texturePath.string()));
} }
break; break;
} }

View File

@ -37,8 +37,9 @@ public:
Object* targetObj = Object::LoadFile("./assets/wizard/wizard.obj"); Object* targetObj = Object::LoadFile("./assets/wizard/wizard.obj");
const auto targetEntity = m_registry.create(); const auto targetEntity = m_registry.create();
m_registry.emplace<transform>(targetEntity, glm::vec3(0.f, 0.0f, 0.f)); m_registry.emplace<transform>(targetEntity, glm::vec3(0.f, 0.0f, 0.f), glm::vec3(0.f, 0.0f, 0.f), glm::vec3(0.5f, 0.5f, 0.5f));
m_registry.emplace<mesh>(targetEntity, std::shared_ptr<Object>(targetObj)); m_registry.emplace<mesh>(targetEntity, std::shared_ptr<Object>(targetObj));
m_registry.emplace<rotate>(targetEntity);
Object* grass = Object::LoadFile("./assets/common/cube/cube.obj"); Object* grass = Object::LoadFile("./assets/common/cube/cube.obj");
const auto cubeEntity = m_registry.create(); const auto cubeEntity = m_registry.create();