paysages3d/src/render/software/NightSky.cpp

108 lines
3.6 KiB
C++
Raw Normal View History

#include "NightSky.h"
#include "Color.h"
#include "Vector3.h"
#include "Geometry.h"
2013-12-26 15:35:29 +00:00
#include "SoftwareRenderer.h"
2013-12-26 15:55:37 +00:00
#include "Scenery.h"
#include "AtmosphereDefinition.h"
2013-12-29 17:44:12 +00:00
#include "AtmosphereRenderer.h"
2013-12-26 15:35:29 +00:00
#include "SurfaceMaterial.h"
2013-12-26 17:28:25 +00:00
#include "LightComponent.h"
#include "LightStatus.h"
2013-12-26 15:35:29 +00:00
#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
2013-12-29 17:44:12 +00:00
Vector3 sun_direction = renderer->getAtmosphereRenderer()->getSunDirection();
if (sun_direction.y < 0.1) {
2013-12-29 17:44:12 +00:00
double factor = (sun_direction.y < 0.0) ? 1.0 : 1.0 - (sun_direction.y * 10.0);
for (const auto &star : atmosphere->stars) {
if (star.location.dotProduct(direction) >= 0) {
2013-12-29 17:44:12 +00:00
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)
2013-12-29 17:44:12 +00:00
Color color = star.col;
if (dist <= 0.5) {
2013-12-29 17:44:12 +00:00
color.a *= (1.0 - dist / 0.5) * factor;
}
result.mask(color);
2013-12-26 16:30:22 +00:00
}
}
}
}
// Get moon
2013-12-26 15:55:37 +00:00
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) {
2013-12-26 15:55:37 +00:00
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)
2013-12-26 15:35:29 +00:00
Vector3 nearest = (hit1.sub(location).getNorm() > hit2.sub(location).getNorm()) ? hit2 : hit1;
2013-12-26 18:03:19 +00:00
SurfaceMaterial moon_material(Color(3.0, 3.0, 3.0));
2013-12-26 15:35:29 +00:00
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;
}
2013-12-26 17:28:25 +00:00
2015-12-10 23:36:50 +00:00
bool NightSky::getLightsAt(vector<LightComponent> &result, const Vector3 &) const {
2013-12-26 18:03:19 +00:00
LightComponent moon, sky;
2013-12-26 17:28:25 +00:00
AtmosphereDefinition *atmosphere = renderer->getScenery()->getAtmosphere();
2013-12-26 17:28:25 +00:00
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;
2015-09-24 22:12:31 +00:00
result.push_back(moon);
2013-12-26 18:03:19 +00:00
sky.color = Color(0.01, 0.012, 0.03);
sky.direction = VECTOR_DOWN;
sky.reflection = 0.0;
sky.altered = 0;
2015-09-24 22:12:31 +00:00
result.push_back(sky);
return true;
2013-12-26 17:28:25 +00:00
}