From 135b075aa105d2a544ba5b7a0b15f3fbf4e88662 Mon Sep 17 00:00:00 2001 From: Dane Johnson Date: Thu, 4 Mar 2021 14:29:48 -0600 Subject: [PATCH] Add point lights --- core/Light.cpp | 45 ++++++++++++++++++++++++++++++-- core/Light.h | 31 ++++++++++++++++++++++ core/Shaders/Shader.cpp | 12 +++++++++ core/Shaders/Shader.h | 3 +++ core/Util.cpp | 6 +++++ core/Util.h | 16 ++++++++++++ core/couch.cpp | 3 +++ demo/exampleworld/main.lua | 18 +++++++++++++ shaders/flat.vert | 53 ++++++++++++++++++++++++++++++-------- 9 files changed, 174 insertions(+), 13 deletions(-) diff --git a/core/Light.cpp b/core/Light.cpp index c130529..f64ab4e 100644 --- a/core/Light.cpp +++ b/core/Light.cpp @@ -74,8 +74,6 @@ Light *Light::Create() { Name Light::GetType() const {return "Light";} -Name DirectionalLight::GetType() const {return "DirectionalLight";} - DirectionalLight::DirectionalLight() { this->direction = Vector3(0.0f); this->color = Vector3(0.0f); @@ -114,3 +112,46 @@ DirectionalLight *DirectionalLight::Duplicate() { DirectionalLight *DirectionalLight::Instance() { return static_cast(Node::Instance()); } + +Name DirectionalLight::GetType() const {return "DirectionalLight";} + +PointLight::PointLight() { + this->radius = 0.0f; + this->color = Vector3(0.0f); + this->ambient = 0.0f; + this->diffuse = 0.0f; + this->specular = 0.0f; +} + +PointLight::PointLight(float radius, Vector3 color, float ambient, float diffuse, float specular) { + this->radius = radius; + this->color = color; + this->ambient = ambient; + this->diffuse = diffuse; + this->specular = specular; +} + +float PointLight::GetRadius() { + return radius; +} + +void PointLight::SetRadius(float radius) { + this->radius = radius; +} + +PointLight *PointLight::Create() { + return new PointLight; +} + +PointLight *PointLight::Duplicate() { + PointLight *pointLight = static_cast(Light::Duplicate()); + pointLight->radius = radius; + + return pointLight; +} + +PointLight *PointLight::Instance() { + return static_cast(Node::Instance()); +} + +Name PointLight::GetType() const {return "PointLight";} diff --git a/core/Light.h b/core/Light.h index f925e28..9452bcf 100644 --- a/core/Light.h +++ b/core/Light.h @@ -24,6 +24,8 @@ #ifndef LIGHT_H #define LIGHT_H +#include + #include "types.h" #include "Spatial.h" @@ -117,4 +119,33 @@ private: Vector3 direction; }; +/** + Point lights are omnidirectional lights that have a limited range. +*/ +class PointLight : public Light { +public: + PointLight(); + PointLight(float radius, Vector3 color, float ambient, float diffuse, float specular); + + /** + The radius of which the light will shine. + @returns The light radius. + */ + float GetRadius(); + /** + Sets the light radius. + @param radius The desired radius + */ + void SetRadius(float radius); + + virtual Name GetType() const; + virtual PointLight *Create(); + virtual PointLight *Duplicate(); + virtual PointLight *Instance(); +private: + float radius; +}; + +typedef std::vector PointLightList; + #endif /* LIGHT_H */ diff --git a/core/Shaders/Shader.cpp b/core/Shaders/Shader.cpp index 43fab07..d1e4c3b 100644 --- a/core/Shaders/Shader.cpp +++ b/core/Shaders/Shader.cpp @@ -1,5 +1,7 @@ #include "Shader.h" +#include + Shader::Shader(const char* vertexCode, const char* fragmentCode) { Id vertex, fragment; int success; @@ -82,6 +84,16 @@ void Shader::UpdateDirectionalLight(DirectionalLight directionalLight) { glUniform1f(glGetUniformLocation(id, "directionalLight.specular"), directionalLight.GetSpecular()); } +void Shader::UpdatePointLights(PointLightList pointLights) { + for (int i = 0; i < pointLights.size() and i < NUM_POINT_LIGHTS; i++) { + glUniform3fv(glGetUniformLocation(id, Util::ShaderArrayName("pointLights", i, "pos").c_str()), 1, glm::value_ptr(pointLights[i]->GetTransform().position)); + glUniform3fv(glGetUniformLocation(id, Util::ShaderArrayName("pointLights", i, "color").c_str()), 1, glm::value_ptr(pointLights[i]->GetColor())); + + glUniform1f(glGetUniformLocation(id, Util::ShaderArrayName("pointLights", i, "radius").c_str()), pointLights[i]->GetRadius()); + glUniform1f(glGetUniformLocation(id, Util::ShaderArrayName("pointLights", i, "ambient").c_str()), pointLights[i]->GetAmbient()); + } +} + Name Shader::GetName() const { return "Unnamed Shader"; } diff --git a/core/Shaders/Shader.h b/core/Shaders/Shader.h index 619dd73..cff1798 100644 --- a/core/Shaders/Shader.h +++ b/core/Shaders/Shader.h @@ -7,6 +7,8 @@ #include "../Material.h" #include "../Light.h" +#define NUM_POINT_LIGHTS 4 + class Shader { public: Id id; @@ -21,6 +23,7 @@ public: void UpdateMaterial(Material material); void UpdateDirectionalLight(DirectionalLight directionalLight); + void UpdatePointLights(PointLightList pointLights); virtual Name GetName() const; }; diff --git a/core/Util.cpp b/core/Util.cpp index bbb817e..5883f60 100644 --- a/core/Util.cpp +++ b/core/Util.cpp @@ -14,3 +14,9 @@ void Util::Die(std::string msg) { std::cerr << msg << std::endl; exit(1); } + +std::string Util::ShaderArrayName(const char* arrName, int index, const char* memberName) { + std::stringstream ss; + ss << arrName << "[" << index << "]." << memberName; + return ss.str(); +} diff --git a/core/Util.h b/core/Util.h index 1f9ecd1..0fd312e 100644 --- a/core/Util.h +++ b/core/Util.h @@ -2,7 +2,9 @@ #define UTIL_H #include +#include #include +#include #include #include "types.h" @@ -28,6 +30,20 @@ namespace Util { } return nullptr; } + template + std::vector FindNodesByType(Node *&root, const Name &type) { + std::vector nodes; + if (root->GetType() == type) { + nodes.push_back(dynamic_cast(root)); + } + for (Node *child : root->GetChildren()) { + std::vector childs = FindNodesByType(child, type); + nodes.insert(nodes.begin(), childs.begin(), childs.end()); + } + return nodes; + } + + std::string ShaderArrayName(const char* arrName, int index, const char* memberName); } #endif /* UTIL_H */ diff --git a/core/couch.cpp b/core/couch.cpp index 8ed25f0..684a181 100644 --- a/core/couch.cpp +++ b/core/couch.cpp @@ -141,6 +141,9 @@ int main() { shader->UpdateDirectionalLight(DirectionalLight()); } + PointLightList pointLights = Util::FindNodesByType(root, "PointLight"); + shader->UpdatePointLights(pointLights); + // Render the scene tree render(root, shader, Matrix(1.0f)); diff --git a/demo/exampleworld/main.lua b/demo/exampleworld/main.lua index 3bdd0ea..68656b1 100644 --- a/demo/exampleworld/main.lua +++ b/demo/exampleworld/main.lua @@ -44,6 +44,8 @@ function init() light:SetSpecular(0.1) couch.Node.GetRoot():AddChild(light:Instance()) + init_point_lights() + local skybox = couch.Skybox.FromFiles( "../resources/skybox/px.png", "../resources/skybox/nx.png", @@ -176,6 +178,22 @@ function update(delta) end end +function init_point_lights() + local colors = {couch.Vector3(1.0, 0.0, 0.0), couch.Vector3(0.0, 1.0, 0.0), couch.Vector3(0.0, 0.0, 1.0)} + for i, color in ipairs(colors) do + local pointLight = couch.PointLight(); + pointLight:Translate(couch.Vector3(i * -10.0, 0, -10)) + pointLight:SetRadius(10.0) + pointLight:SetColor(color) + pointLight:SetAmbient(1.0) + pointLight:SetSpecular(0.1) + local lightBox = couch.Mesh.FromFile("../resources/cube.obj") + lightBox:UniformScale(0.5); + pointLight:AddChild(lightBox); + couch.Node.GetRoot():AddChild(pointLight:Instance()) + end +end + function action_dir(key, action, pos, neg, curr) if key == pos and action == couch.ACTION_PRESS then return 1.0 diff --git a/shaders/flat.vert b/shaders/flat.vert index f759746..5f98d3c 100644 --- a/shaders/flat.vert +++ b/shaders/flat.vert @@ -27,6 +27,17 @@ struct DirectionalLight { float specular; }; +struct PointLight { + vec3 pos; + float radius; + vec3 color; + float ambient; + float diffuse; + float specular; +}; +#define NUM_POINT_LIGHTS 4 +uniform PointLight pointLights[NUM_POINT_LIGHTS]; + struct Material { sampler2D tex; bool usesTex; @@ -44,6 +55,29 @@ struct Material { uniform DirectionalLight directionalLight; uniform Material material; +void calcDirectionalLight(in vec3 normal) { + AMBIENT += directionalLight.ambient * directionalLight.color * material.ambient; + + vec3 direction = -(VIEW * vec4(directionalLight.direction, 0.0)).xyz; + float diff = dot(normalize(direction), normalize(normal)); + diff = max(diff, 0.0); + DIFFUSE += directionalLight.diffuse * diff * directionalLight.color * material.diffuse; + + vec3 viewDir = normalize((VIEW * MODEL * vec4(pos, 1.0)).xyz); + vec3 reflectionDir = reflect(normalize(direction), normalize(normal)); + float spec = dot(viewDir, reflectionDir); + spec = max(spec, 0.0); + spec = pow(spec, material.shininess); + SPECULAR += directionalLight.color * (spec * material.specular); +} + +void calcPointLight(in vec3 normal, in PointLight pointLight) { + vec4 ray = VIEW * MODEL * vec4(pos, 1.0) - VIEW * vec4(pointLight.pos, 1.0); + float dist = length(ray); + float attenuation = max(1.0 - dist * dist / pointLight.radius / pointLight.radius, 0.0); + AMBIENT += pointLight.color * material.ambient * pointLight.ambient * attenuation; +} + void main() { vec4 vertex = PROJECTION * VIEW * MODEL * vec4(pos, 1.0); gl_Position = vertex; @@ -58,17 +92,14 @@ void main() { vec3 my_normal = (VIEW * mat4(NORMAL) * vec4(normal, 0.0)).xyz; // Flat shading, we compute light per vertex - AMBIENT = directionalLight.ambient * directionalLight.color * material.ambient; + AMBIENT = vec3(0.0); + DIFFUSE = vec3(0.0); + SPECULAR = vec3(0.0); - vec3 direction = -(VIEW * vec4(directionalLight.direction, 0.0)).xyz; - float diff = dot(normalize(direction), normalize(my_normal)); - diff = max(diff, 0.0); - DIFFUSE = directionalLight.diffuse * diff * directionalLight.color * material.diffuse; + calcDirectionalLight(my_normal); - vec3 viewDir = normalize((VIEW * MODEL * vec4(pos, 1.0)).xyz); - vec3 reflectionDir = reflect(normalize(direction), normalize(my_normal)); - float spec = dot(viewDir, reflectionDir); - spec = max(spec, 0.0); - spec = pow(spec, material.shininess); - SPECULAR = directionalLight.color * (spec * material.specular); + // PointLights + for(int i = 0; i < NUM_POINT_LIGHTS; i++) { + calcPointLight(my_normal, pointLights[i]); + } }