raise ValueError("Object {} is not a light".format(obj.name))
light = obj.data
- from .datafile import Resource, Statement
+ from .datafile import Resource, Statement, Token
light_res = Resource(light.name+".light", "light")
if light.type=='SUN':
- pos = obj.matrix_world@mathutils.Vector((0.0, 0.0, 1.0, 0.0))
- else:
+ light_res.statements.append(Statement("type", Token("directional")))
+ light_res.statements.append(Statement("direction", *(-obj.matrix_world.col[2])[0:3]))
+ elif light.type=='POINT':
+ light_res.statements.append(Statement("type", Token("point")))
pos = obj.matrix_world@mathutils.Vector((0.0, 0.0, 0.0, 1.0))
+ light_res.statements.append(Statement("position", *obj.matrix_world.col[3][0:3]))
+ else:
+ raise Exception("Can't export light {} of unknown type {}".format(light.name, light.type))
- light_res.statements.append(Statement("position", *tuple(pos)))
c = light.color*light.energy
light_res.statements.append(Statement("color", *tuple(c)))
#include <msp/fs/dir.h>
+#include <msp/gl/directionallight.h>
#include <msp/gl/sequencebuilder.h>
#include <msp/gl/renderer.h>
#include <msp/gl/tests.h>
window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &DesertPillars::exit), 0));
keyboard.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &DesertPillars::key_press), false));
- GL::Light &sun = resources.get<GL::Light>("Sun.light");
+ GL::DirectionalLight &sun = resources.get<GL::DirectionalLight>("Sun.light");
sky = make_unique<GL::Sky>(content, sun);
sky->set_debug_name("Sky");
{
vec3 color = vec3(0.0);
for(int i=0; i<max_lights; ++i)
- if(light_sources[i].enabled!=0)
+ if(light_sources[i].type!=0)
{
vec3 light = get_light_direction(i);
float shadow = get_shadow_factor(i);
{
vec4 position;
vec3 color;
- int enabled;
+ int type;
};
struct ClipPlane
{
vec3 color = phong_ambient(surface_diffuse);
for(int i=0; i<max_lights; ++i)
- if(light_sources[i].enabled!=0)
+ if(light_sources[i].type!=0)
{
vec3 light = get_light_direction(i);
float shadow = get_shadow_factor(i);
#include <msp/strings/format.h>
+#include "directionallight.h"
#include "error.h"
-#include "light.h"
#include "lighting.h"
#include "renderer.h"
#include "resources.h"
}
}
-ShadowMap::ShadowMap(unsigned s, Renderable &r, const Light &l, Renderable &c):
+ShadowMap::ShadowMap(unsigned s, Renderable &r, const DirectionalLight &l, Renderable &c):
ShadowMap(s, s, r, 0, c)
{
add_light(l, s);
ShadowMap(w, h, r, &l, c)
{ }
-void ShadowMap::add_light(const Light &light, unsigned s)
+void ShadowMap::add_light(const DirectionalLight &light, unsigned s)
{
if(!lighting && !lights.empty())
throw invalid_operation("ShadowMap::add_light");
namespace Msp {
namespace GL {
+class DirectionalLight;
class Light;
/**
ShadowMap(unsigned, unsigned, Renderable &, const Lighting *, Renderable &);
public:
- ShadowMap(unsigned, Renderable &, const Light &, Renderable &);
+ ShadowMap(unsigned, Renderable &, const DirectionalLight &, Renderable &);
ShadowMap(unsigned, unsigned, Renderable &, const Lighting &, Renderable &);
- void add_light(const Light &, unsigned);
+ void add_light(const DirectionalLight &, unsigned);
/** Sets the ShadowMap target point and radius. The transformation matrix is
computed so that a sphere with the specified parameters will be completely
#include <msp/geometry/hypersphere.h>
#include <msp/geometry/ray.h>
-#include "light.h"
+#include "directionallight.h"
#include "mesh.h"
#include "renderer.h"
#include "resources.h"
namespace Msp {
namespace GL {
-Sky::Sky(Renderable &r, Light &s):
+Sky::Sky(Renderable &r, DirectionalLight &s):
Effect(r),
sun(s),
transmittance_lookup(128, 64, (COLOR_ATTACHMENT,RGB16F)),
rendered = true;
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))));
+ shdata.uniform("light_dir", -sun.get_direction());
+ sun.set_transmittance(get_transmittance(-sun.get_direction()));
Renderer::Push push(renderer);
namespace Msp {
namespace GL {
+class DirectionalLight;
class Mesh;
-class Light;
class Program;
/**
private:
Planet planet;
- Light &sun;
+ DirectionalLight &sun;
RenderTarget transmittance_lookup;
const Program &transmittance_shprog;
bool transmittance_lookup_dirty;
bool rendered;
public:
- Sky(Renderable &, Light &);
+ Sky(Renderable &, DirectionalLight &);
void set_planet(const Planet &);
void set_view_height(float);
--- /dev/null
+#include "directionallight.h"
+#include "programdata.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+DirectionalLight::DirectionalLight():
+ transmittance(1.0f),
+ direction(0.0f, 0.0f, -1.0f)
+{ }
+
+void DirectionalLight::update_matrix()
+{
+ Vector3 up_dir;
+ if(20*abs(direction.z)>abs(direction.x)+abs(direction.y))
+ up_dir.y = 1;
+ else
+ up_dir.z = 1;
+ Vector3 right_dir = normalize(cross(direction, up_dir));
+
+ Vector4 columns[4];
+ columns[0] = compose(right_dir, 0.0f);
+ columns[1] = compose(cross(right_dir, direction), 0.0f);
+ columns[2] = compose(-direction, 0.0f);
+ columns[3] = Vector4(0.0f, 0.0f, 0.0f, 1.0f);
+ matrix = Matrix::from_columns(columns);
+}
+
+void DirectionalLight::set_matrix(const Matrix &m)
+{
+ Placeable::set_matrix(m);
+ direction = normalize(-matrix.column(2).slice<3>(0));
+ update_matrix();
+ ++generation;
+}
+
+void DirectionalLight::set_direction(const Vector3 &d)
+{
+ direction = normalize(d);
+ update_matrix();
+ ++generation;
+}
+
+void DirectionalLight::set_transmittance(const Color &t)
+{
+ transmittance = t;
+ ++generation;
+}
+
+void DirectionalLight::update_shader_data(ProgramData &shdata, const string &base) const
+{
+ shdata.uniform(base+".type", 1);
+ shdata.uniform(base+".position", -direction.x, -direction.y, -direction.z, 0.0f);
+ shdata.uniform(base+".color", color.r*transmittance.r, color.g*transmittance.g, color.b*transmittance.b);
+ shdata.uniform(base+".attenuation", 1.0f, 0.0f, 0.0f);
+}
+
+
+DataFile::Loader::ActionMap DirectionalLight::Loader::shared_actions;
+
+DirectionalLight::Loader::Loader(DirectionalLight &l):
+ DerivedObjectLoader<DirectionalLight, Light::Loader>(l)
+{
+ set_actions(shared_actions);
+}
+
+void DirectionalLight::Loader::init_actions()
+{
+ Light::Loader::init_actions();
+ add("direction", &Loader::direction);
+}
+
+void DirectionalLight::Loader::direction(float x, float y, float z)
+{
+ obj.set_direction(Vector3(x, y, z));
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_DIRECTIONALLIGHT_H_
+#define MSP_GL_DIRECTIONALLIGHT_H_
+
+#include "light.h"
+#include "vector.h"
+
+namespace Msp {
+namespace GL {
+
+/**
+A light source which has uniform direction and strength everywhere.
+*/
+class DirectionalLight: public Light
+{
+public:
+ class Loader: public DataFile::DerivedObjectLoader<DirectionalLight, Light::Loader>
+ {
+ private:
+ static ActionMap shared_actions;
+
+ public:
+ Loader(DirectionalLight &);
+
+ private:
+ virtual void init_actions();
+
+ void direction(float, float, float);
+ };
+
+private:
+ Color transmittance;
+ Vector3 direction;
+
+public:
+ DirectionalLight();
+
+private:
+ void update_matrix();
+
+public:
+ /** Sets the light's direction from a matrix. The negative Z axis is used
+ as the direction. Other axes and translation are ignored. */
+ virtual void set_matrix(const Matrix &);
+
+ void set_direction(const Vector3 &);
+
+ const Vector3 &get_direction() const { return direction; }
+
+ /** Sets a multiplier on how much light actually reaches the target. Used
+ when modeling an atmosphere. */
+ void set_transmittance(const Color &);
+
+protected:
+ virtual void update_shader_data(ProgramData &, const std::string &) const;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
#include <stdexcept>
#include <msp/strings/format.h>
+#include "directionallight.h"
#include "light.h"
-#include "programdata.h"
+#include "pointlight.h"
using namespace std;
namespace GL {
Light::Light():
- color(1),
- transmittance(1),
- position(0, 0, 1, 0),
- spot_dir(0, 0, -1),
- spot_exp(0),
- spot_cutoff(Geometry::Angle<float>::straight()),
+ color(1.0f),
generation(0)
-{
- attenuation[0] = 1;
- attenuation[1] = 0;
- attenuation[2] = 0;
-}
-
-void Light::update_matrix()
-{
- Vector3 up_dir;
- if(20*abs(direction.z)>abs(direction.x)+abs(direction.y))
- up_dir.y = 1;
- else
- up_dir.z = 1;
- Vector3 right_dir = normalize(cross(direction, up_dir));
-
- Vector4 columns[4];
- columns[0] = compose(right_dir, 0.0f);
- columns[1] = compose(cross(right_dir, direction), 0.0f);
- columns[2] = compose(-direction, 0.0f);
- columns[3] = position;
- matrix = Matrix::from_columns(columns);
-}
+{ }
void Light::set_color(const Color &c)
{
++generation;
}
-void Light::set_transmittance(const Color &t)
-{
- transmittance = t;
- ++generation;
-}
-
-void Light::set_matrix(const Matrix &m)
-{
- Placeable::set_matrix(m);
- position = matrix.column(3);
- spot_dir = normalize(-matrix.column(2).slice<3>(0));
- direction = (position.w ? spot_dir : normalize(-position.slice<3>(0)));
- update_matrix();
- ++generation;
-}
-
-void Light::set_position(const Vector4 &p)
-{
- position = p;
- if(!position.w)
- direction = normalize(-position.slice<3>(0));
- update_matrix();
- ++generation;
-}
-
-void Light::set_spot_direction(const Vector3 &d)
-{
- spot_dir = normalize(d);
- if(position.w)
- direction = spot_dir;
- update_matrix();
- ++generation;
-}
-
-void Light::set_spot_exponent(float e)
-{
- if(e<0)
- throw invalid_argument("Light::set_spot_exponent");
-
- spot_exp = e;
- ++generation;
-}
-
-void Light::set_spot_cutoff(const Geometry::Angle<float> &c)
-{
- if(c<Geometry::Angle<float>::zero() || (c>Geometry::Angle<float>::right() && c!=Geometry::Angle<float>::straight()))
- throw invalid_argument("Light::set_spot_cutoff");
-
- spot_cutoff = c;
- ++generation;
-}
-
-void Light::disable_spot_cutoff()
-{
- set_spot_cutoff(Geometry::Angle<float>::straight());
- ++generation;
-}
-
-void Light::set_attenuation(float c, float l, float q)
+void Light::update_shader_data(ProgramData &shdata, unsigned i) const
{
- attenuation[0] = c;
- attenuation[1] = l;
- attenuation[2] = q;
- ++generation;
+ update_shader_data(shdata, format("light_sources[%d]", i));
}
-void Light::update_shader_data(ProgramData &shdata, unsigned i) const
+Light::GenericLoader::TypeRegistry &Light::get_light_registry()
{
- string base = format("light_sources[%d]", i);
- shdata.uniform(base+".position", position);
- shdata.uniform(base+".color", color.r*transmittance.r, color.g*transmittance.g, color.b*transmittance.b);
- shdata.uniform(base+".enabled", 1);
+ static GenericLoader::TypeRegistry registry;
+ static bool initialized = false;
+ if(!initialized)
+ {
+ initialized = true;
+ registry.register_type<DirectionalLight>("directional");
+ registry.register_type<PointLight>("point");
+ }
+ return registry;
}
Light::Loader::Loader(Light &l):
DataFile::ObjectLoader<Light>(l)
-{
- add("attenuation", &Loader::attenuation);
- add("color", &Loader::color);
- add("position", &Loader::position);
- add("spot_direction", &Loader::spot_direction);
- add("spot_exponent", &Loader::spot_exponent);
- add("spot_cutoff", &Loader::spot_cutoff);
-}
+{ }
-void Light::Loader::attenuation(float c, float l, float q)
+void Light::Loader::init_actions()
{
- obj.set_attenuation(c, l, q);
+ add("color", &Loader::color);
}
void Light::Loader::color(float r, float g, float b)
obj.set_color(Color(r, g, b));
}
-void Light::Loader::position(float x, float y, float z, float w)
-{
- obj.set_position(Vector4(x, y, z, w));
-}
-
-void Light::Loader::spot_direction(float x, float y, float z)
-{
- obj.set_spot_direction(Vector3(x, y, z));
-}
-
-void Light::Loader::spot_exponent(float e)
-{
- obj.set_spot_exponent(e);
-}
-
-void Light::Loader::spot_cutoff(float c)
-{
- obj.set_spot_cutoff(Geometry::Angle<float>::from_degrees(c));
-}
-
} // namespace GL
} // namespace Msp
#ifndef MSP_GL_LIGHT_H_
#define MSP_GL_LIGHT_H_
+#include <string>
+#include <msp/datafile/dynamicobjectloader.h>
#include <msp/datafile/objectloader.h>
-#include <msp/geometry/angle.h>
#include "color.h"
#include "placeable.h"
-#include "vector.h"
namespace Msp {
namespace GL {
class ProgramData;
/**
-Stores properties of a single light source. Lights can be directional, point
-lights or spotlights. No explicit type parameter is provided; rather the
-other parameters determine what kind of light it is. If the fourth component
-of position is zero, it's a directional light. Otherwise, if the spot cutoff
-is not 180 degrees, it's a spotlight. Otherwise it's an omnidirectional point
-light.
+Base class for light sources. The DirectionalLight and PointLight classes
+implement different types of lights.
Lights are usually grouped with a Lighting object, which can be used in a
Sequence::Step.
*/
class Light: public Placeable
{
-public:
+protected:
class Loader: public DataFile::ObjectLoader<Light>
{
- public:
+ protected:
Loader(Light &);
+ virtual void init_actions();
+
private:
- void attenuation(float, float, float);
void color(float, float, float);
- void position(float, float, float, float);
- void spot_direction(float, float, float);
- void spot_exponent(float);
- void spot_cutoff(float);
};
-private:
+public:
+ class GenericLoader: public DataFile::DynamicObjectLoader<Light>
+ {
+ friend class Light;
+
+ public:
+ GenericLoader(Collection &c): DynamicObjectLoader<Light>(&c) { }
+
+ protected:
+ virtual const TypeRegistry &get_type_registry() const { return Light::get_light_registry(); }
+ };
+
+protected:
Color color;
- Color transmittance;
- Vector4 position;
- Vector3 spot_dir;
- Vector3 direction;
- float spot_exp;
- Geometry::Angle<float> spot_cutoff;
- float attenuation[3];
unsigned generation;
public:
Light();
-private:
- void update_matrix();
-
-public:
- /** Sets the color of the Light. Provided
- to shaders as light_sources[i].color. */
+ /** Sets the color of the Light. */
void set_color(const Color &);
- /** Sets a multiplier on how much light actually reaches the target. Used
- when modeling an atmosphere. */
- void set_transmittance(const Color &);
-
const Color &get_color() const { return color; }
- const Color &get_transmittance() const { return transmittance; }
-
- /** Sets the postion and orientation of the Light from a matrix. Negative Z
- axis is used as the spot direction, other axes are ignored. */
- virtual void set_matrix(const Matrix &);
-
- /** Sets the position of the Light. For a directional light, set the xyz
- components to a vector pointing towards the light and the w component to 0. */
- void set_position(const Vector4 &);
-
- const Vector4 &get_position() const { return position; }
-
- /** Sets the direction of a spotlight. Has no effect if spotlight cutoff is
- not set. */
- void set_spot_direction(const Vector3 &);
-
- /** Sets the angular falloff exponent of the spotlight. Must be >= 0. */
- void set_spot_exponent(float);
-
- /** Sets the cutoff angle of a spotlight. Beyond this angle from its axis
- the spotlight provides no illumination. Must be between 0 and 90 degrees,
- or exactly 180 degrees to indicate a non-spotlight. */
- void set_spot_cutoff(const Geometry::Angle<float> &);
-
- /** Disables spotlight, reverting to an omnidirectional point light.
- Equivalent to setting the spot cutoff to 180 degrees. */
- void disable_spot_cutoff();
-
- const Vector3 &get_spot_direction() const { return spot_dir; }
- float get_spot_exponent() const { return spot_exp; }
- const Geometry::Angle<float> &get_spot_cutoff() const { return spot_cutoff; }
- void set_attenuation(float, float, float);
- const float *get_attenuation() const { return attenuation; }
unsigned get_generation() const { return generation; }
/** Updates a ProgramData object with the uniforms for the Light. A light
source index must be passed in. Primarily used by Lighting. */
void update_shader_data(ProgramData &, unsigned) const;
+
+protected:
+ virtual void update_shader_data(ProgramData &, const std::string &) const = 0;
+
+private:
+ static GenericLoader::TypeRegistry &get_light_registry();
};
} // namespace GL
string base = format("light_sources[%d]", i);
shdata.uniform(base+".position", Vector4(0, 0, 1, 0));
shdata.uniform(base+".color", 0.0f, 0.0f, 0.0f);
- shdata.uniform(base+".enabled", 0);
+ shdata.uniform(base+".type", 0);
}
}
void Lighting::Loader::light_inline()
{
- RefPtr<Light> lgt = new Light;
- load_sub(*lgt);
+ Light::GenericLoader ldr(get_collection());
+ load_sub_with(ldr);
+ RefPtr<Light> lgt = ldr.get_object();
get_collection().add(format("%s/%d.light", FS::basename(get_source()), obj.lights.size()), lgt.get());
obj.attach(*lgt.release());
}
--- /dev/null
+#include "pointlight.h"
+#include "programdata.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+PointLight::PointLight():
+ position(0.0f, 0.0f, 0.0f),
+ attenuation{1.0f, 0.0f, 0.1f}
+{ }
+
+void PointLight::update_matrix()
+{
+ matrix = Matrix::translation(position);
+}
+
+void PointLight::set_matrix(const Matrix &m)
+{
+ Placeable::set_matrix(m);
+ position = matrix.column(3).slice<3>(0);
+ update_matrix();
+ ++generation;
+}
+
+void PointLight::set_position(const Vector3 &p)
+{
+ position = p;
+ update_matrix();
+ ++generation;
+}
+
+void PointLight::set_attenuation(float c, float l, float q)
+{
+ attenuation[0] = c;
+ attenuation[1] = l;
+ attenuation[2] = q;
+ ++generation;
+}
+
+void PointLight::update_shader_data(ProgramData &shdata, const string &base) const
+{
+ shdata.uniform(base+".type", 2);
+ shdata.uniform(base+".position", position.x, position.y, position.z, 1.0f);
+ shdata.uniform(base+".color", color.r, color.g, color.b);
+}
+
+
+DataFile::Loader::ActionMap PointLight::Loader::shared_actions;
+
+PointLight::Loader::Loader(PointLight &l):
+ DerivedObjectLoader<PointLight, Light::Loader>(l)
+{
+ set_actions(shared_actions);
+}
+
+void PointLight::Loader::init_actions()
+{
+ Light::Loader::init_actions();
+ add("attenuation", &Loader::attenuation);
+ add("position", &Loader::position);
+}
+
+void PointLight::Loader::attenuation(float c, float l, float q)
+{
+ obj.set_attenuation(c, l, q);
+}
+
+void PointLight::Loader::position(float x, float y, float z)
+{
+ obj.set_position(Vector3(x, y, z));
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_POINTLIGHT_H_
+#define MSP_GL_POINTLIGHT_H_
+
+#include "light.h"
+#include "vector.h"
+
+namespace Msp {
+namespace GL {
+
+/**
+A positional, omnidirectional light source. The light's strength can be
+attenuated based on distance.
+*/
+class PointLight: public Light
+{
+public:
+ class Loader: public DataFile::DerivedObjectLoader<PointLight, Light::Loader>
+ {
+ private:
+ static ActionMap shared_actions;
+
+ public:
+ Loader(PointLight &);
+
+ private:
+ virtual void init_actions();
+
+ void attenuation(float, float, float);
+ void position(float, float, float);
+ };
+
+private:
+ Vector3 position;
+ float attenuation[3];
+
+public:
+ PointLight();
+
+private:
+ void update_matrix();
+
+public:
+ /** Sets the light's position from a matrix. Only the translation part is
+ used. */
+ virtual void set_matrix(const Matrix &);
+
+ void set_position(const Vector3 &);
+ const Vector3 &get_position();
+
+ void set_attenuation(float, float, float);
+ const float *get_attenuation() const { return attenuation; }
+
+protected:
+ virtual void update_shader_data(ProgramData &, const std::string &) const;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
#include "armature.h"
#include "basicmaterial.h"
#include "camera.h"
+#include "directionallight.h"
#include "error.h"
#include "font.h"
#include "keyframe.h"
-#include "light.h"
#include "lighting.h"
#include "mesh.h"
#include "module.h"
#include "orderedscene.h"
#include "pbrmaterial.h"
#include "sequencetemplate.h"
+#include "pointlight.h"
#include "pose.h"
#include "program.h"
#include "resourcemanager.h"
.notify(&set_debug_name<Material>);
add_type<Camera>().keyword("camera")
.notify(&set_debug_name<Camera>);
+ add_type<DirectionalLight>().base<Light>().suffix(".light")
+ .creator([this](const string &n) -> DirectionalLight * { create_generic<Light>(n); return 0; });
add_type<Font>().keyword("font");
add_type<KeyFrame>().suffix(".kframe").keyword("keyframe");
- add_type<Light>().keyword("light");
add_type<Lighting>().suffix(".lightn").keyword("lighting")
.notify(&set_debug_name<Lighting>);
add_type<Mesh>().keyword("mesh")
add_type<PbrMaterial>().base<Material>().suffix(".mat")
.creator([this](const string &n) -> PbrMaterial * { create_generic<Material>(n); return 0; })
.notify(&set_debug_name<Material>);
+ add_type<PointLight>().base<Light>().suffix(".light")
+ .creator([this](const string &n) -> PointLight * { create_generic<Light>(n); return 0; });
add_type<SequenceTemplate>().suffix(".seq").keyword("sequence");
add_type<Pose>().keyword("pose");
add_type<Program>().keyword("shader")
#include <msp/gl/animationplayer.h>
#include <msp/gl/blend.h>
#include <msp/gl/camera.h>
+#include <msp/gl/directionallight.h>
#include <msp/gl/framebuffer.h>
-#include <msp/gl/light.h>
#include <msp/gl/lighting.h>
#include <msp/gl/mesh.h>
#include <msp/gl/object.h>
GL::Renderable *renderable;
GL::AnimatedObject *anim_object;
GL::AnimationPlayer *anim_player;
- GL::Light light;
+ GL::DirectionalLight light;
GL::Lighting lighting;
GL::Camera camera;
float yaw;
mouse.signal_button_release.connect(sigc::bind_return(sigc::mem_fun(this, &Viewer::button_release), false));
mouse.signal_axis_motion.connect(sigc::bind_return(sigc::mem_fun(this, &Viewer::axis_motion), false));
- light.set_position(GL::Vector4(0, 0, 1, 0));
+ light.set_direction(GL::Vector3(0, 0, -1));
lighting.attach(light);
camera.set_up_direction(GL::Vector3(0, 0, 1));
float sy = sin(light_yaw);
float cp = cos(light_pitch);
float sp = sin(light_pitch);
- light.set_position(GL::Vector4(-cy*cp, -sy*cp, -sp, 0));
+ light.set_direction(GL::Vector3(cy*cp, sy*cp, sp));
}