diff --git a/Make/makedefs.linux b/Make/makedefs.linux index db7c0ae02..16e28e1d9 100644 --- a/Make/makedefs.linux +++ b/Make/makedefs.linux @@ -10,16 +10,16 @@ C++ = g++ YFLAGS = -d LCINCS += -I/usr/X11R6/include LC++INCS += ${LCINCS} -#CFLAGS = -O2 -W -Wall $(LCINCS) -CFLAGS = -g -DOSG_USE_MEMORY_MANAGER -W -Wall $(LCINCS) +CFLAGS = -O2 -W -Wall $(LCINCS) +#CFLAGS = -g -DOSG_USE_MEMORY_MANAGER -W -Wall $(LCINCS) C++FLAGS = ${CFLAGS} CPPFLAGS = ${CFLAGS} SO_EXT = so DL_EXT = so -#LDFLAGS = -O2 -W -Wall -L/usr/X11R6/lib -LDFLAGS = -g -W -Wall -L/usr/X11R6/lib +LDFLAGS = -O2 -W -Wall -L/usr/X11R6/lib +#LDFLAGS = -g -W -Wall -L/usr/X11R6/lib LINKERARGS = -Xlinker DYNAMICLIBRARYLIB = -ldl diff --git a/VisualStudio/osg/osg.dsp b/VisualStudio/osg/osg.dsp index 2b9a0f970..3b5bb6c14 100755 --- a/VisualStudio/osg/osg.dsp +++ b/VisualStudio/osg/osg.dsp @@ -269,6 +269,10 @@ SOURCE=..\..\src\osg\PositionAttitudeTransform.cpp # End Source File # Begin Source File +SOURCE=..\..\src\osg\Projection.cpp +# End Source File +# Begin Source File + SOURCE=..\..\src\osg\Quat.cpp # End Source File # Begin Source File @@ -549,6 +553,10 @@ SOURCE=..\..\Include\Osg\PositionAttitudeTransform # End Source File # Begin Source File +SOURCE=..\..\Include\Osg\Projection +# End Source File +# Begin Source File + SOURCE=..\..\Include\Osg\Quat # End Source File # Begin Source File diff --git a/VisualStudio/osgUtil/osgUtil.dsp b/VisualStudio/osgUtil/osgUtil.dsp index 0e9af5ca9..9a9552fd4 100755 --- a/VisualStudio/osgUtil/osgUtil.dsp +++ b/VisualStudio/osgUtil/osgUtil.dsp @@ -109,6 +109,10 @@ SOURCE=..\..\src\osgUtil\CullVisitor.cpp # End Source File # Begin Source File +SOURCE=..\..\src\osgUtil\NewCullVisitor.cpp +# End Source File +# Begin Source File + SOURCE=..\..\src\osgUtil\DepthSortedBin.cpp # End Source File # Begin Source File @@ -225,6 +229,10 @@ SOURCE=..\..\Include\osgUtil\CullVisitor # End Source File # Begin Source File +SOURCE=..\..\Include\osgUtil\NewCullVisitor +# End Source File +# Begin Source File + SOURCE=..\..\Include\osgUtil\DepthSortedBin # End Source File # Begin Source File diff --git a/include/osg/Camera b/include/osg/Camera index a42766607..333fd7981 100644 --- a/include/osg/Camera +++ b/include/osg/Camera @@ -243,20 +243,12 @@ class SG_EXPORT Camera: public osg::Referenced const Matrix& getModelViewMatrix() const; - /** Switch on/off the use of the near clipping plane which creating the - * getClippingVolume(), uses the camera _znear value for the position of the - * near clipping plane. By default this value is off.*/ - void setUseNearClippingPlane(const bool use); - /** get whether the ClippingVolume uses a near clipping plane.*/ - const bool getUseNearClippingPlane() const { return _useNearClippingPlane; } - - - /** Switch on/off the use of the far clipping plane which creating the + /** Switch on/off the use of the near and far clipping plane which creating the * getClippingVolume(), uses the camera _zfar value for the position * of the far clipping plane. By default this value is off.*/ - void setUseFarClippingPlane(const bool use); - /** Get whether the ClippingVolume uses a far clipping plane.*/ - const bool getUseFarClippingPlane() const { return _useFarClippingPlane; } + void setUseNearAndFarClippingPlanes(const bool use); + /** Get whether the ClippingVolume uses a near and far clipping planes.*/ + const bool getUseNearAndFarClippingPlanes() const { return _useNearAndFarClippingPlanes; } /** get the view frustum clipping in model coordinates */ const ClippingVolume& getClippingVolume() const; @@ -348,9 +340,8 @@ class SG_EXPORT Camera: public osg::Referenced ref_ptr _eyeToModelTransform; ref_ptr _modelToEyeTransform; - // flags to determine if near and far clipping planes are required. - bool _useNearClippingPlane; - bool _useFarClippingPlane; + // flag to determine if near and far clipping planes are required. + bool _useNearAndFarClippingPlanes; // cached matrix and clipping volume derived from above settings. mutable bool _dirty; diff --git a/include/osg/ClippingVolume b/include/osg/ClippingVolume index 169680e57..2629c0af1 100644 --- a/include/osg/ClippingVolume +++ b/include/osg/ClippingVolume @@ -36,6 +36,29 @@ class SG_EXPORT ClippingVolume _planeList = cv._planeList; return *this; } + + /** Create a ClippingVolume with is cube, centered at 0,0,0, with sides of 2 units.*/ + void setToUnitFrustum() + { + _planeList.clear(); + _planeList.push_back(Plane(1.0f,0.0f,0.0f,1.0f)); // left plane. + _planeList.push_back(Plane(-1.0f,0.0f,0.0f,1.0f)); // right plane. + _planeList.push_back(Plane(0.0f,1.0f,0.0f,1.0f)); // bottom plane. + _planeList.push_back(Plane(0.0f,-1.0f,0.0f,1.0f)); // top plane. + _planeList.push_back(Plane(0.0f,0.0f,-1.0f,1.0f)); // near plane + _planeList.push_back(Plane(0.0f,0.0f,1.0f,1.0f)); // far plane + setupMask(); + } + + void setToUnitFrustumWithoutNearFar() + { + _planeList.clear(); + _planeList.push_back(Plane(1.0f,0.0f,0.0f,1.0f)); // left plane. + _planeList.push_back(Plane(-1.0f,0.0f,0.0f,1.0f)); // right plane. + _planeList.push_back(Plane(0.0f,1.0f,0.0f,1.0f)); // bottom plane. + _planeList.push_back(Plane(0.0f,-1.0f,0.0f,1.0f)); // top plane. + setupMask(); + } inline void set(const ClippingVolume& cs) { _planeList = cs._planeList; setupMask(); } diff --git a/include/osg/NodeVisitor b/include/osg/NodeVisitor index 34186974c..b4d1a4974 100644 --- a/include/osg/NodeVisitor +++ b/include/osg/NodeVisitor @@ -16,6 +16,7 @@ class Billboard; class LightSource; class Group; class Transform; +class Projection; class LOD; class Switch; class Impostor; @@ -170,6 +171,7 @@ class SG_EXPORT NodeVisitor : public Referenced virtual void apply(LightSource& node){ apply((Node&)node); } virtual void apply(Group& node) { apply((Node&)node); } + virtual void apply(Projection& node) { apply((Group&)node); } virtual void apply(Transform& node) { apply((Group&)node); } virtual void apply(Switch& node) { apply((Group&)node); } virtual void apply(LOD& node) { apply((Group&)node); } diff --git a/include/osg/Projection b/include/osg/Projection new file mode 100644 index 000000000..042168709 --- /dev/null +++ b/include/osg/Projection @@ -0,0 +1,52 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +#ifndef OSG_PROJECTION +#define OSG_PROJECTION 1 + +#include +#include + +namespace osg { + +/** Projection nodes set up the frustum/orthographic projection used when rendering the scene . +*/ +class SG_EXPORT Projection : public Group +{ + public : + + + Projection(); + + /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ + Projection(const Projection&,const CopyOp& copyop=CopyOp::SHALLOW_COPY); + + Projection(const Matrix& matix); + + META_Node(Projection); + + /** Set the transform's matrix.*/ + void setMatrix(const Matrix& mat) { (*_matrix) = mat; } + + /** Get the transform's matrix. */ + inline const Matrix& getMatrix() const { return *_matrix; } + + /** preMult transform.*/ + void preMult(const Matrix& mat) { _matrix->preMult(mat); } + + /** postMult transform.*/ + void postMult(const Matrix& mat) { _matrix->postMult(mat); } + + + protected : + + virtual ~Projection(); + + ref_ptr _matrix; + +}; + +} + +#endif diff --git a/include/osg/Transform b/include/osg/Transform index 9d896cbb1..5de56339d 100644 --- a/include/osg/Transform +++ b/include/osg/Transform @@ -66,12 +66,6 @@ class SG_EXPORT Transform : public Group /** Get the transform mode.*/ inline const MatrixMode getMatrixMode() const { return _mode; } - /** Does the tranform set up the projection matrix.*/ - inline const bool isProjectionTransform() const { return _mode==PROJECTION; } - - /** Does the tranform set up the modelview matrix.*/ - inline const bool isModelViewTransform() const { return _mode!=PROJECTION; } - /** Callback attached to an Transform to specifiy how to compute the modelview or projection transformation * for the transform below the Transform node.*/ struct ComputeTransformCallback : public osg::Referenced diff --git a/include/osgUtil/CullViewState b/include/osgUtil/CullViewState index 9cdfca5dc..a0defbc76 100644 --- a/include/osgUtil/CullViewState +++ b/include/osgUtil/CullViewState @@ -23,6 +23,7 @@ class OSGUTIL_EXPORT CullViewState : public osg::Referenced CullViewState(); + osg::ref_ptr _projection; osg::ref_ptr _matrix; osg::ref_ptr _inverse; osg::Vec3 _eyePoint; diff --git a/include/osgUtil/CullVisitor b/include/osgUtil/CullVisitor index f08a031bb..7f1d24764 100644 --- a/include/osgUtil/CullVisitor +++ b/include/osgUtil/CullVisitor @@ -54,6 +54,7 @@ class OSGUTIL_EXPORT CullVisitor : public osg::NodeVisitor virtual void apply(osg::Group& node); virtual void apply(osg::Transform& node); + virtual void apply(osg::Projection& node); virtual void apply(osg::Switch& node); virtual void apply(osg::LOD& node); virtual void apply(osg::EarthSky& node); @@ -128,9 +129,11 @@ class OSGUTIL_EXPORT CullVisitor : public osg::NodeVisitor /** Get the viewport. */ osg::Viewport* getViewport() { return _viewport.get(); } - inline void pushCullViewState() { pushCullViewState(NULL,NULL); } - void pushCullViewState(osg::Matrix* matrix); - void pushCullViewState(osg::Matrix* matrix,osg::Matrix* inverse); + inline void pushCullViewState() { pushCullViewState_ModelView(NULL,NULL); } + + void pushCullViewState_Projection(osg::Matrix* matrix); + void pushCullViewState_ModelView(osg::Matrix* matrix); + void pushCullViewState_ModelView(osg::Matrix* matrix,osg::Matrix* inverse); void popCullViewState(); @@ -284,7 +287,7 @@ class OSGUTIL_EXPORT CullVisitor : public osg::NodeVisitor _currentRenderBin->addRenderGraph(_currentRenderGraph); } //_currentRenderGraph->addLeaf(new RenderLeaf(drawable,matrix)); - _currentRenderGraph->addLeaf(createOrReuseRenderLeaf(drawable,matrix)); + _currentRenderGraph->addLeaf(createOrReuseRenderLeaf(drawable,_cvs->_projection.get(),matrix)); } /** Add a drawable and depth to current render graph.*/ @@ -298,7 +301,7 @@ class OSGUTIL_EXPORT CullVisitor : public osg::NodeVisitor _currentRenderBin->addRenderGraph(_currentRenderGraph); } //_currentRenderGraph->addLeaf(new RenderLeaf(drawable,matrix,depth)); - _currentRenderGraph->addLeaf(createOrReuseRenderLeaf(drawable,matrix,depth)); + _currentRenderGraph->addLeaf(createOrReuseRenderLeaf(drawable,_cvs->_projection.get(),matrix,depth)); } /** Add a light to current render graph.*/ @@ -379,7 +382,7 @@ class OSGUTIL_EXPORT CullVisitor : public osg::NodeVisitor RenderLeafList _reuseRenderLeafList; unsigned int _currentReuseRenderLeafIndex; - inline RenderLeaf* createOrReuseRenderLeaf(osg::Drawable* drawable,osg::Matrix* matrix, float depth=0.0f) + inline RenderLeaf* createOrReuseRenderLeaf(osg::Drawable* drawable,osg::Matrix* projection,osg::Matrix* matrix, float depth=0.0f) { // skip of any already reused renderleaf. while (_currentReuseRenderLeafIndex<_reuseRenderLeafList.size() && @@ -394,12 +397,12 @@ class OSGUTIL_EXPORT CullVisitor : public osg::NodeVisitor if (_currentReuseRenderLeafIndex<_reuseRenderLeafList.size()) { RenderLeaf* renderleaf = _reuseRenderLeafList[_currentReuseRenderLeafIndex++].get(); - renderleaf->set(drawable,matrix,depth); + renderleaf->set(drawable,projection,matrix,depth); return renderleaf; } // otherwise need to create new renderleaf. - RenderLeaf* renderleaf = new RenderLeaf(drawable,matrix,depth); + RenderLeaf* renderleaf = new RenderLeaf(drawable,projection,matrix,depth); _reuseRenderLeafList.push_back(renderleaf); ++_currentReuseRenderLeafIndex; return renderleaf; diff --git a/include/osgUtil/NewCullVisitor b/include/osgUtil/NewCullVisitor new file mode 100644 index 000000000..f0344e6ac --- /dev/null +++ b/include/osgUtil/NewCullVisitor @@ -0,0 +1,391 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +#ifndef OSGUTIL_NEWCULLVISITOR +#define OSGUTIL_NEWCULLVISITOR 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +namespace osgUtil { + +/** + * Basic NodeVisitor implementation for rendering a scene. + * This visitor traverses the scene graph, collecting transparent and + * opaque osg::Drawables into a depth sorted transparent bin and a state + * sorted opaque bin. The opaque bin is rendered first, and then the + * transparent bin in rendered in order from the furthest osg::Drawable + * from the eye to the one nearest the eye. + */ +class OSGUTIL_EXPORT NewCullVisitor : public osg::NodeVisitor +{ + public: + + NewCullVisitor(); + virtual ~NewCullVisitor(); + + virtual NewCullVisitor* cloneType() const { return new NewCullVisitor(); } + + virtual void reset(); + + virtual void apply(osg::Node&); + virtual void apply(osg::Geode& node); + virtual void apply(osg::Billboard& node); + virtual void apply(osg::LightSource& node); + + virtual void apply(osg::Group& node); + virtual void apply(osg::Transform& node); + virtual void apply(osg::Projection& node); + virtual void apply(osg::Switch& node); + virtual void apply(osg::LOD& node); + virtual void apply(osg::EarthSky& node); + virtual void apply(osg::Impostor& node); + + + + void setCamera(const osg::Camera& camera); + const osg::Camera* getCamera() const { return _camera.get(); } + + + void setEarthSky(const osg::EarthSky* earthSky) { _earthSky = earthSky; } + const osg::EarthSky* getEarthSky() const { return _earthSky.get(); } + + + void setLODBias(const float bias) { _LODBias = bias; } + const float getLODBias() const { return _LODBias; } + + /** Switch the creation of Impostors on or off. + * Setting active to false forces the NewCullVisitor to use the Impostor + * LOD children for rendering. Setting active to true forces the + * NewCullVisitor to create the appropriate pre-rendering stages which + * render to the ImpostorSprite's texture.*/ + void setImpostorsActive(const bool active) { _impostorActive = active; } + + /** Get whether impostors are active or not. */ + const bool getImpostorsActive() const { return _impostorActive; } + + /** Set the impostor error threshold. + * Used in calculation of whether impostors remain valid.*/ + void setImpostorPixelErrorThreshold(const float numPixels) { _impostorPixelErrorThreshold=numPixels; } + + /** Get the impostor error threshold.*/ + const float getImpostorPixelErrorThreshold() const { return _impostorPixelErrorThreshold; } + + /** Set whether ImpsotorSprite's should be placed in a depth sorted bin for rendering.*/ + void setDepthSortImpostorSprites(const bool doDepthSort) { _depthSortImpostorSprites = doDepthSort; } + + /** Get whether ImpsotorSprite's are depth sorted bin for rendering.*/ + const bool setDepthSortImpostorSprites() const { return _depthSortImpostorSprites; } + + /** Set the number of frames that an ImpsotorSprite's is kept whilst not being beyond, + * before being recycled.*/ + void setNumberOfFrameToKeepImpostorSprites(const int numFrames) { _numFramesToKeepImpostorSprites = numFrames; } + + /** Get the number of frames that an ImpsotorSprite's is kept whilst not being beyond, + * before being recycled.*/ + const int getNumberOfFrameToKeepImpostorSprites() const { return _numFramesToKeepImpostorSprites; } + + enum TransparencySortMode { + LOOK_VECTOR_DISTANCE, + OBJECT_EYE_POINT_DISTANCE + }; + + void setTransparencySortMode(TransparencySortMode tsm) { _tsm = tsm; } + + /** Sets the current CullingMode.*/ + void setCullingMode(CullViewState::CullingMode mode); + + /** Returns the current CullingMode.*/ + CullViewState::CullingMode getCullingMode() const; + + + /** Set the viewport. + * Used to enable the NewCullVisitor can make decision + * such as based on viewport dimensions.*/ + void setViewport(osg::Viewport* viewport) { _viewport = viewport; } + + /** Get the const viewport. */ + const osg::Viewport* getViewport() const { return _viewport.get(); } + + /** Get the viewport. */ + osg::Viewport* getViewport() { return _viewport.get(); } + + inline void pushCullViewState() { pushCullViewState_ModelView(NULL,NULL); } + + void pushCullViewState_Projection(osg::Matrix* matrix); + void pushCullViewState_ModelView(osg::Matrix* matrix); + void pushCullViewState_ModelView(osg::Matrix* matrix,osg::Matrix* inverse); + + void popCullViewState(); + + /** Push state set on the current state group. + * If the state exists in a child state group of the current + * state group then move the current state group to that child. + * Otherwise, create a new state group for the state set, add + * it to the current state group then move the current state + * group pointer to the new state group. + */ + inline void pushStateSet(const osg::StateSet* ss) + { + _currentRenderGraph = _currentRenderGraph->find_or_insert(ss); + if (ss->useRenderBinDetails()) + { + _currentRenderBin = _currentRenderBin->find_or_insert(ss->getBinNumber(),ss->getBinName()); + } + } + + /** Pop the top state set and hence associated state group. + * Move the current state group to the parent of the popped + * state group. + */ + inline void popStateSet() + { + if (_currentRenderGraph->_stateset->useRenderBinDetails()) + { + _currentRenderBin = _currentRenderBin->_parent; + } + _currentRenderGraph = _currentRenderGraph->_parent; + } + + void setRenderGraph(RenderGraph* rg) + { + _rootRenderGraph = rg; + _currentRenderGraph = rg; + } + + RenderGraph* getRenderGraph() + { + return _rootRenderGraph.get(); + } + + void setRenderStage(RenderStage* rg) + { + _rootRenderStage = rg; + _currentRenderBin = rg; + } + + RenderStage* getRenderStage() + { + return _rootRenderStage.get(); + } + + const float getCalculatedNearPlane() const { return _calculated_znear; } + + const float getCalculatedFarPlane() const { return _calculated_zfar; } + + protected: + + /** prevent unwanted copy construction.*/ + NewCullVisitor(const NewCullVisitor&):osg::NodeVisitor() {} + + /** prevent unwanted copy operator.*/ + NewCullVisitor& operator = (const NewCullVisitor&) { return *this; } + + inline osg::Matrix* getCurrentMatrix() + { + return _cvs->_matrix.get(); + } + + + inline osg::Matrix* getInverseCurrentMatrix() + { + return _cvs->_inverse.get(); + } + + inline const osg::Vec3& getEyeLocal() const + { + return _cvs->_eyePoint; + } + + inline const osg::Vec3& getUpLocal() const + { + return _cvs->_upVector; + } + + inline const osg::Vec3& getCenterLocal() const + { + return _cvs->_centerPoint; + } + + + inline const osg::Vec3& getLookVectorLocal() const + { + return _cvs->_lookVector; + } + + + inline bool isCulled(const osg::BoundingSphere& sp,CullViewState::CullingMode& mode) const + { + return _cvs->isCulled(sp,mode); + } + + inline const bool isCulled(const osg::BoundingBox& bb,const CullViewState::CullingMode mode) const + { + return _cvs->isCulled(bb,mode); + } + + void updateCalculatedNearFar(const osg::BoundingBox& bb); + + void updateCalculatedNearFar(const osg::Vec3& pos); + + /**calculates near for "global" vertex in scene*/ + double calculateZNear(const osg::Vec3& position, const osg::Vec3& eye, const osg::Vec3& look); + + + /** Add a drawable to current render graph.*/ + inline void addDrawable(osg::Drawable* drawable,osg::Matrix* matrix) + { + if (_currentRenderGraph->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. + _currentRenderBin->addRenderGraph(_currentRenderGraph); + } + //_currentRenderGraph->addLeaf(new RenderLeaf(drawable,matrix)); + _currentRenderGraph->addLeaf(createOrReuseRenderLeaf(drawable,_cvs->_projection.get(),matrix)); + } + + /** Add a drawable and depth to current render graph.*/ + inline void addDrawableAndDepth(osg::Drawable* drawable,osg::Matrix* matrix,const float depth) + { + if (_currentRenderGraph->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. + _currentRenderBin->addRenderGraph(_currentRenderGraph); + } + //_currentRenderGraph->addLeaf(new RenderLeaf(drawable,matrix,depth)); + _currentRenderGraph->addLeaf(createOrReuseRenderLeaf(drawable,_cvs->_projection.get(),matrix,depth)); + } + + /** Add a light to current render graph.*/ + inline void addLight(osg::Light* light,osg::Matrix* matrix) + { + _currentRenderBin->_stage->addLight(light,matrix); + } + + /** create an impostor sprite by setting up a pre-rendering stage + * to generate the impostor texture. */ + osg::ImpostorSprite* createImpostorSprite(osg::Impostor& node); + + typedef std::vector< osg::ref_ptr > CullViewStateStack; + CullViewStateStack _viewStateStack; + osg::ref_ptr _tvs; + osg::ref_ptr _cvs; + + osg::ref_ptr _rootRenderGraph; + RenderGraph* _currentRenderGraph; + + osg::ref_ptr _rootRenderStage; + RenderBin* _currentRenderBin; + + std::vector _cullingModeStack; + + float _LODBias; + + float _calculated_znear; + float _calculated_zfar; + + osg::ref_ptr _camera; + + osg::ref_ptr _earthSky; + + TransparencySortMode _tsm; + + // viewport x,y,width,height respectively. + osg::ref_ptr _viewport; + + bool _impostorActive; + bool _depthSortImpostorSprites; + float _impostorPixelErrorThreshold; + int _numFramesToKeepImpostorSprites; + + typedef std::vector< osg::ref_ptr > MatrixList; + MatrixList _reuseMatrixList; + unsigned int _currentReuseMatrixIndex; + + inline osg::Matrix* createOrReuseMatrix() + { + // skip of any already reused matrix. + while (_currentReuseMatrixIndex<_reuseMatrixList.size() && + _reuseMatrixList[_currentReuseMatrixIndex]->referenceCount()>1) + { + osg::notify(osg::NOTICE)<<"Warning:createOrReuseMatrix() skipping multiply refrenced entry."<< std::endl; + ++_currentReuseMatrixIndex; + } + + // if still within list, element must be singularly referenced + // there return it to be reused. + if (_currentReuseMatrixIndex<_reuseMatrixList.size()) + { + osg::Matrix* matrix = _reuseMatrixList[_currentReuseMatrixIndex++].get(); + matrix->makeIdentity(); + return matrix; + } + + // otherwise need to create new matrix. + osg::Matrix* matrix = new osg::Matrix(); + _reuseMatrixList.push_back(matrix); + ++_currentReuseMatrixIndex; + return matrix; + } + + typedef std::vector< osg::ref_ptr > RenderLeafList; + RenderLeafList _reuseRenderLeafList; + unsigned int _currentReuseRenderLeafIndex; + + inline RenderLeaf* createOrReuseRenderLeaf(osg::Drawable* drawable,osg::Matrix* projection,osg::Matrix* matrix, float depth=0.0f) + { + // skip of any already reused renderleaf. + while (_currentReuseRenderLeafIndex<_reuseRenderLeafList.size() && + _reuseRenderLeafList[_currentReuseRenderLeafIndex]->referenceCount()>1) + { + osg::notify(osg::NOTICE)<<"Warning:createOrReuseRenderLeaf() skipping multiply refrenced entry."<< std::endl; + ++_currentReuseRenderLeafIndex; + } + + // if still within list, element must be singularly referenced + // there return it to be reused. + if (_currentReuseRenderLeafIndex<_reuseRenderLeafList.size()) + { + RenderLeaf* renderleaf = _reuseRenderLeafList[_currentReuseRenderLeafIndex++].get(); + renderleaf->set(drawable,projection,matrix,depth); + return renderleaf; + } + + // otherwise need to create new renderleaf. + RenderLeaf* renderleaf = new RenderLeaf(drawable,projection,matrix,depth); + _reuseRenderLeafList.push_back(renderleaf); + ++_currentReuseRenderLeafIndex; + return renderleaf; + } + + osg::ref_ptr _impostorSpriteManager; + +}; + +} + +#endif + diff --git a/include/osgUtil/RenderLeaf b/include/osgUtil/RenderLeaf index abd5a7900..5cbc2d3c7 100644 --- a/include/osgUtil/RenderLeaf +++ b/include/osgUtil/RenderLeaf @@ -24,18 +24,20 @@ class OSGUTIL_EXPORT RenderLeaf : public osg::Referenced public: - inline RenderLeaf(osg::Drawable* drawable,osg::Matrix* matrix, float depth=0.0f): + inline RenderLeaf(osg::Drawable* drawable,osg::Matrix* projection,osg::Matrix* modelview, float depth=0.0f): _parent(NULL), _drawable(drawable), - _matrix(matrix), + _projection(projection), + _modelview(modelview), _depth(depth) {} - inline void set(osg::Drawable* drawable,osg::Matrix* matrix, float depth=0.0f) + inline void set(osg::Drawable* drawable,osg::Matrix* projection,osg::Matrix* modelview, float depth=0.0f) { _parent = NULL; _drawable = drawable; - _matrix = matrix; + _projection = projection, + _modelview = modelview, _depth = depth; } @@ -43,7 +45,8 @@ class OSGUTIL_EXPORT RenderLeaf : public osg::Referenced { _parent = NULL; _drawable = NULL; - _matrix = NULL; + _projection = NULL; + _modelview = NULL; _depth = 0.0f; } @@ -57,7 +60,8 @@ class OSGUTIL_EXPORT RenderLeaf : public osg::Referenced RenderGraph* _parent; osg::Drawable* _drawable; - osg::ref_ptr _matrix; + osg::ref_ptr _projection; + osg::ref_ptr _modelview; float _depth; private: @@ -66,7 +70,8 @@ class OSGUTIL_EXPORT RenderLeaf : public osg::Referenced RenderLeaf(): _parent(NULL), _drawable(NULL), - _matrix(NULL), + _projection(NULL), + _modelview(NULL), _depth(0.0f) {} /// disallow copy construction. diff --git a/include/osgUtil/SceneView b/include/osgUtil/SceneView index 518a1147f..8bcd9aafb 100644 --- a/include/osgUtil/SceneView +++ b/include/osgUtil/SceneView @@ -12,10 +12,14 @@ #include #include -#include + +//#include +#include namespace osgUtil { +typedef NewCullVisitor CullVisitor; + /** * SceneView is literally a view of a scene, encapsulating the * camera, global state, lights and the scene itself. Provides diff --git a/src/osg/Camera.cpp b/src/osg/Camera.cpp index 3af280a30..e2d89454d 100644 --- a/src/osg/Camera.cpp +++ b/src/osg/Camera.cpp @@ -28,8 +28,7 @@ Camera::Camera(DisplaySettings* ds) _center.set(0.0f,0.0f,-1.0f); _up.set(0.0f,1.0f,0.0f); - _useNearClippingPlane = false; - _useFarClippingPlane = false; + _useNearAndFarClippingPlanes = false; _useEyeOffset = false; _eyeOffset.set(0.0f,0.0f,0.0f); @@ -88,14 +87,13 @@ void Camera::copy(const Camera& camera) _modelToEyeTransform = camera._modelToEyeTransform; // flags to determine if near and far clipping planes are required. - _useNearClippingPlane = camera._useNearClippingPlane; - _useFarClippingPlane = camera._useFarClippingPlane; + _useNearAndFarClippingPlanes = camera._useNearAndFarClippingPlanes; // cached matrix and clipping volume derived from above settings. _dirty = false;// camera._dirty; _projectionMatrix = NULL; //camera._projectionMatrix; _modelViewMatrix = NULL; //camera._modelViewMatrix; -// _clippingVolume = camera._clippingVolume; + _clippingVolume = camera._clippingVolume; _mp = NULL; _inversemp = NULL; @@ -588,20 +586,11 @@ const Matrix& Camera::getModelViewMatrix() const return *_modelViewMatrix; } -void Camera::setUseNearClippingPlane(const bool use) +void Camera::setUseNearAndFarClippingPlanes(const bool use) { - if (_useNearClippingPlane != use) + if (_useNearAndFarClippingPlanes != use) { - _useNearClippingPlane = use; - _dirty = true; - } -} - -void Camera::setUseFarClippingPlane(const bool use) -{ - if (_useFarClippingPlane != use) - { - _useFarClippingPlane = use; + _useNearAndFarClippingPlanes = use; _dirty = true; } } @@ -739,57 +728,56 @@ void Camera::calculateMatricesAndClippingVolume() const } - _clippingVolume.clear(); +// _clippingVolume.clear(); +// +// // set the clipping volume. +// switch(_projectionType) +// { +// case(ORTHO): +// case(ORTHO2D): +// { +// } +// break; +// case(FRUSTUM): +// case(PERSPECTIVE): +// { +// // calculate the frustum normals, postive pointing inwards. +// // left clipping plane +// // note, _left,_right,_top and _bottom are already devided +// // by _zNear so no need to take into account for normal +// // calculations. +// Vec3 leftNormal (1.0f,0.0f,left); +// leftNormal.normalize(); +// _clippingVolume.add(Plane(leftNormal,0.0f)); +// +// +// Vec3 rightNormal (-1.0f,0.0f,-right); +// rightNormal.normalize(); +// _clippingVolume.add(Plane(rightNormal,0.0f)); +// +// Vec3 bottomNormal(0.0f,1.0f,bottom); +// bottomNormal.normalize(); +// _clippingVolume.add(Plane(bottomNormal,0.0f)); +// +// Vec3 topNormal(0.0f,-1.0f,-top); +// topNormal.normalize(); +// _clippingVolume.add(Plane(topNormal,0.0f)); +// +// if (_useNearClippingPlane) +// { +// _clippingVolume.add(Plane(0.0f,0.0f,-1.0f,-_zNear)); +// } +// +// if (_useFarClippingPlane) +// { +// _clippingVolume.add(Plane(0.0f,0.0f,1.0f,_zFar)); +// } +// +// } +// break; +// +// } - // set the clipping volume. - switch(_projectionType) - { - case(ORTHO): - case(ORTHO2D): - { - } - break; - case(FRUSTUM): - case(PERSPECTIVE): - { - // calculate the frustum normals, postive pointing inwards. - // left clipping plane - // note, _left,_right,_top and _bottom are already devided - // by _zNear so no need to take into account for normal - // calculations. - Vec3 leftNormal (1.0f,0.0f,left); - leftNormal.normalize(); - _clippingVolume.add(Plane(leftNormal,0.0f)); - - - Vec3 rightNormal (-1.0f,0.0f,-right); - rightNormal.normalize(); - _clippingVolume.add(Plane(rightNormal,0.0f)); - - Vec3 bottomNormal(0.0f,1.0f,bottom); - bottomNormal.normalize(); - _clippingVolume.add(Plane(bottomNormal,0.0f)); - - Vec3 topNormal(0.0f,-1.0f,-top); - topNormal.normalize(); - _clippingVolume.add(Plane(topNormal,0.0f)); - - if (_useNearClippingPlane) - { - _clippingVolume.add(Plane(0.0f,0.0f,-1.0f,-_zNear)); - } - - if (_useFarClippingPlane) - { - _clippingVolume.add(Plane(0.0f,0.0f,1.0f,_zFar)); - } - - } - break; - - } - - _clippingVolume.transformProvidingInverse(*_modelViewMatrix); if (!_mp.valid()) _mp = osgNew Matrix; _mp->mult(*_modelViewMatrix,*_projectionMatrix); @@ -800,6 +788,18 @@ void Camera::calculateMatricesAndClippingVolume() const notify(WARN)<<"Warning: Camera::calculateMatricesAndClippingVolume() failed to invert _mp"< + +using namespace osg; + +Projection::Projection() +{ + _matrix = osgNew Matrix; +} + +Projection::Projection(const Projection& projection,const CopyOp& copyop): + Group(projection,copyop), + _matrix(osgNew Matrix(*projection._matrix)) +{ +} + +Projection::Projection(const Matrix& mat ) +{ + _matrix = osgNew Matrix(mat); +} + + +Projection::~Projection() +{ +} diff --git a/src/osg/State.cpp b/src/osg/State.cpp index 228251188..188bc817d 100644 --- a/src/osg/State.cpp +++ b/src/osg/State.cpp @@ -569,3 +569,11 @@ void State::haveAppliedAttribute(const StateAttribute::Type type) as.changed = true; } } + +ClippingVolume State::getClippingVolume() const +{ + ClippingVolume cv; + cv.setToUnitFrustum(); + cv.transformProvidingInverse((*_modelView)*(*_projection)); + return cv; +} diff --git a/src/osgUtil/CullViewState.cpp b/src/osgUtil/CullViewState.cpp index 9292b8a68..2919d2c4d 100644 --- a/src/osgUtil/CullViewState.cpp +++ b/src/osgUtil/CullViewState.cpp @@ -18,6 +18,7 @@ using namespace osgUtil; CullViewState::CullViewState() { + _projection = NULL; _matrix = NULL; _inverse = NULL; _ratio2 = 0.002f*0.002f; diff --git a/src/osgUtil/CullVisitor.cpp b/src/osgUtil/CullVisitor.cpp index ad1c5ee46..32e75edce 100644 --- a/src/osgUtil/CullVisitor.cpp +++ b/src/osgUtil/CullVisitor.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -60,6 +61,7 @@ class PrintVisitor : public NodeVisitor virtual void apply(Group& node) { apply((Node&)node); } virtual void apply(Transform& node) { apply((Group&)node); } + virtual void apply(Projection& node) { apply((Group&)node); } virtual void apply(Switch& node) { apply((Group&)node); } virtual void apply(LOD& node) { apply((Group&)node); } virtual void apply(Impostor& node) { apply((LOD&)node); } @@ -487,19 +489,26 @@ void CullVisitor::setCamera(const Camera& camera) } -void CullVisitor::pushCullViewState(Matrix* matrix) +void CullVisitor::pushCullViewState_Projection(Matrix* matrix) +{ + std::cout<<"CullVisitor::pushCullViewState_Projection(Matrix* matrix) not properly implemented yet..."<invert(*matrix); - pushCullViewState(matrix,inverse); + pushCullViewState_ModelView(matrix,inverse); } else - pushCullViewState(NULL,NULL); + pushCullViewState_ModelView(NULL,NULL); } -void CullVisitor::pushCullViewState(Matrix* matrix,osg::Matrix* inverse) +void CullVisitor::pushCullViewState_ModelView(Matrix* matrix,osg::Matrix* inverse) { osg::ref_ptr nvs = osgNew CullViewState; @@ -1117,27 +1126,46 @@ void CullVisitor::apply(Transform& node) StateSet* node_state = node.getStateSet(); if (node_state) pushStateSet(node_state); - bool isModelView = node.isModelViewTransform(); - if (isModelView) - { - - ref_ptr matrix = createOrReuseMatrix(); - ref_ptr inverse = createOrReuseMatrix(); - node.getLocalToWorldMatrix(*matrix,this); - node.getWorldToLocalMatrix(*inverse,this); - pushCullViewState(matrix.get(),inverse.get()); - } - else - { - osg::notify(osg::WARN)<<"Warning: Projection Transform in scene graph has been ignored, not fully implemented yet."< matrix = createOrReuseMatrix(); + ref_ptr inverse = createOrReuseMatrix(); + node.getLocalToWorldMatrix(*matrix,this); + node.getWorldToLocalMatrix(*inverse,this); + pushCullViewState_ModelView(matrix.get(),inverse.get()); traverse(node); - if (isModelView) - { - popCullViewState(); - } + popCullViewState(); + + // pop the node's state off the render graph stack. + if (node_state) popStateSet(); + + // pop the culling mode. + _cullingModeStack.pop_back(); +} + +void CullVisitor::apply(Projection& node) +{ + // return if object's bounding sphere is culled. + CullViewState::CullingMode mode = _cullingModeStack.back(); + + if (!node.getCullingActive()) mode = 0; + else if (node.getNumChildrenWithCullingDisabled()==0 && + isCulled(node.getBound(),mode)) return; + + // push the culling mode. + _cullingModeStack.push_back(mode); + + // push the node's state. + StateSet* node_state = node.getStateSet(); + if (node_state) pushStateSet(node_state); + + ref_ptr matrix = createOrReuseMatrix(); + *matrix = node.getMatrix(); + pushCullViewState_Projection(matrix.get()); + + traverse(node); + + popCullViewState(); // pop the node's state off the render graph stack. if (node_state) popStateSet(); @@ -1398,7 +1426,7 @@ ImpostorSprite* CullVisitor::createImpostorSprite(Impostor& node) // pushing the cull view state will update it so it takes // into account the new camera orientation. - pushCullViewState(rotate_matrix); + pushCullViewState_ModelView(rotate_matrix); // what shall we do about the near far? // we could need to save the near and far, or switch it off. diff --git a/src/osgUtil/Makefile b/src/osgUtil/Makefile index 2509c8a3a..cb857441f 100644 --- a/src/osgUtil/Makefile +++ b/src/osgUtil/Makefile @@ -5,6 +5,7 @@ C++FILES = \ AppVisitor.cpp\ CameraManipulator.cpp\ CullVisitor.cpp\ + NewCullVisitor.cpp\ CullViewState.cpp\ DisplayListVisitor.cpp\ DisplayRequirementsVisitor.cpp\ @@ -46,6 +47,7 @@ TARGET_INCLUDE_FILES = \ osgUtil/AppVisitor\ osgUtil/CameraManipulator\ osgUtil/CullVisitor\ + osgUtil/NewCullVisitor\ osgUtil/CullViewState\ osgUtil/DepthSortedBin\ osgUtil/DisplayListVisitor\ diff --git a/src/osgUtil/NewCullVisitor.cpp b/src/osgUtil/NewCullVisitor.cpp new file mode 100644 index 000000000..a76b10e7e --- /dev/null +++ b/src/osgUtil/NewCullVisitor.cpp @@ -0,0 +1,1297 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include + +#include +#include + +using namespace osg; +using namespace osgUtil; + +inline float MAX_F(float a, float b) + { return a>b?a:b; } +inline int EQUAL_F(float a, float b) + { return a == b || fabsf(a-b) <= MAX_F(fabsf(a),fabsf(b))*1e-3f; } + + +class PrintVisitor : public NodeVisitor +{ + + public: + + PrintVisitor():NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN) + { + _indent = 0; + _step = 4; + } + + inline void moveIn() { _indent += _step; } + inline void moveOut() { _indent -= _step; } + inline void writeIndent() + { + for(int i=0;i<_indent;++i) std::cout << " "; + } + + virtual void apply(Node& node) + { + moveIn(); + writeIndent(); std::cout << node.className() <_eyePoint.set(0.0f,0.0f,1.0f); + _tvs->_centerPoint.set(0.0f,0.0f,0.0f); + _tvs->_lookVector.set(0.0f,0.0f,-1.0f); + _tvs->_upVector.set(0.0f,1.0f,0.0f); + + _cvs = _tvs; + + _tsm = LOOK_VECTOR_DISTANCE; + _tsm = OBJECT_EYE_POINT_DISTANCE; + + + _calculated_znear = FLT_MAX; + _calculated_zfar = -FLT_MAX; + + _viewport = NULL; + + _impostorActive = true; + _depthSortImpostorSprites = false; + _impostorPixelErrorThreshold = 4.0f; + _numFramesToKeepImpostorSprites = 10; + _impostorSpriteManager = osgNew ImpostorSpriteManager; + +} + + +NewCullVisitor::~NewCullVisitor() +{ + reset(); +} + + +void NewCullVisitor::reset() +{ + + // + // first unref all referenced objects and then empty the containers. + // + _viewStateStack.clear(); + + if (_cvs!=_tvs) + { + _cvs = _tvs; + } + + // reset the calculated near far planes. + _calculated_znear = FLT_MAX; + _calculated_zfar = -FLT_MAX; + + + // remove all accept the first element of the stack. + _cullingModeStack.erase(_cullingModeStack.begin()+1,_cullingModeStack.end()); + + // reset the resuse lists. + _currentReuseMatrixIndex = 0; + _currentReuseRenderLeafIndex = 0; + + for(RenderLeafList::iterator itr=_reuseRenderLeafList.begin(); + itr!=_reuseRenderLeafList.end(); + ++itr) + { + (*itr)->reset(); + } + +} + +void NewCullVisitor::setCamera(const Camera& camera) +{ + _camera = &camera; + + _tvs->_clippingVolume.setToUnitFrustumWithoutNearFar(); + _tvs->_clippingVolume.transformProvidingInverse(_camera->getModelViewMatrix()*_camera->getProjectionMatrix()); + + //_tvs->_clippingVolume = camera.getClippingVolume(); + + _tvs->_eyePoint = camera.getEyePoint_Model(); + + _tvs->_centerPoint = camera.getCenterPoint_Model(); + + _tvs->_lookVector = _tvs->_centerPoint-_tvs->_eyePoint; + _tvs->_lookVector.normalize(); + + _tvs->_upVector = camera.getUpVector_Model(); + + _tvs->_bbCornerFar = (_tvs->_lookVector.x()>=0?1:0) | + (_tvs->_lookVector.y()>=0?2:0) | + (_tvs->_lookVector.z()>=0?4:0); + + _tvs->_bbCornerNear = (~_tvs->_bbCornerFar)&7; + +} + +void NewCullVisitor::pushCullViewState_Projection(Matrix* matrix) +{ + std::cout<<"NewCullVisitor::pushCullViewState_Projection(Matrix* matrix) not properly implemented yet..."<invert(*matrix); + pushCullViewState_ModelView(matrix,inverse); + } + else + pushCullViewState_ModelView(NULL,NULL); +} + +void NewCullVisitor::pushCullViewState_ModelView(Matrix* matrix,osg::Matrix* inverse) +{ + + osg::ref_ptr nvs = osgNew CullViewState; + + Matrix* inverse_world = NULL; + + if (matrix) + { + if (_cvs.valid() && _cvs->_matrix.valid()) + { + matrix->postMult(*(_cvs->_matrix)); + } + + nvs->_matrix = matrix; + + } + else + { + if (_cvs.valid()) + { + nvs->_matrix = _cvs->_matrix; + + } + else + { + nvs->_matrix = NULL; + } + } + + if (inverse) + { + if (_cvs.valid() && _cvs->_inverse.valid()) + { + inverse->preMult(*(_cvs->_inverse)); + } + + nvs->_inverse = inverse; + + } + else + { + if (_cvs.valid()) + { + nvs->_inverse = _cvs->_inverse; + } + else + { + nvs->_inverse = NULL; + } + } + inverse_world = nvs->_inverse.get(); + + if (inverse_world) + { + nvs->_eyePoint = _tvs->_eyePoint*(*inverse_world); + //nvs->_eyePoint = inverse_world->getTrans(); + + nvs->_centerPoint = _tvs->_centerPoint*(*inverse_world); + + nvs->_lookVector = nvs->_centerPoint - nvs->_eyePoint; + nvs->_lookVector.normalize(); + + Vec3 zero_transformed = Vec3(0.0f,0.0f,0.0f)*(*inverse_world); + nvs->_upVector = (_tvs->_upVector)*(*inverse_world) - zero_transformed; + nvs->_upVector.normalize(); + + nvs->_clippingVolume = _tvs->_clippingVolume; + nvs->_clippingVolume.transformProvidingInverse(*(nvs->_matrix)); + +// osg::ClippingVolume cv; +// cv.setToUnitFrustum(); +// cv.transformProvidingInverse((*(nvs->_matrix))*_camera->getProjectionMatrix()); +// +// std::cout << "cv "<_clippingVolume "<_clippingVolume.getPlaneList().begin(); +// itr!=nvs->_clippingVolume.getPlaneList().end(); +// ++itr) +// { +// std::cout << " Plane "<<*itr<_eyePoint = _tvs->_eyePoint; + + nvs->_lookVector = _tvs->_lookVector; + + nvs->_centerPoint = _tvs->_centerPoint; + + nvs->_upVector = _tvs->_upVector; + + nvs->_clippingVolume = _tvs->_clippingVolume; + } + + + nvs->_bbCornerFar = (nvs->_lookVector.x()>=0?1:0) | + (nvs->_lookVector.y()>=0?2:0) | + (nvs->_lookVector.z()>=0?4:0); + + nvs->_bbCornerNear = (~nvs->_bbCornerFar)&7; + + _cvs = nvs; + + _viewStateStack.push_back(nvs); +} + +void NewCullVisitor::popCullViewState() +{ + // pop the top of the view stack and unref it. + _viewStateStack.pop_back(); + + // to new cvs and ref it. + if (_viewStateStack.empty()) + { + _cvs = _tvs; + } + else + { + _cvs = _viewStateStack.back().get(); + } + +} + +double NewCullVisitor::calculateZNear(const osg::Vec3& position, const osg::Vec3& eye, const osg::Vec3& look) +{ + //note: the candidate points are always in "global" coordinates + return (position - eye)*look; +} + +inline float distance(const osg::Vec3& coord,const osg::Matrix& matrix) +{ + return -(coord[0]*matrix(0,2)+coord[1]*matrix(1,2)+coord[2]*matrix(2,2)+matrix(3,2)); +} + + +void NewCullVisitor::updateCalculatedNearFar(const osg::BoundingBox& bb) +{ + + if (!bb.isValid()) + { + osg::notify(osg::WARN)<<"Warning: NewCullVisitor::updateCalculatedNearFar(..) passed a null bounding box."<< std::endl; + return; + } + + float d_near,d_far; + if (_cvs->_matrix.valid()) + { + + const osg::Matrix& matrix = *(_cvs->_matrix); + d_near = distance(bb.corner(_cvs->_bbCornerNear),matrix); + d_far = distance(bb.corner(_cvs->_bbCornerFar),matrix); + + } + else + { + d_near = -(bb.corner(_cvs->_bbCornerNear)).z(); + d_far = -(bb.corner(_cvs->_bbCornerFar)).z(); + } + + if (d_near<=d_far) + { + if (d_near<_calculated_znear) _calculated_znear = d_near; + if (d_far>_calculated_zfar) _calculated_zfar = d_far; + } + else + { + if ( !EQUAL_F(d_near, d_far) ) + { + osg::notify(osg::WARN)<<"Warning: NewCullVisitor::updateCalculatedNearFar(.) near>far in range calculation,"<< std::endl; + osg::notify(osg::WARN)<<" correcting by swapping values d_near="<accept(*this); + + // pop the node's state off the render graph stack. + if (node_state) popStateSet(); + + // pop the culling mode. + _cullingModeStack.pop_back(); +} + +void NewCullVisitor::apply(osg::EarthSky& node) +{ + // simply override the current earth sky. + setEarthSky(&node); + + // push the node's state. + StateSet* node_state = node.getStateSet(); + if (node_state) pushStateSet(node_state); + + traverse(node); + + // pop the node's state off the render graph stack. + if (node_state) popStateSet(); + +} + + +void NewCullVisitor::apply(Impostor& node) +{ + const BoundingSphere& bs = node.getBound(); + + // return if object's bounding sphere is culled. + CullViewState::CullingMode mode = _cullingModeStack.back(); + + if (!node.getCullingActive()) mode = 0; + else if (node.getNumChildrenWithCullingDisabled()==0 && + isCulled(node.getBound(),mode)) return; + + osg::Vec3 eyeLocal = getEyeLocal(); + + int eval = node.evaluate(eyeLocal,_LODBias); + if (eval<0){ + return; + } + + // push the culling mode. + _cullingModeStack.push_back(mode); + + // push the node's state. + StateSet* node_state = node.getStateSet(); + if (node_state) pushStateSet(node_state); + + + float distance2 = (eyeLocal-bs.center()).length2(); + if (!_impostorActive || + distance2*_LODBias*_LODBiasaccept(*this); + } + else if (!_viewport.valid()) + { + // need to use impostor but no valid viewport is defined to simply + // default to using the LOD child as above. + node.getChild(eval)->accept(*this); + } + else + { + // within the impostor distance threshold therefore attempt + // to use impostor instead. + + Matrix* matrix = getCurrentMatrix(); + + // search for the best fit ImpostorSprite; + ImpostorSprite* impostorSprite = node.findBestImpostorSprite(eyeLocal); + + if (impostorSprite) + { + // impostor found, now check to see if it is good enough to use + float error = impostorSprite->calcPixelError(*_camera,*_viewport,matrix); + + if (error>_impostorPixelErrorThreshold) + { + // chosen impostor sprite pixel error is too great to use + // from this eye point, therefore invalidate it. + impostorSprite=NULL; + } + } + + +// need to think about sprite reuse and support for multiple context's. + + if (impostorSprite==NULL) + { + // no appropriate sprite has been found therefore need to create + // one for use. + + // create the impostor sprite. + impostorSprite = createImpostorSprite(node); + + } + + if (impostorSprite) + { + + updateCalculatedNearFar(impostorSprite->getBound()); + + StateSet* stateset = impostorSprite->getStateSet(); + + if (stateset) pushStateSet(stateset); + + if (_depthSortImpostorSprites) + { + Vec3 center; + if (matrix) + { + center = node.getCenter()*(*matrix); + } + else + { + center = node.getCenter(); + } + Vec3 delta_center = center-_tvs->_eyePoint; + + float depth; + switch(_tsm) + { + case(LOOK_VECTOR_DISTANCE):depth = _tvs->_lookVector*delta_center;break; + case(OBJECT_EYE_POINT_DISTANCE): + default: depth = delta_center.length2();break; + } + + addDrawableAndDepth(impostorSprite,matrix,depth); + } + else + { + addDrawable(impostorSprite,matrix); + } + + if (stateset) popStateSet(); + + // update frame number to show that impostor is in action. + impostorSprite->setLastFrameUsed(getTraversalNumber()); + + } + else + { + // no impostor has been selected or created so default to + // traversing the usual LOD selected child. + node.getChild(eval)->accept(*this); + } + + } + + // pop the node's state off the render graph stack. + if (node_state) popStateSet(); + + // pop the culling mode. + _cullingModeStack.pop_back(); +} + +ImpostorSprite* NewCullVisitor::createImpostorSprite(Impostor& node) +{ + if (!_camera.valid()) return NULL; + + bool isPerspectiveCamera = _camera->getProjectionType()==Camera::FRUSTUM || + _camera->getProjectionType()==Camera::PERSPECTIVE; + + Matrix* matrix = getCurrentMatrix(); + const BoundingSphere& bs = node.getBound(); + osg::Vec3 eye_local = getEyeLocal(); + int eval = node.evaluate(eye_local,_LODBias); + + if (!bs.isValid()) + { + return NULL; + } + + + Vec3 eye_world = _tvs->_eyePoint; + Vec3 center_world = bs.center()*(*matrix); + + // no appropriate sprite has been found therefore need to create + // one for use. + + // create the render to texture stage. + ref_ptr rtts = osgNew RenderToTextureStage; + + // set up lighting. + // currently ignore lights in the scene graph itself.. + // will do later. + RenderStage* previous_stage = _currentRenderBin->_stage; + + // set up the background color and clear mask. + osg::Vec4 clear_color = previous_stage->getClearColor(); + clear_color[3] = 0.0f; // set the alpha to zero. + rtts->setClearColor(clear_color); + rtts->setClearMask(previous_stage->getClearMask()); + + // set up to charge the same RenderStageLighting is the parent previous stage. + rtts->setRenderStageLighting(previous_stage->getRenderStageLighting()); + + + osg::Camera* camera = osgNew osg::Camera(*_camera); + rtts->setCamera(camera); + + // record the render bin, to be restored after creation + // of the render to text + RenderBin* previousRenderBin = _currentRenderBin; + + // set the current renderbin to be the newly created stage. + _currentRenderBin = rtts.get(); + + // store the previous camera setting + + Vec3 rotate_from = bs.center()-eye_local; + Vec3 rotate_to = getLookVectorLocal(); + + osg::Matrix* rotate_matrix = osgNew osg::Matrix( + osg::Matrix::translate(-eye_local)* + osg::Matrix::rotate(rotate_from,rotate_to)* + osg::Matrix::translate(eye_local)); + + // pushing the cull view state will update it so it takes + // into account the new camera orientation. + pushCullViewState_ModelView(rotate_matrix); + + // what shall we do about the near far? + // we could need to save the near and far, or switch it off. + // simplicist to save near and far. will do this for now. + + float previous_znear = _calculated_znear; + float previous_zfar = _calculated_zfar; + + _calculated_znear = FLT_MAX; + _calculated_zfar = -FLT_MAX; + + ref_ptr dummyState = osgNew StateSet; + + +// dummyState->setMode(GL_BLEND,osg::StateAttribute::OVERRIDE_OFF); + + pushStateSet(dummyState.get()); + + + // switch off the view frustum culling, since we will have + // the whole subgraph in view. + _cullingModeStack.push_back((_cullingModeStack.back() & ~CullViewState::VIEW_FRUSTUM_CULLING)); + + { + + // traversing the usual LOD selected child. + node.getChild(eval)->accept(*this); + + } + + popStateSet(); + + // restore the culling mode. + _cullingModeStack.pop_back(); + + float local_znear = _calculated_znear; + float local_zfar = _calculated_zfar; + + // restore the previous near and far. + _calculated_znear = previous_znear; + _calculated_zfar = previous_zfar; + + // restor the previous renderbin. + _currentRenderBin = previousRenderBin; + + // restore the previous _tvs and _cvs; + popCullViewState(); + + + if (rtts->_renderGraphList.size()==0 && rtts->_bins.size()==0) + { + // getting to this point means that all the subgraph has been + // culled by small feature culling or is beyond LOD ranges. + return NULL; + } + + if (local_znear>local_zfar) + { + notify(WARN) << "Warning : problem with osg::NewCullVisitor::creatImpostorSprite() local_znear ("< ("<_upVector; + Vec3 lv_local = center_local-eye_local; + + float distance_local = lv_local.length(); + lv_local /= distance_local; + + Vec3 sv_local = lv_local^camera_up_local; + sv_local.normalize(); + + Vec3 up_local = sv_local^lv_local; + + + + float width = bs.radius(); + if (isPerspectiveCamera) + { + // expand the width to account for projection onto sprite. + width *= (distance_local/sqrtf(distance_local*distance_local-bs.radius2())); + } + + // scale up and side vectors to sprite width. + up_local *= width; + sv_local *= width; + + // create the corners of the sprite. + Vec3 c00(center_local - sv_local - up_local); + Vec3 c10(center_local + sv_local - up_local); + Vec3 c01(center_local - sv_local + up_local); + Vec3 c11(center_local + sv_local + up_local); + +// adjust camera left,right,up,down to fit (in world coords) + +#define USE_SPHERE_NEAR_FAR + +#ifdef USE_SPHERE_NEAR_FAR + Vec3 near_local ( center_local-lv_local*width ); + Vec3 far_local ( center_local+lv_local*width ); +#endif + Vec3 top_local ( center_local+up_local); + Vec3 right_local ( center_local+sv_local); + +#ifdef USE_SPHERE_NEAR_FAR + Vec3 near_world; + Vec3 far_world; +#endif + Vec3 top_world; + Vec3 right_world; + + if (matrix) + { +#ifdef USE_SPHERE_NEAR_FAR + near_world = near_local * (*matrix); + far_world = far_local * (*matrix); +#endif + top_world = top_local * (*matrix); + right_world = right_local * (*matrix); + } + else + { +#ifdef USE_SPHERE_NEAR_FAR + near_world = near_local; + far_world = far_local; +#endif + top_world = top_local; + right_world = right_local; + } + +#ifdef USE_SPHERE_NEAR_FAR + float znear = (near_world-eye_world).length(); + float zfar = (far_world-eye_world).length(); +#else + float znear = local_znear; + float zfar = local_zfar; +#endif + + if (local_zfar>=local_znear) + { + znear = local_znear; + zfar = local_zfar; + } + + + float top = (top_world-center_world).length(); + float right = (right_world-center_world).length(); + + znear *= 0.9f; + zfar *= 1.1f; + + if (isPerspectiveCamera) + { + // deal with projection issue move the top and right points + // onto the near plane. + float ratio = znear/(center_world-eye_world).length(); + top *= ratio; + right *= ratio; + camera->setFrustum(-right,right,-top,top,znear,zfar); + + } + else + { + // othographic projection. + + camera->setOrtho(-right,right,-top,top,znear,zfar); + } + + if (local_znearzfar) + { + zfar = local_zfar; + } + + // restore the previous near and far. + local_znear = previous_znear; + local_zfar = previous_zfar; + + +// calc texture size for eye, bs. + + Vec3 c00_world; + Vec3 c11_world; + + if (matrix) + { + c00_world = c00 * (*matrix); + c11_world = c11 * (*matrix); + } + else + { + c00_world = c00; + c11_world = c11; + } + + + // convert the corners of the sprite (in world coords) into their + // equivilant window coordinates by using the camera's project method. + Vec3 c00_win; + Vec3 c11_win; + _camera->project(c00_world,*_viewport,c00_win); + _camera->project(c11_world,*_viewport,c11_win); + + +// adjust texture size to be nearest power of 2. + + float s = c11_win.x()-c00_win.x(); + float t = c11_win.y()-c00_win.y(); + + // may need to reverse sign of width or height if a matrix has + // been applied which flips the orientation of this subgraph. + if (s<0.0f) s = -s; + if (t<0.0f) t = -t; + + // bias value used to assist the rounding up or down of + // the texture dimensions to the nearest power of two. + // bias near 0.0 will almost always round down. + // bias near 1.0 will almost always round up. + float bias = 0.7f; + + float sp2 = logf((float)s)/logf(2.0f); + float rounded_sp2 = floorf(sp2+bias); + int new_s = (int)(powf(2.0f,rounded_sp2)); + + float tp2 = logf((float)t)/logf(2.0f); + float rounded_tp2 = floorf(tp2+bias); + int new_t = (int)(powf(2.0f,rounded_tp2)); + + // if dimension is bigger than window divide it down. + while (new_s>_viewport->width()) new_s /= 2; + + // if dimension is bigger than window divide it down. + while (new_t>_viewport->height()) new_t /= 2; + + + // offset the impostor viewport from the center of the main window + // viewport as often the edges of the viewport might be obscured by + // other windows, which can cause image/reading writing problems. + int center_x = _viewport->x()+_viewport->width()/2; + int center_y = _viewport->y()+_viewport->height()/2; + + Viewport* viewport = osgNew Viewport; + viewport->setViewport(center_x-new_s/2,center_y-new_t/2,new_s,new_t); + rtts->setViewport(viewport); + +// create the impostor sprite. + + ImpostorSprite* impostorSprite = + _impostorSpriteManager->createOrReuseImpostorSprite(new_s,new_t,getTraversalNumber()-_numFramesToKeepImpostorSprites); + + if (impostorSprite==NULL) return NULL; + + // have successfully created an impostor sprite so now need to + // add it into the impostor. + node.addImpostorSprite(impostorSprite); + + if (_depthSortImpostorSprites) + { + // the depth sort bin should probably be user definable, + // will look into this later. RO July 2001. + StateSet* stateset = impostorSprite->getStateSet(); + stateset->setRenderBinDetails(1,"DepthSortedBin"); + } + + Texture* texture = impostorSprite->getTexture(); + + // update frame number to show that impostor is in action. + impostorSprite->setLastFrameUsed(getTraversalNumber()); + + Vec3* coords = impostorSprite->getCoords(); + Vec2* texcoords = impostorSprite->getTexCoords(); + + coords[0] = c01; + texcoords[0].set(0.0f,1.0f); + + coords[1] = c00; + texcoords[1].set(0.0f,0.0f); + + coords[2] = c10; + texcoords[2].set(1.0f,0.0f); + + coords[3] = c11; + texcoords[3].set(1.0f,1.0f); + + impostorSprite->dirtyBound(); + + Vec3* controlcoords = impostorSprite->getControlCoords(); + + if (isPerspectiveCamera) + { + // deal with projection issue by moving the coorners of the quad + // towards the eye point. + float ratio = width/(center_local-eye_local).length(); + float one_minus_ratio = 1.0f-ratio; + Vec3 eye_local_ratio = eye_local*ratio; + + controlcoords[0] = coords[0]*one_minus_ratio + eye_local_ratio; + controlcoords[1] = coords[1]*one_minus_ratio + eye_local_ratio; + controlcoords[2] = coords[2]*one_minus_ratio + eye_local_ratio; + controlcoords[3] = coords[3]*one_minus_ratio + eye_local_ratio; + } + else + { + // project the control points forward towards the eyepoint, + // but since this an othographics projection this projection is + // parallel. + Vec3 dv = lv_local*width; + + controlcoords[0] = coords[0]-dv; + controlcoords[1] = coords[1]-dv; + controlcoords[2] = coords[2]-dv; + controlcoords[3] = coords[3]-dv; + } + + impostorSprite->setStoredLocalEyePoint(eye_local); + + + // and the render to texture stage to the current stages + // dependancy list. + _currentRenderBin->_stage->addToDependencyList(rtts.get()); + + // attach texture to the RenderToTextureStage. + rtts->setTexture(texture); + + // must sort the RenderToTextureStage so that all leaves are + // accounted correctly in all renderbins i.e depth sorted bins. + rtts->sort(); + + return impostorSprite; + +} diff --git a/src/osgUtil/RenderBin.cpp b/src/osgUtil/RenderBin.cpp index e091d956b..ca41eced8 100644 --- a/src/osgUtil/RenderBin.cpp +++ b/src/osgUtil/RenderBin.cpp @@ -185,7 +185,7 @@ bool RenderBin::getStats(osg::Statistics* primStats) RenderLeaf* rl = dw_itr->get(); Drawable* dw= rl->_drawable; primStats->addOpaque(); // number of geosets - if (rl->_matrix.get()) primStats->addMatrix(); // number of matrices + if (rl->_modelview.get()) primStats->addMatrix(); // number of matrices if (dw) { // then tot up the types 1-14 // commenting out as having intrusive stats in base classes is // undersirable. diff --git a/src/osgUtil/RenderLeaf.cpp b/src/osgUtil/RenderLeaf.cpp index 4acdc45f9..d1c23a4f8 100644 --- a/src/osgUtil/RenderLeaf.cpp +++ b/src/osgUtil/RenderLeaf.cpp @@ -30,7 +30,8 @@ void RenderLeaf::render(State& state,RenderLeaf* previous) } - state.applyModelViewMatrix(_matrix.get()); + //state.applyProjectionMatrix(_projection.get()); + state.applyModelViewMatrix(_modelview.get()); _drawable->draw(state); } @@ -41,7 +42,8 @@ void RenderLeaf::render(State& state,RenderLeaf* previous) // send state changes and matrix changes to OpenGL. state.apply(_parent->_stateset.get()); - state.applyModelViewMatrix(_matrix.get()); + //state.applyProjectionMatrix(_projection.get()); + state.applyModelViewMatrix(_modelview.get()); _drawable->draw(state); } diff --git a/src/osgUtil/SceneView.cpp b/src/osgUtil/SceneView.cpp index e14cd7930..baffc1a3a 100644 --- a/src/osgUtil/SceneView.cpp +++ b/src/osgUtil/SceneView.cpp @@ -250,10 +250,10 @@ void SceneView::cullStage(osg::Camera* camera, osgUtil::CullVisitor* cullVisitor cullVisitor->setRenderGraph(rendergraph); cullVisitor->setRenderStage(renderStage); - // SandB - //now make it compute "clipping directions" needed for detailed culling - if(cullVisitor->getDetailedCulling()) - cullVisitor->calcClippingDirections();//only once pre frame +// // SandB +// //now make it compute "clipping directions" needed for detailed culling +// if(cullVisitor->getDetailedCulling()) +// cullVisitor->calcClippingDirections();//only once pre frame renderStage->reset(); @@ -285,7 +285,7 @@ void SceneView::cullStage(osg::Camera* camera, osgUtil::CullVisitor* cullVisitor if (_globalState.valid()) cullVisitor->pushStateSet(_globalState.get()); - cullVisitor->pushCullViewState(modelview); + cullVisitor->pushCullViewState_ModelView(modelview); // traverse the scene graph to generate the rendergraph. @@ -331,13 +331,13 @@ void SceneView::cullStage(osg::Camera* camera, osgUtil::CullVisitor* cullVisitor _far_plane *= 1.05; _near_plane *= 0.95; - // if required clamp the near plane to prevent negative or near zero - // near planes. - if(!cullVisitor->getDetailedCulling()) - { +// // if required clamp the near plane to prevent negative or near zero +// // near planes. +// if(!cullVisitor->getDetailedCulling()) +// { float min_near_plane = _far_plane*0.0005f; if (_near_plane