diff --git a/assets/grass_block/grass_block.mtl b/assets/grass_block/grass_block.mtl index 1fe4da4..bcb0ccf 100644 --- a/assets/grass_block/grass_block.mtl +++ b/assets/grass_block/grass_block.mtl @@ -1,4 +1,4 @@ -# Blender 4.3.2 MTL File: 'untitled.blend' +# Blender 4.3.2 MTL File: 'None' # www.blender.org newmtl Grass_Bottom diff --git a/assets/grass_block/grass_block.obj b/assets/grass_block/grass_block.obj index 24d4077..1e90a81 100644 --- a/assets/grass_block/grass_block.obj +++ b/assets/grass_block/grass_block.obj @@ -2,25 +2,25 @@ # www.blender.org mtllib grass_block.mtl o Cube -v -1.000000 -1.000000 1.000000 -v -1.000000 1.000000 1.000000 -v -1.000000 -1.000000 -1.000000 -v -1.000000 1.000000 -1.000000 -v 1.000000 -1.000000 1.000000 -v 1.000000 1.000000 1.000000 -v 1.000000 -1.000000 -1.000000 -v 1.000000 1.000000 -1.000000 +v -0.389000 -0.389000 0.389000 +v -0.389000 0.389000 0.389000 +v -0.389000 -0.389000 -0.389000 +v -0.389000 0.389000 -0.389000 +v 0.389000 -0.389000 0.389000 +v 0.389000 0.389000 0.389000 +v 0.389000 -0.389000 -0.389000 +v 0.389000 0.389000 -0.389000 vn -1.0000 -0.0000 -0.0000 vn -0.0000 -0.0000 -1.0000 vn 1.0000 -0.0000 -0.0000 vn -0.0000 -0.0000 1.0000 -vn -0.0000 -1.0000 -0.0000 vn -0.0000 1.0000 -0.0000 +vn -0.0000 -1.0000 -0.0000 vt 0.000000 1.000000 vt 1.000000 0.000000 vt 0.000000 0.000000 vt 1.000000 1.000000 -s 0 +s 1 usemtl Grass_Side f 2/1/1 3/2/1 1/3/1 f 4/1/2 7/2/2 3/3/2 @@ -31,8 +31,8 @@ f 4/1/2 8/4/2 7/2/2 f 8/4/3 6/1/3 5/3/3 f 6/4/4 2/1/4 1/3/4 usemtl Grass_Top -f 4/1/6 6/2/6 8/4/6 -f 4/1/6 2/3/6 6/2/6 +f 4/1/5 6/2/5 8/4/5 +f 4/1/5 2/3/5 6/2/5 usemtl Grass_Bottom -f 7/4/5 1/3/5 3/1/5 -f 7/4/5 5/2/5 1/3/5 +f 7/4/6 1/3/6 3/1/6 +f 7/4/6 5/2/6 1/3/6 diff --git a/include/components/light.h b/include/components/light.h index 724de44..493dc77 100644 --- a/include/components/light.h +++ b/include/components/light.h @@ -2,10 +2,25 @@ #define COMPONENTS_LIGHT_H_ #include +#include "renderer/renderer.h" struct light { + friend class Renderer; +public: + enum LightType { + DIRECTIONAL = 0, + }; + LightType type; glm::vec3 color; float intensity; + + light(LightType t, const glm::vec3& c, float i) + : type(t), color(c), intensity(i), + shadowMap(0), fbo(0), lightSpace(1.0f) {} +private: + unsigned int shadowMap; + unsigned int fbo; + glm::mat4 lightSpace; }; #endif // COMPONENTS_LIGHT_H_ \ No newline at end of file diff --git a/include/renderer/renderer.h b/include/renderer/renderer.h index b540966..3f055c8 100644 --- a/include/renderer/renderer.h +++ b/include/renderer/renderer.h @@ -23,8 +23,8 @@ private: Shader m_shader; Shader m_depthShader; - unsigned int m_depth_fbo; - unsigned int m_depthMap; + // unsigned int m_depth_fbo; + // unsigned int m_depthMap; glm::mat4 m_model; glm::mat4 m_proj; diff --git a/src/main.cpp b/src/main.cpp index 472e33e..f773bf5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,15 +28,10 @@ class Game : public IApplication { public: Game() { Object* lightObj = Object::LoadFile("./assets/sphere.obj"); - // const auto lightEntity = m_registry.create(); - // m_registry.emplace(lightEntity, glm::vec3(-5.f, 5.f, 5.f), glm::vec3(0.f)); - // m_registry.emplace(lightEntity, glm::vec3(1.f, 0.f, 0.f), 1.f); - // m_registry.emplace(lightEntity, std::unique_ptr(lightObj)); - - const auto lEntt2 = m_registry.create(); - m_registry.emplace(lEntt2, glm::vec3(5.f, 5.f, 5.f), glm::vec3(0.f)); - m_registry.emplace(lEntt2, glm::vec3(1.f, 1.f, 1.f), 1.5f); - m_registry.emplace(lEntt2, std::unique_ptr(lightObj)); + const auto lght = m_registry.create(); + m_registry.emplace(lght, glm::vec3(5.f, 5.f, 5.f), glm::vec3(0.f)); + m_registry.emplace(lght, light::LightType::DIRECTIONAL, glm::vec3(1.f, 1.f, 1.f), 1.5f); + m_registry.emplace(lght, std::unique_ptr(lightObj)); const auto cameraEntity = m_registry.create(); m_registry.emplace(cameraEntity, glm::vec3(0.f, 2.f, 2.f)); @@ -47,7 +42,7 @@ public: m_registry.emplace(targetEntity, glm::vec3(0.f, 0.0f, 0.f)); m_registry.emplace(targetEntity, std::unique_ptr(targetObj)); - Object* cubeObj = Object::LoadFile("./assets/cube.obj"); + Object* cubeObj = Object::LoadFile("./assets/grass_block/grass_block.obj"); const auto cubeEntity = m_registry.create(); m_registry.emplace(cubeEntity, glm::vec3(-1.5f, 0.4f, 0.f)); m_registry.emplace(cubeEntity, std::unique_ptr(cubeObj)); diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index a904ad6..c5dda4f 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -59,12 +59,17 @@ void Renderer::ApplyLights(entt::registry& registry, Shader &shader) { shader.setInt("lightsCount", static_cast(lights.size())); size_t lightIndex = 0; for (auto entity : lights) { - auto &comp = registry.get(entity); + 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", comp.color); - shader.setFloat("lights[" + std::to_string(lightIndex) + "].intensity", comp.intensity); + 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; } @@ -115,81 +120,78 @@ void Renderer::GenerateShadowMaps(entt::registry& registry) { const unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024; m_depthShader.use(); - ApplyLights(registry, m_depthShader); - UpdateView(registry, m_depthShader); - - glGenFramebuffers(1, &m_depth_fbo); - glGenTextures(1, &m_depthMap); - glBindTexture(GL_TEXTURE_2D, m_depthMap); - 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); + auto lights = registry.view(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + for (auto [lEntt, l] : lights.each()) { + // TODO: support other light types when ready + if (l.type != light::LightType::DIRECTIONAL) return; - float borderColor[] = {1.0f, 1.0f, 1.0f, 1.0f}; - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); + 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); - glBindFramebuffer(GL_FRAMEBUFFER, m_depth_fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthMap, 0); - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + 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; - glClearColor(0.1f, 0.1f, 0.1f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - auto shadowLight = registry.view().back(); - auto &comp = registry.get(shadowLight); - - float near_plane = 0.1f, far_plane = 50.0f; - glm::vec3 lightPos = comp.position; - glm::vec3 target = glm::vec3(0.0f, 0.5f, 0.0f); - glm::mat4 lightView = glm::lookAt(lightPos, 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.use(); - m_depthShader.setMat4("u_lightSpace", lightSpaceMatrix); - // glEnable(GL_CULL_FACE); - // glCullFace(GL_FRONT); // only for the depth pass - // glEnable(GL_POLYGON_OFFSET_FILL); - // glPolygonOffset(2.0f, 4.0f); + auto lights = registry.view(); - glCullFace(GL_FRONT); - glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT); - glBindFramebuffer(GL_FRAMEBUFFER, m_depth_fbo); - glClear(GL_DEPTH_BUFFER_BIT); - RenderScene(registry, m_depthShader); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glCullFace(GL_BACK); + for (auto [lEntt, l, t] : lights.each()) { + // TODO: support other light types when ready + if (l.type != light::LightType::DIRECTIONAL) return; - // glEnable(GL_CULL_FACE); - // glCullFace(GL_BACK); // only for the depth pass - // glDisable(GL_POLYGON_OFFSET_FILL); - // glPolygonOffset(0.f, 1.f); + glClearColor(0.1f, 0.1f, 0.1f, 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(); - m_shader.setInt("shadowMap", 31); ApplyLights(registry, m_shader); UpdateView(registry, m_shader); - m_shader.setMat4("u_lightSpace", lightSpaceMatrix); - - glActiveTexture(GL_TEXTURE31); - glBindTexture(GL_TEXTURE_2D, m_depthMap); RenderScene(registry, m_shader); } \ No newline at end of file diff --git a/src/shaders/pbr.fs b/src/shaders/pbr.fs index 02d2a25..ff13cb3 100644 --- a/src/shaders/pbr.fs +++ b/src/shaders/pbr.fs @@ -4,15 +4,17 @@ out vec4 FragColor; in vec3 vertexPos; in vec3 vertexNormal; in vec2 TexCoords; -in vec4 fragPosLightSpace; uniform vec3 viewPos; // Lights struct Light { + int type; vec3 position; vec3 color; float intensity; + mat4 lightSpace; + sampler2D shadowMap; }; #define MAX_LIGHTS 10 uniform int lightsCount; @@ -36,50 +38,16 @@ uniform bool useMetallicMap; uniform bool useRoughnessMap; uniform bool useAoMap; -// Shadows -uniform sampler2D shadowMap; - uniform float opacity; // uniform int currentLight; #define PI 3.14159265359 #define LIGHT_COLOR vec3(1.0, 1.0, 1.0) -// float ShadowCalculation(vec4 fragPosLightSpace, vec3 N, vec3 L) -// { -// // transform to [0,1] -// vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; -// projCoords = projCoords * 0.5 + 0.5; - -// // if outside light's orthographic frustum => not in shadow -// if (projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 || projCoords.y < 0.0 || projCoords.y > 1.0) -// return 0.0; - -// // get depth from shadow map -// float closestDepth = texture(shadowMap, projCoords.xy).r; -// float currentDepth = projCoords.z; - -// // bias to prevent self-shadowing (depend on slope) -// float bias = max(0.001 * (1.0 - dot(N, L)), 0.0005); - -// // PCF (3x3) -// float shadow = 0.0; -// vec2 texelSize = 1.0 / textureSize(shadowMap, 0); -// for(int x = -1; x <= 1; ++x) -// { -// for(int y = -1; y <= 1; ++y) -// { -// float pcfDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelSize).r; -// shadow += (currentDepth - bias > pcfDepth ? 1.0 : 0.0); -// } -// } -// shadow /= 9.0; - -// return shadow; -// } - -float ShadowCalculation(vec4 fragPosLightSpace, vec3 N, vec3 L) +float ShadowCalculation(sampler2D shadowMap, mat4 lightSpace, vec3 N, vec3 L) { + vec4 fragPosLightSpace = lightSpace * vec4(vertexPos, 1.0); + // transform to [0,1] vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; projCoords = projCoords * 0.5 + 0.5; @@ -184,7 +152,7 @@ void main() float G = GeometrySmith(N, V, L, rough); vec3 F = fresnelSchlick(max(dot(H,V),0.0), F0); - shadow = ShadowCalculation(fragPosLightSpace, N, L); + shadow = ShadowCalculation(lights[i].shadowMap, lights[i].lightSpace, N, L); vec3 numerator = NDF * G * F; float denominator = 4.0 * max(dot(N,V),0.0) * max(dot(N,L),0.0) + 0.001; diff --git a/src/shaders/simple.fs b/src/shaders/simple.fs deleted file mode 100644 index 3354918..0000000 --- a/src/shaders/simple.fs +++ /dev/null @@ -1,81 +0,0 @@ -#version 410 core - -// Output color of the fragment (pixel) -out vec4 FragColor; // RGBA color for the fragment, where A is the alpha (opacity) - -in vec3 vertexPos; -in vec3 vertexNormal; -in vec2 TexCoords; - -uniform vec3 viewPos; - -// Lights -struct Light { - vec3 position; - vec3 color; - float intensity; -}; - -#define MAX_LIGHTS 10 -uniform int lightsCount; -uniform Light lights[MAX_LIGHTS]; - -// From Object Renderer - -uniform vec3 ambientColor; -uniform vec3 diffuseColor; -uniform vec3 specularColor; - -uniform float ambientStrength; - -uniform float specularStrength; -uniform float shininess; -uniform bool useSpecular; - -uniform float opacity; - -uniform sampler2D diffuseTex; -uniform bool useTexture; - -uniform bool isLight; - -void main() -{ - // Lighting vectors - vec3 norm = normalize(vertexNormal); - vec3 viewDir = normalize(viewPos - vertexPos); - // vec3 viewDir = normalize(-vertexPos); - - vec3 ambient = ambientStrength * ambientColor; - vec3 texColor = (useTexture) - ? texture(diffuseTex, TexCoords).rgb - : diffuseColor; - - vec3 result = ambient; - - for (int i = 0; i < lightsCount; i++) { - vec3 lightDir = normalize(lights[i].position - vertexPos); - vec3 halfDir = normalize(lightDir + viewDir); - - // Blinn Phong - float diff = max(dot(norm, lightDir), 0.0); - vec3 diffuse = diff * diffuseColor * lights[i].color * lights[i].intensity; - - float spec = pow(max(dot(norm, halfDir), 0.0), clamp(shininess, 2.0, 256.0)); - vec3 specular = (useSpecular) ? - specularStrength * spec * specularColor * lights[i].color * lights[i].intensity - : vec3(0.0); - - result += (diffuse + specular); - } - - result *= texColor; - - if (isLight) { - vec3 emissive = vec3(1.0, 1.0, 1.0) * 10.0; // big intensity - FragColor = vec4(emissive, 1.0); - return; - } - - FragColor = vec4(result, opacity); -} \ No newline at end of file diff --git a/src/shaders/simple.vs b/src/shaders/simple.vs index 6b5bd7a..36680ec 100644 --- a/src/shaders/simple.vs +++ b/src/shaders/simple.vs @@ -15,7 +15,6 @@ out vec4 fragPosLightSpace; uniform mat4 u_model; // Model matrix: transforms from local space to world space uniform mat4 u_view; // View matrix: transforms from world space to camera space (view space) uniform mat4 u_projection; // Projection matrix: transforms from camera space to clip space -uniform mat4 u_lightSpace; void main() { @@ -27,7 +26,7 @@ void main() TexCoords = texCoord; - fragPosLightSpace = u_lightSpace * vec4(vertexPos, 1.0); + // fragPosLightSpace = u_lightSpace * vec4(vertexPos, 1.0); gl_Position = u_projection * u_view * vec4(vertexPos, 1.0); } \ No newline at end of file