diff --git a/include/myEngine/lighting.hpp b/include/myEngine/lighting.hpp new file mode 100644 index 0000000..dec1363 --- /dev/null +++ b/include/myEngine/lighting.hpp @@ -0,0 +1,143 @@ +#ifndef LIGHTING_HPP +#define LIGHTING_HPP + +#include + +#include + +class Light { +private: + glm::vec3 color; + glm::vec3 ambient; + glm::vec3 diffuse; + glm::vec3 specular; +public: + Light(const glm::vec3& color, const glm::vec3& ambient, const glm::vec3& diffuse, const glm::vec3& specular) + : color(color), ambient(ambient), diffuse(diffuse), specular(specular) {} + + glm::vec3 getColor() const { return color; } + glm::vec3 getAmbient() const { return ambient; } + glm::vec3 getDiffuse() const { return diffuse; } + glm::vec3 getSpecular() const { return specular; } + + void setColor(const glm::vec3& newColor) { color = newColor; } + void setAmbient(const glm::vec3& newAmbient) { ambient = newAmbient; } + void setDiffuse(const glm::vec3& newDiffuse) { diffuse = newDiffuse; } + void setSpecular(const glm::vec3& newSpecular) { specular = newSpecular; } + virtual void use(Shader& shader) {} +}; + +class DirectLight : public Light { +private: + glm::vec3 direction; +public: + DirectLight(const glm::vec3& direction, const glm::vec3& color, const glm::vec3& ambient, const glm::vec3& diffuse, const glm::vec3& specular) + : direction(direction), Light(color, ambient, diffuse, specular) {} + + glm::vec3 getDirection() const + { + return direction; + } + + void setDirection(const glm::vec3& newDirection) + { + direction = newDirection; + } + + void use(Shader& shader) override + { + shader.setVec3("dirLight.direction", direction); + shader.setVec3("dirLight.color", getColor()); + shader.setVec3("dirLight.ambient", getAmbient()); + shader.setVec3("dirLight.diffuse", getDiffuse()); + shader.setVec3("dirLight.specular", getSpecular()); + } +}; + +class SpotLight : public Light { +private: + glm::vec3 position; + glm::vec3 direction; + float cutOff; + float outerCutOff; + float constant; + float linear; + float quadratic; +public: + SpotLight(const glm::vec3& position, const glm::vec3& direction, + float cutOff, float outerCutOff, + const glm::vec3& color, const glm::vec3& ambient, + const glm::vec3& diffuse, const glm::vec3& specular, + float constant, float linear, float quadratic) + : position(position), direction(direction), cutOff(cutOff), outerCutOff(outerCutOff), + Light(color, ambient, diffuse, specular), constant(constant), linear(linear), quadratic(quadratic) {} + + glm::vec3 getPosition() const { return position; } + glm::vec3 getDirection() const { return direction; } + float getCutOff() const { return cutOff; } + float getOuterCutOff() const { return outerCutOff; } + float getConstant() const { return constant; } + float getLinear() const { return linear; } + float getQuadratic() const { return quadratic; } + + void setPosition(const glm::vec3& newPosition) { position = newPosition; } + void setDirection(const glm::vec3& newDirection) { direction = newDirection; } + void setCutOff(float newCutOff) { cutOff = newCutOff; } + void setOuterCutOff(float newOuterCutOff) { outerCutOff = newOuterCutOff; } + void setConstant(float newConstant) { constant = newConstant; } + void setLinear(float newLinear) { linear = newLinear; } + void setQuadratic(float newQuadratic) { quadratic = newQuadratic; } + + void use(Shader& shader) override + { + shader.setVec3("spotLight.position", position); + shader.setVec3("spotLight.direction", direction); + shader.setFloat("spotLight.cutOff", glm::cos(glm::radians(cutOff))); + shader.setFloat("spotLight.outerCutOff", glm::cos(glm::radians(outerCutOff))); + shader.setVec3("spotLight.color", getColor()); + shader.setVec3("spotLight.ambient", getAmbient()); + shader.setVec3("spotLight.diffuse", getDiffuse()); + shader.setVec3("spotLight.specular", getSpecular()); + shader.setFloat("spotLight.constant", constant); + shader.setFloat("spotLight.linear", linear); + shader.setFloat("spotLight.quadratic", quadratic); + } +}; + +class PointLight : public Light { +private: + glm::vec3 position; + float constant; + float linear; + float quadratic; +public: + PointLight(const glm::vec3& position, const glm::vec3& color, + const glm::vec3& ambient, const glm::vec3& diffuse, const glm::vec3& specular, + float constant, float linear, float quadratic) + : position(position), Light(color, ambient, diffuse, specular), + constant(constant), linear(linear), quadratic(quadratic) {} + + glm::vec3 getPosition() const { return position; } + float getConstant() const { return constant; } + float getLinear() const { return linear; } + float getQuadratic() const { return quadratic; } + + void setPosition(const glm::vec3& newPosition) { position = newPosition; } + void setConstant(float newConstant) { constant = newConstant; } + void setLinear(float newLinear) { linear = newLinear; } + void setQuadratic(float newQuadratic) { quadratic = newQuadratic; } + + void use(Shader& shader, int index) const + { + shader.setVec3("pointLights[" + std::to_string(index) + "].position", position); + shader.setVec3("pointLights[" + std::to_string(index) + "].color", getColor()); + shader.setVec3("pointLights[" + std::to_string(index) + "].ambient", getAmbient()); + shader.setVec3("pointLights[" + std::to_string(index) + "].diffuse", getDiffuse()); + shader.setVec3("pointLights[" + std::to_string(index) + "].specular", getSpecular()); + shader.setFloat("pointLights[" + std::to_string(index) + "].constant", constant); + shader.setFloat("pointLights[" + std::to_string(index) + "].linear", linear); + shader.setFloat("pointLights[" + std::to_string(index) + "].quadratic", quadratic); + } +}; + +#endif \ No newline at end of file diff --git a/include/myEngine/object.hpp b/include/myEngine/object.hpp index f15ab5c..7df8e95 100644 --- a/include/myEngine/object.hpp +++ b/include/myEngine/object.hpp @@ -1,3 +1,6 @@ +#ifndef OBJECT_HPP +#define OBJECT_HPP + #include #include @@ -47,4 +50,6 @@ public: shader.setMat4("model", modelMatrix); model.Draw(shader); } -}; \ No newline at end of file +}; + +#endif diff --git a/main.cpp b/main.cpp index 79f5786..9a98f3f 100644 --- a/main.cpp +++ b/main.cpp @@ -16,6 +16,7 @@ #include #include #include +#include void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow *window); @@ -85,10 +86,7 @@ int main() ImGui_ImplOpenGL3_Init("#version 330 core"); // Shaders - Shader ourShader("resources/shaders/vert.glsl", "resources/shaders/frag.glsl"); - Shader directional_lightShader("resources/shaders/vert.glsl", "resources/shaders/directional_light.glsl"); - Shader point_lightShader("resources/shaders/vert.glsl", "resources/shaders/point_light.glsl"); - Shader spotlight_lightShader("resources/shaders/vert.glsl", "resources/shaders/spotlight_light.glsl"); + Shader light_shader("resources/shaders/vert.glsl", "resources/shaders/light_shader.glsl"); Shader light_cubeShader("resources/shaders/vert.glsl", "resources/shaders/light_object.glsl"); // Models @@ -101,6 +99,32 @@ int main() Object object3(croissant, glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.1f, 0.1f, 0.1f), glm::vec3(0.0f, 0.0f, 0.0f)); Object light_cube(cube, glm::vec3(1.2f, 1.0f, 2.0f), glm::vec3(0.05f, 0.05f, 0.05f), glm::vec3(0.0f, 0.0f, 0.0f)); + // Lights + DirectLight directLight(glm::vec3(-0.2f, -1.0f, -0.3f), + glm::vec3(1.0f, 1.0f, 1.0f), + glm::vec3(0.2f, 0.2f, 0.2f), + glm::vec3(0.5f, 0.5f, 0.5f), + glm::vec3(1.0f, 1.0f, 1.0f)); + SpotLight spotLight(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 1.0f, 1.0f), + 12.55f, 17.5f, + glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(0.2f, 0.2f, 0.2f), + glm::vec3(0.5f, 0.5f, 0.5f), glm::vec3(1.0f, 1.0f, 1.0f), + 1.0f, 0.09f, + 0.032f); + std::vector pointLights; + pointLights.emplace_back(glm::vec3(1.2f, 1.0f, 2.0f), + glm::vec3(1.0f, 1.0f, 1.0f), + glm::vec3(0.2f, 0.2f, 0.2f), + glm::vec3(0.5f, 0.5f, 0.5f), + glm::vec3(1.0f, 1.0f, 1.0f), + 1.0f, 0.09f, 0.032f); + pointLights.emplace_back(glm::vec3(-1.2f, 1.0f, 2.0f), + glm::vec3(1.0f, 1.0f, 1.0f), + glm::vec3(0.2f, 0.2f, 0.2f), + glm::vec3(0.5f, 0.5f, 0.5f), + glm::vec3(1.0f, 1.0f, 1.0f), + 1.0f, 0.09f, 0.032f); + static float positionX = 0.0f; static float positionY = 0.0f; static float positionZ = 0.0f; @@ -111,9 +135,6 @@ int main() static float* light_color = new float[3]{1.0f, 1.0f, 1.0f}; static float light_cutoff = 12.5f; static float light_outerCutoff = 17.5f; - static float light_directionX = 0.0f; - static float light_directionY = 0.0f; - static float light_directionZ = -1.0f; while(!glfwWindowShouldClose(window)) { @@ -139,7 +160,6 @@ int main() ImGui::Begin("Settings"); ImGui::Text("FPS: %.2f", 1.0f / deltaTime); - ImGui::Text("Camera Direction: (%.2f, %.2f, %.2f)", camera.Front.x, camera.Front.y, camera.Front.z); ImGui::SliderFloat("Object 1 Position X", &positionX, -5.0f, 5.0f); ImGui::SliderFloat("Object 1 Position Y", &positionY, -5.0f, 5.0f); ImGui::SliderFloat("Object 1 Position Z", &positionZ, -5.0f, 5.0f); @@ -149,79 +169,53 @@ int main() ImGui::ColorEdit3("Light Cube Color", light_color); ImGui::SliderFloat("Light Cutoff", &light_cutoff, 0.0f, 90.0f); ImGui::SliderFloat("Light Outer Cutoff", &light_outerCutoff, 0.0f, 90.0f); - ImGui::SliderFloat("Light Direction X", &light_directionX, -1.0f, 1.0f); - ImGui::SliderFloat("Light Direction Y", &light_directionY, -1.0f, 1.0f); - ImGui::SliderFloat("Light Direction Z", &light_directionZ, -1.0f, 1.0f); ImGui::End(); glm::mat4 view = camera.GetViewMatrix(); glm::mat4 projection = glm::perspective(glm::radians(45.0f), float(width) / float(height), 0.1f, 100.0f); - - // Bacis lighting - ourShader.setVec3("viewPos", camera.Position); - ourShader.setVec3("light.position", 1.2f, 1.0f, 2.0f); - ourShader.setVec3("light.color", 1.0f, 1.0f, 1.0f); - ourShader.setVec3("light.ambient", 0.2f, 0.2f, 0.2f); - ourShader.setVec3("light.diffuse", 0.5f, 0.5f, 0.5f); - ourShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f); - ourShader.setMat4("view", view); - ourShader.setMat4("projection", projection); + + light_shader.use(); + light_shader.setMat4("view", view); + light_shader.setVec3("viewPos", camera.Position); + light_shader.setMat4("projection", projection); // Directional light - directional_lightShader.setVec3("light.direction", -0.2f, -1.0f, -0.3f); - directional_lightShader.setVec3("light.color", 1.0f, 1.0f, 1.0f); - directional_lightShader.setVec3("light.ambient", 0.2f, 0.2f, 0.2f); - directional_lightShader.setVec3("light.diffuse", 0.5f, 0.5f, 0.5f); - directional_lightShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f); - directional_lightShader.setMat4("view", view); - directional_lightShader.setMat4("projection", projection); + directLight.use(light_shader); + + // Spotlight + spotLight.setPosition(camera.Position); + spotLight.setDirection(camera.Front); + spotLight.setCutOff(light_cutoff); + spotLight.setOuterCutOff(light_outerCutoff); + spotLight.use(light_shader); // Point light - point_lightShader.use(); - point_lightShader.setVec3("viewPos", camera.Position); - point_lightShader.setVec3("light.position", lightCubePositionX, lightCubePositionY, lightCubePositionZ); - point_lightShader.setVec3("light.color", light_color[0], light_color[1], light_color[2]); - point_lightShader.setVec3("light.ambient", 0.2f, 0.2f, 0.2f); - point_lightShader.setVec3("light.diffuse", 0.5f, 0.5f, 0.5f); - point_lightShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f); - point_lightShader.setFloat("light.constant", 1.0f); - point_lightShader.setFloat("light.linear", 0.09f); - point_lightShader.setFloat("light.quadratic", 0.032f); - point_lightShader.setMat4("view", view); - point_lightShader.setMat4("projection", projection); - - // Spotlight light - spotlight_lightShader.use(); - spotlight_lightShader.setVec3("viewPos", camera.Position); - spotlight_lightShader.setVec3("light.position", lightCubePositionX, lightCubePositionY, lightCubePositionZ); - spotlight_lightShader.setVec3("light.direction", light_directionX, light_directionY, light_directionZ); - spotlight_lightShader.setVec3("light.color", light_color[0], light_color[1], light_color[2]); - spotlight_lightShader.setVec3("light.ambient", 0.2f, 0.2f, 0.2f); - spotlight_lightShader.setVec3("light.diffuse", 0.5f, 0.5f, 0.5f); - spotlight_lightShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f); - spotlight_lightShader.setFloat("light.constant", 1.0f); - spotlight_lightShader.setFloat("light.linear", 0.09f); - spotlight_lightShader.setFloat("light.quadratic", 0.032f); - spotlight_lightShader.setFloat("light.cutOff", glm::cos(glm::radians(light_cutoff))); - spotlight_lightShader.setFloat("light.outerCutOff", glm::cos(glm::radians(light_outerCutoff))); - spotlight_lightShader.setMat4("view", view); - spotlight_lightShader.setMat4("projection", projection); + light_shader.setInt("pointLightCount", static_cast(pointLights.size())); + pointLights[0].setPosition(glm::vec3(lightCubePositionX, lightCubePositionY, lightCubePositionZ)); + pointLights[0].setColor(glm::vec3(light_color[0], light_color[1], light_color[2])); + for (size_t i = 0; i < pointLights.size(); ++i) + { + pointLights[i].use(light_shader, static_cast(i)); + } object1.setPosition(glm::vec3(positionX, positionY, positionZ)); - object1.Draw(spotlight_lightShader, deltaTime); + object1.Draw(light_shader, deltaTime); object2.setAcceleration(glm::vec3(0.0f, 0.001f, 0.0f)); - object2.Draw(spotlight_lightShader, deltaTime); + object2.Draw(light_shader, deltaTime); object3.setAcceleration(glm::vec3(0.0f, -0.001f, 0.0f)); - object3.Draw(spotlight_lightShader, deltaTime); + object3.Draw(light_shader, deltaTime); // Light cube shader light_cubeShader.use(); light_cubeShader.setMat4("view", view); light_cubeShader.setMat4("projection", projection); - light_cubeShader.setVec3("lightColor", light_color[0], light_color[1], light_color[2]); - light_cube.setPosition(glm::vec3(lightCubePositionX, lightCubePositionY, lightCubePositionZ)); - light_cube.Draw(light_cubeShader, deltaTime); + for (size_t i = 0; i < pointLights.size(); ++i) + { + light_cube.setPosition(pointLights[i].getPosition()); + light_cubeShader.setVec3("lightColor", pointLights[i].getColor()); + light_cube.Draw(light_cubeShader, deltaTime); + } ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); diff --git a/resources/shaders/light_shader.glsl b/resources/shaders/light_shader.glsl new file mode 100644 index 0000000..af307b6 --- /dev/null +++ b/resources/shaders/light_shader.glsl @@ -0,0 +1,153 @@ +#version 330 core +out vec4 FragColor; + +in vec3 Normal; +in vec2 TexCoords; +in vec3 FragPos; + +struct DirLight { + vec3 direction; + vec3 color; + + vec3 ambient; + vec3 diffuse; + vec3 specular; +}; + +struct PointLight { + vec3 position; + + vec3 ambient; + vec3 diffuse; + vec3 specular; + vec3 color; + + float constant; + float linear; + float quadratic; +}; + +struct SpotLight { + vec3 position; + vec3 direction; + + vec3 ambient; + vec3 diffuse; + vec3 specular; + vec3 color; + + float constant; + float linear; + float quadratic; + float cutOff; + float outerCutOff; +}; + +uniform sampler2D texture_diffuse1; +uniform vec3 viewPos; +uniform DirLight dirLight; +#define NR_POINT_LIGHTS 16 +uniform PointLight pointLights[NR_POINT_LIGHTS]; +uniform int pointLightCount; +uniform SpotLight spotLight; + +vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir) +{ + // ambient + float ambientStrength = 0.1; + vec3 ambient = ambientStrength * light.color; + + // diffuse + vec3 norm = normalize(Normal); + vec3 lightDir = normalize(-light.direction); + float diff = max(dot(norm, lightDir), 0.0); + vec3 diffuse = diff * light.color; + + // specular + float specularStrength = 0.5; + vec3 reflectDir = reflect(-lightDir, norm); + float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); + vec3 specular = specularStrength * spec * light.color; + + return (ambient + diffuse + specular); +} + +vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir) +{ + float distance = length(light.position - FragPos); + float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); + + // ambient// ambient + float ambientStrength = 0.1; + vec3 ambient = ambientStrength * light.color; + + // diffuse + vec3 norm = normalize(Normal); + vec3 lightDir = normalize(light.position - FragPos); + float diff = max(dot(norm, lightDir), 0.0); + vec3 diffuse = diff * light.color; + + // specular + float specularStrength = 0.5; + vec3 reflectDir = reflect(-lightDir, norm); + float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); + vec3 specular = specularStrength * spec * light.color; + + ambient *= attenuation; + diffuse *= attenuation; + specular *= attenuation; + + return (ambient + diffuse + specular); +} + +vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir) +{ + // Calculate the direction of the light + vec3 lightDir = normalize(light.position - FragPos); + + // Calculate the angle between the light direction and the spotlight direction + float theta = dot(lightDir, normalize(-light.direction)); + float epsilon = light.cutOff - light.outerCutOff; + float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0); + float distance = length(light.position - FragPos); + float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); + + // ambient + float ambientStrength = 0.1; + vec3 ambient = ambientStrength * light.color; + + // diffuse + vec3 norm = normalize(Normal); + float diff = max(dot(norm, lightDir), 0.0); + vec3 diffuse = diff * light.color; + + // specular + float specularStrength = 0.5; + vec3 reflectDir = reflect(-lightDir, norm); + float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); + vec3 specular = specularStrength * spec * light.color; + + // Apply attenuation and intensity + ambient *= attenuation; + diffuse *= attenuation * intensity; + specular *= attenuation * intensity; + + return (ambient + diffuse + specular); +} + +void main() +{ + // properties + vec3 norm = normalize(Normal); + vec3 viewDir = normalize(viewPos - FragPos); + + // phase 1: Directional lighting + vec3 result = CalcDirLight(dirLight, norm, viewDir); + // phase 2: Point lights + for(int i = 0; i < pointLightCount; i++) + result += CalcPointLight(pointLights[i], norm, FragPos, viewDir); + // phase 3: Spot light + result += CalcSpotLight(spotLight, norm, FragPos, viewDir); + + FragColor = texture(texture_diffuse1, TexCoords) * vec4(result, 1.0); +} \ No newline at end of file