From e6ac4cd19022d09bcd80cb39541c95b8a176b78b Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 11 Feb 2002 23:24:23 +0000 Subject: [PATCH] Updates to Transform handling in CullVisitor, in prep for moving camera modelview and projection into Transform nodes. --- src/osg/Matrix.cpp | 350 +++++++++--------------------------- src/osg/Transform.cpp | 10 +- src/osgUtil/CullVisitor.cpp | 92 +++++++--- 3 files changed, 158 insertions(+), 294 deletions(-) diff --git a/src/osg/Matrix.cpp b/src/osg/Matrix.cpp index f70ddc6a5..386d1528f 100644 --- a/src/osg/Matrix.cpp +++ b/src/osg/Matrix.cpp @@ -22,102 +22,6 @@ using namespace osg; -template -inline T SGL_ABS(T a) -{ - return (a >= 0 ? a : -a); -} - -#ifndef SGL_SWAP -#define SGL_SWAP(a,b,temp) ((temp)=(a),(a)=(b),(b)=(temp)) -#endif - -bool inverse(const Matrix& mat,Matrix& m_matrix) -{ - unsigned int indxc[4], indxr[4], ipiv[4]; - unsigned int i,j,k,l,ll; - unsigned int icol = 0; - unsigned int irow = 0; - float temp, pivinv, dum, big; - - // copy in place this may be unnecessary - m_matrix = mat; - - for (j=0; j<4; j++) ipiv[j]=0; - - for(i=0;i<4;i++) - { - big=(float)0.0; - for (j=0; j<4; j++) - if (ipiv[j] != 1) - for (k=0; k<4; k++) - { - if (ipiv[k] == 0) - { - if (SGL_ABS(m_matrix(j,k)) >= big) - { - big = SGL_ABS(m_matrix(j,k)); - irow=j; - icol=k; - } - } - else if (ipiv[k] > 1) - return false; - } - ++(ipiv[icol]); - if (irow != icol) - for (l=0; l<4; l++) SGL_SWAP(m_matrix(irow,l), - m_matrix(icol,l), - temp); - - indxr[i]=irow; - indxc[i]=icol; - if (m_matrix(icol,icol) == 0) - return false; - - pivinv = 1.0/m_matrix(icol,icol); - m_matrix(icol,icol) = 1; - for (l=0; l<4; l++) m_matrix(icol,l) *= pivinv; - for (ll=0; ll<4; ll++) - if (ll != icol) - { - dum=m_matrix(ll,icol); - m_matrix(ll,icol) = 0; - for (l=0; l<4; l++) m_matrix(ll,l) -= m_matrix(icol,l)*dum; - } - } - for (int lx=4; lx>0; --lx) - { - if (indxr[lx-1] != indxc[lx-1]) - for (k=0; k<4; k++) SGL_SWAP(m_matrix(k,indxr[lx-1]), - m_matrix(k,indxc[lx-1]),temp); - } - - return true; -} - -bool inverseAffine(const Matrix& mat,Matrix& m_matrix) -{ - // | R p |' | R' -R'p |' - // | | -> | | - // | 0 0 0 1 | | 0 0 0 1 | - for (unsigned int i=0; i<3; i++) - { - m_matrix(i,3) = 0; - m_matrix(3,i) = -(mat(i,0)*mat(3,0) + - mat(i,1)*mat(3,1) + - mat(i,2)*mat(3,2)); - for (unsigned int j=0; j<3; j++) - { - m_matrix(i,j) = mat(j,i); - } - } - m_matrix(3,3) = 1; - - return true; -} - - Matrix::Matrix() : Object() @@ -339,188 +243,104 @@ void Matrix::postMult( const Matrix& other ) #undef SET_ROW #undef INNER_PRODUCT -bool Matrix::invert( const Matrix& invm ) + +template +inline T SGL_ABS(T a) { - if (&invm==this) { - Matrix tm(invm); - return invert(tm); - } -/* - if ( invm._mat[0][3] == 0.0 - && invm._mat[1][3] == 0.0 - && invm._mat[2][3] == 0.0 - && invm._mat[3][3] == 1.0 ) - { - return inverseAffine( invm,*this ); - } -*/ - return inverse(invm,*this); - - // code lifted from VR Juggler. - // not cleanly added, but seems to work. RO. - - const float* a = reinterpret_cast(invm._mat); - float* b = reinterpret_cast(_mat); - - int n = 4; - int i, j, k; - int r[ 4], c[ 4], row[ 4], col[ 4]; - float m[ 4][ 4*2], pivot, max_m, tmp_m, fac; - - /* Initialization */ - for ( i = 0; i < n; i ++ ) - { - r[ i] = c[ i] = 0; - row[ i] = col[ i] = 0; - } - - /* Set working matrix */ - for ( i = 0; i < n; i++ ) - { - for ( j = 0; j < n; j++ ) - { - m[ i][ j] = a[ i * n + j]; - m[ i][ j + n] = ( i == j ) ? 1.0 : 0.0 ; - } - } - - /* Begin of loop */ - for ( k = 0; k < n; k++ ) - { - /* Choosing the pivot */ - for ( i = 0, max_m = 0; i < n; i++ ) - { - if ( row[ i] ) continue; - for ( j = 0; j < n; j++ ) - { - if ( col[ j] ) continue; - tmp_m = fabs( m[ i][j]); - if ( tmp_m > max_m) - { - max_m = tmp_m; - r[ k] = i; - c[ k] = j; - } - } - } - row[ r[k] ] = col[ c[k] ] = 1; - pivot = m[ r[ k] ][ c[ k] ]; - - if ( fabs( pivot) <= 1e-20) - { - notify(INFO) << "Warning: pivot = "<< pivot <<" in Matrix::invert(), cannot compute inverse."<= big) + { + big = SGL_ABS(operator()(j,k)); + irow=j; + icol=k; + } + } + else if (ipiv[k] > 1) + return false; + } + ++(ipiv[icol]); + if (irow != icol) + for (l=0; l<4; l++) SGL_SWAP(operator()(irow,l), + operator()(icol,l), + temp); + + indxr[i]=irow; + indxc[i]=icol; + if (operator()(icol,icol) == 0) + return false; + + pivinv = 1.0/operator()(icol,icol); + operator()(icol,icol) = 1; + for (l=0; l<4; l++) operator()(icol,l) *= pivinv; + for (ll=0; ll<4; ll++) + if (ll != icol) + { + dum=operator()(ll,icol); + operator()(ll,icol) = 0; + for (l=0; l<4; l++) operator()(ll,l) -= operator()(icol,l)*dum; + } + } + for (int lx=4; lx>0; --lx) + { + if (indxr[lx-1] != indxc[lx-1]) + for (k=0; k<4; k++) SGL_SWAP(operator()(k,indxr[lx-1]), + operator()(k,indxc[lx-1]),temp); } - - // inverse is adj(A)/det(A) - det_1 = 1.0 / det_1; - - _mat[0][0] = (other._mat[1][1] * other._mat[2][2] - other._mat[1][2] * other._mat[2][1]) * det_1; - _mat[1][0] = (other._mat[1][0] * other._mat[2][2] - other._mat[1][2] * other._mat[2][0]) * det_1; - _mat[2][0] = (other._mat[1][0] * other._mat[2][1] - other._mat[1][1] * other._mat[2][0]) * det_1; - _mat[0][1] = (other._mat[0][1] * other._mat[2][2] - other._mat[0][2] * other._mat[2][1]) * det_1; - _mat[1][1] = (other._mat[0][0] * other._mat[2][2] - other._mat[0][2] * other._mat[2][0]) * det_1; - _mat[2][1] = (other._mat[0][0] * other._mat[2][1] - other._mat[0][1] * other._mat[2][0]) * det_1; - _mat[0][2] = (other._mat[0][1] * other._mat[1][2] - other._mat[0][2] * other._mat[1][1]) * det_1; - _mat[1][2] = (other._mat[0][0] * other._mat[1][2] - other._mat[0][2] * other._mat[1][0]) * det_1; - _mat[2][2] = (other._mat[0][0] * other._mat[1][1] - other._mat[0][1] * other._mat[1][0]) * det_1; - - // calculate -C * inv(A) - _mat[3][0] = -(other._mat[3][0] * _mat[0][0] + other._mat[3][1] * _mat[1][0] + other._mat[3][2] * _mat[2][0] ); - _mat[3][1] = -(other._mat[3][0] * _mat[0][1] + other._mat[3][1] * _mat[1][1] + other._mat[3][2] * _mat[2][1] ); - _mat[3][2] = -(other._mat[3][0] * _mat[0][2] + other._mat[3][1] * _mat[1][2] + other._mat[3][2] * _mat[2][2] ); - - _mat[0][3] = 0.0; - _mat[1][3] = 0.0; - _mat[2][3] = 0.0; - _mat[3][3] = 1.0; return true; } +bool Matrix::invertAffine( const Matrix& mat) +{ + // | R p |' | R' -R'p |' + // | | -> | | + // | 0 0 0 1 | | 0 0 0 1 | + for (unsigned int i=0; i<3; i++) + { + operator()(i,3) = 0; + operator()(3,i) = -(mat(i,0)*mat(3,0) + + mat(i,1)*mat(3,1) + + mat(i,2)*mat(3,2)); + for (unsigned int j=0; j<3; j++) + { + operator()(i,j) = mat(j,i); + } + } + operator()(3,3) = 1; + + return true; +} diff --git a/src/osg/Transform.cpp b/src/osg/Transform.cpp index 94c0217fd..a5c838ede 100644 --- a/src/osg/Transform.cpp +++ b/src/osg/Transform.cpp @@ -8,6 +8,8 @@ Transform::Transform() _mode = MODEL; _matrix = new Matrix; + _inverse = new Matrix; + _inverseDirty = false; } Transform::Transform(const Transform& transform,const CopyOp& copyop): @@ -15,7 +17,9 @@ Transform::Transform(const Transform& transform,const CopyOp& copyop): _type(transform._type), _mode(transform._mode), _computeTransformCallback(_computeTransformCallback), - _matrix(new Matrix(*transform._matrix)) + _matrix(new Matrix(*transform._matrix)), + _inverse(new Matrix(*transform._inverse)), + _inverseDirty(transform._inverseDirty) { } @@ -25,6 +29,8 @@ Transform::Transform(const Matrix& mat ) _mode = MODEL; _matrix = new Matrix(mat); + _inverse = new Matrix(); + _inverseDirty = false; } @@ -39,7 +45,7 @@ const bool Transform::computeBound() const // note, NULL pointer for NodeVisitor, so compute's need // to handle this case gracefully, normally this should not be a problem. Matrix l2w; - if (getLocalToWorldMatrix(l2w,NULL)) + if (_mode!=PROJECTION && getLocalToWorldMatrix(l2w,NULL)) { Vec3 xdash = _bsphere._center; diff --git a/src/osgUtil/CullVisitor.cpp b/src/osgUtil/CullVisitor.cpp index 71eb95fd1..c96739c86 100644 --- a/src/osgUtil/CullVisitor.cpp +++ b/src/osgUtil/CullVisitor.cpp @@ -480,6 +480,18 @@ void CullVisitor::setCamera(const Camera& camera) } void CullVisitor::pushCullViewState(Matrix* matrix) +{ + if (matrix) + { + osg::Matrix* inverse = new osg::Matrix; + inverse->invert(*matrix); + pushCullViewState(matrix,inverse); + } + else + pushCullViewState(NULL,NULL); +} + +void CullVisitor::pushCullViewState(Matrix* matrix,osg::Matrix* inverse) { osg::ref_ptr nvs = new CullViewState; @@ -494,11 +506,6 @@ void CullVisitor::pushCullViewState(Matrix* matrix) } nvs->_matrix = matrix; - - inverse_world = createOrReuseMatrix(); - inverse_world->invert(*(matrix)); - - nvs->_inverse = inverse_world; } else @@ -506,21 +513,41 @@ void CullVisitor::pushCullViewState(Matrix* matrix) if (_cvs.valid()) { nvs->_matrix = _cvs->_matrix; - nvs->_inverse = _cvs->_inverse; - inverse_world = nvs->_inverse.get(); } else { nvs->_matrix = NULL; - nvs->_inverse = NULL; - inverse_world = 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); @@ -560,7 +587,6 @@ void CullVisitor::pushCullViewState(Matrix* matrix) _viewStateStack.push_back(nvs); } - void CullVisitor::popCullViewState() { // pop the top of the view stack and unref it. @@ -706,6 +732,11 @@ void CullVisitor::updateCalculatedNearFar(osg::Drawable* pDrawable) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +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 CullVisitor::updateCalculatedNearFar(const osg::BoundingBox& bb) { @@ -715,26 +746,20 @@ void CullVisitor::updateCalculatedNearFar(const osg::BoundingBox& bb) osg::notify(osg::WARN)<<"Warning: CullVisitor::updateCalculatedNearFar(..) passed a null bounding box."<< std::endl; return; } - - 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; + d_near = distance(bb.corner(_cvs->_bbCornerNear),matrix); + d_far = distance(bb.corner(_cvs->_bbCornerFar),matrix); } else { - d_near = (bb.corner(_cvs->_bbCornerNear)-eyePoint)*lookVector; - d_far = (bb.corner(_cvs->_bbCornerFar)-eyePoint)*lookVector; + d_near = -(bb.corner(_cvs->_bbCornerNear)).z(); + d_far = -(bb.corner(_cvs->_bbCornerFar)).z(); } if (d_near<=d_far) @@ -1049,14 +1074,27 @@ void CullVisitor::apply(Transform& node) StateSet* node_state = node.getStateSet(); if (node_state) pushStateSet(node_state); - ref_ptr matrix = createOrReuseMatrix(); - matrix->makeIdentity(); - node.getLocalToWorldMatrix(*matrix,this); - pushCullViewState(matrix.get()); + 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."<