+#include <msp/geometry/hypersphere.h>
+#include <msp/geometry/ray.h>
#include "light.h"
#include "mesh.h"
#include "renderer.h"
namespace Msp {
namespace GL {
-Sky::Sky(Renderable &r, const Light &s):
+Sky::Sky(Renderable &r, Light &s):
Effect(r),
sun(s),
transmittance_lookup(128, 64, (RENDER_COLOR, RGB16F)),
set_view_height(5.0f);
}
-void Sky::set_planet(const Planet &planet)
+void Sky::set_planet(const Planet &p)
{
+ planet = p;
shdata.uniform("events.rayleigh_scatter", planet.rayleigh_scatter.r, planet.rayleigh_scatter.g, planet.rayleigh_scatter.b);
shdata.uniform("events.mie_scatter", planet.mie_scatter.r, planet.mie_scatter.g, planet.mie_scatter.b);
shdata.uniform("events.mie_absorb", planet.mie_absorb.r, planet.mie_absorb.g, planet.mie_absorb.b);
void Sky::set_view_height(float h)
{
+ view_height = h;
shdata.uniform("view_height", h);
}
+Color Sky::get_transmittance(const Vector3 &look_dir)
+{
+ Vector3 pos(0.0f, 0.0f, view_height);
+ Vector3 planet_center(0.0f, 0.0f, -planet.planet_radius);
+
+ Geometry::Ray<float, 3> ray(pos-planet_center, look_dir);
+ Geometry::HyperSphere<float, 3> surface(planet.planet_radius);
+ Geometry::SurfacePoint<float, 3> intersection;
+ if(surface.get_intersections(ray, &intersection, 1))
+ return Color(0.0f);
+
+ Geometry::HyperSphere<float, 3> space(planet.planet_radius+planet.atmosphere_thickness);
+ if(!space.get_intersections(ray, &intersection, 1))
+ return Color(1.0f);
+
+ float step_size = intersection.distance/50;
+
+ Color path_extinction(0.0f);
+ for(unsigned i=0; i<50; ++i)
+ {
+ Vector3 from_center = pos-planet_center;
+ float height = from_center.norm()-planet.planet_radius;
+
+ Color rayleigh_scatter = planet.rayleigh_scatter*exp(height/planet.rayleigh_density_decay);
+ Color mie_scatter = planet.mie_scatter*exp(height/planet.mie_density_decay);
+ Color mie_absorb = planet.mie_absorb*exp(height/planet.mie_density_decay);
+ Color ozone_absorb = planet.ozone_absorb*max(1.0f-abs(height-planet.ozone_band_center)/planet.ozone_band_extent, 0.0f);
+
+ path_extinction = path_extinction+(rayleigh_scatter+mie_scatter+mie_absorb+ozone_absorb)*step_size;
+ pos += look_dir*step_size;
+ }
+
+ return Color(exp(-path_extinction.r), exp(-path_extinction.g), exp(-path_extinction.b));
+}
+
void Sky::setup_frame(Renderer &renderer)
{
if(rendered)
shdata.uniform("light_color", sun.get_color());
shdata.uniform("light_dir", sun.get_position().slice<3>(0));
+ sun.set_transmittance(get_transmittance(normalize(sun.get_position().slice<3>(0))));
Renderer::Push push(renderer);
};
private:
- const Light &sun;
+ Planet planet;
+ Light &sun;
RenderTarget transmittance_lookup;
const Program &transmittance_shprog;
bool transmittance_lookup_dirty;
const Sampler &sampler;
const Sampler &wrap_sampler;
mutable ProgramData shdata;
+ float view_height;
bool rendered;
public:
- Sky(Renderable &, const Light &);
+ Sky(Renderable &, Light &);
void set_planet(const Planet &);
void set_view_height(float);
+ Color get_transmittance(const Vector3 &);
+
virtual void setup_frame(Renderer &);
virtual void finish_frame();
virtual void render(Renderer &, Tag = Tag()) const;
Light::Light():
color(1),
+ transmittance(1),
position(0, 0, 1, 0),
spot_dir(0, 0, -1),
spot_exp(0),
color = c;
}
+void Light::set_transmittance(const Color &t)
+{
+ transmittance = t;
+}
+
void Light::set_matrix(const Matrix &m)
{
Placeable::set_matrix(m);
{
string base = format("light_sources[%d]", i);
shdata.uniform(base+".position", view_matrix*position);
- shdata.uniform(base+".color", color.r, color.g, color.b);
+ shdata.uniform(base+".color", color.r*transmittance.r, color.g*transmittance.g, color.b*transmittance.b);
}