Hi Robert,

Thanks to this advice I finally appear to have solved my problem! I  
used my cull callback to highjack the matrix clamping implementation  
callback of all cull visitors passing through the camera node. This  
isn't thread safe, and undoes the flexibility of making the clamp  
function overridable with a callback, but works for my needs. I've  
pasted the code at the bottom of this email incase the code should  
prove useful to anyone else with similar problems.

I know it might seem like a selfish thing to say and OSG's design  
shouldn't be driven by the needs of individual users and programs,  
but with the advent of shaders and freedom from the fixed pipeline  
rendering, getting "program-side" access to the actual OpenGL state  
used to render a scene is becoming more and important. Back when OSG  
was strictly fixed function it didn't really matter if OSG was  
sliding the culling planes around the place to improve visual  
quality, nobody needed to know it was going on and it produced nicer  
images with less z-fighting. But now that OpenGL and OSG has given  
programmers the freedom to redefine parts of the pipeline, knowing  
what "hidden changes" OSG is making to the OpenGL state behind the  
scenes is becoming more important I think.

In this program of mine for example I need to reverse the normalised  
z-buffer values stored in a depth texture to world space coordinates.  
With the projection matrix used to generate the image, this is  
trivial. But when OSG changes the matrix used, the values I back- 
project become skewed. Does it make sense to provide an additional  
callback or something in the CullVisitor class to provide access to  
this matrix once it is computed? It seems like this kind of problem  
will only become more common in the future with the proliferation of  
RTT and all the rest of it.

Thanks,
Alan.

class WriteProjectionMatrixToUniformCallback : public osg::NodeCallback
{
        private:
        struct ClampProjectionMatrixCallback : public  
osg::CullSettings::ClampProjectionMatrixCallback
        {
                private:
                osg::ref_ptr<osg::Uniform> _uniform;
                
                template<class matrix_type> bool clampprojectionmatriximpl 
(matrix_type &PROJECTION, double &ZNEAR, double &ZFAR) const
                {
                        double epsilon = 1e-6;
                        double nearfarratio = 0.0005;
                        
                        bool valid = true;
                        if(ZFAR < ZNEAR -epsilon)
                        {
                                osg::notify(osg::INFO) << 
"_clampProjectionMatrix not applied,  
invalid depth range, ZNEAR = " << ZNEAR <<"  ZFAR = "<< ZFAR <<  
std::endl;
                                valid = false;
                        }
                        else
                        {
                                if(ZFAR < ZNEAR +epsilon)
                                {
                                        double average = (ZNEAR +ZFAR) *0.5;
                                        ZNEAR = average -epsilon;
                                        ZFAR = average +epsilon;
                                }

                                if(fabs(PROJECTION(0, 3)) < epsilon && 
fabs(PROJECTION(1, 3)) <  
epsilon && fabs(PROJECTION(2, 3)) < epsilon)
                                {
                                        double deltaspan = (ZFAR -ZNEAR) *0.02;
                                        if(deltaspan < 1.0) deltaspan = 1.0;
                                        double desiredznear = ZNEAR -deltaspan;
                                        double desiredzfar = ZFAR +deltaspan;

                                        ZNEAR = desiredznear;
                                        ZFAR = desiredzfar;

                                        PROJECTION(2, 2) =- 2.0f /(desiredzfar 
-desiredznear);
                                        PROJECTION(3, 2) =- (desiredzfar 
+desiredznear) /(desiredzfar - 
desiredznear);
                                }
                                else
                                {
                                        double zpushratio = 1.02;
                                        double zpullratio = 0.98;

                                        double desiredznear = ZNEAR *zpullratio;
                                        double desiredzfar = ZFAR *zpushratio;

                                        double minnearplane = ZFAR 
*nearfarratio;
                                        if(desiredznear < minnearplane) 
desiredznear = minnearplane;

                                        ZNEAR = desiredznear;
                                        ZFAR = desiredzfar;

                                        double transnearplane = (-desiredznear 
*PROJECTION(2, 2)  
+PROJECTION(3, 2)) /(-desiredznear *PROJECTION(2, 3) +PROJECTION(3, 3));
                                        double transfarplane = (-desiredzfar 
*PROJECTION(2, 2)  
+PROJECTION(3, 2)) /(-desiredzfar *PROJECTION(2, 3) +PROJECTION(3, 3));

                                        double ratio = fabs(2.0 
/(transnearplane -transfarplane));
                                        double center = -(transnearplane 
+transfarplane) /2.0;

                                        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));
                                }
                        }
                        
                        if(_uniform != NULL) _uniform->set(PROJECTION);
                        
                        /*
                        float n = (PROJECTION(3, 2) +PROJECTION(3, 3)) 
/(PROJECTION(2, 2)  
+PROJECTION(2, 3));
                        float f = (PROJECTION(3, 3) -PROJECTION(3, 2)) 
/(PROJECTION(2, 3) - 
PROJECTION(2, 2));

                        std::cout << "n = " << n << ", f = " << f << "\n";
                        */
                        
                        return valid;
                }
                
                public:
                ClampProjectionMatrixCallback(osg::ref_ptr<osg::Uniform> 
UNIFORM)  
{ _uniform = UNIFORM; }
                virtual ~ClampProjectionMatrixCallback(void) {}

                virtual bool clampProjectionMatrixImplementation(osg::Matrixf  
&PROJECTION, double &ZNEAR, double &ZFAR) const
                {
                        return clampprojectionmatriximpl(PROJECTION, ZNEAR, 
ZFAR);
                }
                virtual bool clampProjectionMatrixImplementation(osg::Matrixd  
&PROJECTION, double &ZNEAR, double &ZFAR) const
                {
                        return clampprojectionmatriximpl(PROJECTION, ZNEAR, 
ZFAR);
                }
        };
        
        static osg::ref_ptr<ClampProjectionMatrixCallback> _cpmc;
        
        public:
        WriteProjectionMatrixToUniformCallback(osg::ref_ptr<osg::Uniform>  
UNIFORM) { if(_cpmc == NULL) _cpmc = new ClampProjectionMatrixCallback 
(UNIFORM); }
        virtual ~WriteProjectionMatrixToUniformCallback(void) {}
        
        virtual void operator()(osg::Node* NODE, osg::NodeVisitor* NV)
        {
                NodeCallback::traverse(NODE, NV);
                
                osgUtil::CullVisitor *cv = 
dynamic_cast<osgUtil::CullVisitor*>(NV);
                if(cv == NULL) return;
                
                cv->setClampProjectionMatrixCallback(_cpmc.get());
        }
};

osg::ref_ptr<WriteProjectionMatrixToUniformCallback::ClampProjectionMatr 
ixCallback> WriteProjectionMatrixToUniformCallback::_cpmc = NULL;


On 7 Dec 2007, at 15:58, Robert Osfield wrote:

> On Dec 7, 2007 3:34 PM, Alan Purvis <[EMAIL PROTECTED]> wrote:
>> Does anyone have an idea what I might be doing wrong? Am I right to
>> call traverse before I deference the pointer to the matrix? Am I
>> getting a pointer to the right matrix?
>
> Reading through your you email the reason pinged into my head.  Your
> not doing anything wrong in terms of accessing the projection matrix,
> the problem lies in the fact that the cull visitor does the clamping
> of the projection matrix once its traversed the whole subgraph below a
> camera - which will be after your cull callback returns.  The actual
> clamping is dispatched within the CullVisitor;:popProjectionMatrix()
> method.
>
> Looking at your code you are setting a uniform with the projection
> matrix.   Perhaps you can dispense with this completely as OpenGL
> itself has the projection matrix as a built in uniform.
>
> Robert.
> _______________________________________________
> osg-users mailing list
> [email protected]
> http://lists.openscenegraph.org/listinfo.cgi/osg-users- 
> openscenegraph.org
>

_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Reply via email to