Merge branch 'night_sky'

This commit is contained in:
Michaël Lemaire 2013-12-26 19:28:24 +01:00
commit ce7aa1e179
17 changed files with 297 additions and 20 deletions

View file

@ -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);
}
}

View file

@ -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<Star> stars;
};
}

View file

@ -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();
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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;
}*/
}

View file

@ -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;

View file

@ -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));

View file

@ -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);
}
}

View file

@ -25,6 +25,7 @@ public:
Color apply(const Vector3 &normal, const SurfaceMaterial &material);
private:
double max_power;
LightingManager* manager;
Vector3 location;
Vector3 eye;

View file

@ -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);
}

View file

@ -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

View file

@ -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);

View file

@ -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;
};
}

View file

@ -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)
{

View file

@ -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 {

View file

@ -40,6 +40,8 @@ namespace software {
class LightStatus;
class LightFilter;
class LightComponent;
class NightSky;
}
}