From 20e5aaa4b094a99db642eb0f606904970f1117b0 Mon Sep 17 00:00:00 2001 From: Andrey Doroschenko Date: Wed, 14 Sep 2022 21:18:29 +0300 Subject: [PATCH] Implemented directional, point and spot lighting sources --- include/core/ecs/component.hpp | 5 +-- include/core/graphics/lighting/base.hpp | 9 +++++ include/meta.hpp | 2 +- resources/shaders/default.frag | 44 +++++++++++++++++++++---- resources/shaders/material.frag | 44 +++++++++++++++++++++---- src/core/render/api.cpp | 21 +++++++++--- src/editor.cpp | 19 ++++++----- src/main.cpp | 4 +-- 8 files changed, 118 insertions(+), 30 deletions(-) diff --git a/include/core/ecs/component.hpp b/include/core/ecs/component.hpp index 7ea9d7b..74357ed 100644 --- a/include/core/ecs/component.hpp +++ b/include/core/ecs/component.hpp @@ -34,7 +34,7 @@ namespace Engine { const Type type = Type::TRANSFORM; glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f); - glm::vec3 rotation = glm::vec3(1.0f, 1.0f, 1.0f); + glm::vec3 rotation = glm::vec3(0.0f, 1.0f, 1.0f); glm::vec3 scale = glm::vec3(1.0f, 1.0f, 1.0f); }; @@ -87,7 +87,8 @@ namespace Engine { float quadratic = 0.44f; // Only for spot lighting - float angle = glm::cos(glm::radians(0.0f)); + float cutOff = 12.5f; + float outerCutOff = 17.5f; Light(Graphics::Lighting::Type type) : lightType(type) {}; }; diff --git a/include/core/graphics/lighting/base.hpp b/include/core/graphics/lighting/base.hpp index 34f5743..8895057 100644 --- a/include/core/graphics/lighting/base.hpp +++ b/include/core/graphics/lighting/base.hpp @@ -33,6 +33,15 @@ namespace Engine { light = std::make_unique(Type::POINT); }; }; + + + class SpotLight : public Light { + public: + SpotLight() : Light() { + name = "Spot light"; + light = std::make_unique(Type::SPOT); + }; + }; } } } diff --git a/include/meta.hpp b/include/meta.hpp index 334a753..787fc23 100644 --- a/include/meta.hpp +++ b/include/meta.hpp @@ -1,7 +1,7 @@ #ifndef __META_HPP__ #define __META_HPP__ -#define ENGINE_VERSION "0.1.1" +#define ENGINE_VERSION "0.1.2" #define GLSL_VERSION "#version 420" #endif diff --git a/resources/shaders/default.frag b/resources/shaders/default.frag index 69d7d65..d44f200 100644 --- a/resources/shaders/default.frag +++ b/resources/shaders/default.frag @@ -9,6 +9,10 @@ struct Light { float linear; float quadratic; + // Only for spot lighting + float cutOff; + float outerCutOff; + // Type of lighting int isDirection; int isPoint; @@ -31,9 +35,9 @@ uniform Light light; uniform vec3 viewPosition; -vec3 calculateDirectionLight(Light light, vec3 normal, vec3 viewDir); -vec3 calculatePointLight(Light light, vec3 normal, vec3 fragPos, vec3 viewDir); -vec3 calculateSpotLight(); +vec3 calculateDirectionLight(Light, vec3, vec3); +vec3 calculatePointLight(Light, vec3, vec3, vec3); +vec3 calculateSpotLight(Light, vec3, vec3, vec3); void main() { @@ -49,7 +53,7 @@ void main() { result = calculatePointLight(light, norm, FragPos, viewDir); } else if (light.isSpot == 1) { - result = calculateSpotLight(); + result = calculateSpotLight(light, norm, FragPos, viewDir); } color = vec4(result * defaultColor * light.intensity, 1.0f); @@ -99,6 +103,34 @@ vec3 calculatePointLight(Light light, vec3 normal, vec3 fragPos, vec3 viewDir) { } -vec3 calculateSpotLight() { - return vec3(0.0f); +vec3 calculateSpotLight(Light light, vec3 normal, vec3 fragPos, vec3 viewDir) { + // Ambient + vec3 ambient = light.ambient * light.color; + + // Diffuse + vec3 lightDir = normalize(light.position - fragPos); + float diff = max(dot(normal, lightDir), 0.0); + vec3 diffuse = light.diffuse * (diff * light.color); + + // Specular + vec3 reflectDir = reflect(-lightDir, normal); + float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); + vec3 specular = light.specular * (spec * light.color); + + // Spotlight - soft edges + float theta = dot(lightDir, normalize(-light.direction)); + float epsilon = (light.cutOff - light.outerCutOff); + float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0); + diffuse *= intensity; + specular *= intensity; + + // TODO: Why it's not work?? + // Attenuation + // float distance = length(light.position - FragPos); + // float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); + // ambient *= attenuation; + // diffuse *= attenuation; + // specular *= attenuation; + + return ambient + diffuse + specular; } diff --git a/resources/shaders/material.frag b/resources/shaders/material.frag index 7358881..7236193 100644 --- a/resources/shaders/material.frag +++ b/resources/shaders/material.frag @@ -9,6 +9,10 @@ struct Light { float linear; float quadratic; + // Only for spot lighting + float cutOff; + float outerCutOff; + // TODO: Investigate to change on boolean // Type of lighting int isDirection; @@ -41,9 +45,9 @@ uniform vec3 viewPosition; out vec4 color; -vec3 calculateDirectionLight(Light light, Material material, vec3 normal, vec3 viewDir); -vec3 calculatePointLight(Light light, Material material, vec3 normal, vec3 fragPos, vec3 viewDir); -vec3 calculateSpotLight(); +vec3 calculateDirectionLight(Light, Material, vec3, vec3); +vec3 calculatePointLight(Light, Material, vec3, vec3, vec3); +vec3 calculateSpotLight(Light, Material, vec3, vec3, vec3); void main() { @@ -58,7 +62,7 @@ void main() { result = calculatePointLight(light, material, norm, FragPos, viewDir); } else if (light.isSpot == 1) { - result = calculateSpotLight(); + result = calculateSpotLight(light, material, norm, FragPos, viewDir); } color = vec4((result * material.color) * light.intensity, 1.0f); @@ -109,6 +113,34 @@ vec3 calculatePointLight(Light light, Material material, vec3 normal, vec3 fragP } -vec3 calculateSpotLight() { - return vec3(0.0f); +vec3 calculateSpotLight(Light light, Material material, vec3 normal, vec3 fragPos, vec3 viewDir) { + // Ambient + vec3 ambient = light.ambient * material.ambient; + + // Diffuse + vec3 lightDir = normalize(light.position - fragPos); + float diff = max(dot(normal, lightDir), 0.0); + vec3 diffuse = light.diffuse * (diff * material.diffuse); + + // Specular + vec3 reflectDir = reflect(-lightDir, normal); + float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); + vec3 specular = light.specular * (spec * material.specular); + + // Spotlight - soft edges + float theta = dot(lightDir, normalize(-light.direction)); + float epsilon = (light.cutOff - light.outerCutOff); + float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0); + diffuse *= intensity; + specular *= intensity; + + // TODO: Why it's not work?? + // Attenuation + // float distance = length(light.position - FragPos); + // float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); + // ambient *= attenuation; + // diffuse *= attenuation; + // specular *= attenuation; + + return ambient + diffuse + specular; } diff --git a/src/core/render/api.cpp b/src/core/render/api.cpp index 470c29a..228e7d7 100644 --- a/src/core/render/api.cpp +++ b/src/core/render/api.cpp @@ -159,33 +159,44 @@ void Render::RenderObject(Object *object, glm::mat4 projection, glm::mat4 view, shader->UniformFloat("light.quadratic", lighting->light->quadratic); shader->UniformInt("light.isPoint", 1); } + else if (lighting->light->lightType == Graphics::Lighting::Type::SPOT) { + shader->UniformInt("light.isSpot", 1); + shader->UniformPosition( + "light.direction", + lighting->light->direction.x, + lighting->light->direction.y, + lighting->light->direction.z + ); + shader->UniformFloat("light.cutOff", glm::cos(glm::radians(lighting->light->cutOff))); + shader->UniformFloat("light.outerCutOff", glm::cos(glm::radians(lighting->light->outerCutOff))); + } if (object->HasComponent(Ecs::Component::Type::MATERIAL)) { - materialShader->UniformPosition( + shader->UniformPosition( "material.ambient", object->material->ambient.x, object->material->ambient.y, object->material->ambient.z ); - materialShader->UniformPosition( + shader->UniformPosition( "material.diffuse", object->material->diffuse.x, object->material->diffuse.y, object->material->diffuse.z ); - materialShader->UniformPosition( + shader->UniformPosition( "material.specular", object->material->specular.x, object->material->specular.y, object->material->specular.z ); - materialShader->UniformPosition( + shader->UniformPosition( "material.color", object->material->color.x, object->material->color.y, object->material->color.z ); - materialShader->UniformFloat("material.shininess", object->material->shininess); + shader->UniformFloat("material.shininess", object->material->shininess); } object->mesh->VAO->bind(); diff --git a/src/editor.cpp b/src/editor.cpp index 295d347..f4ac836 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -63,14 +63,14 @@ namespace Engine { ImGui::Separator(); if (ImGui::BeginMenu("mesh")) { - // if (ImGui::MenuItem("Plane")) { - // std::shared_ptr plane = std::make_shared(); - // app->scene->root->entities.push_back(plane); - // } - // if (ImGui::MenuItem("Cube")) { - // std::shared_ptr cube = std::make_shared(); - // app->scene->root->entities.push_back(cube); - // } + if (ImGui::MenuItem("Plane")) { + std::shared_ptr plane = std::make_shared(); + app->scene->root->entities.push_back(plane); + } + if (ImGui::MenuItem("Cube")) { + std::shared_ptr cube = std::make_shared(); + app->scene->root->entities.push_back(cube); + } ImGui::EndMenu(); } ImGui::EndPopup(); @@ -167,6 +167,9 @@ namespace Engine { ImGui::SliderFloat("quadratic", &selectedEntity->light->quadratic, 0, 1.0); break; case Engine::Graphics::Lighting::Type::SPOT: + ImGui::SliderFloat("cutOff", &selectedEntity->light->cutOff, 0, 90.0); + ImGui::SliderFloat("outerCutOff", &selectedEntity->light->outerCutOff, 0, 90.0); + ImGui::SliderFloat3("direction", &selectedEntity->light->direction[0], -10.0, 10.0); break; default: // TODO: Throw exception about unknown lighting type diff --git a/src/main.cpp b/src/main.cpp index f542787..b81f67a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -205,8 +205,8 @@ class UserApplication : public Engine::EngineApplication { // End geometry primitives // Add sun to the scene - std::shared_ptr sun = - std::make_shared(); + std::shared_ptr sun = + std::make_shared(); sun->name = "Sun"; sun->light->intensity = 2.0f;