From f5873a82c5460d27567a8cc668f85dfaf9515843 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sun, 16 Dec 2001 22:20:26 +0000 Subject: [PATCH] Integrated detailed near clipping plane calculation into osgUtil::CullVisitor, submitted by Sasa Bistroviae. --- NEWS | 10 +- include/osgUtil/CullVisitor | 32 +++ src/osgUtil/CullVisitor.cpp | 487 +++++++++++++++++++++++++++++++++++- src/osgUtil/SceneView.cpp | 12 +- 4 files changed, 521 insertions(+), 20 deletions(-) diff --git a/NEWS b/NEWS index 03864ddf1..8e29acec5 100644 --- a/NEWS +++ b/NEWS @@ -16,7 +16,7 @@ OSG News (most significant items from ChangeLog) library which provides support for true type font rendering, as textured, polygonal, pixmap, bitmap and 3D fonts. - An new osg::Matrix class has been implemented which cleans its interface. + We now have new osg::Matrix implementation which cleans up its interface. Also all angular paramters are now based on radians rather than degrees as before (and as in Performer), this has been done to be more consistent with the basic trignometric functions and standard maths conventions. @@ -39,10 +39,10 @@ OSG News (most significant items from ChangeLog) src/Demos/osgcluster has been added to demonstrate how easy it is to set up a graphics cluster across a standard networked PC's. - There have been many minor code changes to fix bugs, bottlenecks or - hinderances to extensibility have been addressed, there are too many - to list, but it does represent a significant step towards API maturity - and a beta release which is now not far away. + There have been many minor code changes to fix bugs and address + performance bottlenecks or to improve extensibility was, representing + a significant step towards API maturity and a beta release which is + now not far away. 9th August 2001 - osg-0.8.42.tar.gz diff --git a/include/osgUtil/CullVisitor b/include/osgUtil/CullVisitor index 624681439..b6304cabc 100644 --- a/include/osgUtil/CullVisitor +++ b/include/osgUtil/CullVisitor @@ -24,6 +24,8 @@ #include #include +#include + namespace osgUtil { /** @@ -182,6 +184,16 @@ class OSGUTIL_EXPORT CullVisitor : public osg::NodeVisitor const float getCalculatedFarPlane() const { return _calculated_zfar; } + //SandB + /**sets the flag for detailed culling*/ + void setDetailedCulling(bool detailed) {_detailedCulling = detailed;} + + /**gets the status of detailed culling*/ + const bool getDetailedCulling() const {return _detailedCulling;} + + /**calculates unit directions of vectors that are intersections of cameras' clipping planes*/ + void calcClippingDirections() const; + protected: /** prevent unwanted copy construction.*/ @@ -232,6 +244,24 @@ class OSGUTIL_EXPORT CullVisitor : public osg::NodeVisitor void updateCalculatedNearFar(const osg::BoundingBox& bb); void updateCalculatedNearFar(const osg::Vec3& pos); + + + //SandB added: //////////////////////////////////////////////////////////////////////////////// + /**updates near and far clipping values for case of detailed culling*/ + void updateCalculatedNearFar(osg::Drawable* pDrawable); + + /**calculates near for "global" vertex in scene*/ + double calculateZNear(const osg::Vec3& position, const osg::Vec3& eye, const osg::Vec3& look); + /////////////////////////////////////////////////////////////////////////////////////////////// + + /**unit vector of direction along intersection of cameras left and top clipping planes in "global" coordinates*/ + mutable osg::Vec3 _LeftUp; + /**unit vector of direction along intersection of cameras right and top clipping planes in "global" coordinates*/ + mutable osg::Vec3 _RightUp; + /**unit vector of direction along intersection of cameras left and down clipping planes in "global" coordinates*/ + mutable osg::Vec3 _LeftDown; + /**unit vector of direction along intersection of cameras right and down clipping planes in "global" coordinates*/ + mutable osg::Vec3 _RightDown; /** Add a drawable to current render graph.*/ @@ -272,6 +302,8 @@ class OSGUTIL_EXPORT CullVisitor : public osg::NodeVisitor * to generate the impostor texture. */ osg::ImpostorSprite* createImpostorSprite(osg::Impostor& node); + bool _detailedCulling; + typedef std::vector< osg::ref_ptr > CullViewStateStack; CullViewStateStack _viewStateStack; osg::ref_ptr _tvs; diff --git a/src/osgUtil/CullVisitor.cpp b/src/osgUtil/CullVisitor.cpp index 70cd19eab..2c9568d57 100644 --- a/src/osgUtil/CullVisitor.cpp +++ b/src/osgUtil/CullVisitor.cpp @@ -7,6 +7,10 @@ #include #include +#include + +#include + #include #include @@ -18,7 +22,7 @@ using namespace osg; using namespace osgUtil; -#define DEG2RAD(x) ((x)*M_PI/180.0) +#define DEG2RAD(x) ((x)*M_PI/180.0) static bool g_debugging2 = false; @@ -71,6 +75,308 @@ class PrintVisitor : public NodeVisitor int _step; }; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SandB change to this + +struct TriangleViewFrustumIntersect +{ + //members ................. + + //the clipping volume, so that triangle vertices can be shecked if inside + osg::ClippingVolume _cv; + + //map serves not to have mulitple entries of same vertices + std::map _listVectors; + + //transformation matrix + const osg::Matrix* _t_mat; + + //value needed to set up triangles properly + double _current_near; + + //eye point of camera + osg::Vec3 _eye; + + osg::Vec3 _LeftUp; + osg::Vec3 _LeftDown; + osg::Vec3 _RightUp; + osg::Vec3 _RightDown; + + //constructor + TriangleViewFrustumIntersect( + const osg::ClippingVolume& clip_vol, + const osg::Matrix* matr, + double current_near, + const osg::Vec3& eyePoint, + const osg::Vec3& LeftUp, + const osg::Vec3& LeftDown, + const osg::Vec3& RightUp, + const osg::Vec3& RightDown) + { + _cv = clip_vol; + _t_mat = matr; + _current_near = current_near; + _eye = eyePoint; + _LeftUp = LeftUp; + _LeftDown = LeftDown; + _RightUp = RightUp; + _RightDown = RightDown; + } + + //pretty much the copy of IntersectVisitor intersect() function + int intersect_linesegment_and_triangle( + osg::Vec3& to_return, + const osg::LineSegment& ls, + const osg::Vec3& vertex1, + const osg::Vec3& vertex2, + const osg::Vec3& vertex3); + + void intersect_triangle(const osg::Vec3& vert1, const osg::Vec3& vert2, const osg::Vec3& vert3); + + //and crucial: + void operator() (const osg::Vec3& vert1, const osg::Vec3& vert2, const osg::Vec3& vert3) + { + intersect_triangle(vert1, vert2, vert3); + } +}; + + +//SandB added: pretty much copy of the IntersectVisitor intersection of traingle function +int TriangleViewFrustumIntersect::intersect_linesegment_and_triangle(osg::Vec3& to_return, + const osg::LineSegment& ls, + const osg::Vec3& v1, + const osg::Vec3& v2, + const osg::Vec3& v3) +{ + + if(v1 == v2 || v1 == v3 || v2 == v3) return -1; + + osg::Vec3 _s = ls.start(); + osg::Vec3 _d = ls.end() - ls.start(); + float _length = _d.length(); + _d /= _length; + + osg::Vec3 v12 = v2 - v1; + osg::Vec3 n12 = v12^_d; + + float ds12 = (_s-v1)*n12; + float d312 = (v3-v1)*n12; + if (d312>=0.0f) + { + if (ds12<0.0f) return 3; + if (ds12>d312) return 3; + } + else // d312 < 0 + { + if (ds12>0.0f) return 3; + if (ds12=0.0f) + { + if (ds23<0.0f) return 3; + if (ds23>d123) return 3; + } + else // d123 < 0 + { + if (ds23>0.0f) return 3; + if (ds23=0.0f) + { + if (ds31<0.0f) return 3; + if (ds31>d231) return 3; + } + else // d231 < 0 + { + if (ds31>0.0f) return 3; + if (ds31_length) return 2; + + return 0; +} + +void TriangleViewFrustumIntersect::intersect_triangle(const osg::Vec3& vert1, const osg::Vec3& vert2, const osg::Vec3& vert3) +{ + //if we have vertices in "transformed" coordinates, transform them to "global" coordinates + osg::Vec3 v1, v2, v3; + if(_t_mat) + { + v1 = vert1*(*_t_mat); + v2 = vert2*(*_t_mat); + v3 = vert3*(*_t_mat); + } + else + { + v1 = vert1; + v2 = vert2; + v3 = vert3; + } + + //construct positions of truncated clipping volume corners + osg::Vec3 UpLeft(_eye + _LeftUp * _current_near); + osg::Vec3 DownLeft(_eye + _LeftDown*_current_near); + osg::Vec3 UpRight(_eye + _RightUp*_current_near); + osg::Vec3 DownRight(_eye + _RightDown*_current_near); + + //construct truncation "back plane" + osg::Plane back_plane(DownLeft, DownRight, UpRight);//CCW, to have normal where it should be + + //add this plane to clipping volume + _cv.add(back_plane); + + //check if all three triangle vertices are contained in truncated clipping volume + unsigned int check = 0; + + //check if all three triangle vertices are behind truncation ("back") plane + unsigned int check2 = 0; + + if(back_plane.distance(v1) <= 0.0) + check2 |= 1; + else if(_cv.contains(v1)) //can not be contained if behind + { + _listVectors[v1] = true; + check |= 1; + } + + if(back_plane.distance(v2)<=0.0) + check2 |= 2; + else if(_cv.contains(v2)) + { + _listVectors[v2] = true; + check |= 2; + } + + if(back_plane.distance(v3) <= 0.0) + check2 |= 4; + else if(_cv.contains(v3)) + { + _listVectors[v3] = true; + check |= 4; + } + + if(check2 == 7) + { + //all three traingle vertices are behind truncation plane so no need to check them + //for heavily tesselated situation, htis is where most of tries will end + return; + } + + + + if(check != 7) + { + //just if it happens that all three are contained in truncated clipping volume, no need to do extra calculation + //(and they already are added to candidate vertices)) + + //at least one of the trianngle vertices is not contained in clipping volume, so extra checks are necessary + + //"working" variable + osg::Vec3 returned; + + //construct line segment of two triangle vertices and check if they intersect any clipping plane + //but within correct clipping plane triangle + osg::LineSegment s12(v1, v2); + + + //left triangle + if(intersect_linesegment_and_triangle(returned, s12, _eye, UpLeft, DownLeft) == 0) + _listVectors[returned] = true; + + //up triangle + if(intersect_linesegment_and_triangle(returned, s12, _eye, UpLeft, UpRight) == 0) + _listVectors[returned] = true; + + //right triangle + if(intersect_linesegment_and_triangle(returned, s12, _eye, UpRight, DownRight) == 0) + _listVectors[returned] = true; + + //bottom triangled + if(intersect_linesegment_and_triangle(returned, s12, _eye, DownLeft, DownRight) == 0) + _listVectors[returned] = true; + + //now for second edge of triangle + s12.set(v2, v3); + + //left triangle + if(intersect_linesegment_and_triangle(returned, s12, _eye, UpLeft, DownLeft) == 0) + _listVectors[returned] = true; + + //up triangle + if(intersect_linesegment_and_triangle(returned, s12, _eye, UpLeft, UpRight) == 0) + _listVectors[returned] = true; + + //right triangle + if(intersect_linesegment_and_triangle(returned, s12, _eye, UpRight, DownRight) == 0) + _listVectors[returned] = true; + + //bottom triangled + if(intersect_linesegment_and_triangle(returned, s12, _eye, DownLeft, DownRight) == 0) + _listVectors[returned] = true; + + s12.set(v3, v1); + + //left triangle + if(intersect_linesegment_and_triangle(returned, s12, _eye, UpLeft, DownLeft) == 0) + _listVectors[returned] = true; + + //up triangle + if(intersect_linesegment_and_triangle(returned, s12, _eye, UpLeft, UpRight) == 0) + _listVectors[returned] = true; + + //right triangle + if(intersect_linesegment_and_triangle(returned, s12, _eye, UpRight, DownRight) == 0) + _listVectors[returned] = true; + + //bottom triangled + if(intersect_linesegment_and_triangle(returned, s12, _eye, DownLeft, DownRight) == 0) + _listVectors[returned] = true; + + + //we still have possibility of camera being above huge triangle, so it is possible that clipping volume + //intersects this triangle thus giving coordinates relevant for determination of near plane + + s12.set(_eye, UpLeft); + + if(intersect_linesegment_and_triangle(returned, s12, v1, v2, v3) == 0) + _listVectors[returned] = true; + + s12.set(_eye, DownLeft); + + if(intersect_linesegment_and_triangle(returned, s12, v1, v2, v3) == 0) + _listVectors[returned] = true; + + s12.set(_eye, UpRight); + + if(intersect_linesegment_and_triangle(returned, s12, v1, v2, v3) == 0) + _listVectors[returned] = true; + + s12.set(_eye, DownRight); + + if(intersect_linesegment_and_triangle(returned, s12, v1, v2, v3) == 0) + _listVectors[returned] = true; + } +} CullVisitor::CullVisitor() { @@ -109,6 +415,9 @@ CullVisitor::CullVisitor() _numFramesToKeepImpostorSprites = 10; _impostorSpriteManager = new ImpostorSpriteManager; + //SandB change + _detailedCulling = false; + } @@ -144,10 +453,10 @@ void CullVisitor::reset() _currentReuseRenderLeafIndex = 0; for(RenderLeafList::iterator itr=_reuseRenderLeafList.begin(); - itr!=_reuseRenderLeafList.end(); - ++itr) + itr!=_reuseRenderLeafList.end(); + ++itr) { - (*itr)->reset(); + (*itr)->reset(); } } @@ -168,8 +477,8 @@ void CullVisitor::setCamera(const Camera& camera) _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->_lookVector.y()>=0?2:0) | + (_tvs->_lookVector.z()>=0?4:0); _tvs->_bbCornerNear = (~_tvs->_bbCornerFar)&7; @@ -247,8 +556,8 @@ void CullVisitor::pushCullViewState(const Matrix* matrix) nvs->_bbCornerFar = (nvs->_lookVector.x()>=0?1:0) | - (nvs->_lookVector.y()>=0?2:0) | - (nvs->_lookVector.z()>=0?4:0); + (nvs->_lookVector.y()>=0?2:0) | + (nvs->_lookVector.z()>=0?4:0); nvs->_bbCornerNear = (~nvs->_bbCornerFar)&7; @@ -275,6 +584,135 @@ void CullVisitor::popCullViewState() } +double CullVisitor::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; +} + +void CullVisitor::calcClippingDirections() const +{ + //need to calculate intersections of clipping planes + osg::Vec3 t_up = _camera->getUpVector(); + osg::Vec3 t_side = _camera->getSideVector(); + + double t_VFOV_2 = _camera->calc_fovy() * M_PI / 360.0;//half of vertical FOV in radians + + //we need to pitch up the cameras up vector for angle that is half fovy, + osg::Vec3 pitched_up_up = t_up * osg::Matrix::rotate(t_VFOV_2, t_side.x(), t_side.y(), t_side.z()); + + //we need also pitched down cameras up vector + osg::Vec3 pitched_down_up = t_up * osg::Matrix::rotate(-t_VFOV_2, t_side.x(), t_side.y(), t_side.z()); + + //we need either left and right or up and down planes of clipping volume (their normals better said) + + osg::Vec4 temp_plane = _cvs.get()->_clippingVolume.getPlaneList()[0].asVec4();//take left + osg::Vec3 left(temp_plane.x(), temp_plane.y(), temp_plane.z()); + + temp_plane = _cvs.get()->_clippingVolume.getPlaneList()[1].asVec4();//take right + osg::Vec3 right(temp_plane.x(), temp_plane.y(), temp_plane.z()); + + //now, the line from eye along intersecion of left and up clipping planes is cross product of properly pitched up "up" vector and left + //clipping plane normal + _LeftUp = pitched_up_up^left; _LeftUp.normalize();//upper left line of clipping volume + _LeftDown = pitched_down_up^left; _LeftDown.normalize();//lower left line of clipping volume + _RightUp = right^pitched_up_up; _RightUp.normalize();//upper right line of clipping volume + _RightDown = right^pitched_down_up; _RightDown.normalize();//lower right line of clipping volume +} + +void CullVisitor::updateCalculatedNearFar(osg::Drawable* pDrawable) +{ + //new philosophy, to have detailed checking + + //do all the same as non-detailed update near and far + const BoundingBox& bb = pDrawable->getBound(); + + const osg::Vec3& eyePoint = _tvs->_eyePoint; // note world eye point. + const osg::Vec3& lookVector = _tvs->_lookVector; // world look vector. + + float d_near,d_far; + + if (_cvs->_matrix.valid()) + { + + const osg::Matrix& matrix = *(_cvs->_matrix); + // calculate the offset from the eye in local coords then transform + // the offset into world and then compare against the world look vector. + d_near = ((bb.corner(_cvs->_bbCornerNear)*matrix) - eyePoint)*lookVector; + d_far = ((bb.corner(_cvs->_bbCornerFar)*matrix) - eyePoint)*lookVector; + + } + else + { + d_near = (bb.corner(_cvs->_bbCornerNear)-eyePoint)*lookVector; + d_far = (bb.corner(_cvs->_bbCornerFar)-eyePoint)*lookVector; + } + + //this is where difference arises: check if near is less than zero: + + if(d_near >= 0.0) + { + //this is the same as before (non detailed: + 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: CullVisitor::updateCalculatedNearFar(.) near>far in range calculation,"<getDetailedCulling()) + _cullVisitor->calcClippingDirections();//only once pre frame + _renderStage->reset(); _renderStage->setViewport(_viewport.get()); @@ -251,8 +256,11 @@ void SceneView::cull() // if required clamp the near plane to prevent negative or near zero // near planes. - float min_near_plane = _far_plane*0.0005f; - if (_near_planegetDetailedCulling()) + { + float min_near_plane = _far_plane*0.0005f; + if (_near_plane