Full implementation of the spotlight by Effects

This commit is contained in:
Frederic Bouvier 2012-01-03 00:32:00 +01:00
parent d929323e93
commit ec7e59eda1
2 changed files with 90 additions and 67 deletions

View File

@ -26,21 +26,37 @@
#include <osg/MatrixTransform> #include <osg/MatrixTransform>
#include <simgear/scene/material/EffectGeode.hxx> #include <simgear/scene/material/EffectGeode.hxx>
#include <boost/scoped_array.hpp> #include <boost/scoped_array.hpp>
#include <simgear/scene/util/CopyOp.hxx>
#define GET_COLOR_VALUE(n) \
SGVec4d( getConfig()->getDoubleValue(n "/r"), \
getConfig()->getDoubleValue(n "/g"), \
getConfig()->getDoubleValue(n "/b"), \
getConfig()->getDoubleValue(n "/a") )
SGLightAnimation::SGLightAnimation(const SGPropertyNode* configNode, SGLightAnimation::SGLightAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot) : SGPropertyNode* modelRoot) :
SGAnimation(configNode, modelRoot) SGAnimation(configNode, modelRoot)
{ {
_position = SGVec3d( getConfig()->getDoubleValue("position/x"), getConfig()->getDoubleValue("position/y"), getConfig()->getDoubleValue("position/z") );
_direction = SGVec3d( getConfig()->getDoubleValue("direction/x"), getConfig()->getDoubleValue("direction/y"), getConfig()->getDoubleValue("direction/z") );
double l = length(_direction);
if (l > 0.001) _direction /= l;
_ambient = GET_COLOR_VALUE("ambient");
_diffuse = GET_COLOR_VALUE("diffuse");
_specular = GET_COLOR_VALUE("specular");
_attenuation = SGVec3d( getConfig()->getDoubleValue("attenuation/c"), getConfig()->getDoubleValue("attenuation/l"), getConfig()->getDoubleValue("attenuation/q") );
_exponent = getConfig()->getDoubleValue("exponent");
_cutoff = getConfig()->getDoubleValue("cutoff");
_near = getConfig()->getDoubleValue("near-m");
_far = getConfig()->getDoubleValue("far-m");
} }
osg::Group* osg::Group*
SGLightAnimation::createAnimationGroup(osg::Group& parent) SGLightAnimation::createAnimationGroup(osg::Group& parent)
{ {
osg::MatrixTransform* grp = new osg::MatrixTransform; osg::MatrixTransform* grp = new osg::MatrixTransform;
osg::Vec3 position( getConfig()->getDoubleValue("position/x-m"), grp->setMatrix(osg::Matrix::translate(toOsg(_position)));
getConfig()->getDoubleValue("position/y-m"),
getConfig()->getDoubleValue("position/z-m") );
grp->setMatrix(osg::Matrix::translate(position));
parent.addChild(grp); parent.addChild(grp);
grp->setNodeMask( simgear::MODELLIGHT_BIT ); grp->setNodeMask( simgear::MODELLIGHT_BIT );
return grp; return grp;
@ -53,66 +69,63 @@ SGLightAnimation::install(osg::Node& node)
std::string light_type = getConfig()->getStringValue("light-type"); std::string light_type = getConfig()->getStringValue("light-type");
if (light_type == "spot") { if (light_type == "spot") {
osg::Vec3 axis( getConfig()->getDoubleValue("axis/x"),
getConfig()->getDoubleValue("axis/y"),
getConfig()->getDoubleValue("axis/z") );
double l = axis.length();
if (l < 0.001) return;
axis /= l;
osg::Vec3 p1( axis.z(), axis.x(), axis.y() ), SGVec3d p1( _direction.z(), _direction.x(), _direction.y() ),
p2 = axis ^ p1; p2 = cross( _direction, p1 );
p1 = p2 ^ axis; p1 = cross( p2, _direction );
float n = getConfig()->getFloatValue("near-m"), float r2 = _far * tan( _cutoff * SG_DEGREES_TO_RADIANS );
f = getConfig()->getFloatValue("far-m"),
a1 = getConfig()->getFloatValue("angle-inner-deg"),
a2 = getConfig()->getFloatValue("angle-outer-deg"),
r1 = n * tan( a2 * SG_DEGREES_TO_RADIANS ),
r2 = f * tan( a2 * SG_DEGREES_TO_RADIANS );
osg::Geometry* cone = new osg::Geometry; osg::Geometry* cone = new osg::Geometry;
cone->setUseDisplayList(false); cone->setUseDisplayList(false);
osg::Vec3Array* vertices = new osg::Vec3Array(36); osg::Vec3Array* vertices = new osg::Vec3Array(34);
(*vertices)[0] = osg::Vec3(0.0,0.0,0.0); (*vertices)[0] = osg::Vec3(0.0,0.0,0.0);
for (int i=0; i<16; ++i) { for (int i=0; i<16; ++i) {
(*vertices)[16-i] = axis*f + p1*r2*cos( i * 2 * M_PI / 16 ) + p2*r2*sin( i * 2 * M_PI / 16 ); (*vertices)[16-i] = toOsg(_direction)*_far + toOsg(p1)*r2*cos( i * 2 * M_PI / 16 ) + toOsg(p2)*r2*sin( i * 2 * M_PI / 16 );
} }
(*vertices)[17] = (*vertices)[1]; (*vertices)[17] = (*vertices)[1];
// Bottom // Bottom
(*vertices)[18] = axis*f;
for (int i=0; i<16; ++i) { for (int i=0; i<16; ++i) {
(*vertices)[19+i] = axis*f + p1*r2*cos( i * 2 * M_PI / 16 ) + p2*r2*sin( i * 2 * M_PI / 16 ); (*vertices)[18+i] = toOsg(_direction)*_far + toOsg(p1)*r2*cos( i * 2 * M_PI / 16 ) + toOsg(p2)*r2*sin( i * 2 * M_PI / 16 );
} }
(*vertices)[35] = (*vertices)[19];
osg::Vec4Array* colours = new osg::Vec4Array(1); osg::Vec4Array* colours = new osg::Vec4Array(1);
(*colours)[0].set( getConfig()->getFloatValue("color/red"), (*colours)[0] = osg::Vec4d(toOsg(getConfig()->getValue<SGVec3d>("diffuse")), 1.0f);
getConfig()->getFloatValue("color/green"),
getConfig()->getFloatValue("color/blue"),
1.0f);
cone->setColorArray(colours); cone->setColorArray(colours);
cone->setColorBinding(osg::Geometry::BIND_OVERALL); cone->setColorBinding(osg::Geometry::BIND_OVERALL);
osg::Vec3Array* normals = new osg::Vec3Array(1); osg::Vec3Array* normals = new osg::Vec3Array(1);
(*normals)[0] = axis; (*normals)[0] = toOsg(_direction);
cone->setNormalArray(normals); cone->setNormalArray(normals);
cone->setNormalBinding(osg::Geometry::BIND_OVERALL); cone->setNormalBinding(osg::Geometry::BIND_OVERALL);
cone->setVertexArray(vertices); cone->setVertexArray(vertices);
cone->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLE_FAN, 0, 18 ) ); cone->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLE_FAN, 0, 18 ) );
cone->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLE_FAN, 18, 18 ) ); cone->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLE_FAN, 18, 16 ) );
simgear::EffectGeode* geode = new simgear::EffectGeode; simgear::EffectGeode* geode = new simgear::EffectGeode;
geode->addDrawable( cone ); geode->addDrawable( cone );
node.asGroup()->addChild( geode ); node.asGroup()->addChild( geode );
simgear::Effect *effect = simgear::makeEffect("Effects/light-spot", true);
if (effect) { // TODO: build a cache - problem: what is the key ?
effect->parametersProp->setFloatValue("inner-angle",getConfig()->getFloatValue("angle-inner-deg")); SGPropertyNode_ptr effectProp = new SGPropertyNode;
effect->parametersProp->setFloatValue("outer-angle",getConfig()->getFloatValue("angle-outer-deg")); makeChild(effectProp, "inherits-from")->setStringValue("Effects/light-spot");
SGPropertyNode* params = makeChild(effectProp, "parameters");
params->getNode("light-spot/position",true)->setValue(SGVec4d(_position.x(),_position.y(),_position.z(),1.0));
params->getNode("light-spot/direction",true)->setValue(SGVec4d(_direction.x(),_direction.y(),_direction.z(),0.0));
params->getNode("light-spot/ambient",true)->setValue(_ambient);
params->getNode("light-spot/diffuse",true)->setValue(_diffuse);
params->getNode("light-spot/specular",true)->setValue(_specular);
params->getNode("light-spot/attenuation",true)->setValue(_attenuation);
params->getNode("light-spot/exponent",true)->setValue(_exponent);
params->getNode("light-spot/cutoff",true)->setValue(_cutoff);
params->getNode("light-spot/cosCutoff",true)->setValue( cos(_cutoff*SG_DEGREES_TO_RADIANS) );
params->getNode("light-spot/near",true)->setValue(_near);
params->getNode("light-spot/far",true)->setValue(_far);
simgear::Effect* effect = simgear::makeEffect(effectProp, true);
geode->setEffect(effect); geode->setEffect(effect);
} }
} }
}

View File

@ -355,6 +355,16 @@ public:
virtual osg::Group* createAnimationGroup(osg::Group& parent); virtual osg::Group* createAnimationGroup(osg::Group& parent);
virtual void install(osg::Node& node); virtual void install(osg::Node& node);
private: private:
SGVec3d _position;
SGVec3d _direction;
SGVec4d _ambient;
SGVec4d _diffuse;
SGVec4d _specular;
SGVec3d _attenuation;
double _exponent;
double _cutoff;
double _near;
double _far;
}; };
#endif // _SG_ANIMATION_HXX #endif // _SG_ANIMATION_HXX