diff --git a/engine/include/rev/Light.h b/engine/include/rev/Light.h index 79e4e55..699b145 100644 --- a/engine/include/rev/Light.h +++ b/engine/include/rev/Light.h @@ -1,21 +1,37 @@ #pragma once +#include + #include namespace rev { class Light { public: - Light(); + enum class Type + { + Directional, + Point + }; + + Light(Type type); const glm::vec3& getBaseColor() const; - void setBaseColor(const glm::vec3& color); + void setBaseColor(const glm::vec3& baseColor); + + const glm::vec3& getDirection() const; + void setDirection(const glm::vec3& direction); const glm::vec3& getPosition() const; void setPosition(const glm::vec3& position); + + Type getType() const; + private: glm::vec3 _baseColor; - glm::vec3 _position; + std::optional _position; + std::optional _direction; + Type _type; }; -} // namespace rev \ No newline at end of file +} // namespace rev diff --git a/engine/include/rev/Scene.h b/engine/include/rev/Scene.h index 2d2a747..6bce244 100644 --- a/engine/include/rev/Scene.h +++ b/engine/include/rev/Scene.h @@ -18,15 +18,18 @@ class SceneObject; class Scene { public: - std::shared_ptr addLight(); + std::shared_ptr addPointLight(); + std::shared_ptr addDirectionalLight(); void renderAllObjects(Camera &camera); - void renderAllLights(Uniform& lightPositionUniform, Uniform& lightBaseColor); + void renderAllPointLights(Uniform& lightPositionUniform, Uniform& lightBaseColor); + void renderAllDirectionalLights(Uniform& lightDirectionUniform, Uniform& lightBaseColor); void addObjectGroup(std::shared_ptr group); private: std::vector> _objectGroups; - std::set> _lights; + std::set> _pointLights; + std::set> _directionalLights; }; } // namespace rev \ No newline at end of file diff --git a/engine/include/rev/SceneView.h b/engine/include/rev/SceneView.h index 83e94de..e0fa9ba 100644 --- a/engine/include/rev/SceneView.h +++ b/engine/include/rev/SceneView.h @@ -35,7 +35,8 @@ class SceneView std::shared_ptr _camera; RectSize _outputSize; - ProgramResource _lightingProgram; + ProgramResource _pointLightingProgram; + ProgramResource _directionalLightingProgram; struct WorldSpaceNormalProperty { @@ -108,8 +109,21 @@ class SceneView VertexArray _fullScreenVao; Buffer _fullScreenVertexBuffer; - Uniform _lightPosition; - Uniform _lightBaseColor; - Uniform _camPosition; + struct DirectionalLightUniforms + { + Uniform lightDirection; + Uniform lightBaseColor; + Uniform camPosition; + }; + + struct PointLightUniforms + { + Uniform lightPosition; + Uniform lightBaseColor; + Uniform camPosition; + }; + + PointLightUniforms _pointLightUniforms; + DirectionalLightUniforms _directionalLightUniforms; }; } // namespace rev \ No newline at end of file diff --git a/engine/src/Light.cpp b/engine/src/Light.cpp index e8b804e..a5b5713 100644 --- a/engine/src/Light.cpp +++ b/engine/src/Light.cpp @@ -1,30 +1,54 @@ #include "rev/Light.h" +using namespace std; +using namespace glm; + namespace rev { - Light::Light() - : _baseColor(glm::vec3(1.0)) - , _position(glm::vec3(0.0)) + // Light + Light::Light(Type type) + : _baseColor(0.f), _type(type) { } + Light::Type Light::getType() const + { + return _type; + } + const glm::vec3& Light::getBaseColor() const { return _baseColor; } - void Light::setBaseColor(const glm::vec3& color) + void Light::setBaseColor(const glm::vec3& baseColor) { - _baseColor = color; + _baseColor = baseColor; } const glm::vec3& Light::getPosition() const { - return _position; + assert(_position.has_value()); + return *_position; } void Light::setPosition(const glm::vec3& position) { - _position = position; + assert(_type == Type::Point); + _position = make_optional(position); + } + + const glm::vec3& Light::getDirection() const + { + assert(_direction.has_value()); + return *_direction; + } + + void Light::setDirection(const glm::vec3& direction) + { + //TODO: Is there a way to ensure that the programmer is not + // calling these methods on the wrong type of light statically? + assert(_type == Type::Directional); + _direction = make_optional(direction); } } diff --git a/engine/src/Scene.cpp b/engine/src/Scene.cpp index eebfac3..8a91c73 100644 --- a/engine/src/Scene.cpp +++ b/engine/src/Scene.cpp @@ -6,10 +6,17 @@ namespace rev { -std::shared_ptr Scene::addLight() +std::shared_ptr Scene::addPointLight() { - auto light = std::make_shared(); - _lights.insert(light); + auto light = std::make_shared(Light::Type::Point); + _pointLights.insert(light); + return std::move(light); +} + +std::shared_ptr Scene::addDirectionalLight() +{ + auto light = std::make_shared(Light::Type::Directional); + _directionalLights.insert(light); return std::move(light); } @@ -26,10 +33,22 @@ void Scene::renderAllObjects(Camera &camera) } } -void Scene::renderAllLights(Uniform &lightPositionUniform, +void Scene::renderAllDirectionalLights(Uniform &lightDirectionUniform, + Uniform &lightBaseColor) +{ + for (const auto & light : _directionalLights) + { + lightDirectionUniform.set(light->getDirection()); + lightBaseColor.set(light->getBaseColor()); + + glDrawArrays(GL_TRIANGLES, 0, 6); + } +} + +void Scene::renderAllPointLights(Uniform &lightPositionUniform, Uniform &lightBaseColor) { - for (const auto & light : _lights) + for (const auto & light : _pointLights) { lightPositionUniform.set(light->getPosition()); lightBaseColor.set(light->getBaseColor()); diff --git a/engine/src/SceneView.cpp b/engine/src/SceneView.cpp index 127bc3b..ad5ada7 100644 --- a/engine/src/SceneView.cpp +++ b/engine/src/SceneView.cpp @@ -27,7 +27,54 @@ constexpr const char *kDeferredVertexShader = R"vertexShader( )vertexShader"; -constexpr const char *kDeferredFragmentShader = R"fragmentShader( +constexpr const char *kDeferredDirectionalLightFragmentShader = R"fragmentShader( + #version 330 core + + in vec2 texCoord; + + uniform vec3 lightDirection; + uniform vec3 lightBaseColor; + uniform vec3 camPosition; + + uniform sampler2D fragPosition; + uniform sampler2D normals; + + uniform sampler2D ambient; + uniform sampler2D emissive; + uniform sampler2D diffuse; + uniform sampler2D specular; + uniform sampler2D specularExponent; + + out vec4 fragColor; + void main() + { + vec3 normal = texture(normals, texCoord).rgb; + vec3 diffuse = texture(diffuse, texCoord).rgb; + + vec3 fragmentPosition = texture(fragPosition, texCoord).rgb; + vec3 lightVector = -1.0f * lightDirection; + float angleMultiplier = max(dot(normalize(lightVector), normalize(normal)), 0.0f); + + float specularExponent = texture(specularExponent, texCoord).r; + vec3 specularCoefficient = texture(specular, texCoord).rgb; + + vec3 eyeVector = normalize(camPosition - fragmentPosition); + vec3 reflectVector = normalize(reflect(lightVector, normalize(normal))); + float specularComponent = max(dot(eyeVector, reflectVector), 0.0f); + + vec3 ambientLight = vec3(0.01f) * diffuse; + vec3 diffuseLight = diffuse * lightBaseColor * angleMultiplier; + vec3 specularLight = (specularExponent > 0.01) + ? lightBaseColor * specularCoefficient * pow(vec3(specularComponent) , vec3(specularExponent)) + : vec3(0.0f); + + vec3 totalLight = diffuseLight + specularLight; + + fragColor = vec4(totalLight, 1.0f); + } + )fragmentShader"; + +constexpr const char *kDeferredPointLightFragmentShader = R"fragmentShader( #version 330 core in vec2 texCoord; @@ -87,22 +134,42 @@ constexpr glm::vec2 kFullScreenQuadVertices[] = { SceneView::SceneView() : _camera(std::make_shared()) { - _lightingProgram.buildWithSource(kDeferredVertexShader, - kDeferredFragmentShader); + _pointLightingProgram.buildWithSource(kDeferredVertexShader, + kDeferredPointLightFragmentShader); { - ProgramContext programContext(_lightingProgram); - _lightPosition = _lightingProgram.getUniform("lightPosition"); - _lightBaseColor = _lightingProgram.getUniform("lightBaseColor"); - _camPosition = _lightingProgram.getUniform("camPosition"); - - _lightingProgram.getUniform("fragPosition").set(0); - _lightingProgram.getUniform("normals").set(1); - - _lightingProgram.getUniform("ambient").set(2); - _lightingProgram.getUniform("emissive").set(3); - _lightingProgram.getUniform("diffuse").set(4); - _lightingProgram.getUniform("specular").set(5); - _lightingProgram.getUniform("specularExponent").set(6); + ProgramContext programContext(_pointLightingProgram); + + _pointLightUniforms.lightPosition = _pointLightingProgram.getUniform("lightPosition"); + _pointLightUniforms.lightBaseColor = _pointLightingProgram.getUniform("lightBaseColor"); + _pointLightUniforms.camPosition = _pointLightingProgram.getUniform("camPosition"); + + _pointLightingProgram.getUniform("fragPosition").set(0); + _pointLightingProgram.getUniform("normals").set(1); + + _pointLightingProgram.getUniform("ambient").set(2); + _pointLightingProgram.getUniform("emissive").set(3); + _pointLightingProgram.getUniform("diffuse").set(4); + _pointLightingProgram.getUniform("specular").set(5); + _pointLightingProgram.getUniform("specularExponent").set(6); + } + + _directionalLightingProgram.buildWithSource(kDeferredVertexShader, + kDeferredDirectionalLightFragmentShader); + { + ProgramContext programContext(_directionalLightingProgram); + + _directionalLightUniforms.lightDirection = _directionalLightingProgram.getUniform("lightDirection"); + _directionalLightUniforms.lightBaseColor = _directionalLightingProgram.getUniform("lightBaseColor"); + _directionalLightUniforms.camPosition = _directionalLightingProgram.getUniform("camPosition"); + + _directionalLightingProgram.getUniform("fragPosition").set(0); + _directionalLightingProgram.getUniform("normals").set(1); + + _directionalLightingProgram.getUniform("ambient").set(2); + _directionalLightingProgram.getUniform("emissive").set(3); + _directionalLightingProgram.getUniform("diffuse").set(4); + _directionalLightingProgram.getUniform("specular").set(5); + _directionalLightingProgram.getUniform("specularExponent").set(6); } VertexArrayContext vaoContext(_fullScreenVao); @@ -162,10 +229,8 @@ void SceneView::render() // Lighting pass { - ProgramContext programContext(_lightingProgram); auto fbContext = _lightingStage.getRenderContext(); - _camPosition.set(_camera->getPosition()); glViewport(0, 0, _outputSize.width, _outputSize.height); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); @@ -192,7 +257,19 @@ void SceneView::render() VertexArrayContext vaoContext(_fullScreenVao); - _scene->renderAllLights(_lightPosition, _lightBaseColor); + // Render all point lights + { + ProgramContext programContext(_pointLightingProgram); + _pointLightUniforms.camPosition.set(_camera->getPosition()); + _scene->renderAllPointLights(_pointLightUniforms.lightPosition, _pointLightUniforms.lightBaseColor); + } + + // Render all directional lights + { + ProgramContext programContext(_directionalLightingProgram); + _directionalLightUniforms.camPosition.set(_camera->getPosition()); + _scene->renderAllDirectionalLights(_directionalLightUniforms.lightDirection, _directionalLightUniforms.lightBaseColor); + } } } diff --git a/testGame/src/main.cpp b/testGame/src/main.cpp index 1740374..edad1fc 100644 --- a/testGame/src/main.cpp +++ b/testGame/src/main.cpp @@ -339,18 +339,22 @@ int main(void) auto bikeController = std::make_shared(bikeParticle, object); - auto yellowLight = scene->addLight(); + auto yellowLight = scene->addPointLight(); yellowLight->setPosition(glm::vec3(4.0f, 3.0f, 3.0f)); yellowLight->setBaseColor(glm::vec3(1.0f, 1.0f, 0.8f)); - auto blueLight = scene->addLight(); + auto blueLight = scene->addPointLight(); blueLight->setPosition(glm::vec3(-1.5f, -2.0f, 1.5f)); blueLight->setBaseColor(glm::vec3(0.2f, 0.2f, 1.0f)); - auto orangeLight = scene->addLight(); + auto orangeLight = scene->addPointLight(); orangeLight->setPosition(glm::vec3(3.0f, 0.75f, -2.5f)); orangeLight->setBaseColor(glm::vec3(1.0f, 0.3f, 0.0f)); + auto directionalLight = scene->addDirectionalLight(); + directionalLight->setDirection(glm::vec3(-1.0, 0.0f, 0.0f)); + directionalLight->setBaseColor(glm::vec3(1.0f, 1.0f, 1.0f)); + auto camera = sceneView->getCamera(); camera->setTarget({0.0f, 0.0f, 0.0f}); camera->setPosition({4.0f, 4.0f, 4.0f});