Added osgSim library which encapulsulates light points.

Added osglightpoint demo.
This commit is contained in:
Robert Osfield 2002-11-19 10:57:40 +00:00
parent 5fca8ea229
commit e02ae73edc
19 changed files with 1618 additions and 4 deletions

View File

@ -14,6 +14,7 @@ SRC_DIRS = \
osgParticle\ osgParticle\
osgGLUT\ osgGLUT\
osgText\ osgText\
osgSim\
osgPlugins\ osgPlugins\
Demos Demos
@ -80,27 +81,28 @@ DEMOS_DIRS = \
osgcopy\ osgcopy\
osgcube\ osgcube\
osgcubemap\ osgcubemap\
osggeodemo\
osggeometry\ osggeometry\
osghangglide\ osghangglide\
osghud\ osghud\
osgimpostor\ osgimpostor\
osglight\ osglight\
osglightpoint\
osgmultitexture\ osgmultitexture\
osgoccluder\ osgoccluder\
osggeodemo\
osgparticle\ osgparticle\
osgprerender\ osgprerender\
osgreflect\ osgreflect\
osgscribe\ osgscribe\
osgstereoimage\
osgsequence\ osgsequence\
osgshape\ osgshape\
osgstereoimage\
osgteapot\ osgteapot\
osgtext\ osgtext\
osgtexture1D\ osgtexture1D\
osgtexture2D\ osgtexture2D\
osgtexture3D\ osgtexture3D\
osgunittests\ osgunittests\
osgviews\
osgversion\ osgversion\
osgviews\
sgv sgv

6
NEWS
View File

@ -2,9 +2,13 @@
OSG News (most significant items from ChangeLog) OSG News (most significant items from ChangeLog)
================================================ ================================================
Addition osgSim which is NodeKit designed for visual simulation
market, currently features high fidelity light points support.
13th November 2002 - OpenSceneGraph-0.9.2.tar.gz 13th November 2002 - OpenSceneGraph-0.9.2.tar.gz
>>> New AC3D and GEO loaders, new Shape primitives, improved OpenFlight support. . >>> New AC3D and GEO loaders, new Shape primitives, improved OpenFlight support.
From Geoff Michel, AC3D .wc and Carbon Graphics GEO .geo loaders. From Geoff Michel, AC3D .wc and Carbon Graphics GEO .geo loaders.

View File

@ -0,0 +1,151 @@
//C++ header - Open Scene Graph Simulation - Copyright (C) 1998-2002 Robert Osfield
// Distributed under the terms of the GNU General Public License (GPL)
// as published by the Free Software Foundation.
//
// All software using osgSim must be GPL'd or excempted via the
// purchase of the Open Scene Graph Professional License (OSGPL)
// for further information contact robert@openscenegraph.com.
#ifndef OSGSIM_BLINKSQUENCE
#define OSGSIM_BLINKSQUENCE 1
#include <osgSim/Export>
#include <osg/Quat>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/ref_ptr>
#include <vector>
namespace osgSim {
class OSGSIM_EXPORT BlinkSequence : public osg::Referenced
{
public:
/** sequence group which can be used to synchronize related blink sequences.*/
class OSGSIM_EXPORT SequenceGroup : public osg::Referenced
{
public:
SequenceGroup();
SequenceGroup(double baseTime);
double _baseTime;
};
BlinkSequence();
BlinkSequence(const BlinkSequence& bs);
/** add a pulse of specified color and duration to the BlinkSequence.*/
inline void addPulse(double length,const osg::Vec4& color);
/** get the total pulse period of the blink sequence, which is equal to the sum of all the pulse periods.*/
inline double getPulsePeriod() const { return _pulsePeriod; }
/** set the sequence group which can be used to synchronize related blink sequences.*/
inline void setSequenceGroup(SequenceGroup* sg) { _sequenceGroup = sg; }
/** get the non const sequence group.*/
inline SequenceGroup* getSequenceGroup() { return _sequenceGroup.get(); }
/** get the const sequence group.*/
inline const SequenceGroup* getSequenceGroup() const { return _sequenceGroup.get(); }
/** set the phase shift of the blink sequence, this would be used to shift a sequence within a sequence group.*/
inline void setPhaseShift(double ps) { _phaseShift = ps; }
/** get the pahse shift.*/
inline double getPhaseShift() const { return _phaseShift; }
/** compute the local time clamped to this BlinkSequences period, and accounting for the phase shift and sequence group.*/
inline double localTime(double time) const;
/** compute the color for the time interval sepecifed. Averages the colors if the length is greater than the current pulse.*/
inline osg::Vec4 color(double time,double length) const;
protected:
typedef std::pair<double,osg::Vec4> IntervalColor;
typedef std::vector<IntervalColor> PulseData;
double _pulsePeriod;
double _phaseShift;
PulseData _pulseData;
osg::ref_ptr<SequenceGroup> _sequenceGroup;
};
inline double BlinkSequence::localTime(double time) const
{
if (_sequenceGroup.valid()) time -= _sequenceGroup->_baseTime;
time -= _phaseShift;
return time - floor(time/_pulsePeriod)*_pulsePeriod;
}
inline void BlinkSequence::addPulse(double length,const osg::Vec4& color)
{
_pulseData.push_back(IntervalColor(length,color));
_pulsePeriod += length;
}
inline osg::Vec4 BlinkSequence::color(double time,double length) const
{
if (_pulseData.empty()) return osg::Vec4(1.0f,1.0f,1.0f,1.0f);
double lt = localTime(time);
PulseData::const_iterator itr = _pulseData.begin();
// find the first sample at this time point.
while (lt>itr->first)
{
lt -= itr->first;
++itr;
if (itr==_pulseData.end()) itr = _pulseData.begin();
}
// if time interval fits inside the current pulse
// then simply return this pulses color value.
if (lt+length<=itr->first)
{
return itr->second;
}
// time length exceeds the current pulse therefore
// we have to average out the pules to get the correct
// results...
// accumulate final part of the first active pulses.
osg::Vec4 color(itr->second*(itr->first-lt));
double len = length-(itr->first-lt);
++itr;
if (itr==_pulseData.end()) itr = _pulseData.begin();
// accumulate all the whole pluses pulses.
while (len>itr->first)
{
len -= itr->first;
color += itr->second*itr->first;
++itr;
if (itr==_pulseData.end()) itr = _pulseData.begin();
}
// add remaining part of the final pulse.
color += itr->second*len;
// normalise the time waited color.
color /= length;
return color;
}
}
#endif

40
include/osgSim/Export Normal file
View File

@ -0,0 +1,40 @@
//C++ header - Open Scene Graph Simulation - Copyright (C) 1998-2002 Robert Osfield
// Distributed under the terms of the GNU General Public License (GPL)
// as published by the Free Software Foundation.
//
// All software using osgSim must be GPL'd or excempted via the
// purchase of the Open Scene Graph Professional License (OSGPL)
// for further information contact robert@openscenegraph.com.
#ifndef OSGSIM_EXPORT_
#define OSGSIM_EXPORT_ 1
#if defined(WIN32) && !(defined(__CYGWIN__) || defined(__MINGW32__))
#pragma warning( disable : 4244 )
#pragma warning( disable : 4251 )
#pragma warning( disable : 4275 )
#pragma warning( disable : 4786 )
#pragma warning( disable : 4290 )
#endif
#if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) || defined( __BCPLUSPLUS__) || defined( __MWERKS__)
# ifdef OSGSIM_LIBRARY
# define OSGSIM_EXPORT __declspec(dllexport)
# else
# define OSGSIM_EXPORT __declspec(dllimport)
# endif /* SG_LIBRARY */
#else
# define OSGSIM_EXPORT
#endif
/* Define NULL pointer value */
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
#endif

44
include/osgSim/LightPoint Normal file
View File

@ -0,0 +1,44 @@
//C++ header - Open Scene Graph Simulation - Copyright (C) 1998-2002 Robert Osfield
// Distributed under the terms of the GNU General Public License (GPL)
// as published by the Free Software Foundation.
//
// All software using osgSim must be GPL'd or excempted via the
// purchase of the Open Scene Graph Professional License (OSGPL)
// for further information contact robert@openscenegraph.com.
#ifndef OSGSIM_LGIHTPOINT
#define OSGSIM_LIGHTPOINT 1
#include <osgSim/Export>
#include <osgSim/Sector>
#include <osgSim/BlinkSequence>
#include <osg/Quat>
#include <osg/Vec3>
#include <osg/Vec4>
namespace osgSim {
class OSGSIM_EXPORT LightPoint
{
public:
LightPoint();
LightPoint(const LightPoint& lp);
bool _on;
osg::Vec3 _position;
osg::Vec4 _color;
float _intensity;
float _radius;
float _maxPixelSize;
osg::ref_ptr<Sector> _sector;
osg::ref_ptr<BlinkSequence> _blinkSequence;
};
}
#endif

View File

@ -0,0 +1,113 @@
//C++ header - Open Scene Graph Simulation - Copyright (C) 1998-2002 Robert Osfield
// Distributed under the terms of the GNU General Public License (GPL)
// as published by the Free Software Foundation.
//
// All software using osgSim must be GPL'd or excempted via the
// purchase of the Open Scene Graph Professional License (OSGPL)
// for further information contact robert@openscenegraph.com.
#ifndef OSGSIM_LIGHTPOINTDRAWABLE
#define OSGSIM_LIGHTPOINTDRAWABLE 1
#include <osgSim/Export>
#include <osg/Drawable>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Depth>
#include <osg/BlendFunc>
#include <osg/ColorMask>
#include <osg/Point>
#include <vector>
namespace osgSim {
class OSGSIM_EXPORT LightPointDrawable : public osg::Drawable
{
public :
LightPointDrawable();
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
LightPointDrawable(const LightPointDrawable&,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
virtual osg::Object* cloneType() const { return osgNew LightPointDrawable(); }
virtual osg::Object* clone(const osg::CopyOp&) const { return osgNew LightPointDrawable(); }
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const LightPointDrawable*>(obj)!=NULL; }
virtual const char* className() const { return "LightPointDrawable"; }
//typedef std::pair<unsigned long,osg::Vec3> ColorPosition;
struct ColorPosition
{
unsigned long first;
osg::Vec3 second;
ColorPosition() {}
ColorPosition(unsigned long f,const osg::Vec3& s):first(f),second(s) {}
};
void reset()
{
for(SizedLightPointList::iterator itr=_sizedLightPointList.begin();
itr!=_sizedLightPointList.end();
++itr)
{
if (!itr->empty())
itr->erase(itr->begin(),itr->end());
}
}
inline void addLightPoint(unsigned int pointSize,const osg::Vec3& position,const osg::Vec4& color)
{
if (pointSize>=_sizedLightPointList.size()) _sizedLightPointList.resize(pointSize+1);
_sizedLightPointList[pointSize].push_back(ColorPosition(color.asRGBA(),position));
}
/** draw LightPoints. */
virtual void drawImplementation(osg::State& state) const;
void setReferenceTime(double time)
{
_referenceTime = time;
_referenceTimeInterval = 0.0;
}
void updateReferenceTime(double time)
{
_referenceTimeInterval = osg::clampAbove(time-_referenceTime,0.0);
_referenceTime = time;
}
double getReferenceTime() const { return _referenceTime; }
double getReferenceTimeInterval() const { return _referenceTimeInterval; }
protected:
virtual bool computeBound() const;
~LightPointDrawable() {}
double _referenceTime;
double _referenceTimeInterval;
typedef std::vector<ColorPosition> LightPointList;
typedef std::vector<LightPointList> SizedLightPointList;
SizedLightPointList _sizedLightPointList;
osg::ref_ptr<osg::Depth> _depthOff;
osg::ref_ptr<osg::Depth> _depthOn;
osg::ref_ptr<osg::BlendFunc> _blendOn;
osg::ref_ptr<osg::ColorMask> _colorMaskOff;
osg::ref_ptr<osg::Point> _point;
};
}
#endif

View File

@ -0,0 +1,72 @@
//C++ header - Open Scene Graph Simulation - Copyright (C) 1998-2002 Robert Osfield
// Distributed under the terms of the GNU General Public License (GPL)
// as published by the Free Software Foundation.
//
// All software using osgSim must be GPL'd or excempted via the
// purchase of the Open Scene Graph Professional License (OSGPL)
// for further information contact robert@openscenegraph.com.
#ifndef OSGSIM_LIGHTPOINTNODE
#define OSGSIM_LIGHTPOINTNODE 1
#include <osgSim/Export>
#include <osgSim/LightPoint>
#include <osgSim/LightPointDrawable>
#include <osg/Node>
#include <osg/NodeVisitor>
#include <osg/BoundingBox>
#include <osg/Quat>
#include <osg/Vec4>
#include <vector>
#include <set>
namespace osgSim {
class OSGSIM_EXPORT LightPointNode : public osg::Node
{
public :
typedef std::vector< LightPoint > LightPointList;
LightPointNode();
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
LightPointNode(const LightPointNode&,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
META_Node(osgSim,LightPointNode);
virtual void traverse(osg::NodeVisitor& nv);
unsigned int addLightPoint(const LightPoint& lp);
LightPoint& getLightPoint(unsigned int pos) { return _lightPointList[pos]; }
const LightPoint& getLightPoint(unsigned int pos) const { return _lightPointList[pos]; }
void removeLightPoint(unsigned int pos);
void removeLightPoints(LightPointList::iterator start,LightPointList::iterator end);
LightPointList _lightPointList;
protected:
~LightPointNode() {}
// used to cache the bouding box of the lightpoints as a tighter
// view frustum check.
mutable osg::BoundingBox _bbox;
virtual bool computeBound() const;
};
}
#endif

203
include/osgSim/Sector Normal file
View File

@ -0,0 +1,203 @@
//C++ header - Open Scene Graph Simulation - Copyright (C) 1998-2002 Robert Osfield
// Distributed under the terms of the GNU General Public License (GPL)
// as published by the Free Software Foundation.
//
// All software using osgSim must be GPL'd or excempted via the
// purchase of the Open Scene Graph Professional License (OSGPL)
// for further information contact robert@openscenegraph.com.
#ifndef OSGSIM_SECTOR
#define OSGSIM_SECTOR 1
#include <osgSim/Export>
#include <osg/Quat>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Math>
namespace osgSim {
class Sector : public osg::Referenced
{
public:
virtual float operator() (const osg::Vec3& /*eyeLocal*/) const = 0;
protected:
virtual ~Sector() {}
};
class OSGSIM_EXPORT AzimRange
{
public:
AzimRange():
_cosAzim(1.0f),
_sinAzim(0.0f),
_cosAngle(-1.0f),
_cosFadeAngle(-1.0f) {}
void setAzimuthRange(float minAzimuth,float maxAzimuth,float fadeAngle=0.0f);
inline float azimSector(const osg::Vec3& eyeLocal) const
{
float dotproduct = eyeLocal.x()*_sinAzim+eyeLocal.y()*_cosAzim;
float length = sqrt(osg::square(eyeLocal.x())+osg::square(eyeLocal.y()));
if (dotproduct<_cosFadeAngle*length) return 0.0f; // out of sector.
if (dotproduct>_cosAngle*length) return 1.0f; // fully in sector.
return (dotproduct-_cosFadeAngle*length)/((_cosAngle-_cosFadeAngle)*length);
}
protected:
float _cosAzim;
float _sinAzim;
float _cosAngle;
float _cosFadeAngle;
};
class OSGSIM_EXPORT ElevationRange
{
public:
ElevationRange():
_cosMinElevation(-1.0f),
_cosMinFadeElevation(-1.0f),
_cosMaxElevation(1.0),
_cosMaxFadeElevation(1.0) {}
void setElevationRange(float minElevation,float maxElevation,float fadeAngle=0.0f);
float getMinElevation() const;
float getMaxElevation() const;
inline float elevationSector(const osg::Vec3& eyeLocal) const
{
float dotproduct = eyeLocal.z(); // against z axis - eyeLocal*(0,0,1).
float length = eyeLocal.length();
if (dotproduct>_cosMaxFadeElevation*length) return 0.0f; // out of sector
if (dotproduct<_cosMinFadeElevation*length) return 0.0f; // out of sector
if (dotproduct>_cosMaxElevation*length)
{
// in uppoer fade band.
return (dotproduct-_cosMaxFadeElevation*length)/((_cosMaxElevation-_cosMaxFadeElevation)*length);
}
if (dotproduct<_cosMinElevation*length)
{
// in lower fade band.
return (dotproduct-_cosMinFadeElevation*length)/((_cosMinElevation-_cosMinFadeElevation)*length);
}
return 1.0f; // fully in sector
}
protected:
float _cosMinElevation;
float _cosMinFadeElevation;
float _cosMaxElevation;
float _cosMaxFadeElevation;
};
class OSGSIM_EXPORT AzimSector : public Sector, public AzimRange
{
public:
AzimSector():
Sector(),
AzimRange() {}
AzimSector(float minAzimuth,float maxAzimuth,float fadeAngle=0.0f);
virtual float operator() (const osg::Vec3& eyeLocal) const;
protected:
virtual ~AzimSector() {}
};
class OSGSIM_EXPORT ElevationSector : public Sector, public ElevationRange
{
public:
ElevationSector():
Sector(),
ElevationRange() {}
ElevationSector(float minElevation,float maxElevation,float fadeAngle=0.0f);
virtual float operator() (const osg::Vec3& eyeLocal) const;
protected:
virtual ~ElevationSector() {}
float _cosMinElevation;
float _cosMinFadeElevation;
float _cosMaxElevation;
float _cosMaxFadeElevation;
};
class OSGSIM_EXPORT AzimElevationSector : public Sector, public AzimRange, public ElevationRange
{
public:
AzimElevationSector():
Sector(),
AzimRange(),
ElevationRange() {}
AzimElevationSector(float minAzimuth,float maxAzimuth,float minElevation,float maxElevation,float fadeAngle=0.0f);
virtual float operator() (const osg::Vec3& eyeLocal) const;
protected:
virtual ~AzimElevationSector() {}
};
class OSGSIM_EXPORT ConeSector : public Sector
{
public:
ConeSector():
Sector(),
_axis(0.0f,0.0f,1.0f),
_cosAngle(-1.0f),
_cosAngleFade(-1.0f) {}
ConeSector(const osg::Vec3& axis,float angle,float fadeangle=0.0f);
void setAxis(const osg::Vec3& axis);
const osg::Vec3& getAxis() const;
void setAngle(float angle,float fadeangle=0.0f);
float getAngle() const;
float getFadeAngle() const;
virtual float operator() (const osg::Vec3& eyeLocal) const;
protected:
virtual ~ConeSector() {}
osg::Vec3 _axis;
float _cosAngle;
float _cosAngleFade;
};
}
#endif

41
include/osgSim/Version Normal file
View File

@ -0,0 +1,41 @@
//C++ header - Open Scene Graph Simulation - Copyright (C) 1998-2002 Robert Osfield
// Distributed under the terms of the GNU General Public License (GPL)
// as published by the Free Software Foundation.
//
// All software using osgSim must be GPL'd or excempted via the
// purchase of the Open Scene Graph Professional License (OSGPL)
// for further information contact robert@openscenegraph.com.
#ifndef OSGSIM_VERSION
#define OSGSIM_VERSION 1
#include <osgSim/Export>
extern "C" {
/**
* osgSimGetVersion() returns the library version number.
* Numbering convention : OpenSceneGraph-Sim-0.1 will return 0.1 from osgSimgetVersion.
*
* This C function can be also used to check for the existence of the OpenSceneGraph
* library using autoconf and its m4 macro AC_CHECK_LIB.
*
* Here is the code to add to your configure.in:
\verbatim
#
# Check for the OpenSceneGraph-Sim library
#
AC_CHECK_LIB(osg, osgSimGetVersion, ,
[AC_MSG_ERROR(OpenSceneGraph library not found. See http://www.openscenegraph.org)],)
\endverbatim
*/
extern SG_EXPORT const char* osgSimGetVersion();
/**
* osgSimGetLibraryName() returns the library name in human friendly form.
*/
extern SG_EXPORT const char* osgSimGetLibraryName();
}
#endif

View File

@ -0,0 +1,16 @@
TOPDIR = ../../..
include $(TOPDIR)/Make/makedefs
CXXFILES =\
osglightpoint.cpp\
LIBS += -losgSim $(OSG_LIBS) $(GLUT_LIB) $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS)
INSTFILES = \
$(CXXFILES)\
Makefile.inst=Makefile
EXEC = osglightpoint
include $(TOPDIR)/Make/makerules

View File

@ -0,0 +1,12 @@
TOPDIR = ../..
include $(TOPDIR)/Make/makedefs
CXXFILES =\
osglightpoint.cpp\
LIBS += -losgSim $(OSG_LIBS) $(GLUT_LIB) $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS)
EXEC = osglightpoint
include $(TOPDIR)/Make/makerules

View File

@ -0,0 +1,201 @@
#include <osg/GL>
#include <osgGLUT/glut>
#include <osgGLUT/Viewer>
#include <osg/Transform>
#include <osg/Billboard>
#include <osg/Geode>
#include <osg/Group>
#include <osg/Notify>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/DriveManipulator>
#include <osgUtil/Optimizer>
#include <osgSim/LightPointNode>
void write_usage(std::ostream& out,const std::string& name)
{
out << std::endl;
out <<"usage:"<< std::endl;
out <<" "<<name<<" [options] infile1 [infile2 ...]"<< std::endl;
out << std::endl;
out <<"options:"<< std::endl;
out <<" -l libraryName - load plugin of name libraryName"<< std::endl;
out <<" i.e. -l osgdb_pfb"<< std::endl;
out <<" Useful for loading reader/writers which can load"<< std::endl;
out <<" other file formats in addition to its extension."<< std::endl;
out <<" -e extensionName - load reader/wrter plugin for file extension"<< std::endl;
out <<" i.e. -e pfb"<< std::endl;
out <<" Useful short hand for specifying full library name as"<< std::endl;
out <<" done with -l above, as it automatically expands to"<< std::endl;
out <<" the full library name appropriate for each platform."<< std::endl;
out <<std::endl;
out <<" -stereo - switch on stereo rendering, using the default of,"<< std::endl;
out <<" ANAGLYPHIC or the value set in the OSG_STEREO_MODE "<< std::endl;
out <<" environmental variable. See doc/stereo.html for "<< std::endl;
out <<" further details on setting up accurate stereo "<< std::endl;
out <<" for your system. "<< std::endl;
out <<" -stereo ANAGLYPHIC - switch on anaglyphic(red/cyan) stereo rendering."<< std::endl;
out <<" -stereo QUAD_BUFFER - switch on quad buffered stereo rendering."<< std::endl;
out <<std::endl;
out <<" -stencil - use a visual with stencil buffer enabled, this "<< std::endl;
out <<" also allows the depth complexity statistics mode"<< std::endl;
out <<" to be used (press 'p' three times to cycle to it)."<< std::endl;
out << std::endl;
}
#define INTERPOLATE(member) lp.member = start.member*rstart + end.member*rend;
void addToLightPointNode(osgSim::LightPointNode& lpn,osgSim::LightPoint& start,osgSim::LightPoint& end,unsigned int noSteps)
{
if (noSteps<=1)
{
lpn.addLightPoint(start);
return;
}
float rend = 0.0f;
float rdelta = 1.0f/((float)noSteps-1.0f);
lpn._lightPointList.reserve(noSteps);
for(unsigned int i=0;i<noSteps;++i,rend+=rdelta)
{
float rstart = 1.0f-rend;
osgSim::LightPoint lp(start);
INTERPOLATE(_position)
INTERPOLATE(_intensity);
INTERPOLATE(_color);
INTERPOLATE(_radius);
//INTERPOLATE(_minPixelSize);
//INTERPOLATE(_maxPixelSize);
// INTERPOLATE(_maxVisibileDistance2);
lpn.addLightPoint(lp);
}
}
#undef INTERPOLATE
osg::Node* createLightPointsDatabase()
{
osgSim::LightPoint start;
osgSim::LightPoint end;
start._position.set(0.0f,0.0f,0.0f);
start._color.set(1.0f,0.0f,0.0f,1.0f);
end._position.set(1000.0f,0.0f,0.0f);
end._color.set(1.0f,1.0f,1.0f,1.0f);
osg::Transform* transform = osgNew osg::Transform;
osg::Vec3 start_delta(0.0f,10.0f,0.0f);
osg::Vec3 end_delta(0.0f,10.0f,1.0f);
int noStepsX = 100;
int noStepsY = 100;
// osgSim::BlinkSequence* bs = osgNew osgSim::BlinkSequence;
// bs->addPulse(1.0,osg::Vec4(1.0f,0.0f,0.0f,1.0f));
// bs->addPulse(0.5,osg::Vec4(0.0f,0.0f,0.0f,0.0f)); // off
// bs->addPulse(1.5,osg::Vec4(1.0f,1.0f,0.0f,1.0f));
// bs->addPulse(0.5,osg::Vec4(0.0f,0.0f,0.0f,0.0f)); // off
// bs->addPulse(1.0,osg::Vec4(1.0f,1.0f,1.0f,1.0f));
// bs->addPulse(0.5,osg::Vec4(0.0f,0.0f,0.0f,0.0f)); // off
// osgSim::Sector* sector = osgNew osgSim::ConeSector(osg::Vec3(0.0f,0.0f,1.0f),osg::inDegrees(45.0),osg::inDegrees(45.0));
// osgSim::Sector* sector = osgNew osgSim::ElevationSector(-osg::inDegrees(45.0),osg::inDegrees(45.0),osg::inDegrees(45.0));
// osgSim::Sector* sector = osgNew osgSim::AzimSector(-osg::inDegrees(45.0),osg::inDegrees(45.0),osg::inDegrees(90.0));
// osgSim::Sector* sector = osgNew osgSim::AzimElevationSector(osg::inDegrees(180),osg::inDegrees(90), // azim range
// osg::inDegrees(0.0),osg::inDegrees(90.0), // elevation range
// osg::inDegrees(5.0));
for(int i=0;i<noStepsY;++i)
{
// osgSim::BlinkSequence* local_bs = osgNew osgSim::BlinkSequence(*bs);
// local_bs->setSequenceGroup(osgNew osgSim::BlinkSequence::SequenceGroup((double)i*0.1));
// start._blinkSequence = local_bs;
// start._sector = sector;
osgSim::LightPointNode* lpn = osgNew osgSim::LightPointNode;
addToLightPointNode(*lpn,start,end,noStepsX);
start._position += start_delta;
end._position += end_delta;
transform->addChild(lpn);
}
osg::Group* group = osgNew osg::Group;
group->addChild(transform);
return group;
}
int main( int argc, char **argv )
{
// initialize the GLUT
glutInit( &argc, argv );
// create the commandline args.
std::vector<std::string> commandLine;
for(int i=1;i<argc;++i) commandLine.push_back(argv[i]);
// initialize the viewer.
osgGLUT::Viewer viewer;
viewer.setWindowTitle(argv[0]);
// configure the viewer from the commandline arguments, and eat any
// parameters that have been matched.
viewer.readCommandLine(commandLine);
// configure the plugin registry from the commandline arguments, and
// eat any parameters that have been matched.
osgDB::readCommandLine(commandLine);
osg::Group* rootnode = osgNew osg::Group;
// load the nodes from the commandline arguments.
rootnode->addChild(osgDB::readNodeFiles(commandLine));
rootnode->addChild(createLightPointsDatabase());
if (!rootnode)
{
return 1;
}
// run optimization over the scene graph
osgUtil::Optimizer optimzer;
optimzer.optimize(rootnode);
// add a viewport to the viewer and attach the scene graph.
viewer.addViewport( rootnode );
// register trackball, flight and drive.
viewer.registerCameraManipulator(new osgGA::TrackballManipulator);
viewer.registerCameraManipulator(new osgGA::FlightManipulator);
viewer.registerCameraManipulator(new osgGA::DriveManipulator);
// open the viewer window.
viewer.open();
// fire up the event loop.
viewer.run();
return 0;
}

View File

@ -6,6 +6,8 @@
#include <osgDB/Input> #include <osgDB/Input>
#include <osgDB/Output> #include <osgDB/Output>
#include <set>
using namespace osg; using namespace osg;
using namespace osgDB; using namespace osgDB;
using namespace std; using namespace std;

View File

@ -0,0 +1,40 @@
//C++ header - Open Scene Graph Simulation - Copyright (C) 1998-2002 Robert Osfield
// Distributed under the terms of the GNU General Public License (GPL)
// as published by the Free Software Foundation.
//
// All software using osgSim must be GPL'd or excempted via the
// purchase of the Open Scene Graph Professional License (OSGPL)
// for further information contact robert@openscenegraph.com.
#include <osgSim/BlinkSequence>
#include <stdlib.h>
using namespace osgSim;
BlinkSequence::BlinkSequence():
Referenced(),
_pulsePeriod(0.0),
_phaseShift(0.0),
_pulseData(),
_sequenceGroup(0) {}
BlinkSequence::BlinkSequence(const BlinkSequence& bs):
Referenced(),
_pulsePeriod(bs._pulsePeriod),
_phaseShift(bs._phaseShift),
_pulseData(bs._pulseData),
_sequenceGroup(bs._sequenceGroup) {}
BlinkSequence::SequenceGroup::SequenceGroup():
Referenced()
{
// set a random base time between 0 and 1000.0
_baseTime = ((double)rand()/(double)RAND_MAX)*1000.0;
}
BlinkSequence::SequenceGroup::SequenceGroup(double baseTime):
Referenced(),
_baseTime(baseTime) {}

35
src/osgSim/LightPoint.cpp Normal file
View File

@ -0,0 +1,35 @@
//C++ header - Open Scene Graph Simulation - Copyright (C) 1998-2002 Robert Osfield
// Distributed under the terms of the GNU General Public License (GPL)
// as published by the Free Software Foundation.
//
// All software using osgSim must be GPL'd or excempted via the
// purchase of the Open Scene Graph Professional License (OSGPL)
// for further information contact robert@openscenegraph.com.
#include <osgSim/LightPoint>
using namespace osgSim;
LightPoint::LightPoint():
_on(true),
_position(0.0f,0.0f,0.0f),
_color(1.0f,1.0f,1.0f,1.0f),
_intensity(1.0f),
_radius(1.0f),
_maxPixelSize(30),
_sector(0),
_blinkSequence(0)
{
}
LightPoint::LightPoint(const LightPoint& lp):
_on(lp._on),
_position(lp._position),
_color(lp._color),
_intensity(lp._intensity),
_radius(lp._radius),
_maxPixelSize(lp._maxPixelSize),
_sector(lp._sector),
_blinkSequence(lp._blinkSequence)
{
}

View File

@ -0,0 +1,131 @@
//C++ header - Open Scene Graph Simulation - Copyright (C) 1998-2002 Robert Osfield
// Distributed under the terms of the GNU General Public License (GPL)
// as published by the Free Software Foundation.
//
// All software using osgSim must be GPL'd or excempted via the
// purchase of the Open Scene Graph Professional License (OSGPL)
// for further information contact robert@openscenegraph.com.
#include <osgSim/LightPointDrawable>
#include <osg/Point>
using namespace osgSim;
LightPointDrawable::LightPointDrawable():
Drawable(),
_referenceTime(0.0),
_referenceTimeInterval(0.0),
_sizedLightPointList()
{
setSupportsDisplayList(false);
_depthOff = osgNew osg::Depth;
_depthOff->setWriteMask(false);
_depthOn = osgNew osg::Depth;
_depthOn->setWriteMask(true);
_blendOn = osgNew osg::BlendFunc;
_blendOn->setFunction(osg::BlendFunc::SRC_ALPHA,osg::BlendFunc::ONE);
_colorMaskOff = osgNew osg::ColorMask;
_colorMaskOff->setMask(false,false,false,false);
_point = osgNew osg::Point;
}
LightPointDrawable::LightPointDrawable(const LightPointDrawable& lpd,const osg::CopyOp& copyop):
Drawable(lpd,copyop),
_referenceTime(lpd._referenceTime),
_referenceTimeInterval(lpd._referenceTimeInterval),
_sizedLightPointList(lpd._sizedLightPointList)
{
}
void LightPointDrawable::drawImplementation(osg::State& state) const
{
if (_sizedLightPointList.empty()) return;
state.applyMode(GL_POINT_SMOOTH,true);
state.applyMode(GL_BLEND,true);
state.applyMode(GL_LIGHTING,false);
state.applyTextureMode(0,GL_TEXTURE_1D,false);
state.applyTextureMode(0,GL_TEXTURE_2D,false);
glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
state.applyAttribute(_blendOn.get());
state.applyAttribute(_depthOff.get());
int pointsize;
SizedLightPointList::const_iterator sitr;
for(pointsize=1,sitr=_sizedLightPointList.begin();
sitr!=_sizedLightPointList.end();
++sitr,++pointsize)
{
const LightPointList& lpl = *sitr;
if (!lpl.empty())
{
glPointSize(pointsize);
glInterleavedArrays(GL_C4UB_V3F,0,&lpl.front());
//state.setInterleavedArrays(GL_C4UB_V3F,0,&lpl.front());
glDrawArrays(GL_POINTS,0,lpl.size());
}
}
// switch on depth mask to do set up depth mask.
state.applyAttribute(_depthOn.get());
// glDepthMask(GL_TRUE);
state.applyMode(GL_BLEND,false);
state.applyAttribute(_colorMaskOff.get());
// glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
for(pointsize=1,sitr=_sizedLightPointList.begin();
sitr!=_sizedLightPointList.end();
++sitr,++pointsize)
{
const LightPointList& lpl = *sitr;
if (!lpl.empty())
{
glPointSize(pointsize);
glInterleavedArrays(GL_C4UB_V3F,0,&lpl.front());
//state.setInterleavedArrays(GL_C4UB_V3F,0,&lpl.front());
glDrawArrays(GL_POINTS,0,lpl.size());
}
}
glPointSize(1);
glHint(GL_POINT_SMOOTH_HINT,GL_FASTEST);
state.haveAppliedAttribute(osg::StateAttribute::POINT);
}
bool LightPointDrawable::computeBound() const
{
_bbox.init();
for(SizedLightPointList::const_iterator sitr=_sizedLightPointList.begin();
sitr!=_sizedLightPointList.end();
++sitr)
{
const LightPointList& lpl = *sitr;
for(LightPointList::const_iterator litr=lpl.begin();
litr!=lpl.end();
++litr)
{
_bbox.expandBy(litr->second);
}
}
return true;
}

View File

@ -0,0 +1,310 @@
//C++ header - Open Scene Graph Simulation - Copyright (C) 1998-2002 Robert Osfield
// Distributed under the terms of the GNU General Public License (GPL)
// as published by the Free Software Foundation.
//
// All software using osgSim must be GPL'd or excempted via the
// purchase of the Open Scene Graph Professional License (OSGPL)
// for further information contact robert@openscenegraph.com.
#include <osgSim/LightPointNode>
#include <osgSim/LightPointDrawable>
#include <osg/Timer>
#include <osg/BoundingBox>
#include <osg/BlendFunc>
#include <osg/Material>
#include <osgUtil/CullVisitor>
#include <typeinfo>
using namespace osgSim;
LightPointNode::LightPointNode()
{
}
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
LightPointNode::LightPointNode(const LightPointNode& lpn,const osg::CopyOp& copyop):
Node(lpn,copyop),
_lightPointList(lpn._lightPointList)
{
}
unsigned int LightPointNode::addLightPoint(const LightPoint& lp)
{
unsigned int num = _lightPointList.size();
_lightPointList.push_back(lp);
dirtyBound();
return num;
}
void LightPointNode::removeLightPoint(unsigned int pos)
{
if (pos<_lightPointList.size())
{
_lightPointList.erase(_lightPointList.begin()+pos);
dirtyBound();
}
dirtyBound();
}
void LightPointNode::removeLightPoints(LightPointList::iterator start,LightPointList::iterator end)
{
_lightPointList.erase(start,end);
}
bool LightPointNode::computeBound() const
{
_bsphere.init();
_bbox.init();
LightPointList::const_iterator itr;
for(itr=_lightPointList.begin();
itr!=_lightPointList.end();
++itr)
{
_bbox.expandBy(itr->_position);
}
_bsphere.set(_bbox.center(),0.0f);
for(itr=_lightPointList.begin();
itr!=_lightPointList.end();
++itr)
{
_bsphere.expandRadiusBy(itr->_position);
}
_bsphere_computed=true;
return true;
}
void LightPointNode::traverse(osg::NodeVisitor& nv)
{
//#define USE_TIMER
#ifdef USE_TIMER
osg::Timer timer;
osg::Timer_t t1=0,t2=0,t3=0,t4=0,t5=0,t6=0,t7=0,t8=0;
#endif
#ifdef USE_TIMER
t1 = timer.tick();
#endif
osgUtil::CullVisitor* cv = NULL;
if (typeid(nv)==typeid(osgUtil::CullVisitor))
{
cv = static_cast<osgUtil::CullVisitor*>(&nv);
}
#ifdef USE_TIMER
t2 = timer.tick();
#endif
// should we disabled small feature culling here?
if (cv /*&& !cv->isCulled(_bbox)*/)
{
osg::Matrix matrix = cv->getModelViewMatrix();
osg::Matrix& projection = cv->getProjectionMatrix();
osgUtil::RenderGraph* rg = cv->getCurrentRenderGraph();
if (rg->leaves_empty())
{
// this is first leaf to be added to RenderGraph
// and therefore should not already know to current render bin,
// so need to add it.
cv->getCurrentRenderBin()->addRenderGraph(rg);
}
#ifdef USE_TIMER
t3 = timer.tick();
#endif
LightPointDrawable* drawable = NULL;
osg::Referenced* object = rg->getUserData();
if (object)
{
if (typeid(*object)==typeid(LightPointDrawable))
{
// resuse the user data attached to the render graph.
drawable = static_cast<LightPointDrawable*>(object);
}
else
{
// will need to replace UserData.
osg::notify(osg::WARN) << "Warning: Replacing osgUtil::RenderGraph::_userData to support osgSim::LightPointNode, may have undefined results."<<std::endl;
}
}
if (!drawable)
{
// set it for the frst time.
drawable = osgNew LightPointDrawable;
rg->setUserData(drawable);
if (cv->getFrameStamp())
{
drawable->setReferenceTime(cv->getFrameStamp()->getReferenceTime());
}
}
// search for a drawable in the RenderLead list equal to the attached the one attached to RenderGraph user data
// as this will be our special light point drawable.
osgUtil::RenderGraph::LeafList::iterator litr;
for(litr = rg->_leaves.begin();
litr != rg->_leaves.end() && (*litr)->_drawable!=drawable;
++litr)
{}
if (litr == rg->_leaves.end())
{
// havn't found the drawable added in the RenderLeaf list, there this my be the
// first time through LightPointNode in this frame, so need to add drawable into the RenderGraph RenderLeaf list
// and update its time signatures.
drawable->reset();
rg->addLeaf(osgNew osgUtil::RenderLeaf(drawable,&projection,NULL,FLT_MAX));
// need to update the drawable's frame count.
if (cv->getFrameStamp())
{
drawable->updateReferenceTime(cv->getFrameStamp()->getReferenceTime());
}
}
#ifdef USE_TIMER
t4 = timer.tick();
#endif
#ifdef USE_TIMER
t7 = timer.tick();
#endif
cv->updateCalculatedNearFar(matrix,_bbox);
const float minimumIntensity = 1.0f/256.0f;
const osg::Vec3 eyePoint = cv->getEyeLocal();
double time=drawable->getReferenceTime();
double timeInterval=drawable->getReferenceTimeInterval();
const osg::Polytope clipvol(cv->getModelViewCullingStack().back()->getFrustum());
const bool computeClipping = false;//(clipvol.getCurrentMask()!=0);
//LightPointDrawable::ColorPosition cp;
for(LightPointList::iterator itr=_lightPointList.begin();
itr!=_lightPointList.end();
++itr)
{
const LightPoint& lp = *itr;
if (!lp._on) continue;
const osg::Vec3& position = lp._position;
// skip light point if it is not contianed in the view frustum.
if (computeClipping && !clipvol.contains(position)) continue;
// delta vector between eyepoint and light point.
osg::Vec3 dv(eyePoint-position);
float intensity = lp._intensity;
// slip light point if it is intensity is 0.0 or negative.
if (intensity<=minimumIntensity) continue;
osg::Vec4 color = lp._color;
// check the sector.
if (lp._sector.valid())
{
intensity *= (*lp._sector)(dv);
// slip light point if it is intensity is 0.0 or negative.
if (intensity<=minimumIntensity) continue;
}
// temporary accounting of intensity.
//color *= intensity;
// check the blink sequence.
if (lp._blinkSequence.valid())
{
osg::Vec4 bs = lp._blinkSequence->color(time,timeInterval);
color[0] *= bs[0];
color[1] *= bs[1];
color[2] *= bs[2];
color[3] *= bs[3];
}
// if alpha value is less than the min intentsive then skip
if (color[3]<=minimumIntensity) continue;
float pixelSize = cv->pixelSize(position,lp._radius);
// cout << "pixelsize = "<<pixelSize<<endl;
// adjust pixel size to account for intensity.
if (intensity!=1.0) pixelSize *= sqrt(intensity);
if (pixelSize<1.0f)
{
// need to use alpha blending...
//color[3] = pixelSize;
color[3] *= osg::square(pixelSize);
if (color[3]<=minimumIntensity) continue;
drawable->addLightPoint(0, position*matrix,color);
}
else if (pixelSize<lp._maxPixelSize)
{
unsigned int lowerBoundPixelSize = (unsigned int)pixelSize;
//float remainder = pixelSize-(float)lowerBoundPixelSize;
float remainder = osg::square(pixelSize-(float)lowerBoundPixelSize);
osg::Vec3 xpos = position*matrix;
float alpha = color[3];
color[3] = alpha*(1.0f-remainder);
drawable->addLightPoint(lowerBoundPixelSize-1, xpos,color);
//color[3] = osg::square(remainder);
color[3] = alpha*remainder;
drawable->addLightPoint(lowerBoundPixelSize, xpos,color);
}
else // use a billboard geometry.
{
drawable->addLightPoint((unsigned int)(lp._maxPixelSize-1.0), position*matrix,color);
}
}
#ifdef USE_TIMER
t8 = timer.tick();
#endif
}
#ifdef USE_TIMER
cout << "compute"<<endl;
cout << " t2-t1="<<t2-t1<<endl;
cout << " t4-t3="<<t4-t3<<endl;
cout << " t6-t5="<<t6-t5<<endl;
cout << " t8-t7="<<t8-t7<<endl;
cout << "_lightPointList.size()="<<_lightPointList.size()<<endl;
cout << " t8-t7/size = "<<(float)(t8-t7)/(float)_lightPointList.size()<<endl;
#endif
}

19
src/osgSim/Makefile Normal file
View File

@ -0,0 +1,19 @@
TOPDIR = ../..
include $(TOPDIR)/Make/makedefs
CXXFILES = \
BlinkSequence.cpp\
LightPoint.cpp\
LightPointDrawable.cpp\
LightPointNode.cpp\
Sector.cpp\
DEF += -DOSGSIM_LIBRARY
LIBS += -losg $(GL_LIBS) $(OTHER_LIBS)
TARGET_BASENAME = osgSim
LIB = $(LIB_PREFIX)$(TARGET_BASENAME).$(LIB_EXT)
include $(TOPDIR)/Make/makerules

178
src/osgSim/Sector.cpp Normal file
View File

@ -0,0 +1,178 @@
//C++ header - Open Scene Graph Simulation - Copyright (C) 1998-2002 Robert Osfield
// Distributed under the terms of the GNU General Public License (GPL)
// as published by the Free Software Foundation.
//
// All software using osgSim must be GPL'd or excempted via the
// purchase of the Open Scene Graph Professional License (OSGPL)
// for further information contact robert@openscenegraph.com.
#include <osgSim/Sector>
using namespace osgSim;
//
// Elevation Range
//
void AzimRange::setAzimuthRange(float minAzimuth,float maxAzimuth,float fadeAngle)
{
// clamp the azimuth range.
const float twoPI = 2.0f*(float)osg::PI;
while(minAzimuth>maxAzimuth) minAzimuth -= twoPI;
// compute the centerline
float centerAzim = (minAzimuth+maxAzimuth)*0.5f;
_cosAzim = cos(centerAzim);
_sinAzim = sin(centerAzim);
// compute the half angle range of the sector.
float angle = (maxAzimuth-minAzimuth)*0.5f;
_cosAngle = cos(angle);
// clamp the fade angle to valid values.
fadeAngle = osg::clampAbove(fadeAngle,0.0f);
if (angle+fadeAngle>osg::PI) _cosFadeAngle = -1.0f;
else _cosFadeAngle = cos(angle+fadeAngle);
}
//
// Elevation Range
//
void ElevationRange::setElevationRange(float minElevation,float maxElevation,float fadeAngle)
{
if (minElevation>maxElevation)
{
// need to swap angle pair.
float tmp = minElevation;
minElevation = maxElevation;
maxElevation = tmp;
}
minElevation = osg::clampTo(minElevation,(float)-osg::PI_2,(float)osg::PI_2);
maxElevation = osg::clampTo(maxElevation,(float)-osg::PI_2,(float)osg::PI_2);
fadeAngle = osg::clampTo(fadeAngle,0.0f,(float)osg::PI_2);
_cosMinElevation = cos(osg::PI_2-minElevation);
_cosMaxElevation = cos(osg::PI_2-maxElevation);
float minFadeAngle = osg::PI_2-minElevation+fadeAngle;
if (minFadeAngle>=osg::PI) _cosMinFadeElevation = -1.0f;
else _cosMinFadeElevation = cos(minFadeAngle);
float maxFadeAngle = osg::PI_2-maxElevation-fadeAngle;
if (maxFadeAngle<=0.0f) _cosMaxFadeElevation = 1.0f;
else _cosMaxFadeElevation = cos(maxFadeAngle);
}
float ElevationRange::getMinElevation() const
{
return osg::PI_2-acos(_cosMinElevation);
}
float ElevationRange::getMaxElevation() const
{
return osg::PI_2-acos(_cosMaxElevation);
}
//
// ElevationSector
//
AzimSector::AzimSector(float minAzimuth,float maxAzimuth,float fadeAngle):
Sector(),
AzimRange()
{
setAzimuthRange(minAzimuth,maxAzimuth,fadeAngle);
}
float AzimSector::operator() (const osg::Vec3& eyeLocal) const
{
return azimSector(eyeLocal);
}
//
// ElevationSector
//
ElevationSector::ElevationSector(float minElevation,float maxElevation,float fadeAngle):
Sector(),
ElevationRange()
{
setElevationRange(minElevation,maxElevation,fadeAngle);
}
float ElevationSector::operator() (const osg::Vec3& eyeLocal) const
{
return elevationSector(eyeLocal);
}
//
// AzimElevationSector
//
AzimElevationSector::AzimElevationSector(float minAzimuth,float maxAzimuth,float minElevation,float maxElevation,float fadeAngle):
Sector(),
AzimRange(),
ElevationRange()
{
setAzimuthRange(minAzimuth,maxAzimuth,fadeAngle);
setElevationRange(minElevation,maxElevation,fadeAngle);
}
float AzimElevationSector::operator() (const osg::Vec3& eyeLocal) const
{
float azimIntensity = azimSector(eyeLocal);
if (azimIntensity==0.0) return 0.0; // out of sector.
float elevIntensity = elevationSector(eyeLocal);
if (elevIntensity==0.0) return 0.0; // out of sector.
if (azimIntensity<=elevIntensity) return azimIntensity;
return elevIntensity;
}
//
// ConeSector
//
ConeSector::ConeSector(const osg::Vec3& axis,float angle,float fadeangle):
Sector()
{
setAxis(axis);
setAngle(angle,fadeangle);
}
void ConeSector::setAxis(const osg::Vec3& axis)
{
_axis = axis;
_axis.normalize();
}
const osg::Vec3& ConeSector::getAxis() const
{
return _axis;
}
void ConeSector::setAngle(float angle,float fadeangle)
{
_cosAngle = cos(angle);
_cosAngleFade = cos(angle+fadeangle);
}
float ConeSector::getAngle() const
{
return acos(_cosAngle);
}
float ConeSector::getFadeAngle() const
{
return acos(_cosAngleFade)-acos(_cosAngle);
}
float ConeSector::operator() (const osg::Vec3& eyeLocal) const
{
float dotproduct = eyeLocal*_axis;
float length = eyeLocal.length();
if (dotproduct>_cosAngle*length) return 1.0f; // fully in sector
if (dotproduct<_cosAngleFade*length) return 0.0f; // out of sector
return (dotproduct-_cosAngleFade*length)/((_cosAngle-_cosAngleFade)*length);
}