[osg-users] GL_DEPTH_COMPONENT data not clamped to [0, 1] when doing osg::Image::readPixels(...)

Daniel Holz danielh at cm-labs.com
Tue Mar 3 13:27:33 PST 2009


Hi everyone,

I am trying to store the Z-Buffer of a subgraph of my scene in an 
osg::Image for later processing,
but the values I obtain are not as expected in the range [0,1] but 
appear to be integer values starting at 0 and going up to about 200.
I am writing the depth buffer to the osg::Image by using 
image->readPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT);
The osg code which is executed is:

    void Image::readPixels(int x,int y,int width,int height,GLenum 
format,GLenum type)
    {
        allocateImage(width,height,1,format,type);

        glPixelStorei(GL_PACK_ALIGNMENT,_packing);

        glReadPixels(x,y,width,height,format,type,_data);
    }

And according to the OpenGL reference manual 
(http://www.opengl.org/sdk/docs/man/xhtml/glReadPixels.xml) the values 
written to the buffer "_data" should be of type float and in the range 
[0,1] which they are not for me.

I am wondering if I am doing something wrong.
In the following I posted a short version of my implementation, which is 
based on the osgprerender example.

First I set up a render to texture pass:
    ...
    // texture to render to
    osg::Texture* texture = 0;
    osg::Texture2D* texture2D = new osg::Texture2D;
    texture2D->setTextureSize(tex_width, tex_height);
    texture2D->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
    texture2D->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
    // set up texture for z-buffer values
    texture2D->setInternalFormat(GL_DEPTH_COMPONENT);
    texture = texture2D;

    // attach an image to the texture.
    // this allows us to modify the image data before it is being 
rendered to the quad
    osg::Image* image = new osg::Image;
    texture2D->setImage(image);
    ...

Then I create a second camera as copy of the main camera which renders 
to the above texture.

    ...
    // obtain main camera
    osg::Camera* pCamera = ...
    osg::Camera* pCamCopy = new osg::Camera;
    // set update callback to update the copied camera's view and 
projection matrix
    pCamCopy->setPreDrawCallback(new UpdateCamCallback(pCamera)); // 
just keeps the copied and the main camera aligned
       
    // set the clear mask. -> just the depth buffer is cleared.
    pCamCopy->setClearMask(GL_DEPTH_BUFFER_BIT);
    // set the color mask. -> since we do not want any color information 
to be written we can set all bits to zero.
    pCamCopy->setColorMask(new osg::ColorMask(0,0,0,0));
       
    // set up projection.
    pCamCopy->setProjectionMatrix(pCamera->getProjectionMatrix());
    // set view
    pCamCopy->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
    pCamCopy->setViewMatrix(pCamera->getViewMatrix());
    // set viewport
    pCamCopy->setViewport(0,0,tex_width,tex_height);

    // set the camera to render before the main camera.
    pCamCopy->setRenderOrder(osg::Camera::PRE_RENDER);
    // tell the camera to use OpenGL frame buffer object where supported.
    
pCamCopy->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
    // attach the texture and use it as the depth buffer
    pCamCopy->attach(osg::Camera::DEPTH_BUFFER, texture);

    // add sub graph to camera for rendering
    pCamCopy->addChild(subGraph);
    // add camera to scene
    pRoot->addChild(pCamCopy)

Finally I set a post draw callback to the copied camera, where the post 
processing of the depth buffer should be performed.
There I call osg::Image::readPixels(...) to copy the depth buffer data 
from the gpu to the image but the obtained data does not seem to be correct.
   
    // set post processing callback
    pCamCopy->setPostDrawCallback(new FilterImageCallback(image, 
tex_width, tex_height));

The Code for the callback is as follows:

struct FilterImageCallback : osg::Camera::DrawCallback
{
    FilterImageCallback(osg::Image* pImage, int width, int height)
        :   m_pImage(pImage),
            m_width(width),
            m_height(height)
    {}
   
    void operator () (osg::RenderInfo& renderInfo) const
    {
        m_pImage->readPixels(0, 0, m_width, m_height, 
GL_DEPTH_COMPONENT, GL_FLOAT);

        // apply post processing here:

        // test: obtain first pixel's z value and convert to float.
        float z = (float) (m_pImage->data())[0];
        // Problem: z-value is not in range [0, 1] but appears to be 
0,1,2, etc. It is 0 for areas where the z-buffer is clear, i.e. z-value 
corresponds to "infinity".
    }

private:
    osg::Image* m_pImage;
    int m_width;
    int m_height;
};

I can't find the mistake.
Any help is much appreciated!

Cheers and Thank you
Daniel







More information about the osg-users mailing list