2013-11-12 20:34:35 +00:00
|
|
|
#include "AtmosphereRenderer.h"
|
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
#include "SoftwareRenderer.h"
|
2013-11-15 23:27:40 +00:00
|
|
|
#include "AtmosphereDefinition.h"
|
2013-12-08 19:54:34 +00:00
|
|
|
#include "AtmosphereModelBruneton.h"
|
|
|
|
#include "AtmosphereResult.h"
|
|
|
|
#include "LightComponent.h"
|
|
|
|
#include "LightStatus.h"
|
2013-11-12 20:34:35 +00:00
|
|
|
#include "Scenery.h"
|
2013-12-26 14:36:15 +00:00
|
|
|
#include "NightSky.h"
|
2015-08-18 18:31:11 +00:00
|
|
|
#include "FloatNode.h"
|
2013-11-12 20:34:35 +00:00
|
|
|
|
2013-12-08 19:54:34 +00:00
|
|
|
/* Factor to convert software units to kilometers */
|
|
|
|
#define WORLD_SCALING 0.05
|
|
|
|
#define SUN_DISTANCE 149597870.0
|
|
|
|
#define SUN_DISTANCE_SCALED (SUN_DISTANCE / WORLD_SCALING)
|
|
|
|
#define SUN_RADIUS 6.955e5
|
|
|
|
#define SUN_RADIUS_SCALED (SUN_RADIUS / WORLD_SCALING)
|
|
|
|
|
2013-11-12 20:34:35 +00:00
|
|
|
static inline double _getDayFactor(double daytime)
|
|
|
|
{
|
|
|
|
daytime = 1.0 - fabs(0.5 - daytime) / 0.5;
|
|
|
|
return daytime < 0.45 ? 0.0 : sqrt((daytime - 0.45) / 0.55);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void _applyWeatherEffects(AtmosphereDefinition* definition, AtmosphereResult* result)
|
|
|
|
{
|
2013-12-15 13:28:46 +00:00
|
|
|
if (definition->model == AtmosphereDefinition::ATMOSPHERE_MODEL_DISABLED)
|
|
|
|
{
|
|
|
|
result->updateFinal();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-12 20:34:35 +00:00
|
|
|
double distance = result->distance;
|
2015-08-23 23:19:19 +00:00
|
|
|
double max_distance = 100.0 - 90.0 * definition->propHumidity()->getValue();
|
2013-11-12 20:34:35 +00:00
|
|
|
double distancefactor, dayfactor;
|
|
|
|
|
|
|
|
if (distance > max_distance)
|
|
|
|
{
|
|
|
|
distance = max_distance;
|
|
|
|
}
|
|
|
|
distancefactor = (distance > max_distance ? max_distance : distance) / max_distance;
|
|
|
|
/* TODO Get day lighting from model */
|
2015-08-18 18:31:11 +00:00
|
|
|
dayfactor = _getDayFactor(definition->propDayTime()->getValue());
|
2013-11-12 20:34:35 +00:00
|
|
|
|
2015-08-23 23:19:19 +00:00
|
|
|
double humidity = definition->propHumidity()->getValue();
|
|
|
|
|
2013-11-12 20:34:35 +00:00
|
|
|
/* Fog masking */
|
2015-08-23 23:19:19 +00:00
|
|
|
if (humidity > 0.3)
|
2013-11-12 20:34:35 +00:00
|
|
|
{
|
2015-08-23 23:19:19 +00:00
|
|
|
result->mask.r = result->mask.g = result->mask.b = (10.0 - 8.0 * humidity) * dayfactor;
|
|
|
|
result->mask.a = distancefactor * (humidity - 0.3) / 0.7;
|
2013-11-12 20:34:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Scattering tweaking */
|
2015-08-23 23:19:19 +00:00
|
|
|
if (humidity < 0.15)
|
2013-11-12 20:34:35 +00:00
|
|
|
{
|
|
|
|
/* Limit scattering on ultra clear day */
|
2015-08-23 23:19:19 +00:00
|
|
|
double force = (0.15 - humidity) / 0.15;
|
2013-12-11 09:24:35 +00:00
|
|
|
result->inscattering.limitPower(100.0 - 90.0 * pow(force, 0.1));
|
2013-11-12 20:34:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Scattering boost */
|
2015-08-23 23:19:19 +00:00
|
|
|
double force = 1.2 * (humidity < 0.5 ? sqrt((humidity - 0.15) / 0.35) : 1.0 - (humidity - 0.5) / 0.5);
|
|
|
|
result->inscattering.r *= 1.0 + force * distancefactor * (humidity - 0.15) / 0.85;
|
|
|
|
result->inscattering.g *= 1.0 + force * distancefactor * (humidity - 0.15) / 0.85;
|
|
|
|
result->inscattering.b *= 1.0 + force * distancefactor * (humidity - 0.15) / 0.85;
|
2013-11-12 20:34:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Attenuation */
|
2015-08-23 23:19:19 +00:00
|
|
|
result->attenuation.r *= 1.0 - 0.4 * distancefactor * humidity;
|
|
|
|
result->attenuation.g *= 1.0 - 0.4 * distancefactor * humidity;
|
|
|
|
result->attenuation.b *= 1.0 - 0.4 * distancefactor * humidity;
|
2013-11-12 20:34:35 +00:00
|
|
|
|
2013-12-08 19:54:34 +00:00
|
|
|
result->updateFinal();
|
2013-11-12 20:34:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BaseAtmosphereRenderer::BaseAtmosphereRenderer(SoftwareRenderer* renderer):
|
2013-12-09 10:59:57 +00:00
|
|
|
parent(renderer)
|
2013-11-12 20:34:35 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void BaseAtmosphereRenderer::getLightingStatus(LightStatus* status, Vector3, int)
|
|
|
|
{
|
2013-12-15 13:28:46 +00:00
|
|
|
for (LightComponent light:lights)
|
|
|
|
{
|
|
|
|
status->pushComponent(light);
|
|
|
|
}
|
2013-11-12 20:34:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AtmosphereResult BaseAtmosphereRenderer::applyAerialPerspective(Vector3, Color base)
|
|
|
|
{
|
|
|
|
AtmosphereResult result;
|
|
|
|
result.base = result.final = base;
|
|
|
|
result.inscattering = result.attenuation = COLOR_BLACK;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
AtmosphereResult BaseAtmosphereRenderer::getSkyColor(Vector3)
|
|
|
|
{
|
|
|
|
AtmosphereResult result;
|
|
|
|
result.base = result.final = COLOR_WHITE;
|
|
|
|
result.inscattering = result.attenuation = COLOR_BLACK;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-08-18 18:31:11 +00:00
|
|
|
Vector3 BaseAtmosphereRenderer::getSunDirection(bool cache) const
|
2013-11-12 20:34:35 +00:00
|
|
|
{
|
2015-08-18 18:31:11 +00:00
|
|
|
if (cache and lights.size() > 0)
|
2013-12-20 16:30:27 +00:00
|
|
|
{
|
|
|
|
return lights[0].direction.scale(-1.0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
AtmosphereDefinition* atmosphere = getDefinition();
|
2015-08-18 18:31:11 +00:00
|
|
|
double sun_angle = (atmosphere->propDayTime()->getValue() + 0.75) * M_PI * 2.0;
|
2013-12-20 16:30:27 +00:00
|
|
|
return Vector3(cos(sun_angle), sin(sun_angle), 0.0);
|
|
|
|
}
|
2013-11-12 20:34:35 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 13:28:46 +00:00
|
|
|
void BaseAtmosphereRenderer::setBasicLights()
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-08-18 18:31:11 +00:00
|
|
|
AtmosphereDefinition* BaseAtmosphereRenderer::getDefinition() const
|
2013-11-12 20:34:35 +00:00
|
|
|
{
|
2013-12-09 10:59:57 +00:00
|
|
|
return parent->getScenery()->getAtmosphere();
|
2013-11-12 20:34:35 +00:00
|
|
|
}
|
|
|
|
|
2013-12-08 19:54:34 +00:00
|
|
|
SoftwareBrunetonAtmosphereRenderer::SoftwareBrunetonAtmosphereRenderer(SoftwareRenderer* renderer):
|
|
|
|
BaseAtmosphereRenderer(renderer)
|
|
|
|
{
|
2013-12-09 10:59:57 +00:00
|
|
|
model = new AtmosphereModelBruneton(parent);
|
2013-12-08 19:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SoftwareBrunetonAtmosphereRenderer::~SoftwareBrunetonAtmosphereRenderer()
|
|
|
|
{
|
|
|
|
delete model;
|
|
|
|
}
|
|
|
|
|
2013-11-12 20:34:35 +00:00
|
|
|
void SoftwareBrunetonAtmosphereRenderer::getLightingStatus(LightStatus* status, Vector3 normal, int opaque)
|
|
|
|
{
|
2013-12-26 17:28:25 +00:00
|
|
|
model->fillLightingStatus(status, normal, opaque);
|
|
|
|
parent->getNightSky()->fillLightingStatus(status, normal, opaque);
|
2013-11-12 20:34:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AtmosphereResult SoftwareBrunetonAtmosphereRenderer::applyAerialPerspective(Vector3 location, Color base)
|
|
|
|
{
|
|
|
|
AtmosphereDefinition* definition = getDefinition();
|
|
|
|
AtmosphereResult result;
|
|
|
|
|
|
|
|
/* Get base perspective */
|
|
|
|
switch (definition->model)
|
|
|
|
{
|
2013-11-15 23:27:40 +00:00
|
|
|
case AtmosphereDefinition::ATMOSPHERE_MODEL_BRUNETON:
|
2013-12-08 19:54:34 +00:00
|
|
|
result = model->applyAerialPerspective(location, base);
|
2013-11-12 20:34:35 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Apply weather effects */
|
|
|
|
_applyWeatherEffects(definition, &result);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
AtmosphereResult SoftwareBrunetonAtmosphereRenderer::getSkyColor(Vector3 direction)
|
|
|
|
{
|
|
|
|
AtmosphereDefinition* definition;
|
|
|
|
Vector3 sun_direction, sun_position, camera_location;
|
|
|
|
Color base;
|
|
|
|
|
|
|
|
definition = getDefinition();
|
2013-12-09 10:59:57 +00:00
|
|
|
camera_location = parent->getCameraLocation(VECTOR_ZERO);
|
2013-11-12 20:34:35 +00:00
|
|
|
|
|
|
|
sun_direction = getSunDirection();
|
2013-12-11 10:32:10 +00:00
|
|
|
direction = direction.normalize();
|
|
|
|
sun_position = sun_direction.scale(SUN_DISTANCE_SCALED);
|
2013-11-12 20:34:35 +00:00
|
|
|
|
|
|
|
base = COLOR_BLACK;
|
2013-12-26 14:36:15 +00:00
|
|
|
|
|
|
|
/* Get night sky */
|
|
|
|
base = base.add(parent->getNightSky()->getColor(camera_location.y, direction));
|
|
|
|
|
|
|
|
/* Get sun shape */
|
2013-11-12 20:34:35 +00:00
|
|
|
/*if (v3Dot(sun_direction, direction) >= 0)
|
|
|
|
{
|
|
|
|
double sun_radius = definition->sun_radius * SUN_RADIUS_SCALED * 5.0; // FIXME Why should we multiply by 5 ?
|
|
|
|
Vector3 hit1, hit2;
|
|
|
|
int hits = euclidRayIntersectSphere(camera_location, direction, sun_position, sun_radius, &hit1, &hit2);
|
|
|
|
if (hits > 1)
|
|
|
|
{
|
|
|
|
double dist = v3Norm(v3Sub(hit2, hit1)) / sun_radius; // distance between intersection points (relative to radius)
|
|
|
|
|
|
|
|
Color sun_color = definition->sun_color;
|
|
|
|
sun_color.r *= 100.0;
|
|
|
|
sun_color.g *= 100.0;
|
|
|
|
sun_color.b *= 100.0;
|
|
|
|
|
|
|
|
if (dist <= 0.05)
|
|
|
|
{
|
|
|
|
sun_color.r *= 1.0 - dist / 0.05;
|
|
|
|
sun_color.g *= 1.0 - dist / 0.05;
|
|
|
|
sun_color.b *= 1.0 - dist / 0.05;
|
|
|
|
}
|
|
|
|
base = sun_color;
|
|
|
|
}
|
|
|
|
}*/
|
|
|
|
|
|
|
|
/* Get scattering */
|
|
|
|
AtmosphereResult result;
|
2013-12-11 10:32:10 +00:00
|
|
|
Vector3 location = camera_location.add(direction.scale(6421.0));
|
2013-11-12 20:34:35 +00:00
|
|
|
switch (definition->model)
|
|
|
|
{
|
2013-11-15 23:27:40 +00:00
|
|
|
case AtmosphereDefinition::ATMOSPHERE_MODEL_BRUNETON:
|
2013-12-08 19:54:34 +00:00
|
|
|
result = model->getSkyColor(camera_location, direction, sun_position, base);
|
2013-11-12 20:34:35 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
result = BaseAtmosphereRenderer::applyAerialPerspective(location, result.base);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Apply weather effects */
|
|
|
|
_applyWeatherEffects(definition, &result);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|