From ec7e59eda10cf17a267e8a195b8ea466b397230e Mon Sep 17 00:00:00 2001 From: Frederic Bouvier Date: Tue, 3 Jan 2012 00:32:00 +0100 Subject: [PATCH] Full implementation of the spotlight by Effects --- simgear/scene/model/SGLightAnimation.cxx | 155 ++++++++++++----------- simgear/scene/model/animation.hxx | 10 ++ 2 files changed, 94 insertions(+), 71 deletions(-) diff --git a/simgear/scene/model/SGLightAnimation.cxx b/simgear/scene/model/SGLightAnimation.cxx index bad681c3..6d6257b4 100644 --- a/simgear/scene/model/SGLightAnimation.cxx +++ b/simgear/scene/model/SGLightAnimation.cxx @@ -26,93 +26,106 @@ #include #include #include +#include + +#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, SGPropertyNode* 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* SGLightAnimation::createAnimationGroup(osg::Group& parent) { osg::MatrixTransform* grp = new osg::MatrixTransform; - osg::Vec3 position( getConfig()->getDoubleValue("position/x-m"), - getConfig()->getDoubleValue("position/y-m"), - getConfig()->getDoubleValue("position/z-m") ); - grp->setMatrix(osg::Matrix::translate(position)); - parent.addChild(grp); - grp->setNodeMask( simgear::MODELLIGHT_BIT ); - return grp; + grp->setMatrix(osg::Matrix::translate(toOsg(_position))); + parent.addChild(grp); + grp->setNodeMask( simgear::MODELLIGHT_BIT ); + return grp; } void SGLightAnimation::install(osg::Node& node) { - SGAnimation::install(node); - - std::string light_type = getConfig()->getStringValue("light-type"); - 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() ), - p2 = axis ^ p1; - p1 = p2 ^ axis; - - float n = getConfig()->getFloatValue("near-m"), - 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; -cone->setUseDisplayList(false); - osg::Vec3Array* vertices = new osg::Vec3Array(36); - (*vertices)[0] = osg::Vec3(0.0,0.0,0.0); - 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)[17] = (*vertices)[1]; + SGAnimation::install(node); - // Bottom - (*vertices)[18] = axis*f; - 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)[35] = (*vertices)[19]; - - osg::Vec4Array* colours = new osg::Vec4Array(1); - (*colours)[0].set( getConfig()->getFloatValue("color/red"), - getConfig()->getFloatValue("color/green"), - getConfig()->getFloatValue("color/blue"), - 1.0f); - cone->setColorArray(colours); - cone->setColorBinding(osg::Geometry::BIND_OVERALL); - - osg::Vec3Array* normals = new osg::Vec3Array(1); - (*normals)[0] = axis; - cone->setNormalArray(normals); - cone->setNormalBinding(osg::Geometry::BIND_OVERALL); - - cone->setVertexArray(vertices); - cone->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLE_FAN, 0, 18 ) ); - cone->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLE_FAN, 18, 18 ) ); - - simgear::EffectGeode* geode = new simgear::EffectGeode; - geode->addDrawable( cone ); - - node.asGroup()->addChild( geode ); - simgear::Effect *effect = simgear::makeEffect("Effects/light-spot", true); - if (effect) { - effect->parametersProp->setFloatValue("inner-angle",getConfig()->getFloatValue("angle-inner-deg")); - effect->parametersProp->setFloatValue("outer-angle",getConfig()->getFloatValue("angle-outer-deg")); - geode->setEffect(effect); + std::string light_type = getConfig()->getStringValue("light-type"); + if (light_type == "spot") { + + SGVec3d p1( _direction.z(), _direction.x(), _direction.y() ), + p2 = cross( _direction, p1 ); + p1 = cross( p2, _direction ); + + float r2 = _far * tan( _cutoff * SG_DEGREES_TO_RADIANS ); + + osg::Geometry* cone = new osg::Geometry; +cone->setUseDisplayList(false); + osg::Vec3Array* vertices = new osg::Vec3Array(34); + (*vertices)[0] = osg::Vec3(0.0,0.0,0.0); + for (int i=0; i<16; ++i) { + (*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]; + + // Bottom + for (int i=0; i<16; ++i) { + (*vertices)[18+i] = toOsg(_direction)*_far + toOsg(p1)*r2*cos( i * 2 * M_PI / 16 ) + toOsg(p2)*r2*sin( i * 2 * M_PI / 16 ); + } + + osg::Vec4Array* colours = new osg::Vec4Array(1); + (*colours)[0] = osg::Vec4d(toOsg(getConfig()->getValue("diffuse")), 1.0f); + cone->setColorArray(colours); + cone->setColorBinding(osg::Geometry::BIND_OVERALL); + + osg::Vec3Array* normals = new osg::Vec3Array(1); + (*normals)[0] = toOsg(_direction); + cone->setNormalArray(normals); + cone->setNormalBinding(osg::Geometry::BIND_OVERALL); + + cone->setVertexArray(vertices); + cone->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLE_FAN, 0, 18 ) ); + cone->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLE_FAN, 18, 16 ) ); + + simgear::EffectGeode* geode = new simgear::EffectGeode; + geode->addDrawable( cone ); + + node.asGroup()->addChild( geode ); + + // TODO: build a cache - problem: what is the key ? + SGPropertyNode_ptr effectProp = new SGPropertyNode; + 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); } - } } diff --git a/simgear/scene/model/animation.hxx b/simgear/scene/model/animation.hxx index d6c18633..fcd81a97 100644 --- a/simgear/scene/model/animation.hxx +++ b/simgear/scene/model/animation.hxx @@ -355,6 +355,16 @@ public: virtual osg::Group* createAnimationGroup(osg::Group& parent); virtual void install(osg::Node& node); 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 -- 2.39.2