fosky 发表于 2011-12-11 17:41:31

osg做阴影时,得不到深度图的问题

各位:
      用osg::Camera渲染了一个深度图,想把它用到阴影里面,但是,发现整个深度图里面的像素值都是0.可能是代码错误或是Shader错误.这个是模仿一个OpenGL例子来做的,实在找不到问题了.
      大家有时间帮我看一下,是哪里有问题,我好改正过来.谢谢了.
      代码如下:#include <osg/Group>
#include <osg/MatrixTransform>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>

#include <osg/Texture>
#include <osg/Texture2D>
#include <osg/Image>
#include <osg/StateSet>
#include <osg/StateAttribute>
#include <osg/Geode>
#include <osg/Array>
#include <osg/Light>
#include <osg/Shape>
#include <osg/ShapeDrawable>

#include <osg/Matrix>
#include <osg/Camera>
#include <osgGA/GUIEventHandler>

#include <osgViewer/View>
#include <osg/Timer>

#include <osg/Program>
#include <osg/Uniform>
#include <osg/Shader>

#include <osg/ColorMask>

class CameraProjectUpdate : public osgGA::GUIEventHandler
{
public:
        CameraProjectUpdate( osg::Camera *camera, osg::Light *light, osg::Node *shadowRoot )
        {
                _shadowCamera = camera;
                _light = light;
                _shadowRoot = shadowRoot;
                _maxtrixUniform = NULL;
        }
        bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
        {

                osgViewer::View *view = dynamic_cast<osgViewer::View*>(&aa);
                if ( !view )
                {
                        return false;
                }

                osg::Camera *camera = view->getCamera();
                if ( !camera )
                {
                        return false;
                }

                osg::BoundingSphere bs = _shadowRoot->getBound();

                if (!bs.valid())
                {
                        return false;
                }

                float znear = 1.0f*bs.radius();
                float zfar= 3.0f*bs.radius();

                // 2:1 aspect ratio as per flag geometry below.
                float proj_top   = 0.25f*znear;
                float proj_right = 0.5f*znear;

                znear *= 0.9f;
                zfar *= 1.1f;

                _shadowCamera->setProjectionMatrixAsFrustum(-proj_right,proj_right,-proj_top,proj_top,znear,zfar);
                osg::Vec4 lightPos = _light->getPosition();

                _shadowCamera->setViewMatrixAsLookAt( osg::Vec3( lightPos.x(), lightPos.y(), lightPos.z() ), bs.center(), _light->getDirection() );

               
                // 视图变换矩阵
                osg::Matrix lightViewMatrix = _shadowCamera->getViewMatrix();
                // 投影矩阵
                osg::Matrix lightProjectMatrix = _shadowCamera->getProjectionMatrix();

                osg::Matrix cameraInverseViewMatrix = camera->getInverseViewMatrix();
                osg::Matrix lightResultMatrix;

                if ( ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_SHIFT )
                {
                        lightResultMatrix =   cameraInverseViewMatrix * lightViewMatrix * lightProjectMatrix/* * biasMt*/;
                }else
                {
                        lightResultMatrix =   /*biasMt * */lightProjectMatrix * lightViewMatrix * cameraInverseViewMatrix;
                }

                if ( !_maxtrixUniform )
                {
                        return false;
                }
                _maxtrixUniform->set( lightResultMatrix );


                return false;
        }

        osg::Camera *_shadowCamera;
        osg::Light *_light;
        osg::Node *_shadowRoot;
        osg::Uniform *_maxtrixUniform;

};




osg::Texture* createRenderTexture(int tex_width, int tex_height, bool nearest = false)
{
        // create simple 2D texture
        osg::Texture2D* texture2D = new osg::Texture2D;
        texture2D->setTextureSize(tex_width, tex_height);
        texture2D->setFilter(osg::Texture2D::MIN_FILTER, nearest ? osg::Texture2D::NEAREST : osg::Texture2D::LINEAR);
        texture2D->setFilter(osg::Texture2D::MAG_FILTER, nearest ? osg::Texture2D::NEAREST : osg::Texture2D::LINEAR);
        texture2D->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_EDGE);
        texture2D->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_EDGE);
        texture2D->setBorderColor(osg::Vec4(0.0f,0.0f,0.0f,0.0f));
        texture2D->setResizeNonPowerOfTwoHint(false);

        texture2D->setInternalFormat(GL_RGBA32F_ARB);
        texture2D->setSourceFormat(GL_RGBA);
        texture2D->setSourceType(GL_FLOAT);

        return texture2D;
}
osg::Drawable* createTexturedQuadDrawable(const osg::Vec3& center,const osg::Vec3& widthVec,const osg::Vec3& heightVec, osg::Texture *tex )
{
        //osg::Geometry* geom = osg::createTexturedQuadGeometry(corner, widthVec, heightVec, l,b,r,t);

        osg::Geometry* geom = new osg::Geometry;

        osg::Vec4Array* colors = new osg::Vec4Array;
        colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
        geom->setColorArray(colors);
        geom->setColorBinding(osg::Geometry::BIND_OVERALL);

        // Vertex coordinates
        osg::Vec3Array* coords = new osg::Vec3Array(4);
        (*coords) = center + heightVec / 2 - widthVec / 2;
        (*coords) = center - heightVec / 2 - widthVec / 2;
        (*coords) = center - heightVec / 2 + widthVec / 2;
        (*coords) = center + heightVec / 2 + widthVec / 2;
        geom->setVertexArray(coords);

        // Add texture coordinates for every input texture
       
        int unit = 0;

      // start with default normalised
      float l = 0.0;
      float b = 0.0;
      float r = 1.0;
      float t = 1.0;

      osg::Vec2Array* tcoords = new osg::Vec2Array(4);
      (*tcoords).set(l,t);
      (*tcoords).set(l,b);
      (*tcoords).set(r,b);
      (*tcoords).set(r,t);
      geom->setTexCoordArray(unit, tcoords);
               

        osg::Vec3Array* normals = new osg::Vec3Array(1);
        (*normals) = widthVec^heightVec;
        (*normals).normalize();
        geom->setNormalArray(normals);
        geom->setNormalBinding(osg::Geometry::BIND_OVERALL);

        geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));

        // setup default state set
        geom->setStateSet(new osg::StateSet());
        if ( tex )
        {
                geom->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex );
        }

        geom->setUseDisplayList(false);

        return geom;
}



int _tmain(int argc, _TCHAR* argv[])
{
        osgViewer::Viewer v;

        osg::ref_ptr<osg::Node> cow = osgDB::readNodeFile("cow.osg");
        osg::ref_ptr<osg::Group> root = new osg::Group;
        osg::ref_ptr<osg::Group> modelRoot = new osg::Group;
        osg::ref_ptr<osg::Group> shadowRoot = new osg::Group;
        osg::ref_ptr<osg::Group> modelsGroup = new osg::Group;

        modelsGroup->addChild( cessna );
        shadowRoot->addChild( modelsGroup );
        modelRoot->addChild( modelsGroup );

        root->addChild( modelRoot );

        // add a sphere to modelsGroup
        {
                osg::ref_ptr<osg::Geode> shadowGeode = new osg::Geode;
                osg::ref_ptr<osg::Sphere> shadowSphere = new osg::Sphere;
                shadowSphere->setRadius( 5.0 );
                shadowSphere->setCenter( osg::Vec3 ( 0.0, 0.0, 0.0 ) );
                osg::ref_ptr<osg::ShapeDrawable> shadowShape = new osg::ShapeDrawable;
                shadowShape->setColor( osg::Vec4 ( 1.0, 1.0, 0.0, 1.0 ) );
                shadowShape->setShape( shadowSphere );
                shadowGeode->addDrawable( shadowShape );
                modelsGroup->addChild( shadowGeode );
        }

        osg::ref_ptr<osg::Light> light = new osg::Light;
        osg::Vec3 lightPos = osg::Vec3 ( 0, 0, 100 );
        osg::Vec3 lightDir = osg::Vec3 ( 0.0, 0.0, -1.0 );
        light->setPosition( osg::Vec4 ( lightPos.x(), lightPos.y(), lightPos.z(), 1.0 ) );
        light->setDirection( lightDir );

        int windowWidth = 2048;
        int windowHeight = 2048;
        osg::Texture* textureDepthView = createRenderTexture(windowWidth, windowHeight, true);


      // 添加一个平面,表示地面
        {
                osg::Geode *geode = new osg::Geode;
                modelsGroup->addChild( geode );
                osg::ref_ptr<osg::Drawable> depthNode = createTexturedQuadDrawable( osg::Vec3 ( 0.0, 0.0, -10.0 )
                        , osg::Vec3 ( 60.0, 0.0, 0.0 )
                        , osg::Vec3( 0.0, 60.0, 0.0 )
                        , NULL );
                geode->addDrawable( depthNode );
        }

        osg::Camera::RenderTargetImplementation renderImplementation = osg::Camera::PIXEL_BUFFER_RTT;/*osg::Camera::FRAME_BUFFER_OBJECT*/;
        osg::ref_ptr<osg::Camera> shadowCamera = new osg::Camera;
        root->addChild( shadowCamera );

        // 在这里,需要设置相机的变换矩阵,从模型到光源空间的变换
      // 通过回调这种方式,得到相机的变换矩阵,并设置到uniform里面
        CameraProjectUpdate *cpu = new CameraProjectUpdate( shadowCamera, light, shadowRoot );
        {       
                shadowCamera->setEventCallback( cpu );
                shadowCamera->setViewport(new osg::Viewport(0,0,windowWidth,windowHeight));
                shadowCamera->setClearColor( osg::Vec4 ( 0.0, 0.0, 0.0, 0.0 ) );

               
                textureDepthView->setShadowComparison( true );
                textureDepthView->setShadowCompareFunc( osg::Texture::LEQUAL );
                shadowCamera->setClearDepth( 1.0 );

                shadowCamera->attach(osg::Camera::DEPTH_BUFFER, textureDepthView);



                shadowCamera->setRenderTargetImplementation(renderImplementation);
                // set view
                shadowCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);

                // set the camera to render before the main camera.
                shadowCamera->setRenderOrder(osg::Camera::PRE_RENDER);

                shadowCamera->addChild( shadowRoot );

        }
        // setup shadow shader to modelRoot
        {
                osg::Shader *vertShader = osgDB::readShaderFile( osg::Shader::VERTEX, "ShadowMappingPCF.vert");
                osg::Shader *fragShader = osgDB::readShaderFile( osg::Shader::FRAGMENT, "ShadowMappingPCF.frag" );
                if ( vertShader && fragShader )
                {
                        osg::Program *progam = new osg::Program;
                        progam->addShader( vertShader );
                        progam->addShader( fragShader );
                        modelRoot->getOrCreateStateSet()->setAttributeAndModes( progam );
                        modelRoot->getOrCreateStateSet()->setTextureAttributeAndModes( 2, textureDepthView );
                        modelRoot->getOrCreateStateSet()->addUniform( new osg::Uniform( "shadowMap", 2 ) );

                        osg::Matrix m;
                        osg::Uniform *viewMatrixUniform = new osg::Uniform("changeMatrix", m);
                        modelRoot->getOrCreateStateSet()->addUniform( viewMatrixUniform );
                        cpu->_maxtrixUniform = viewMatrixUniform;
                }
        }


      // 添加一个小球,表示灯光所有位置
        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
        root->addChild( geode );
        osg::ref_ptr<osg::Sphere> sphere = new osg::Sphere;
        sphere->setCenter( lightPos );
        sphere->setRadius( 2.0 );
        osg::ref_ptr<osg::ShapeDrawable> sd = new osg::ShapeDrawable;
        sd->setShape( sphere );
        sd->setColor( osg::Vec4 ( 1.0, 1.0, 1.0, 1.0 ) );
        geode->addDrawable( sd );


        v.setLight( light );
        v.setSceneData( root );


        return v.run();


        return 0;
}

其中用到了两个Shader,如下:
ShadowMappingPCF.vertuniform mat4 changeMatrix;

varying vec4 projCoord;

void main()
{
vec4 texcoord = changeMatrix * gl_ModelViewMatrix * gl_Vertex;
texcoord = texcoord / texcoord.w;
projCoord = 0.5 * projCoord + 0.5;
gl_FrontColor = gl_Color;
gl_Position = ftransform();
}ShadowMappingPCF.fraguniform sampler2DShadow shadowMap;

varying vec4 projCoord;

void main ()
{

vec4 color = gl_Color;

vec3 shadowUV = projCoord.xyz / projCoord.q;
float mapScale = 1.0 / 512.0;

vec4 shadowColor = shadow2D(shadowMap, shadowUV);
shadowColor = clamp(shadowColor, 0.0, 1.0);

if(shadowUV.x >= 0.0 && shadowUV.y >= 0.0
      && shadowUV.x <= 1.0 && shadowUV.y <= 1.0 )
{
          gl_FragColor = color * shadowColor;
}
else
{
          gl_FragColor = color;
}
}

fosky 发表于 2011-12-11 21:10:08

Shader里面有一个错误,修改如下
ShadowMappingPCF.vertuniform mat4 changeMatrix;

varying vec4 projCoord;

void main()
{
vec4 texcoord = changeMatrix * gl_ModelViewMatrix * gl_Vertex;
texcoord = texcoord / texcoord.w;
projCoord = 0.5 * texcoord + 0.5;
gl_FrontColor = gl_Color;
gl_Position = ftransform();
}此时,还是不出阴影

luo9168 发表于 2011-12-22 14:03:59

楼主怎么保存深度图像的?

hustlab 发表于 2012-2-28 19:26:53

ding

aya_daxiang 发表于 2012-3-7 14:18:42

保存深度纹理应该是setInternalFormat(GL_DEPTH_COMPONENT);吧
页: [1]
查看完整版本: osg做阴影时,得不到深度图的问题