diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index 4a39ac5f44..1c033cc38c 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -162,6 +162,7 @@ private: // Used to project points glm::mat4 _ourModelViewProjectionMatrix; }; +using ViewFrustumPointer = std::shared_ptr; #endif // hifi_ViewFrustum_h diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index a5fce0b377..b5f866166e 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -69,6 +69,8 @@ void DeferredLightingEffect::init() { _allocatedLights.push_back(std::make_shared()); model::LightPointer lp = _allocatedLights[0]; + // Add the global light to the light stage (for later shadow rendering) + _lightStage.addLight(lp); lp->setDirection(-glm::vec3(1.0f, 1.0f, 1.0f)); lp->setColor(glm::vec3(1.0f)); @@ -541,10 +543,6 @@ void DeferredLightingEffect::setGlobalLight(const glm::vec3& direction, const gl light->setAmbientIntensity(ambientIntensity); } -model::LightPointer DeferredLightingEffect::getGlobalLight() { - return _allocatedLights[_globalLights.front()]; -} - void DeferredLightingEffect::setGlobalSkybox(const model::SkyboxPointer& skybox) { _skybox = skybox; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index e75961e11a..d11dee7d49 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -21,6 +21,8 @@ #include "model/Stage.h" #include "model/Geometry.h" +#include "LightStage.h" + class RenderArgs; struct LightLocations; using LightLocationsPtr = std::shared_ptr; @@ -50,9 +52,11 @@ public: void setGlobalAtmosphere(const model::AtmospherePointer& atmosphere) { _atmosphere = atmosphere; } void setGlobalSkybox(const model::SkyboxPointer& skybox); - model::LightPointer getGlobalLight(); + const LightStage& getLightStage() { return _lightStage; } private: + LightStage _lightStage; + DeferredLightingEffect() = default; model::MeshPointer _spotLightMesh; @@ -72,26 +76,7 @@ private: gpu::PipelinePointer _spotLight; LightLocationsPtr _spotLightLocations; - class PointLight { - public: - glm::vec4 position; - float radius; - glm::vec4 ambient; - glm::vec4 diffuse; - glm::vec4 specular; - float constantAttenuation; - float linearAttenuation; - float quadraticAttenuation; - }; - - class SpotLight : public PointLight { - public: - glm::vec3 direction; - float exponent; - float cutoff; - }; - - typedef std::vector< model::LightPointer > Lights; + using Lights = std::vector; Lights _allocatedLights; std::vector _globalLights; diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp new file mode 100644 index 0000000000..0e79d7239c --- /dev/null +++ b/libraries/render-utils/src/LightStage.cpp @@ -0,0 +1,79 @@ +// +// LightStage.cpp +// render-utils/src +// +// Created by Zach Pomerantz on 1/14/2015. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ViewFrustum.h" + +#include "LightStage.h" + +LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum{ std::make_shared() } { + framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE)); + map = framebuffer->getDepthStencilBuffer(); +} + +void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float zBack, float zFront) { + // Orient the keylight frustum + const auto& direction = glm::normalize(_light->getDirection()); + glm::quat orientation; + if (direction == IDENTITY_UP) { + orientation = glm::quat(glm::mat3(IDENTITY_UP, -IDENTITY_FRONT, IDENTITY_RIGHT)); + } else { + auto side = glm::normalize(glm::cross(direction, IDENTITY_UP)); + auto up = glm::normalize(glm::cross(side, direction)); + auto orientation = glm::quat(glm::mat3(direction, up, side)); + } + _frustum->setOrientation(orientation); + + // Position the keylight frustum + _frustum->setPosition(viewFrustum->getPosition() - 21.0f * direction); + + _view = _frustum->getView(); + const Transform viewInverse{ _view.getInverseMatrix() }; + + viewFrustum->calculate(); + //const auto nearCorners = viewFrustum->getCorners(0); + const auto nearClip = viewFrustum->getNearClip(); + const auto nearCorners = viewFrustum->getCorners(nearClip - 1); + const auto farCorners = viewFrustum->getCorners(nearClip + 20); + + vec3 min{ viewInverse.transform(nearCorners.bottomLeft) }; + vec3 max{ min }; + // Expand keylight frustum to fit view frustum + auto fitFrustum = [&min, &max, &viewInverse](const vec3& viewCorner) { + const auto corner = viewInverse.transform(viewCorner); + + min.x = glm::min(min.x, corner.x); + min.y = glm::min(min.y, corner.y); + min.z = glm::min(min.z, corner.z); + + max.x = glm::max(max.x, corner.x); + max.y = glm::max(max.y, corner.y); + max.z = glm::max(max.z, corner.z); + }; + fitFrustum(nearCorners.bottomLeft); + fitFrustum(nearCorners.bottomRight); + fitFrustum(nearCorners.topLeft); + fitFrustum(nearCorners.topRight); + fitFrustum(farCorners.bottomLeft); + fitFrustum(farCorners.bottomRight); + fitFrustum(farCorners.topLeft); + fitFrustum(farCorners.topRight); + + glm::mat4 ortho = glm::ortho(min.x, max.x, min.y, max.y, -max.z, -min.z); + _frustum->setProjection(ortho); + _projection = ortho; +} + +const LightStage::LightPointer& LightStage::addLight(model::LightPointer light) { + Shadow stageShadow{light}; + LightPointer stageLight = std::make_shared(std::move(stageShadow)); + lights.push_back(stageLight); + return stageLight; +} diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h new file mode 100644 index 0000000000..de6e138ace --- /dev/null +++ b/libraries/render-utils/src/LightStage.h @@ -0,0 +1,62 @@ +// +// LightStage.h +// render-utils/src +// +// Created by Zach Pomerantz on 1/14/2015. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_render_utils_LightStage_h +#define hifi_render_utils_LightStage_h + +#include "gpu/Framebuffer.h" + +#include "model/Light.h" + +class ViewFrustum; + +// Light stage to set up light-related rendering tasks +class LightStage { +public: + class Shadow { + public: + const int MAP_SIZE = 2048; + + Shadow(model::LightPointer light); + + void setKeylightFrustum(ViewFrustum* viewFrustum, float zBack, float zFront); + + const std::shared_ptr getFrustum() const { return _frustum; } + const glm::mat4& getProjection() const { return _projection; } + const Transform& getView() const { return _view; } + + gpu::FramebufferPointer framebuffer; + gpu::TexturePointer map; + protected: + model::LightPointer _light; + std::shared_ptr _frustum; + glm::mat4 _projection; + Transform _view; + }; + using ShadowPointer = std::shared_ptr; + + class Light { + public: + Light(Shadow&& shadow) : shadow{ shadow } {} + + model::LightPointer light; + Shadow shadow; + }; + using LightPointer = std::shared_ptr; + using Lights = std::vector; + + const LightPointer& addLight(model::LightPointer light); + // TODO: removeLight + + Lights lights; +}; + +#endif