Added support for compute the near and far planes and then applying to
the current projection matrix into CullVisitor itself. Similar code to support this has been moved out of SceneView completely. Added Matrix:: infront of the definition of the static osg::Matrix::inverse(Matrix) method which was missing.
This commit is contained in:
parent
c5a93ab44d
commit
56dc083330
@ -299,7 +299,7 @@ inline Matrix Matrix::rotate(const Vec3& from, const Vec3& to )
|
||||
return m;
|
||||
}
|
||||
|
||||
inline Matrix inverse( const Matrix& matrix)
|
||||
inline Matrix Matrix::inverse( const Matrix& matrix)
|
||||
{
|
||||
Matrix m;
|
||||
m.invert(matrix);
|
||||
|
@ -171,9 +171,9 @@ class OSGUTIL_EXPORT CullVisitor : public osg::NodeVisitor
|
||||
return _rootRenderStage.get();
|
||||
}
|
||||
|
||||
const float getCalculatedNearPlane() const { return _calculated_znear; }
|
||||
const float getCalculatedNearPlane() const { return _computed_znear; }
|
||||
|
||||
const float getCalculatedFarPlane() const { return _calculated_zfar; }
|
||||
const float getCalculatedFarPlane() const { return _computed_zfar; }
|
||||
|
||||
protected:
|
||||
|
||||
@ -197,11 +197,6 @@ class OSGUTIL_EXPORT CullVisitor : public osg::NodeVisitor
|
||||
else acceptNode->accept(*this);
|
||||
}
|
||||
|
||||
inline osg::Matrix* getCurrentMatrix()
|
||||
{
|
||||
return _modelviewStack.back().get();
|
||||
}
|
||||
|
||||
inline const osg::Vec3& getEyeLocal() const
|
||||
{
|
||||
return _eyePointStack.back();
|
||||
@ -245,8 +240,7 @@ class OSGUTIL_EXPORT CullVisitor : public osg::NodeVisitor
|
||||
return !_modelviewClippingVolumeStack.back().contains(bb,mode);
|
||||
}
|
||||
|
||||
void updateCalculatedNearFar(const osg::BoundingBox& bb);
|
||||
|
||||
void updateCalculatedNearFar(const osg::Matrix& matrix,const osg::Drawable& drawable);
|
||||
void updateCalculatedNearFar(const osg::Vec3& pos);
|
||||
|
||||
/** Add a drawable to current render graph.*/
|
||||
@ -392,8 +386,17 @@ class OSGUTIL_EXPORT CullVisitor : public osg::NodeVisitor
|
||||
|
||||
float _LODBias;
|
||||
|
||||
float _calculated_znear;
|
||||
float _calculated_zfar;
|
||||
|
||||
enum ComputeNearFarMode
|
||||
{
|
||||
DO_NOT_COMPUTE_NEAR_FAR = 0,
|
||||
COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES,
|
||||
COMPUTE_NEAR_FAR_USING_PRIMITIVES
|
||||
};
|
||||
|
||||
ComputeNearFarMode _computeNearFar;
|
||||
float _computed_znear;
|
||||
float _computed_zfar;
|
||||
|
||||
osg::ref_ptr<const osg::EarthSky> _earthSky;
|
||||
|
||||
|
@ -93,8 +93,9 @@ CullVisitor::CullVisitor()
|
||||
_tsm = OBJECT_EYE_POINT_DISTANCE;
|
||||
|
||||
|
||||
_calculated_znear = FLT_MAX;
|
||||
_calculated_zfar = -FLT_MAX;
|
||||
_computeNearFar = COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES;
|
||||
_computed_znear = FLT_MAX;
|
||||
_computed_zfar = -FLT_MAX;
|
||||
|
||||
_impostorActive = true;
|
||||
_depthSortImpostorSprites = false;
|
||||
@ -132,8 +133,9 @@ void CullVisitor::reset()
|
||||
|
||||
|
||||
// reset the calculated near far planes.
|
||||
_calculated_znear = FLT_MAX;
|
||||
_calculated_zfar = -FLT_MAX;
|
||||
_computeNearFar = COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES;
|
||||
_computed_znear = FLT_MAX;
|
||||
_computed_zfar = -FLT_MAX;
|
||||
|
||||
|
||||
osg::Vec3 lookVector(0.0,0.0,-1.0);
|
||||
@ -196,6 +198,32 @@ void CullVisitor::pushProjectionMatrix(Matrix* matrix)
|
||||
|
||||
void CullVisitor::popProjectionMatrix()
|
||||
{
|
||||
|
||||
if (_computed_zfar>0.0f)
|
||||
{
|
||||
|
||||
// adjust the projection matrix so that it encompases the local coords.
|
||||
// so it doesn't cull them out.
|
||||
osg::Matrix& projection = *_projectionStack.back();
|
||||
|
||||
double desired_znear = _computed_znear*0.95;
|
||||
double desired_zfar = _computed_zfar*1.05;
|
||||
|
||||
double min_near_plane = _computed_zfar*0.0005f;
|
||||
if (desired_znear<min_near_plane) desired_znear=min_near_plane;
|
||||
|
||||
double trans_near_plane = (-desired_znear*projection(0,2)-desired_znear*projection(1,2)-desired_znear*projection(2,2)+projection(3,2))/(-desired_znear*projection(2,3));
|
||||
double trans_far_plane = (-desired_zfar*projection(0,2)-desired_zfar*projection(1,2)-desired_zfar*projection(2,2)+projection(3,2))/(-desired_zfar*projection(2,3));
|
||||
|
||||
double ratio = fabs(2.0f/(trans_near_plane-trans_far_plane));
|
||||
double center = -(trans_near_plane+trans_far_plane)/2.0f;
|
||||
|
||||
projection.postMult(osg::Matrix(1.0f,0.0f,0.0f,0.0f,
|
||||
0.0f,1.0f,0.0f,0.0f,
|
||||
0.0f,0.0f,ratio,0.0f,
|
||||
0.0f,0.0f,center*ratio,1.0f));
|
||||
}
|
||||
|
||||
_projectionStack.pop_back();
|
||||
_projectionClippingVolumeStack.pop_back();
|
||||
|
||||
@ -264,34 +292,16 @@ inline float distance(const osg::Vec3& coord,const osg::Matrix& matrix)
|
||||
}
|
||||
|
||||
|
||||
void CullVisitor::updateCalculatedNearFar(const osg::BoundingBox& bb)
|
||||
void CullVisitor::updateCalculatedNearFar(const osg::Matrix& matrix,const osg::Drawable& drawable)
|
||||
{
|
||||
|
||||
if (!bb.isValid())
|
||||
{
|
||||
osg::notify(osg::WARN)<<"Warning: CullVisitor::updateCalculatedNearFar(..) passed a null bounding box."<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
float d_near,d_far;
|
||||
if (!_modelviewStack.empty())
|
||||
{
|
||||
|
||||
const osg::Matrix& matrix = *(_modelviewStack.back());
|
||||
d_near = distance(bb.corner(_bbCornerNear),matrix);
|
||||
d_far = distance(bb.corner(_bbCornerFar),matrix);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
d_near = -(bb.corner(_bbCornerNear)).z();
|
||||
d_far = -(bb.corner(_bbCornerFar)).z();
|
||||
}
|
||||
const osg::BoundingBox& bb = drawable.getBound();
|
||||
float d_near = distance(bb.corner(_bbCornerNear),matrix);
|
||||
float d_far = distance(bb.corner(_bbCornerFar),matrix);
|
||||
|
||||
if (d_near<=d_far)
|
||||
{
|
||||
if (d_near<_calculated_znear) _calculated_znear = d_near;
|
||||
if (d_far>_calculated_zfar) _calculated_zfar = d_far;
|
||||
if (d_near<_computed_znear) _computed_znear = d_near;
|
||||
if (d_far>_computed_zfar) _computed_zfar = d_far;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -302,9 +312,10 @@ void CullVisitor::updateCalculatedNearFar(const osg::BoundingBox& bb)
|
||||
}
|
||||
// note, need to reverse the d_near/d_far association because they are
|
||||
// the wrong way around...
|
||||
if (d_far<_calculated_znear) _calculated_znear = d_far;
|
||||
if (d_near>_calculated_zfar) _calculated_zfar = d_near;
|
||||
if (d_far<_computed_znear) _computed_znear = d_far;
|
||||
if (d_near>_computed_zfar) _computed_zfar = d_near;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CullVisitor::updateCalculatedNearFar(const osg::Vec3& pos)
|
||||
@ -320,8 +331,8 @@ void CullVisitor::updateCalculatedNearFar(const osg::Vec3& pos)
|
||||
d = -pos.z();
|
||||
}
|
||||
|
||||
if (d<_calculated_znear) _calculated_znear = d;
|
||||
if (d>_calculated_zfar) _calculated_zfar = d;
|
||||
if (d<_computed_znear) _computed_znear = d;
|
||||
if (d>_computed_zfar) _computed_zfar = d;
|
||||
}
|
||||
|
||||
void CullVisitor::setCullingMode(CullViewState::CullingMode mode)
|
||||
@ -374,7 +385,7 @@ void CullVisitor::apply(Geode& node)
|
||||
StateSet* node_state = node.getStateSet();
|
||||
if (node_state) pushStateSet(node_state);
|
||||
|
||||
Matrix* matrix = getCurrentMatrix();
|
||||
Matrix& matrix = getModelViewMatrix();
|
||||
for(int i=0;i<node.getNumDrawables();++i)
|
||||
{
|
||||
Drawable* drawable = node.getDrawable(i);
|
||||
@ -391,7 +402,7 @@ void CullVisitor::apply(Geode& node)
|
||||
}
|
||||
|
||||
|
||||
updateCalculatedNearFar(bb);
|
||||
if (_computeNearFar) updateCalculatedNearFar(matrix,*drawable);
|
||||
|
||||
// push the geoset's state on the geostate stack.
|
||||
StateSet* stateset = drawable->getStateSet();
|
||||
@ -400,15 +411,7 @@ void CullVisitor::apply(Geode& node)
|
||||
if (isTransparent)
|
||||
{
|
||||
|
||||
Vec3 center;
|
||||
if (matrix)
|
||||
{
|
||||
center = (drawable->getBound().center())*(*matrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
center = drawable->getBound().center();
|
||||
}
|
||||
Vec3 center = (drawable->getBound().center())*matrix;
|
||||
|
||||
float depth;
|
||||
switch(_tsm)
|
||||
@ -419,14 +422,14 @@ void CullVisitor::apply(Geode& node)
|
||||
}
|
||||
|
||||
if (stateset) pushStateSet(stateset);
|
||||
addDrawableAndDepth(drawable,matrix,depth);
|
||||
addDrawableAndDepth(drawable,&matrix,depth);
|
||||
if (stateset) popStateSet();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stateset) pushStateSet(stateset);
|
||||
addDrawable(drawable,matrix);
|
||||
addDrawable(drawable,&matrix);
|
||||
if (stateset) popStateSet();
|
||||
}
|
||||
|
||||
@ -462,12 +465,19 @@ void CullVisitor::apply(Billboard& node)
|
||||
// need to modify isCulled to handle the billboard offset.
|
||||
// if (isCulled(drawable->getBound())) continue;
|
||||
|
||||
updateCalculatedNearFar(pos);
|
||||
|
||||
Matrix* billboard_matrix = createOrReuseMatrix(modelview);
|
||||
|
||||
node.getMatrix(*billboard_matrix,eye_local,pos);
|
||||
|
||||
Vec3 center;
|
||||
center = pos*modelview;
|
||||
|
||||
if (_computeNearFar)
|
||||
{
|
||||
float d = center.z();
|
||||
if (d<_computed_znear) _computed_znear = d;
|
||||
if (d>_computed_zfar) _computed_zfar = d;
|
||||
}
|
||||
|
||||
StateSet* stateset = drawable->getStateSet();
|
||||
|
||||
@ -475,8 +485,6 @@ void CullVisitor::apply(Billboard& node)
|
||||
if (isTransparent)
|
||||
{
|
||||
|
||||
Vec3 center;
|
||||
center = pos*modelview;
|
||||
|
||||
float depth;
|
||||
switch(_tsm)
|
||||
@ -512,11 +520,11 @@ void CullVisitor::apply(LightSource& node)
|
||||
StateSet* node_state = node.getStateSet();
|
||||
if (node_state) pushStateSet(node_state);
|
||||
|
||||
Matrix* matrix = getCurrentMatrix();
|
||||
Matrix& matrix = getModelViewMatrix();
|
||||
Light* light = node.getLight();
|
||||
if (light)
|
||||
{
|
||||
addLight(light,matrix);
|
||||
addLight(light,&matrix);
|
||||
}
|
||||
|
||||
// pop the node's state off the geostate stack.
|
||||
@ -596,6 +604,14 @@ void CullVisitor::apply(Projection& node)
|
||||
StateSet* node_state = node.getStateSet();
|
||||
if (node_state) pushStateSet(node_state);
|
||||
|
||||
|
||||
// record previous near and far values.
|
||||
float previous_znear = _computed_znear;
|
||||
float previous_zfar = _computed_zfar;
|
||||
|
||||
_computed_znear = FLT_MAX;
|
||||
_computed_zfar = -FLT_MAX;
|
||||
|
||||
ref_ptr<osg::Matrix> matrix = createOrReuseMatrix(node.getMatrix());
|
||||
pushProjectionMatrix(matrix.get());
|
||||
|
||||
@ -603,6 +619,10 @@ void CullVisitor::apply(Projection& node)
|
||||
|
||||
popProjectionMatrix();
|
||||
|
||||
_computed_znear = previous_znear;
|
||||
_computed_zfar = previous_zfar;
|
||||
|
||||
|
||||
// pop the node's state off the render graph stack.
|
||||
if (node_state) popStateSet();
|
||||
|
||||
@ -709,7 +729,7 @@ void CullVisitor::apply(Impostor& node)
|
||||
// within the impostor distance threshold therefore attempt
|
||||
// to use impostor instead.
|
||||
|
||||
Matrix* matrix = getCurrentMatrix();
|
||||
Matrix& matrix = getModelViewMatrix();
|
||||
|
||||
// search for the best fit ImpostorSprite;
|
||||
ImpostorSprite* impostorSprite = node.findBestImpostorSprite(eyeLocal);
|
||||
@ -743,7 +763,7 @@ void CullVisitor::apply(Impostor& node)
|
||||
if (impostorSprite)
|
||||
{
|
||||
|
||||
updateCalculatedNearFar(impostorSprite->getBound());
|
||||
if (_computeNearFar) updateCalculatedNearFar(matrix,*impostorSprite);
|
||||
|
||||
StateSet* stateset = impostorSprite->getStateSet();
|
||||
|
||||
@ -751,15 +771,7 @@ void CullVisitor::apply(Impostor& node)
|
||||
|
||||
if (_depthSortImpostorSprites)
|
||||
{
|
||||
Vec3 center;
|
||||
if (matrix)
|
||||
{
|
||||
center = node.getCenter()*(*matrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
center = node.getCenter();
|
||||
}
|
||||
Vec3 center = node.getCenter()*matrix;
|
||||
|
||||
float depth;
|
||||
switch(_tsm)
|
||||
@ -769,11 +781,11 @@ void CullVisitor::apply(Impostor& node)
|
||||
default: depth = center.length2();break;
|
||||
}
|
||||
|
||||
addDrawableAndDepth(impostorSprite,matrix,depth);
|
||||
addDrawableAndDepth(impostorSprite,&matrix,depth);
|
||||
}
|
||||
else
|
||||
{
|
||||
addDrawable(impostorSprite,matrix);
|
||||
addDrawable(impostorSprite,&matrix);
|
||||
}
|
||||
|
||||
if (stateset) popStateSet();
|
||||
@ -805,7 +817,7 @@ ImpostorSprite* CullVisitor::createImpostorSprite(Impostor& node)
|
||||
// projection matrix...
|
||||
bool isPerspectiveProjection = true;
|
||||
|
||||
Matrix* matrix = getCurrentMatrix();
|
||||
const Matrix& matrix = getModelViewMatrix();
|
||||
const BoundingSphere& bs = node.getBound();
|
||||
osg::Vec3 eye_local = getEyeLocal();
|
||||
int eval = node.evaluate(eye_local,_LODBias);
|
||||
@ -818,7 +830,7 @@ ImpostorSprite* CullVisitor::createImpostorSprite(Impostor& node)
|
||||
|
||||
|
||||
Vec3 eye_world(0.0,0.0,0.0);
|
||||
Vec3 center_world = bs.center()*(*matrix);
|
||||
Vec3 center_world = bs.center()*matrix;
|
||||
|
||||
// no appropriate sprite has been found therefore need to create
|
||||
// one for use.
|
||||
@ -888,25 +900,10 @@ ImpostorSprite* CullVisitor::createImpostorSprite(Impostor& node)
|
||||
Vec3 top_local ( center_local+up_local);
|
||||
Vec3 right_local ( center_local+sv_local);
|
||||
|
||||
Vec3 near_world;
|
||||
Vec3 far_world;
|
||||
Vec3 top_world;
|
||||
Vec3 right_world;
|
||||
|
||||
if (matrix)
|
||||
{
|
||||
near_world = near_local * (*matrix);
|
||||
far_world = far_local * (*matrix);
|
||||
top_world = top_local * (*matrix);
|
||||
right_world = right_local * (*matrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
near_world = near_local;
|
||||
far_world = far_local;
|
||||
top_world = top_local;
|
||||
right_world = right_local;
|
||||
}
|
||||
Vec3 near_world = near_local * matrix;
|
||||
Vec3 far_world = far_local * matrix;
|
||||
Vec3 top_world = top_local * matrix;
|
||||
Vec3 right_world = right_local * matrix;
|
||||
|
||||
float znear = (near_world-eye_world).length();
|
||||
float zfar = (far_world-eye_world).length();
|
||||
|
@ -279,11 +279,6 @@ void SceneView::cull()
|
||||
_cullVisitor->setTraversalMask(_cullMask);
|
||||
cullStage(projection.get(),modelview.get(),_cullVisitor.get(),_rendergraph.get(),_renderStage.get());
|
||||
}
|
||||
|
||||
if (_camera.valid() && _calc_nearfar)
|
||||
{
|
||||
_camera->setNearFar(_near_plane,_far_plane);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -313,11 +308,6 @@ void SceneView::cullStage(osg::Matrix* projection,osg::Matrix* modelview,osgUtil
|
||||
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
|
||||
|
||||
renderStage->reset();
|
||||
|
||||
// comment out reset of rendergraph since clean is more efficient.
|
||||
@ -382,37 +372,6 @@ void SceneView::cullStage(osg::Matrix* projection,osg::Matrix* modelview,osgUtil
|
||||
}
|
||||
|
||||
|
||||
if (_calc_nearfar)
|
||||
{
|
||||
_near_plane = cullVisitor->getCalculatedNearPlane();
|
||||
_far_plane = cullVisitor->getCalculatedFarPlane();
|
||||
|
||||
if (_near_plane<=_far_plane)
|
||||
{
|
||||
// shift the far plane slight further away from the eye point.
|
||||
// and shift the near plane slightly near the eye point, this
|
||||
// will give a little space betwenn the near and far planes
|
||||
// and the model, crucial when the naer and far planes are
|
||||
// coincedent.
|
||||
_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())
|
||||
// {
|
||||
float min_near_plane = _far_plane*0.0005f;
|
||||
if (_near_plane<min_near_plane) _near_plane=min_near_plane;
|
||||
// }
|
||||
}
|
||||
else
|
||||
{
|
||||
_near_plane = 1.0f;
|
||||
_far_plane = 1000.0f;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// prune out any empty RenderGraph children.
|
||||
// note, this would be not required if the rendergraph had been
|
||||
// reset at the start of each frame (see top of this method) but
|
||||
|
Loading…
Reference in New Issue
Block a user