diff --git a/src/definition/AtmosphereDefinition.cpp b/src/definition/AtmosphereDefinition.cpp index c6dc88f..d1fd3c5 100644 --- a/src/definition/AtmosphereDefinition.cpp +++ b/src/definition/AtmosphereDefinition.cpp @@ -1,6 +1,7 @@ #include "AtmosphereDefinition.h" #include "PackStream.h" +#include "RandomGenerator.h" AtmosphereDefinition::AtmosphereDefinition(BaseDefinition* parent): BaseDefinition(parent) @@ -20,6 +21,18 @@ void AtmosphereDefinition::save(PackStream* stream) const stream->write(&sun_radius); stream->write(&dome_lighting); stream->write(&humidity); + stream->write(&moon_radius); + stream->write(&moon_theta); + stream->write(&moon_phi); + + int star_count = stars.size(); + stream->write(&star_count); + for (const auto &star : stars) + { + star.location.save(stream); + star.col.save(stream); + stream->write(&star.radius); + } } void AtmosphereDefinition::load(PackStream* stream) @@ -31,6 +44,22 @@ void AtmosphereDefinition::load(PackStream* stream) stream->read(&sun_radius); stream->read(&dome_lighting); stream->read(&humidity); + stream->read(&moon_radius); + stream->read(&moon_theta); + stream->read(&moon_phi); + + int star_count; + stream->read(&star_count); + for (int i = 0; i < star_count; i++) + { + Star star; + + star.location.load(stream); + star.col.load(stream); + stream->read(&star.radius); + + stars.push_back(star); + } validate(); } @@ -46,6 +75,10 @@ void AtmosphereDefinition::copy(BaseDefinition* _destination) const destination->sun_radius = sun_radius; destination->dome_lighting = dome_lighting; destination->humidity = humidity; + destination->moon_radius = moon_radius; + destination->moon_theta = moon_theta; + destination->moon_phi = moon_phi; + destination->stars = stars; destination->validate(); } @@ -79,6 +112,9 @@ void AtmosphereDefinition::applyPreset(AtmospherePreset preset) sun_color.b = 0.9; sun_color.a = 1.0; sun_radius = 1.0; + moon_radius = 1.0; + moon_theta = 0.3; + moon_phi = 0.5; humidity = 0.1; model = ATMOSPHERE_MODEL_BRUNETON; @@ -118,5 +154,29 @@ void AtmosphereDefinition::applyPreset(AtmospherePreset preset) ; } + generateStars(5000); + validate(); } + +void AtmosphereDefinition::generateStars(int count) +{ + stars.clear(); + + for (int i = 0; i < count; ++i) + { + Star star; + + star.location = Vector3((RandomGenerator::random() - 0.5) * 100000.0, (RandomGenerator::random() - 0.5) * 100000.0, (RandomGenerator::random() - 0.5) * 100000.0); + if (star.location.getNorm() < 30000.0) + { + i--; + continue; + } + double brillance = RandomGenerator::random() * 0.05 + 0.1; + star.col = Color(brillance + RandomGenerator::random() * 0.03, brillance + RandomGenerator::random() * 0.03, brillance + RandomGenerator::random() * 0.03, 1.0); + star.radius = 30.0 + RandomGenerator::random() * 20.0; + + stars.push_back(star); + } +} diff --git a/src/definition/AtmosphereDefinition.h b/src/definition/AtmosphereDefinition.h index ae3a635..39d4838 100644 --- a/src/definition/AtmosphereDefinition.h +++ b/src/definition/AtmosphereDefinition.h @@ -5,6 +5,7 @@ #include "BaseDefinition.h" +#include "Vector3.h" #include "Color.h" namespace paysages { @@ -12,6 +13,14 @@ namespace definition { class AtmosphereDefinition : public BaseDefinition { +public: + typedef struct + { + Vector3 location; + double radius; + Color col; + } Star; + public: typedef enum { @@ -38,6 +47,7 @@ public: virtual void validate() override; void applyPreset(AtmospherePreset preset); + void generateStars(int count); public: AtmosphereModel model; @@ -48,7 +58,13 @@ public: double sun_radius; double dome_lighting; + double moon_radius; + double moon_theta; + double moon_phi; + double _daytime; + + std::vector stars; }; } diff --git a/src/interface/desktop/formatmosphere.cpp b/src/interface/desktop/formatmosphere.cpp index 6a1519f..37abd33 100644 --- a/src/interface/desktop/formatmosphere.cpp +++ b/src/interface/desktop/formatmosphere.cpp @@ -42,6 +42,9 @@ FormAtmosphere::FormAtmosphere(QWidget *parent): addInputDouble(tr("Sun radius"), &_definition->sun_radius, 0.0, 5.0, 0.05, 0.5); //addInputDouble(tr("Influence of skydome on lighting"), &_definition->dome_lighting, 0.0, 2.0, 0.01, 0.1); addInputDouble(tr("Humidity"), &_definition->humidity, 0.0, 1.0, 0.01, 0.1); + addInputDouble(tr("Moon radius"), &_definition->moon_radius, 0.5, 3.0, 0.03, 0.3); + addInputDouble(tr("Moon location (horizontal)"), &_definition->moon_phi, 0.0, M_PI * 2.0, 0.05, 0.5); + addInputDouble(tr("Moon location (vertical)"), &_definition->moon_theta, -0.1, M_PI * 0.5, 0.02, 0.2); revertConfig(); } diff --git a/src/render/opengl/OpenGLRenderer.cpp b/src/render/opengl/OpenGLRenderer.cpp index e86ef48..7df1940 100644 --- a/src/render/opengl/OpenGLRenderer.cpp +++ b/src/render/opengl/OpenGLRenderer.cpp @@ -21,7 +21,7 @@ OpenGLRenderer::OpenGLRenderer(Scenery* scenery): shared_state = new OpenGLSharedState(); shared_state->set("viewDistance", 300.0); - shared_state->set("exposure", 1.6); + shared_state->set("exposure", 1.2); skybox = new OpenGLSkybox(this); water = new OpenGLWater(this); diff --git a/src/render/opengl/shaders/skybox.frag b/src/render/opengl/shaders/skybox.frag index 8acc7da..604677b 100644 --- a/src/render/opengl/shaders/skybox.frag +++ b/src/render/opengl/shaders/skybox.frag @@ -15,5 +15,7 @@ void main(void) vec3 attenuation; vec3 inscattering = _getInscatterColor(x, t, v, s, r, mu, attenuation); - gl_FragColor = applyToneMapping(sunTransmittance + vec4(inscattering, 0.0)); + gl_FragColor = vec4(0.01, 0.012, 0.03, 1.0); // night sky + gl_FragColor += sunTransmittance + vec4(inscattering, 0.0); + gl_FragColor = applyToneMapping(gl_FragColor); } diff --git a/src/render/opengl/shaders/tonemapping.frag b/src/render/opengl/shaders/tonemapping.frag index 2ea09af..5614cab 100644 --- a/src/render/opengl/shaders/tonemapping.frag +++ b/src/render/opengl/shaders/tonemapping.frag @@ -12,21 +12,23 @@ float _uncharted2Tonemap(float x) return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F; } -vec4 applyToneMapping(vec4 color) -{ - return vec4(((color * exposure) / (1.0 + color * exposure)).rgb, 1.0); -} - /*vec4 applyToneMapping(vec4 color) { + float e = mix(exposure, exposure * 3.0, clamp(-sunDirection.y * 10.0, 0.0, 1.0)); + return vec4(((color * e) / (1.0 + color * e)).rgb, 1.0); +}*/ + +vec4 applyToneMapping(vec4 color) +{ + float e = mix(exposure, exposure * 3.0, clamp(-sunDirection.y * 10.0, 0.0, 1.0)); float W = 11.2; float white_scale = 1.0 / _uncharted2Tonemap(W); vec4 result; - result.r = pow(_uncharted2Tonemap(color.r * exposure) * white_scale, 1.0 / 2.2); - result.g = pow(_uncharted2Tonemap(color.g * exposure) * white_scale, 1.0 / 2.2); - result.b = pow(_uncharted2Tonemap(color.b * exposure) * white_scale, 1.0 / 2.2); + result.r = pow(_uncharted2Tonemap(color.r * e) * white_scale, 1.0 / 2.2); + result.g = pow(_uncharted2Tonemap(color.g * e) * white_scale, 1.0 / 2.2); + result.b = pow(_uncharted2Tonemap(color.b * e) * white_scale, 1.0 / 2.2); result.a = 1.0; return result; -}*/ +} diff --git a/src/render/software/AtmosphereModelBruneton.cpp b/src/render/software/AtmosphereModelBruneton.cpp index ccaed98..330e155 100644 --- a/src/render/software/AtmosphereModelBruneton.cpp +++ b/src/render/software/AtmosphereModelBruneton.cpp @@ -1154,7 +1154,7 @@ AtmosphereModelBruneton::AtmosphereModelBruneton(SoftwareRenderer *parent): { } -AtmosphereResult AtmosphereModelBruneton::getSkyColor(Vector3 eye, const Vector3 &direction, const Vector3 &sun_position, const Color &) +AtmosphereResult AtmosphereModelBruneton::getSkyColor(Vector3 eye, const Vector3 &direction, const Vector3 &sun_position, const Color &base) { double yoffset = GROUND_OFFSET - parent->getWaterRenderer()->getHeightInfo().base_height; eye.y += yoffset; @@ -1177,7 +1177,7 @@ AtmosphereResult AtmosphereModelBruneton::getSkyColor(Vector3 eye, const Vector3 /*result.base.r = base.r + sunColor.r; result.base.g = base.g + sunColor.g; result.base.b = base.b + sunColor.b;*/ - result.base = sunColor; + result.base = base.add(sunColor); result.inscattering = _getInscatterColor(&x, &t, v, s, &r, &mu, &attenuation); /* S[L]-T(x,xs)S[l]|xs */ /* TODO Use atmosphere attenuation */ result.distance = SPHERE_SIZE; @@ -1254,7 +1254,14 @@ void AtmosphereModelBruneton::fillLightingStatus(LightStatus *status, const Vect Vector3 s = sun_position.sub(x).normalize(); muS = up.dotProduct(s); - sun.color = _transmittanceWithShadow(r0, muS); + if (altitude * WORLD_SCALING > RL) + { + sun.color = parent->getScenery()->getAtmosphere()->sun_color; + } + else + { + sun.color = _transmittanceWithShadow(r0, muS); + } sun.direction = s.scale(-1.0); sun.reflection = ISun; sun.altered = 1; diff --git a/src/render/software/AtmosphereRenderer.cpp b/src/render/software/AtmosphereRenderer.cpp index 5b79eba..49e8d5f 100644 --- a/src/render/software/AtmosphereRenderer.cpp +++ b/src/render/software/AtmosphereRenderer.cpp @@ -8,6 +8,7 @@ #include "LightComponent.h" #include "LightStatus.h" #include "Scenery.h" +#include "NightSky.h" /* Factor to convert software units to kilometers */ #define WORLD_SCALING 0.05 @@ -170,7 +171,8 @@ SoftwareBrunetonAtmosphereRenderer::~SoftwareBrunetonAtmosphereRenderer() void SoftwareBrunetonAtmosphereRenderer::getLightingStatus(LightStatus* status, Vector3 normal, int opaque) { - return model->fillLightingStatus(status, normal, opaque); + model->fillLightingStatus(status, normal, opaque); + parent->getNightSky()->fillLightingStatus(status, normal, opaque); } AtmosphereResult SoftwareBrunetonAtmosphereRenderer::applyAerialPerspective(Vector3 location, Color base) @@ -207,8 +209,12 @@ AtmosphereResult SoftwareBrunetonAtmosphereRenderer::getSkyColor(Vector3 directi direction = direction.normalize(); sun_position = sun_direction.scale(SUN_DISTANCE_SCALED); - /* Get sun shape */ base = COLOR_BLACK; + + /* Get night sky */ + base = base.add(parent->getNightSky()->getColor(camera_location.y, direction)); + + /* Get sun shape */ /*if (v3Dot(sun_direction, direction) >= 0) { double sun_radius = definition->sun_radius * SUN_RADIUS_SCALED * 5.0; // FIXME Why should we multiply by 5 ? @@ -233,8 +239,6 @@ AtmosphereResult SoftwareBrunetonAtmosphereRenderer::getSkyColor(Vector3 directi } }*/ - /* TODO Get stars */ - /* Get scattering */ AtmosphereResult result; Vector3 location = camera_location.add(direction.scale(6421.0)); diff --git a/src/render/software/LightStatus.cpp b/src/render/software/LightStatus.cpp index a424267..ae26119 100644 --- a/src/render/software/LightStatus.cpp +++ b/src/render/software/LightStatus.cpp @@ -6,6 +6,7 @@ LightStatus::LightStatus(LightingManager *manager, const Vector3 &location, const Vector3 &eye) { + this->max_power = 0.0; this->manager = manager; this->location = location; this->eye = eye; @@ -13,8 +14,19 @@ LightStatus::LightStatus(LightingManager *manager, const Vector3 &location, cons void LightStatus::pushComponent(LightComponent component) { + double power = component.color.getPower(); + if (component.altered && (power < max_power * 0.05 || power < 0.001)) + { + // Exclude filtered lights that are owerpowered by a previous one + return; + } + if (manager->alterLight(component, location)) { + if (power > max_power) + { + max_power = power; + } components.push_back(component); } } diff --git a/src/render/software/LightStatus.h b/src/render/software/LightStatus.h index 048bd31..947ee8a 100644 --- a/src/render/software/LightStatus.h +++ b/src/render/software/LightStatus.h @@ -25,6 +25,7 @@ public: Color apply(const Vector3 &normal, const SurfaceMaterial &material); private: + double max_power; LightingManager* manager; Vector3 location; Vector3 eye; diff --git a/src/render/software/NightSky.cpp b/src/render/software/NightSky.cpp new file mode 100644 index 0000000..b8c1cdb --- /dev/null +++ b/src/render/software/NightSky.cpp @@ -0,0 +1,112 @@ +#include "NightSky.h" + +#include "Color.h" +#include "Vector3.h" +#include "Geometry.h" +#include "SoftwareRenderer.h" +#include "Scenery.h" +#include "AtmosphereDefinition.h" +#include "SurfaceMaterial.h" +#include "LightComponent.h" +#include "LightStatus.h" + +#define WORLD_SCALING 0.05 +#define MOON_DISTANCE 384403.0 +#define MOON_DISTANCE_SCALED (MOON_DISTANCE / WORLD_SCALING) +#define MOON_RADIUS 1737.4 +#define MOON_RADIUS_SCALED (MOON_RADIUS / WORLD_SCALING) + +NightSky::NightSky(SoftwareRenderer* renderer): + renderer(renderer) +{ +} + +NightSky::~NightSky() +{ +} + +void NightSky::update() +{ +} + +const Color NightSky::getColor(double altitude, const Vector3 &direction) +{ + AtmosphereDefinition* atmosphere = renderer->getScenery()->getAtmosphere(); + Color result(0.01, 0.012, 0.03); + + Vector3 location(0.0, altitude, 0.0); + + // Get stars + for (const auto &star: atmosphere->stars) + { + if (star.location.dotProduct(direction) >= 0) + { + double radius = star.radius; + Vector3 hit1, hit2; + int hits = Geometry::rayIntersectSphere(location, direction, star.location, radius, &hit1, &hit2); + if (hits > 1) + { + double dist = hit2.sub(hit1).getNorm() / radius; // distance between intersection points (relative to radius) + + Color color = star.col; + if (dist <= 0.5) + { + color.a *= 1.0 - dist / 0.5; + } + result.mask(color); + } + } + } + + // Get moon + VectorSpherical moon_location_s = {MOON_DISTANCE_SCALED, atmosphere->moon_theta, -atmosphere->moon_phi}; + Vector3 moon_position(moon_location_s); + Vector3 moon_direction = moon_position.normalize(); + if (moon_direction.dotProduct(direction) >= 0) + { + double moon_radius = MOON_RADIUS_SCALED * 5.0 * atmosphere->moon_radius; + Vector3 hit1, hit2; + int hits = Geometry::rayIntersectSphere(location, direction, moon_position, moon_radius, &hit1, &hit2); + if (hits > 1) + { + double dist = hit2.sub(hit1).getNorm() / moon_radius; // distance between intersection points (relative to radius) + + Vector3 nearest = (hit1.sub(location).getNorm() > hit2.sub(location).getNorm()) ? hit2 : hit1; + SurfaceMaterial moon_material(Color(3.0, 3.0, 3.0)); + moon_material.validate(); + + Color moon_color = renderer->applyLightingToSurface(nearest, nearest.sub(moon_position).normalize(), moon_material); + if (dist <= 0.05) + { + moon_color.a *= 1.0 - dist / 0.05; + } + result.mask(moon_color); + } + } + + + return result; + +} + +void NightSky::fillLightingStatus(LightStatus *status, const Vector3 &, int) +{ + LightComponent moon, sky; + + AtmosphereDefinition* atmosphere = renderer->getScenery()->getAtmosphere(); + VectorSpherical moon_location_s = {MOON_DISTANCE_SCALED, atmosphere->moon_theta, -atmosphere->moon_phi}; + + moon.color = Color(0.03, 0.03, 0.03); // TODO take moon phase into account + moon.direction = Vector3(moon_location_s).normalize().scale(-1.0); + moon.reflection = 0.2; + moon.altered = 1; + + status->pushComponent(moon); + + sky.color = Color(0.01, 0.012, 0.03); + sky.direction = VECTOR_DOWN; + sky.reflection = 0.0; + sky.altered = 0; + + status->pushComponent(sky); +} diff --git a/src/render/software/NightSky.h b/src/render/software/NightSky.h new file mode 100644 index 0000000..c1bc3c5 --- /dev/null +++ b/src/render/software/NightSky.h @@ -0,0 +1,38 @@ +#ifndef NIGHTSKY_H +#define NIGHTSKY_H + +#include "software_global.h" + +namespace paysages { +namespace software { + +/*! + * \brief Night sky renderer. + */ +class SOFTWARESHARED_EXPORT NightSky +{ +public: + NightSky(SoftwareRenderer* renderer); + virtual ~NightSky(); + + /*! + * \brief Update the night sky renderer, when the scenery or parent renderer changed. + */ + void update(); + + /*! + * \brief Get the color of the night sky at a given direction. + * \param altitude Altitude above water level, in coordinate units (not kilometers). + */ + virtual const Color getColor(double altitude, const Vector3 &direction); + + virtual void fillLightingStatus(LightStatus *status, const Vector3 &normal, int opaque); + +private: + SoftwareRenderer* renderer; +}; + +} +} + +#endif // NIGHTSKY_H diff --git a/src/render/software/SoftwareRenderer.cpp b/src/render/software/SoftwareRenderer.cpp index c0d8882..a876c83 100644 --- a/src/render/software/SoftwareRenderer.cpp +++ b/src/render/software/SoftwareRenderer.cpp @@ -14,6 +14,7 @@ #include "SkyRasterizer.h" #include "TerrainRasterizer.h" #include "WaterRasterizer.h" +#include "NightSky.h" #include "LightStatus.h" #include "LightingManager.h" #include "System.h" @@ -39,6 +40,8 @@ SoftwareRenderer::SoftwareRenderer(Scenery* scenery) textures_renderer = new TexturesRenderer(this); water_renderer = new WaterRenderer(this); + nightsky_renderer = new NightSky(this); + fluid_medium = new FluidMediumManager(this); lighting = new LightingManager(); @@ -61,6 +64,8 @@ SoftwareRenderer::~SoftwareRenderer() delete fluid_medium; delete lighting; + delete nightsky_renderer; + delete atmosphere_renderer; delete clouds_renderer; delete terrain_renderer; @@ -96,6 +101,8 @@ void SoftwareRenderer::prepare() water_renderer->update(); textures_renderer->update(); + nightsky_renderer->update(); + // Prepare global tools fluid_medium->clearMedia(); //fluid_medium->registerMedium(water_renderer); diff --git a/src/render/software/SoftwareRenderer.h b/src/render/software/SoftwareRenderer.h index 4894949..9f269f3 100644 --- a/src/render/software/SoftwareRenderer.h +++ b/src/render/software/SoftwareRenderer.h @@ -90,6 +90,8 @@ public: inline TexturesRenderer* getTexturesRenderer() const {return textures_renderer;} inline WaterRenderer* getWaterRenderer() const {return water_renderer;} + inline NightSky* getNightSky() const {return nightsky_renderer;} + inline FluidMediumManager* getFluidMediumManager() const {return fluid_medium;} inline LightingManager* getLightingManager() const {return lighting;} @@ -108,6 +110,7 @@ private: TerrainRenderer* terrain_renderer; TexturesRenderer* textures_renderer; WaterRenderer* water_renderer; + NightSky* nightsky_renderer; }; } diff --git a/src/render/software/TerrainRenderer.cpp b/src/render/software/TerrainRenderer.cpp index cd55247..66ad070 100644 --- a/src/render/software/TerrainRenderer.cpp +++ b/src/render/software/TerrainRenderer.cpp @@ -192,6 +192,12 @@ bool TerrainRenderer::applyLightFilter(LightComponent &light, const Vector3 &at) Vector3 inc_vector, direction_to_light, cursor; double inc_value, inc_base, inc_factor, height, diff, light_factor, smoothing, length; + if (at.y > definition->getHeightInfo().max_height) + { + // Location is above terrain, don't bother + return true; + } + direction_to_light = light.direction.scale(-1.0); if (direction_to_light.y < -0.05) { diff --git a/src/render/software/software.pro b/src/render/software/software.pro index 070ad32..f00ec48 100644 --- a/src/render/software/software.pro +++ b/src/render/software/software.pro @@ -35,7 +35,8 @@ SOURCES += SoftwareRenderer.cpp \ TexturesRenderer.cpp \ WaterRenderer.cpp \ RenderArea.cpp \ - RayCastingManager.cpp + RayCastingManager.cpp \ + NightSky.cpp HEADERS += SoftwareRenderer.h\ software_global.h \ @@ -60,7 +61,8 @@ HEADERS += SoftwareRenderer.h\ TexturesRenderer.h \ WaterRenderer.h \ RenderArea.h \ - RayCastingManager.h + RayCastingManager.h \ + NightSky.h unix:!symbian { maemo5 { diff --git a/src/render/software/software_global.h b/src/render/software/software_global.h index f14bf27..a7f2c68 100644 --- a/src/render/software/software_global.h +++ b/src/render/software/software_global.h @@ -40,6 +40,8 @@ namespace software { class LightStatus; class LightFilter; class LightComponent; + + class NightSky; } }