Refactored lighting manager

This commit is contained in:
Michaël Lemaire 2015-09-25 00:12:31 +02:00
parent ba02442fea
commit 6f2d23d960
16 changed files with 269 additions and 143 deletions

View file

@ -15,6 +15,7 @@
#include "Scenery.h"
#include "AtmosphereDefinition.h"
#include "AtmosphereRenderer.h"
#include "AtmosphereResult.h"
#include "SoftwareRenderer.h"
#include "WaterRenderer.h"
#include "LightComponent.h"
@ -1153,6 +1154,10 @@ AtmosphereModelBruneton::AtmosphereModelBruneton(SoftwareRenderer *parent):
{
}
AtmosphereModelBruneton::~AtmosphereModelBruneton()
{
}
AtmosphereResult AtmosphereModelBruneton::getSkyColor(Vector3 eye, const Vector3 &direction, const Vector3 &sun_position, const Color &base)
{
Vector3 x = {0.0, Rg + eye.y * WORLD_SCALING, 0.0};
@ -1215,12 +1220,12 @@ AtmosphereResult AtmosphereModelBruneton::applyAerialPerspective(Vector3 locatio
return result;
}
void AtmosphereModelBruneton::fillLightingStatus(LightStatus *status, const Vector3 &, int)
bool AtmosphereModelBruneton::getLightsAt(std::vector<LightComponent> &result, const Vector3 &location) const
{
LightComponent sun, irradiance;
double muS;
double altitude = status->getLocation().y * WORLD_SCALING;
double altitude = location.y * WORLD_SCALING;
double r0 = Rg + WORKAROUND_OFFSET + altitude;
Vector3 up = {0.0, 1.0, 0.0};
@ -1241,14 +1246,16 @@ void AtmosphereModelBruneton::fillLightingStatus(LightStatus *status, const Vect
sun.reflection = ISun;
sun.altered = 1;
status->pushComponent(sun);
result.push_back(sun);
irradiance.color = _irradiance(_irradianceTexture, r0, muS);
irradiance.direction = VECTOR_DOWN;
irradiance.reflection = 0.0;
irradiance.altered = 0;
status->pushComponent(irradiance);
result.push_back(irradiance);
return true;
}
Texture2D *AtmosphereModelBruneton::getTextureTransmittance() const

View file

@ -3,19 +3,20 @@
#include "software_global.h"
#include "AtmosphereResult.h"
#include "LightSource.h"
namespace paysages {
namespace software {
class SOFTWARESHARED_EXPORT AtmosphereModelBruneton
class SOFTWARESHARED_EXPORT AtmosphereModelBruneton: public LightSource
{
public:
AtmosphereModelBruneton(SoftwareRenderer *parent);
virtual ~AtmosphereModelBruneton();
AtmosphereResult getSkyColor(Vector3 eye, const Vector3 &direction, const Vector3 &sun_position, const Color &base);
AtmosphereResult applyAerialPerspective(Vector3 location, const Color &base);
void fillLightingStatus(LightStatus *status, const Vector3 &normal, int opaque);
virtual bool getLightsAt(std::vector<LightComponent> &result, const Vector3 &location) const override;
/* Functions to get access to internal textures (for opengl shaders) */
Texture2D* getTextureTransmittance() const;

View file

@ -80,15 +80,6 @@ static inline void _applyWeatherEffects(AtmosphereDefinition* definition, Atmosp
BaseAtmosphereRenderer::BaseAtmosphereRenderer(SoftwareRenderer* renderer):
parent(renderer)
{
}
void BaseAtmosphereRenderer::getLightingStatus(LightStatus* status, Vector3, int)
{
for (LightComponent light:lights)
{
status->pushComponent(light);
}
}
AtmosphereResult BaseAtmosphereRenderer::applyAerialPerspective(Vector3, Color base)
@ -109,50 +100,14 @@ AtmosphereResult BaseAtmosphereRenderer::getSkyColor(Vector3)
Vector3 BaseAtmosphereRenderer::getSunDirection(bool cache) const
{
if (cache and lights.size() > 0)
{
return lights[0].direction.scale(-1.0);
}
else
{
AtmosphereDefinition* atmosphere = getDefinition();
double sun_angle = (atmosphere->propDayTime()->getValue() + 0.75) * M_PI * 2.0;
return Vector3(cos(sun_angle), sin(sun_angle), 0.0);
}
}
void BaseAtmosphereRenderer::setBasicLights()
bool BaseAtmosphereRenderer::getLightsAt(std::vector<LightComponent> &, const Vector3 &) const
{
LightComponent light;
lights.clear();
light.color.r = 0.6;
light.color.g = 0.6;
light.color.b = 0.6;
light.direction.x = -1.0;
light.direction.y = -0.5;
light.direction.z = 1.0;
light.direction = light.direction.normalize();
light.altered = 1;
light.reflection = 0.0;
lights.push_back(light);
light.color.r = 0.2;
light.color.g = 0.2;
light.color.b = 0.2;
light.direction.x = 1.0;
light.direction.y = -0.5;
light.direction.z = -1.0;
light.direction = light.direction.normalize();
light.altered = 0;
light.reflection = 0.0;
lights.push_back(light);
}
void BaseAtmosphereRenderer::setStaticLights(const std::vector<LightComponent> &lights)
{
this->lights = lights;
return false;
}
AtmosphereDefinition* BaseAtmosphereRenderer::getDefinition() const
@ -171,12 +126,6 @@ SoftwareBrunetonAtmosphereRenderer::~SoftwareBrunetonAtmosphereRenderer()
delete model;
}
void SoftwareBrunetonAtmosphereRenderer::getLightingStatus(LightStatus* status, Vector3 normal, int opaque)
{
model->fillLightingStatus(status, normal, opaque);
parent->getNightSky()->fillLightingStatus(status, normal, opaque);
}
AtmosphereResult SoftwareBrunetonAtmosphereRenderer::applyAerialPerspective(Vector3 location, Color base)
{
AtmosphereDefinition* definition = getDefinition();
@ -258,3 +207,11 @@ AtmosphereResult SoftwareBrunetonAtmosphereRenderer::getSkyColor(Vector3 directi
return result;
}
bool SoftwareBrunetonAtmosphereRenderer::getLightsAt(std::vector<LightComponent> &result, const Vector3 &location) const
{
bool changed = false;
changed |= model->getLightsAt(result, location);
changed |= parent->getNightSky()->getLightsAt(result, location);
return changed;
}

View file

@ -3,30 +3,26 @@
#include "software_global.h"
#include "Color.h"
#include "LightComponent.h"
#include "LightSource.h"
namespace paysages {
namespace software {
class BaseAtmosphereRenderer
class BaseAtmosphereRenderer: public LightSource
{
public:
BaseAtmosphereRenderer(SoftwareRenderer* parent);
virtual ~BaseAtmosphereRenderer() {}
virtual void getLightingStatus(LightStatus* status, Vector3 normal, int opaque);
virtual AtmosphereResult applyAerialPerspective(Vector3 location, Color base);
virtual AtmosphereResult getSkyColor(Vector3 direction);
virtual Vector3 getSunDirection(bool cache=true) const;
void setBasicLights();
void setStaticLights(const std::vector<LightComponent> &lights);
virtual bool getLightsAt(std::vector<LightComponent> &result, const Vector3 &location) const override;
protected:
virtual AtmosphereDefinition* getDefinition() const;
SoftwareRenderer* parent;
std::vector<LightComponent> lights;
};
class SoftwareBrunetonAtmosphereRenderer: public BaseAtmosphereRenderer
@ -35,10 +31,11 @@ public:
SoftwareBrunetonAtmosphereRenderer(SoftwareRenderer* parent);
virtual ~SoftwareBrunetonAtmosphereRenderer();
virtual void getLightingStatus(LightStatus* status, Vector3 normal, int opaque) override;
virtual AtmosphereResult applyAerialPerspective(Vector3 location, Color base) override;
virtual AtmosphereResult getSkyColor(Vector3 direction) override;
virtual bool getLightsAt(std::vector<LightComponent> &result, const Vector3 &location) const override;
inline const AtmosphereModelBruneton* getModel() const {return model;}
private:

View file

@ -0,0 +1 @@
#include "LightSource.h"

View file

@ -0,0 +1,28 @@
#ifndef LIGHTSOURCE_H
#define LIGHTSOURCE_H
#include "software_global.h"
namespace paysages {
namespace software {
/**
* Source of dynamic lights.
*/
class SOFTWARESHARED_EXPORT LightSource
{
public:
LightSource() = default;
/**
* Get the list of raw lights that may be applied at a given location.
*
* Returns true if lights were added to *result*.
*/
virtual bool getLightsAt(std::vector<LightComponent> &result, const Vector3 &location) const = 0;
};
}
}
#endif // LIGHTSOURCE_H

View file

@ -2,6 +2,8 @@
#include "LightFilter.h"
#include "LightComponent.h"
#include "LightStatus.h"
#include "LightSource.h"
#include "Color.h"
#include "SurfaceMaterial.h"
@ -10,9 +12,55 @@ LightingManager::LightingManager()
specularity = true;
}
int LightingManager::getStaticLightsCount() const
{
return static_lights.size();
}
int LightingManager::getSourcesCount() const
{
return sources.size();
}
int LightingManager::getFiltersCount() const
{
return filters.size();
}
void LightingManager::clearStaticLights()
{
static_lights.clear();
}
void LightingManager::addStaticLight(const LightComponent &light)
{
static_lights.push_back(light);
}
void LightingManager::registerSource(LightSource *source)
{
if (std::find(sources.begin(), sources.end(), source) == sources.end())
{
sources.push_back(source);
}
}
void LightingManager::unregisterSource(LightSource *source)
{
sources.erase(std::find(sources.begin(), sources.end(), source));
}
void LightingManager::registerFilter(LightFilter* filter)
{
if (std::find(filters.begin(), filters.end(), filter) == filters.end())
{
filters.push_back(filter);
}
}
void LightingManager::unregisterFilter(LightFilter *filter)
{
filters.erase(std::find(filters.begin(), filters.end(), filter));
}
bool LightingManager::alterLight(LightComponent &component, const Vector3 &location)
@ -119,3 +167,26 @@ Color LightingManager::applyFinalComponent(const LightComponent &component, cons
return result;
}
Color LightingManager::apply(const Vector3 &eye, const Vector3 &location, const Vector3 &normal, const SurfaceMaterial &material)
{
LightStatus status(this, location, eye);
for (auto &light: static_lights)
{
status.pushComponent(light);
}
for (auto source: sources)
{
std::vector<LightComponent> lights;
if (source->getLightsAt(lights, location))
{
for (auto &light: lights)
{
status.pushComponent(light);
}
}
}
return status.apply(normal, material);
}

View file

@ -3,44 +3,86 @@
#include "software_global.h"
#include "LightComponent.h"
namespace paysages {
namespace software {
/**
* @brief Global lighting manager.
*
* This manager handles the light filters and final light rendering.
* This manager handles the lights, light filters and final light rendering.
*
* There are both static and dynamic lights.
* A dynamic light depends on the location at which the lighting occurs.
*/
class SOFTWARESHARED_EXPORT LightingManager
{
public:
LightingManager();
/**
* @brief Register a filter that will receive all alterable lights.
*/
void registerFilter(LightFilter* filter);
int getStaticLightsCount() const;
int getSourcesCount() const;
int getFiltersCount() const;
/**
* @brief Alter the light component at a given location.
* @return true if the light is useful
* Clear the static lights.
*/
void clearStaticLights();
/**
* Add a static light.
*/
void addStaticLight(const LightComponent &light);
/**
* Register a source of dynamic lighting.
*/
void registerSource(LightSource *source);
/**
* Remove a registered light source.
*/
void unregisterSource(LightSource *source);
/**
* Register a filter that will receive all alterable lights.
*/
void registerFilter(LightFilter *filter);
/**
* Remove a registered light filter.
*/
void unregisterFilter(LightFilter *filter);
/**
* Alter the light component at a given location.
*
* Returns true if the light is useful
*/
bool alterLight(LightComponent &component, const Vector3 &location);
/**
* @brief Enable or disable the specularity lighting.
* Enable or disable the specularity lighting.
*/
void setSpecularity(bool enabled);
/**
* @brief Apply a final component on a surface material.
* Apply a final component on a surface material.
*/
Color applyFinalComponent(const LightComponent &component, const Vector3 &eye, const Vector3 &location, const Vector3 &normal, const SurfaceMaterial &material);
/**
* Apply lighting to a surface at a given location.
*/
Color apply(const Vector3 &eye, const Vector3 &location, const Vector3 &normal, const SurfaceMaterial &material);
private:
int specularity;
std::vector<LightComponent> static_lights;
std::vector<LightFilter *> filters;
std::vector<LightSource *> sources;
std::vector<LightFilter*> filters;
};
}

View file

@ -95,7 +95,7 @@ const Color NightSky::getColor(double altitude, const Vector3 &direction)
}
void NightSky::fillLightingStatus(LightStatus *status, const Vector3 &, int)
bool NightSky::getLightsAt(std::vector<LightComponent> &result, const Vector3 &location) const
{
LightComponent moon, sky;
@ -107,12 +107,14 @@ void NightSky::fillLightingStatus(LightStatus *status, const Vector3 &, int)
moon.reflection = 0.2;
moon.altered = 1;
status->pushComponent(moon);
result.push_back(moon);
sky.color = Color(0.01, 0.012, 0.03);
sky.direction = VECTOR_DOWN;
sky.reflection = 0.0;
sky.altered = 0;
status->pushComponent(sky);
result.push_back(sky);
return true;
}

View file

@ -3,13 +3,15 @@
#include "software_global.h"
#include "LightSource.h"
namespace paysages {
namespace software {
/*!
* \brief Night sky renderer.
*/
class SOFTWARESHARED_EXPORT NightSky
class SOFTWARESHARED_EXPORT NightSky: public LightSource
{
public:
NightSky(SoftwareRenderer* renderer);
@ -26,7 +28,7 @@ public:
*/
virtual const Color getColor(double altitude, const Vector3 &direction);
virtual void fillLightingStatus(LightStatus *status, const Vector3 &normal, int opaque);
virtual bool getLightsAt(std::vector<LightComponent> &result, const Vector3 &location) const override;
private:
SoftwareRenderer* renderer;

View file

@ -41,6 +41,7 @@ SoftwareRenderer::SoftwareRenderer(Scenery* scenery):
lighting->registerFilter(water_renderer);
lighting->registerFilter(terrain_renderer);
lighting->registerFilter(clouds_renderer);
lighting->registerSource(atmosphere_renderer);
setQuality(0.5);
}
@ -66,7 +67,8 @@ void SoftwareRenderer::prepare()
scenery->validate();
// Prepare sub renderers
// TODO Don't recreate the renderer each time
// TODO Don't recreate the renderer each time, only when it changes
lighting->unregisterSource(atmosphere_renderer);
delete atmosphere_renderer;
if (getScenery()->getAtmosphere()->model == AtmosphereDefinition::ATMOSPHERE_MODEL_BRUNETON)
{
@ -76,6 +78,7 @@ void SoftwareRenderer::prepare()
{
atmosphere_renderer = new BaseAtmosphereRenderer(this);
}
lighting->registerSource(atmosphere_renderer);
clouds_renderer->update();
terrain_renderer->update();
@ -98,50 +101,9 @@ void SoftwareRenderer::setQuality(double quality)
render_quality = (int)(quality * 9.0) + 1;
}
void SoftwareRenderer::disableAtmosphere()
{
LightComponent light;
std::vector<LightComponent> lights;
light.color.r = 1.5;
light.color.g = 1.5;
light.color.b = 1.5;
light.direction.x = -1.0;
light.direction.y = -0.3;
light.direction.z = 1.0;
light.direction = light.direction.normalize();
light.altered = 1;
light.reflection = 0.0;
lights.push_back(light);
light.color.r = 0.25;
light.color.g = 0.25;
light.color.b = 0.265;
light.direction.x = 1.0;
light.direction.y = -0.5;
light.direction.z = -1.0;
light.direction = light.direction.normalize();
light.altered = 0;
light.reflection = 0.0;
lights.push_back(light);
disableAtmosphere(lights);
}
void SoftwareRenderer::disableAtmosphere(const std::vector<LightComponent> &lights)
{
scenery->getAtmosphere()->model = AtmosphereDefinition::ATMOSPHERE_MODEL_DISABLED;
delete atmosphere_renderer;
atmosphere_renderer = new BaseAtmosphereRenderer(this);
atmosphere_renderer->setStaticLights(lights);
}
Color SoftwareRenderer::applyLightingToSurface(const Vector3 &location, const Vector3 &normal, const SurfaceMaterial &material)
{
LightStatus status(lighting, location, getCameraLocation(location));
atmosphere_renderer->getLightingStatus(&status, normal, 0);
return status.apply(normal, material);
return lighting->apply(getCameraLocation(location), location, normal, material);
}
Color SoftwareRenderer::applyMediumTraversal(Vector3 location, Color color)

View file

@ -45,16 +45,6 @@ public:
*/
virtual void setQuality(double quality);
/*!
* \brief Disable atmosphere and sky lighting, replacing it by static lights.
*
* This function needs to be called after each prepare().
*
* WARNING : This method changes the scenery attached to the renderer !
*/
void disableAtmosphere();
void disableAtmosphere(const std::vector<LightComponent> &lights);
inline Scenery* getScenery() const {return scenery;}
inline BaseAtmosphereRenderer* getAtmosphereRenderer() const {return atmosphere_renderer;}

View file

@ -51,7 +51,8 @@ SOURCES += SoftwareRenderer.cpp \
clouds/CloudModelAltoCumulus.cpp \
clouds/CloudModelCirrus.cpp \
clouds/CloudModelCumuloNimbus.cpp \
RenderProgress.cpp
RenderProgress.cpp \
LightSource.cpp
HEADERS += SoftwareRenderer.h\
software_global.h \
@ -92,7 +93,8 @@ HEADERS += SoftwareRenderer.h\
clouds/CloudModelAltoCumulus.h \
clouds/CloudModelCirrus.h \
clouds/CloudModelCumuloNimbus.h \
RenderProgress.h
RenderProgress.h \
LightSource.h
unix:!symbian {
maemo5 {

View file

@ -43,6 +43,7 @@ namespace software {
class LightStatus;
class LightFilter;
class LightComponent;
class LightSource;
class NightSky;

View file

@ -0,0 +1,62 @@
#include "BaseTestCase.h"
#include "LightingManager.h"
#include "LightSource.h"
#include "LightFilter.h"
class FakeLightSource: public LightSource
{
virtual bool getLightsAt(std::vector<LightComponent> &, const Vector3 &) const override
{
return false;
}
};
TEST(LightingManager, registerSource)
{
LightingManager manager;
FakeLightSource source;
EXPECT_EQ(0, manager.getSourcesCount());
manager.registerSource(&source);
EXPECT_EQ(1, manager.getSourcesCount());
manager.registerSource(&source);
EXPECT_EQ(1, manager.getSourcesCount());
manager.unregisterSource(&source);
EXPECT_EQ(0, manager.getSourcesCount());
}
class FakeLightFilter: public LightFilter
{
virtual bool applyLightFilter(LightComponent &, const Vector3 &) override
{
return false;
}
};
TEST(LightingManager, registerFilter)
{
LightingManager manager;
FakeLightFilter filter;
EXPECT_EQ(0, manager.getFiltersCount());
manager.registerFilter(&filter);
EXPECT_EQ(1, manager.getFiltersCount());
manager.registerFilter(&filter);
EXPECT_EQ(1, manager.getFiltersCount());
manager.unregisterFilter(&filter);
EXPECT_EQ(0, manager.getFiltersCount());
}

View file

@ -28,7 +28,8 @@ SOURCES += main.cpp \
DiffManager_Test.cpp \
ColorHSL_Test.cpp \
RenderProgress_Test.cpp \
IntNode_Test.cpp
IntNode_Test.cpp \
LightingManager_Test.cpp
HEADERS += \
BaseTestCase.h