#include #include #include #ifdef WIN32 #include #endif #include #define GLM_ENABLE_EXPERIMENTAL #include #include "renderer/renderer.h" #include "window/window.h" #include "IO/file_manager.h" #include "components/transform.h" #include "components/camera.h" #include "components/light.h" #include "components/mesh.h" Renderer::Renderer() { m_proj = glm::perspective( static_cast(M_PI_2), static_cast(Window::GetWidth()) / static_cast(Window::GetHeight()), 0.01f, 100.0f ); m_shader.init( FileManager::read("./src/shaders/simple.vs"), FileManager::read("./src/shaders/pbr.fs") ); m_depthShader.init( FileManager::read("./src/shaders/depth.vs"), FileManager::read("./src/shaders/depth.fs") ); m_model = glm::mat4(1.f); m_shader.use(); m_shader.setMat4("u_projection", m_proj); } void Renderer::OnWindowResized(int w, int h) { m_proj = glm::perspective( static_cast(M_PI_2), static_cast(w) / static_cast(h), 0.01f, 100.0f ); m_shader.setMat4("u_projection", m_proj); m_depthShader.setMat4("u_projection", m_proj); } void Renderer::ApplyLights(entt::registry& registry, Shader &shader) { auto lights = registry.view(); // TODO: Pass Lights Data to depth shader as well shader.setInt("lightsCount", static_cast(lights.size())); size_t lightIndex = 0; for (auto entity : lights) { auto &l = registry.get(entity); auto &transf = registry.get(entity); shader.setInt("lights[" + std::to_string(lightIndex) + "].type", static_cast(l.type)); shader.setVec3("lights[" + std::to_string(lightIndex) + "].position", transf.position); shader.setVec3("lights[" + std::to_string(lightIndex) + "].color", l.color); shader.setFloat("lights[" + std::to_string(lightIndex) + "].intensity", l.intensity); shader.setMat4("lights[" + std::to_string(lightIndex) + "].lightSpace", l.lightSpace); shader.setInt("lights[" + std::to_string(lightIndex) + "].shadowMap", 10 + lightIndex); glActiveTexture(GL_TEXTURE10 + lightIndex); glBindTexture(GL_TEXTURE_2D, l.shadowMap); ++lightIndex; } } void Renderer::UpdateView(entt::registry& registry, Shader &shader) { auto cam = registry.view().back(); auto camTransform = registry.get(cam); m_view = glm::lookAt( camTransform.position, camTransform.position + camTransform.rotation, glm::vec3(0.f, 1.f, 0.f) ); shader.setMat4("u_view", m_view); shader.setMat4("u_projection", m_proj); shader.setVec3("viewPos", camTransform.position); } void Renderer::RenderScene(entt::registry& registry, Shader &shader) { auto view = registry.view(); for (auto [entity, transf, mesh] : view.each()) { if (mesh.object == nullptr) { std::cerr << "WARN: Entity doesn't have a mesh to render" << std::endl; return; } if (registry.all_of(entity)) { auto &l = registry.get(entity); shader.setBool("isLight", true); shader.setVec3("currentLightColor", l.color); } else { shader.setBool("isLight", false); shader.setVec3("currentLightColor", glm::vec3(0.f)); } glm::mat4 rotation = glm::yawPitchRoll(transf.rotation.y, transf.rotation.x, transf.rotation.z); m_model = glm::translate(glm::mat4(1.f), transf.position) * rotation; shader.setMat4("u_model", m_model); mesh.object->Render(shader); } } void Renderer::GenerateShadowMaps(entt::registry& registry) { const unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024; m_depthShader.use(); auto lights = registry.view(); for (auto [lEntt, l] : lights.each()) { // TODO: support other light types when ready if (l.type != light::LightType::DIRECTIONAL) return; 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(entt::registry& registry) { const unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024; m_depthShader.use(); auto lights = registry.view(); for (auto [lEntt, l, t] : lights.each()) { // TODO: support other light types when ready if (l.type != light::LightType::DIRECTIONAL) return; glClearColor(0x18/255.0f, 0x18/255.0f, 0x18/255.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); float near_plane = 0.1f, far_plane = 50.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 lightProjection = glm::ortho(-6.0f, 6.0f, -6.0f, 6.0f, 1.0f, 20.0f); glm::mat4 lightSpaceMatrix = lightProjection * lightView; m_depthShader.setMat4("u_lightSpace", lightSpaceMatrix); l.lightSpace = lightSpaceMatrix; glCullFace(GL_FRONT); glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT); glBindFramebuffer(GL_FRAMEBUFFER, l.fbo); glClear(GL_DEPTH_BUFFER_BIT); RenderScene(registry, m_depthShader); glBindFramebuffer(GL_FRAMEBUFFER, 0); glCullFace(GL_BACK); } // actual rendering glViewport(0, 0, Window::GetWidth(), Window::GetHeight()); glClearColor(0x18/255.0f, 0x18/255.0f, 0x18/255.0f, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); m_shader.use(); ApplyLights(registry, m_shader); UpdateView(registry, m_shader); RenderScene(registry, m_shader); }