Hi all May some one can suppport me in working out the artefacts in this implementation (GLSL)
/regards adrian -- ******************************************** Adrian Egli
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commericial and non commericial applications, * as long as this copyright notice is maintained. * * This application is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #include <osgDB/ReadFile> #include <osgUtil/Optimizer> #include <osg/CoordinateSystemNode> #include <osg/Switch> #include <osg/Uniform> #include <osgText/Text> #include <osg/ShapeDrawable> #include <osg/Geometry> #include <osgViewer/Viewer> #include <osgViewer/ViewerEventHandlers> #include <osg/BlendFunc> #include <osgGA/TrackballManipulator> #include <osgGA/FlightManipulator> #include <osgGA/DriveManipulator> #include <osgGA/KeySwitchMatrixManipulator> #include <osgGA/StateSetManipulator> #include <osgGA/AnimationPathManipulator> #include <osgGA/TerrainManipulator> #include <iostream> #include <osgFX/Effect> #include <osgFX/Technique> #include <osgFX/Registry> #include <osg/TexGen> #include <osg/Texture2D> #include <osg/PolygonOffset> #include <osgDB/WriteFile> bool global_debug_on = false; struct WriteCameraPostDrawCallback : public osg::Camera::DrawCallback { WriteCameraPostDrawCallback(osg::Image* image,std::string filename, bool write): _image(image), _filename(filename) { char* write_file = getenv("DEBUG"); global_debug_on = (write_file!=NULL) || write; } virtual void operator () (const osg::Camera& /*camera*/) const { _image->dirty(); if ( global_debug_on ) { std::cout << "write " << _filename << std::endl; osgDB::writeImageFile(*(_image.get()),_filename); } } osg::ref_ptr<osg::Image> _image; std::string _filename; }; namespace osgFX { class SSAO : public Effect { public: SSAO() {}; SSAO(osg::Group*); SSAO(const SSAO& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); META_Effect(osgFX, SSAO, "Screen Space Ambient Occlusion", "SSAO : test implementation", "Adrian Egli"); protected: virtual ~SSAO() {} SSAO& operator=(const SSAO&) { return *this; } bool define_techniques(); osg::ref_ptr<osg::Group> _root; }; } using namespace osgFX; namespace { osg::Node* createBase(osg::Texture2D* texture ,osg::Texture2D* texture2=NULL ) { osg::ref_ptr<osg::Geode> geode = new osg::Geode; // set up the texture of the base. osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet(); stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON); if (texture2)stateset->setTextureAttributeAndModes(1,texture2,osg::StateAttribute::ON); geode->setStateSet( stateset.get() ); osg::ref_ptr<osg::HeightField> grid = new osg::HeightField; grid->allocate(2,2); grid->setOrigin(osg::Vec3(0.0,0.0,0.0)); grid->setXInterval(1.0); grid->setYInterval(1.0); grid->setHeight(0,0,-1.0); grid->setHeight(0,1,-1.0); grid->setHeight(1,1,-1.0); grid->setHeight(1,0,-1.0); geode->addDrawable(new osg::ShapeDrawable(grid.get())); osg::Group* group = new osg::Group; group->addChild(geode.get()); return group; } Registry::Proxy proxy(new SSAO); class DefaultTechnique: public Technique { public: DefaultTechnique(osg::Group* scene,osg::Group* ssaoFX) : Technique(), _scene(scene) { ////////////////////////////////////////////////////////////////////////// depth // texture resolution _RTTInfoTangentDepth._resolution_x = 512; _RTTInfoTangentDepth._resolution_y = 512; // texture _RTTInfoTangentDepth._texture = new osg::Texture2D; _RTTInfoTangentDepth._texture->setTextureSize(_RTTInfoTangentDepth._resolution_x, _RTTInfoTangentDepth._resolution_y); _RTTInfoTangentDepth._texture->setInternalFormat(GL_RGBA); _RTTInfoTangentDepth._texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST); _RTTInfoTangentDepth._texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST); // camera _RTTInfoTangentDepth._camera = new osg::Camera; _RTTInfoTangentDepth._camera->setClearColor(osg::Vec4(0.0f,0.0f,0.0f,1.0f)); _RTTInfoTangentDepth._camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); _RTTInfoTangentDepth._camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); // set viewport _RTTInfoTangentDepth._camera->setViewport(0,0,_RTTInfoTangentDepth._resolution_x,_RTTInfoTangentDepth._resolution_y); // set the camera to render before the main camera. _RTTInfoTangentDepth._camera->setRenderOrder(osg::Camera::PRE_RENDER); // tell the camera to use OpenGL frame buffer object where supported. _RTTInfoTangentDepth._camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); // image (SSAO filter) _RTTInfoTangentDepth._image=new osg::Image; _RTTInfoTangentDepth._image->allocateImage(_RTTInfoTangentDepth._resolution_x, _RTTInfoTangentDepth._resolution_y, 1, GL_RGBA, GL_UNSIGNED_BYTE); _RTTInfoTangentDepth._camera->attach(osg::Camera::COLOR_BUFFER, _RTTInfoTangentDepth._image.get(),0,0); _RTTInfoTangentDepth._camera->setPostDrawCallback(new WriteCameraPostDrawCallback(_RTTInfoTangentDepth._image.get(),"RTTInfoDepth.png",false)); _RTTInfoTangentDepth._texture->setImage(0,_RTTInfoTangentDepth._image.get()); // add subgraph to render _RTTInfoTangentDepth._camera->addChild(_scene.get()); ////////////////////////////////////////////////////////////////////////// SSAO difference // texture resolution _RTTInfoSSAO._resolution_x = 512; _RTTInfoSSAO._resolution_y = 512; // texture _RTTInfoSSAO._texture = new osg::Texture2D; _RTTInfoSSAO._texture->setTextureSize(_RTTInfoSSAO._resolution_x, _RTTInfoSSAO._resolution_y); _RTTInfoSSAO._texture->setInternalFormat(GL_RGB); _RTTInfoSSAO._texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST); _RTTInfoSSAO._texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST); // camera _RTTInfoSSAO._camera = new osg::Camera; _RTTInfoSSAO._camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); _RTTInfoSSAO._camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); _RTTInfoSSAO._camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); // set viewport _RTTInfoSSAO._camera->setViewport(0,0,_RTTInfoSSAO._resolution_x,_RTTInfoSSAO._resolution_y); _RTTInfoSSAO._camera->setViewMatrixAsLookAt(osg::Vec3(0.5,0.5,1),osg::Vec3(0.5,0.5,0),osg::Vec3(0,1,0)); _RTTInfoSSAO._camera->setProjectionMatrixAsOrtho2D(-0.5,0.5,-0.5,0.5); // set the camera to render before the main camera. _RTTInfoSSAO._camera->setRenderOrder(osg::Camera::PRE_RENDER); // tell the camera to use OpenGL frame buffer object where supported. _RTTInfoSSAO._camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); // image (SSAO filter) _RTTInfoSSAO._image=new osg::Image; _RTTInfoSSAO._image->allocateImage(_RTTInfoSSAO._resolution_x, _RTTInfoSSAO._resolution_y, 1, GL_RGB, GL_UNSIGNED_BYTE); _RTTInfoSSAO._camera->attach(osg::Camera::COLOR_BUFFER, _RTTInfoSSAO._image.get(),0,0); _RTTInfoSSAO._camera->setPostDrawCallback(new WriteCameraPostDrawCallback(_RTTInfoSSAO._image.get(),"RTTInfoSSAO.png",false)); _RTTInfoSSAO._texture->setImage(0,_RTTInfoSSAO._image.get()); // add subgraph to render _RTTInfoSSAO._camera->addChild(createBase(_RTTInfoTangentDepth._texture.get())); ////////////////////////////////////////////////////////////////////////// Gaussian Vertical // texture resolution _RTTInfoGaussianV._resolution_x = 512; _RTTInfoGaussianV._resolution_y = 512; // texture _RTTInfoGaussianV._texture = new osg::Texture2D; _RTTInfoGaussianV._texture->setTextureSize(_RTTInfoGaussianV._resolution_x, _RTTInfoGaussianV._resolution_y); _RTTInfoGaussianV._texture->setInternalFormat(GL_RGB); _RTTInfoGaussianV._texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST); _RTTInfoGaussianV._texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST); // camera _RTTInfoGaussianV._camera = new osg::Camera; _RTTInfoGaussianV._camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); _RTTInfoGaussianV._camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); _RTTInfoGaussianV._camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); // set viewport _RTTInfoGaussianV._camera->setViewport(0,0,_RTTInfoGaussianV._resolution_x,_RTTInfoGaussianV._resolution_y); _RTTInfoGaussianV._camera->setViewMatrixAsLookAt(osg::Vec3(0.5,0.5,1.0),osg::Vec3(0.5,0.5,0.0),osg::Vec3(0,1,0)); _RTTInfoGaussianV._camera->setProjectionMatrixAsOrtho2D(-0.5,0.5,-0.5,0.5); // set the camera to render before the main camera. _RTTInfoGaussianV._camera->setRenderOrder(osg::Camera::PRE_RENDER); // tell the camera to use OpenGL frame buffer object where supported. _RTTInfoGaussianV._camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); // image (SSAO filter) _RTTInfoGaussianV._image=new osg::Image; _RTTInfoGaussianV._image->allocateImage(_RTTInfoGaussianV._resolution_x, _RTTInfoGaussianV._resolution_y, 1, GL_RGB, GL_UNSIGNED_BYTE); _RTTInfoGaussianV._camera->attach(osg::Camera::COLOR_BUFFER, _RTTInfoGaussianV._image.get(),0,0); _RTTInfoGaussianV._camera->setPostDrawCallback(new WriteCameraPostDrawCallback(_RTTInfoGaussianV._image.get(),"RTTInfoGaussianV.png",false)); _RTTInfoGaussianV._texture->setImage(0,_RTTInfoGaussianV._image.get()); // add subgraph to render _RTTInfoGaussianV._camera->addChild(createBase(_RTTInfoSSAO._texture.get())); ////////////////////////////////////////////////////////////////////////// Gaussian Horizontal // texture resolution _RTTInfoGaussianH._resolution_x = 512; _RTTInfoGaussianH._resolution_y = 512; // texture _RTTInfoGaussianH._texture = new osg::Texture2D; _RTTInfoGaussianH._texture->setTextureSize(_RTTInfoGaussianH._resolution_x, _RTTInfoGaussianH._resolution_y); _RTTInfoGaussianH._texture->setInternalFormat(GL_RGB); _RTTInfoGaussianH._texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST); _RTTInfoGaussianH._texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST); // camera _RTTInfoGaussianH._camera = new osg::Camera; _RTTInfoGaussianH._camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); _RTTInfoGaussianH._camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); _RTTInfoGaussianH._camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); // set viewport _RTTInfoGaussianH._camera->setViewport(0,0,_RTTInfoGaussianH._resolution_x,_RTTInfoGaussianH._resolution_y); _RTTInfoGaussianH._camera->setViewMatrixAsLookAt(osg::Vec3(0.5,0.5,1),osg::Vec3(0.5,0.5,0),osg::Vec3(0,1,0)); _RTTInfoGaussianH._camera->setProjectionMatrixAsOrtho2D(-0.5,0.5,-0.5,0.5); // set the camera to render before the main camera. _RTTInfoGaussianH._camera->setRenderOrder(osg::Camera::PRE_RENDER); // tell the camera to use OpenGL frame buffer object where supported. _RTTInfoGaussianH._camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); // image (SSAO filter) _RTTInfoGaussianH._image=new osg::Image; _RTTInfoGaussianH._image->allocateImage(_RTTInfoGaussianH._resolution_x, _RTTInfoGaussianH._resolution_y, 1, GL_RGB, GL_UNSIGNED_BYTE); _RTTInfoGaussianH._camera->attach(osg::Camera::COLOR_BUFFER, _RTTInfoGaussianH._image.get(),0,0); _RTTInfoGaussianH._camera->setPostDrawCallback(new WriteCameraPostDrawCallback(_RTTInfoGaussianH._image.get(),"RTTInfoGaussianH.png",false)); _RTTInfoGaussianH._texture->setImage(0,_RTTInfoGaussianH._image.get()); // add subgraph to render _RTTInfoGaussianH._camera->addChild(createBase(_RTTInfoGaussianV._texture.get())); ////////////////////////////////////////////////////////////////////////// SSAO final pass osg::ref_ptr<osg::StateSet> ss = ssaoFX->getOrCreateStateSet(); { unsigned int textLoop(0); // fake texture for baseTexture, add a fake texture // we support by default at least one texture layer // without this fake texture we can not support // textured and not textured scene // TODO: at the moment the PSSM supports just one texture layer in the GLSL shader, multitexture are // not yet supported ! osg::ref_ptr<osg::Image> image = new osg::Image; // allocate the image data, noPixels x 1 x 1 with 4 rgba floats - equivalent to a Vec4! int noPixels = 1; image->allocateImage(noPixels,1,1,GL_RGBA,GL_FLOAT); image->setInternalTextureFormat(GL_RGBA); // fill in the image data. osg::Vec4* dataPtr = (osg::Vec4*)image->data(); osg::Vec4f color(1.0f,1.0f,1.0f,0.0f); *dataPtr = color; // make fake texture osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D; texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER); texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER); texture->setBorderColor(osg::Vec4(1.0,1.0,1.0,1.0)); texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); texture->setImage(image.get()); // add fake texture ss->setTextureAttribute(textLoop,texture.get(),osg::StateAttribute::ON); ss->setTextureMode(textLoop,GL_TEXTURE_1D,osg::StateAttribute::OFF); ss->setTextureMode(textLoop,GL_TEXTURE_2D,osg::StateAttribute::ON); ss->setTextureMode(textLoop,GL_TEXTURE_3D,osg::StateAttribute::OFF); } ss->setTextureAttributeAndModes(1,_RTTInfoGaussianV._texture.get(),osg::StateAttribute::ON); osg::ref_ptr<osg::Program> program = new osg::Program; ss->setAttribute(program.get()); osg::ref_ptr<osg::Uniform> samplerText = new osg::Uniform("samplerText",0); ss->addUniform(samplerText.get()); osg::ref_ptr<osg::Uniform> samplerRTScene = new osg::Uniform("samplerRTScene",1); ss->addUniform(samplerRTScene.get()); osg::ref_ptr<osg::Shader> fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, "uniform sampler2D samplerRTScene;"\ "uniform sampler2D samplerText;"\ "void main(void)"\ "{"\ " vec4 text = texture2D(samplerText,gl_TexCoord[0].st);"\ " vec4 ssao = texture2D(samplerRTScene, vec2(1.0/512.0*gl_FragCoord.x, 1.0/512.0*gl_FragCoord.y));"\ " gl_FragColor = (gl_Color*1.0+0.0*text*gl_Color) - ssao;"\ "}" ); program->addShader(fragment_shader.get()); } virtual void getRequiredExtensions(std::vector<std::string>& extensions) { } bool validate(osg::State& state) const { if (!Technique::validate(state)) return false; //osg::TextureCubeMap::Extensions *ext = osg::TextureCubeMap::getExtensions(state.getContextID(), true); //if (ext) { // return ext->isCubeMapSupported(); //} return true; } /** optional: return a node that overrides the child node on a specified pass */ inline virtual osg::Node* getOverrideChild(int passNum) { if ( passNum == 0 ) { //Depth return _RTTInfoTangentDepth._camera.get(); } if ( passNum == 1 ) { // SSAO return _RTTInfoSSAO._camera.get(); } if ( passNum == 2 ) { // Gaussian V return _RTTInfoGaussianV._camera.get(); } if ( passNum == 3) { // Gaussian H return _RTTInfoGaussianH._camera.get(); } return 0; } inline virtual void traverse(osg::NodeVisitor& nv, Effect* fx) { // special actions must be taken if the node visitor is actually a CullVisitor osgUtil::CullVisitor *cv = dynamic_cast<osgUtil::CullVisitor *>(&nv); if ( cv ) { osgUtil::RenderStage* orig_rs = cv->getRenderStage(); _RTTInfoTangentDepth._camera->setViewMatrix(cv->getRenderInfo().getView()->getCamera()->getViewMatrix()); _RTTInfoTangentDepth._camera->setProjectionMatrix(cv->getRenderInfo().getView()->getCamera()->getProjectionMatrix()); osg::ref_ptr<osg::Viewport> vp = cv->getRenderInfo().getView()->getCamera()->getViewport(); osg::ref_ptr<osg::Viewport> vpCam = _RTTInfoTangentDepth._camera->getViewport(); if ( vpCam->width()!=vp->width() || vpCam->height()!=vp->height() ) { _RTTInfoTangentDepth._camera->getViewport()->setViewport( 0, 0, std::min((unsigned int)vp->width(),_RTTInfoTangentDepth._resolution_x), std::min((unsigned int)vp->height(),_RTTInfoTangentDepth._resolution_y) ); } double f,a,zn,zf; cv->getRenderInfo().getView()->getCamera()->getProjectionMatrix().getPerspective(f,a,zn,zf); osg::Vec3 eye,center,up; cv->getRenderInfo().getView()->getCamera()->getViewMatrixAsLookAt(eye,center,up); if ( _cameraPos.valid() ) _cameraPos->set(eye); if ( _nearUniform.valid() ) { _nearUniform->set((float)zn); std::cout << "_nearUniform" << zn << std::endl; } if ( _farUniform.valid() ) { _farUniform->set((float)zf); std::cout << "_farUniform" << zf << std::endl; } if ( _inverseMVPWUniform.valid() ) { osg::Matrix matrix( cv->getRenderInfo().getView()->getCamera()->getViewMatrix() * cv->getRenderInfo().getView()->getCamera()->getProjectionMatrix()); matrix.postMult(cv->getRenderInfo().getView()->getCamera()->getViewport()->computeWindowMatrix()); osg::Matrix inverseMVPW; inverseMVPW.invert(matrix); _inverseMVPWUniform->set(inverseMVPW); osg::Vec3f nearA = osg::Vec3(-1.0f,-1.0f, 0.0f) * inverseMVPW; osg::Vec3f nearB = osg::Vec3( 1.0f,-1.0f, 0.0f) * inverseMVPW; osg::Vec3f nearC = osg::Vec3(-1.0f, 1.0f, 0.0f) * inverseMVPW; osg::Vec3f farA = osg::Vec3(-1.0f,-1.0f, 1.0f) * inverseMVPW; osg::Vec3f farB = osg::Vec3( 1.0f,-1.0f, 1.0f) * inverseMVPW; osg::Vec3f farC = osg::Vec3(-1.0f, 1.0f, 1.0f) * inverseMVPW; #if ( 0 ) osg::Vec3 vdir = center - eye;vdir.normalize(); std::cout << "*****************************************************************" << std::endl; std::cout << "view " << eye.x() << " , " << eye.y() << " , " << eye.z() << std::endl; std::cout << "vdir " << vdir.x() << " , " << vdir.y() << " , " << vdir.z() << std::endl; std::cout << "up " << up.x() << " , " << up.y() << " , " << up.z() << std::endl; std::cout << "nearA " << nearA.x() << " , " << nearA.y() << " , " << nearA.z() << std::endl; std::cout << "nearB " << nearB.x() << " , " << nearB.y() << " , " << nearB.z() << std::endl; std::cout << "nearC " << nearC.x() << " , " << nearC.y() << " , " << nearC.z() << std::endl; std::cout << "farA " << farA.x() << " , " << farA.y() << " , " << farA.z() << std::endl; std::cout << "farB " << farB.x() << " , " << farB.y() << " , " << farB.z() << std::endl; std::cout << "farC " << farC.x() << " , " << farC.y() << " , " << farC.z() << std::endl; #endif if ( _nearA.valid() ) _nearA->set(nearA); if ( _nearB.valid() ) _nearB->set(nearB); if ( _nearC.valid() ) _nearC->set(nearC); if ( _farA.valid() ) _farA->set(farA); if ( _farB.valid() ) _farB->set(farB); if ( _farC.valid() ) _farC->set(farC); } } traverse_implementation(nv, fx); } protected: void define_passes() { _cameraPos = new osg::Uniform("cameraPos",osg::Vec3f(0.0f,0.0f,0.0f)); _nearA = new osg::Uniform("nearA_Uniform",osg::Vec3f(0.0f,0.0f,0.0f)); _nearB = new osg::Uniform("nearB_Uniform",osg::Vec3f(0.0f,0.0f,0.0f)); _nearC = new osg::Uniform("nearC_Uniform",osg::Vec3f(0.0f,0.0f,0.0f)); _farA = new osg::Uniform("farA_Uniform",osg::Vec3f(0.0f,0.0f,0.0f)); _farB = new osg::Uniform("farB_Uniform",osg::Vec3f(0.0f,0.0f,0.0f)); _farC = new osg::Uniform("farC_Uniform",osg::Vec3f(0.0f,0.0f,0.0f)); _nearUniform = new osg::Uniform("nearUniform",FLT_MIN); _farUniform = new osg::Uniform("farUniform",FLT_MAX); osg::Matrixf mat;mat.identity(); _inverseMVPWUniform = new osg::Uniform("inverseMVPWUniform",mat); { // Tangent Depth Pass 1 osg::ref_ptr<osg::StateSet> ss = new osg::StateSet; osg::ref_ptr<osg::Program> program = new osg::Program; ss->setAttribute(program.get()); ss->addUniform(_nearUniform.get()); ss->addUniform(_farUniform.get()); ss->addUniform(_cameraPos.get()); osg::ref_ptr<osg::Shader> vertex_shader = new osg::Shader(osg::Shader::VERTEX, "varying vec3 vTangent;"\ "varying vec3 vVertex;"\ "uniform vec3 cameraPos;"\ "void main(void)"\ "{"\ " vec3 n = normalize(gl_NormalMatrix * gl_Normal);"\ " vec3 b = normalize(gl_NormalMatrix * vec3(1.0,1.0,0.0));"\ " vec3 c = normalize(cross(b,n));"\ " vTangent = normalize(cross(c,n));"\ " vVertex = cameraPos - vec3(gl_ModelViewMatrix * gl_Vertex);"\ " gl_Position = ftransform();"\ "}" ); program->addShader(vertex_shader.get()); osg::ref_ptr<osg::Shader> fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, "uniform float nearUniform;"\ "uniform float farUniform;"\ "varying vec3 vVertex;"\ "varying vec3 vTangent;"\ " "\ "void main() {"\ " float z = (gl_FragCoord.z/gl_FragCoord.w+1.0)/(farUniform);"\ " gl_FragColor = vec4(z*vec3(1.0,1.0,1.0)*1.0+0.0*normalize(vTangent),step(0.9,gl_FrontMaterial.diffuse.a));"\ "} " ); program->addShader(fragment_shader.get()); addPass(ss.get()); } { // SSAO 2 osg::ref_ptr<osg::StateSet> ss = new osg::StateSet; osg::ref_ptr<osg::Program> program = new osg::Program; ss->setAttribute(program.get()); osg::ref_ptr<osg::Uniform> samplerTangentDepth = new osg::Uniform("samplerTangentDepth",0); ss->addUniform(samplerTangentDepth.get()); ss->addUniform(_nearUniform.get()); ss->addUniform(_farUniform.get()); ss->addUniform(_nearA.get()); ss->addUniform(_nearB.get()); ss->addUniform(_nearC.get()); ss->addUniform(_farA.get()); ss->addUniform(_farB.get()); ss->addUniform(_farC.get()); ss->addUniform(_inverseMVPWUniform.get()); osg::ref_ptr<osg::Shader> vertex_shader = new osg::Shader(osg::Shader::VERTEX, "varying vec2 vTexCoord;"\ "uniform float farUniform;"\ "uniform float nearUniform;"\ "void main(void)"\ "{"\ " gl_Position = ftransform();"\ " vec2 Pos = gl_Vertex.xy;"\ " vTexCoord = Pos;"\ "}" ); program->addShader(vertex_shader.get()); osg::ref_ptr<osg::Shader> fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, "uniform sampler2D samplerTangentDepth;"\ "uniform mat4 inverseMVPWUniform;"\ "uniform float farUniform;"\ "uniform float nearUniform;"\ "uniform vec3 nearA_Uniform;"\ "uniform vec3 nearB_Uniform;"\ "uniform vec3 nearC_Uniform;"\ "uniform vec3 farA_Uniform;"\ "uniform vec3 farB_Uniform;"\ "uniform vec3 farC_Uniform;"\ "varying vec2 vTexCoord;"\ " "\ "float readDepth( in vec2 coord ) {"\ " vec4 depth = texture2D(samplerTangentDepth,coord);"\ " return length(depth.rgb);" "}"\ " "\ "vec3 unProject( in vec2 coord, in float depth) {"\ " vec3 diffNx = (nearB_Uniform - nearA_Uniform);"\ " vec3 diffNy = (nearC_Uniform - nearA_Uniform);"\ " vec3 diffFx = (farB_Uniform - farA_Uniform);"\ " vec3 diffFy = (farC_Uniform - farA_Uniform);"\ " vec3 n = nearA_Uniform + diffNx*coord.x + diffNy*coord.y;"\ " vec3 f = farA_Uniform + diffFx*coord.x + diffFy*coord.y;"\ " vec3 diffNF = (f-n);"\ " return (n + diffNF*depth);"\ "}"\ " "\ "vec3 readTanget( in vec2 coord ) {"\ " float tangentDepth1 = readDepth(coord+vec2(-1,-1)/512.0);"\ " float tangentDepth2 = readDepth(coord+vec2(-1, 1)/512.0);"\ " float tangentDepth3 = readDepth(coord+vec2( 1, 1)/512.0);"\ " float tangentDepth4 = readDepth(coord+vec2( 1,-1)/512.0);"\ " vec3 a = unProject(coord+vec2(-1,-1)/512.0,tangentDepth1);"\ " vec3 b = unProject(coord+vec2(-1, 1)/512.0,tangentDepth2);"\ " vec3 c = unProject(coord+vec2( 1, 1)/512.0,tangentDepth3);"\ " vec3 d = unProject(coord+vec2( 1,-1)/512.0,tangentDepth4);"\ " vec3 e = abs(a-0.5*c);"\ " vec3 f = abs(b-0.5*d);"\ " return 0.5*(e+f);"\ "}"\ " "\ "void main(void)"\ "{"\ " float depth0 = readDepth(vTexCoord.xy);"\ " vec3 tangent0 = readTanget(vTexCoord.xy);"\ " vec3 objectCoord0 = unProject(vTexCoord.xy,depth0);"\ " float runRmin = 2.0;"\ " float runRmax = 8.0;"\ " float runRfactor = 1.5;"\ " float runPhiStep = 30.0;"\ " float sampleCount = 0.0;"\ " float aoH = 0.0;"\ " for (float fPhi=0; fPhi < 360.0+runPhiStep; fPhi+=runPhiStep)"\ " {"\ " float sampleCountR = 0.0;"\ " float maxAOH=0.0;"\ " for (float fRadius=runRmin; fRadius < runRmax; fRadius*=runRfactor)"\ " {"\ " sampleCountR = sampleCountR + 1.0;"\ " float iX = fRadius * sin ( 0.0175 * fPhi)/512.0;"\ " float iY = fRadius * cos ( 0.0175 * fPhi)/512.0;"\ " vec2 offsetXY = vec2(iX,iY);"\ " float depth = readDepth(offsetXY+vTexCoord.xy);"\ " vec3 tangent = readTanget(offsetXY+vTexCoord.xy);"\ " vec3 objectCoord = unProject(offsetXY+vTexCoord.xy,depth);"\ " vec3 objectCoordDiff = normalize(objectCoord-objectCoord0);"\ " float angleDiff = (objectCoordDiff.z)/(length(objectCoordDiff.xy)+1/1024.0);"\ " float aoHDiff = angleDiff * step(abs(depth0-depth),0.05) * step(0.2693,angleDiff);"\ " float updateMaxAOH = step(maxAOH,aoHDiff);"\ " maxAOH = maxAOH + updateMaxAOH * aoHDiff + (1.0-updateMaxAOH)*(maxAOH*(1.0-(fRadius/runRmax)));"\ " }"\ " sampleCount = sampleCount + 0.0+1.0*sampleCountR;"\ " aoH = aoH + sin( atan( maxAOH ));"\ " }"\ " aoH = clamp(aoH/sampleCount,0.0,1.0);"\ " float aoTangle = atan( tangent0.z/length(tangent0.xy) );"\ " float aoT = sin( aoTangle );"\ " float ao = aoH + 0.0*aoT;"\ " float notValid = 0.0*(1.0-step(0.0,depth0));"\ " float notValid_T = 0.0*(step(1.5708,abs(aoTangle)));"\ " ao = (1.0-notValid) *ao;"\ " ao = (1.0-notValid_T)*ao;"\ " gl_FragColor.rgb = tangent0*0.0+1.0*clamp(vec3(ao,ao,ao),0.0,1.0);"\ " gl_FragColor.a = 1.0;"\ "}" ); program->addShader(fragment_shader.get()); addPass(ss.get()); } { // Gaussian V 3 osg::ref_ptr<osg::StateSet> ss = new osg::StateSet; osg::ref_ptr<osg::Program> program = new osg::Program; ss->setAttribute(program.get()); osg::ref_ptr<osg::Uniform> samplerRTScene = new osg::Uniform("samplerRTScene",0); ss->addUniform(samplerRTScene.get()); osg::ref_ptr<osg::Shader> vertex_shader = new osg::Shader(osg::Shader::VERTEX, "varying vec2 vTexCoord;"\ "void main(void)"\ "{"\ " gl_Position = ftransform();"\ " vec2 Pos = gl_Vertex.xy;"\ " vTexCoord = Pos;"\ "}" ); program->addShader(vertex_shader.get()); osg::ref_ptr<osg::Shader> fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, "uniform sampler2D samplerRTScene;"\ "varying vec2 vTexCoord;"\ "const float blurSize = 1.0/256.0; "\ "void main(void)"\ "{"\ " vec4 sum = vec4(0.0);"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x - 6.0*blurSize, vTexCoord.y)) * 1.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x - 5.0*blurSize, vTexCoord.y)) * 2.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x - 4.0*blurSize, vTexCoord.y)) * 4.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x - 3.0*blurSize, vTexCoord.y)) * 8.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x - 2.0*blurSize, vTexCoord.y)) * 16.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x - blurSize , vTexCoord.y)) * 32.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x , vTexCoord.y)) * 64.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x + blurSize , vTexCoord.y)) * 32.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x + 2.0*blurSize, vTexCoord.y)) * 16.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x + 3.0*blurSize, vTexCoord.y)) * 8.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x + 4.0*blurSize, vTexCoord.y)) * 4.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x + 5.0*blurSize, vTexCoord.y)) * 2.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x + 6.0*blurSize, vTexCoord.y)) * 1.0/190.0;"\ " gl_FragColor = sum;"\ "}" ); program->addShader(fragment_shader.get()); addPass(ss.get()); } { // Gaussian H 4 osg::ref_ptr<osg::StateSet> ss = new osg::StateSet; osg::ref_ptr<osg::Program> program = new osg::Program; ss->setAttribute(program.get()); osg::ref_ptr<osg::Uniform> samplerRTScene = new osg::Uniform("samplerRTScene",0); ss->addUniform(samplerRTScene.get()); osg::ref_ptr<osg::Shader> vertex_shader = new osg::Shader(osg::Shader::VERTEX, "varying vec2 vTexCoord;"\ "void main(void)"\ "{"\ " gl_Position = ftransform();"\ " vec2 Pos = gl_Vertex.xy;"\ " vTexCoord = Pos;"\ "}" ); program->addShader(vertex_shader.get()); osg::ref_ptr<osg::Shader> fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, "uniform sampler2D samplerRTScene;"\ "varying vec2 vTexCoord;"\ "const float blurSize = 1.0/256.0; "\ "void main(void)"\ "{"\ " vec4 sum = vec4(0.0);"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y - 6.0*blurSize)) * 1.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y - 5.0*blurSize)) * 2.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y - 4.0*blurSize)) * 4.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y - 3.0*blurSize)) * 8.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y - 2.0*blurSize)) * 16.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y - blurSize )) * 32.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y )) * 64.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y + blurSize )) * 32.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y + 2.0*blurSize)) * 16.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y + 3.0*blurSize)) * 8.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y + 4.0*blurSize)) * 4.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y + 5.0*blurSize)) * 2.0/190.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y + 6.0*blurSize)) * 1.0/190.0;"\ " gl_FragColor = sum;"\ "}" ); program->addShader(fragment_shader.get()); addPass(ss.get()); } { // Final Pass osg::ref_ptr<osg::StateSet> ss = new osg::StateSet; addPass(ss.get()); } } private: struct RTTInfo { // RTT osg::ref_ptr<osg::Camera> _camera; osg::ref_ptr<osg::TexGen> _texgen; osg::ref_ptr<osg::Texture2D> _texture; osg::ref_ptr<osg::StateSet> _stateset; osg::ref_ptr<osg::Image> _image; unsigned int _resolution_x; unsigned int _resolution_y; }; RTTInfo _RTTInfoTangentDepth; RTTInfo _RTTInfoSSAO; RTTInfo _RTTInfoGaussianH; RTTInfo _RTTInfoGaussianV; osg::ref_ptr<osg::Group> _scene; osg::ref_ptr<osg::Uniform> _nearUniform; osg::ref_ptr<osg::Uniform> _farUniform; osg::ref_ptr<osg::Uniform> _cameraPos; osg::ref_ptr<osg::Uniform> _nearA; osg::ref_ptr<osg::Uniform> _nearB; osg::ref_ptr<osg::Uniform> _nearC; osg::ref_ptr<osg::Uniform> _farA; osg::ref_ptr<osg::Uniform> _farB; osg::ref_ptr<osg::Uniform> _farC; osg::ref_ptr<osg::Uniform> _inverseMVPWUniform; }; } SSAO::SSAO(osg::Group* rootGrp) : Effect(),_root(rootGrp) { } SSAO::SSAO(const SSAO& copy, const osg::CopyOp& copyop) : Effect(copy, copyop){ } bool SSAO::define_techniques() { addTechnique(new DefaultTechnique(_root.get(),this)); return true; } class SSAOViewerEventHandler : public osgGA::GUIEventHandler { public: SSAOViewerEventHandler(osg::Switch* s) : _switch(s) { } virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa, osg::Object*, osg::NodeVisitor*) { osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa); if (!viewer) return false; if (ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN) { switch (ea.getKey()) { case 'a': if ( _switch->getValue(0) ) { _switch->setAllChildrenOff(); _switch->setValue(1,true); } else { _switch->setAllChildrenOff(); _switch->setValue(0,true); } return true; case 'q': global_debug_on = !global_debug_on; std::cout << ">> write debug images:" << global_debug_on << std::endl; return true; } } return false; } osg::ref_ptr<osg::Switch> _switch; }; int main(int argc, char** argv) { putenv("OSG_WINDOW=128 128 512 512"); // use an ArgumentParser object to manage the program arguments. osg::ArgumentParser arguments(&argc,argv); arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName()); arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the standard OpenSceneGraph example which loads and visualises 3d models."); arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ..."); arguments.getApplicationUsage()->addCommandLineOption("--image <filename>","Load an image and render it on a quad"); arguments.getApplicationUsage()->addCommandLineOption("--dem <filename>","Load an image/DEM and render it on a HeightField"); arguments.getApplicationUsage()->addCommandLineOption("--login <url> <username> <password>","Provide authentication information for http file access."); osgViewer::Viewer viewer(arguments); unsigned int helpType = 0; if ((helpType = arguments.readHelpType())) { arguments.getApplicationUsage()->write(std::cout, helpType); return 1; } // report any errors if they have occurred when parsing the program arguments. if (arguments.errors()) { arguments.writeErrorMessages(std::cout); return 1; } if (arguments.argc()<=1) { arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION); return 1; } std::string url, username, password; while(arguments.read("--login",url, username, password)) { if (!osgDB::Registry::instance()->getAuthenticationMap()) { osgDB::Registry::instance()->setAuthenticationMap(new osgDB::AuthenticationMap); osgDB::Registry::instance()->getAuthenticationMap()->addAuthenticationDetails( url, new osgDB::AuthenticationDetails(username, password) ); } } // set up the camera manipulators. { osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator; keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() ); keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() ); keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() ); keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() ); std::string pathfile; char keyForAnimationPath = '5'; while (arguments.read("-p",pathfile)) { osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile); if (apm || !apm->valid()) { unsigned int num = keyswitchManipulator->getNumMatrixManipulators(); keyswitchManipulator->addMatrixManipulator( keyForAnimationPath, "Path", apm ); keyswitchManipulator->selectMatrixManipulator(num); ++keyForAnimationPath; } } viewer.setCameraManipulator( keyswitchManipulator.get() ); } // add the state manipulator viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) ); // add the thread model handler viewer.addEventHandler(new osgViewer::ThreadingHandler); // add the window size toggle handler viewer.addEventHandler(new osgViewer::WindowSizeHandler); // add the stats handler viewer.addEventHandler(new osgViewer::StatsHandler); // add the help handler viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage())); // add the record camera path handler viewer.addEventHandler(new osgViewer::RecordCameraPathHandler); // add the LOD Scale handler viewer.addEventHandler(new osgViewer::LODScaleHandler); // add the screen capture handler viewer.addEventHandler(new osgViewer::ScreenCaptureHandler); osg::ref_ptr<osg::Switch> switchNode = new osg::Switch; osg::ref_ptr<SSAOViewerEventHandler> ssaoViewerEventHandler= new SSAOViewerEventHandler(switchNode.get()); viewer.addEventHandler(ssaoViewerEventHandler.get()); // load the data osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments); if (!loadedModel) { std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl; loadedModel = osgDB::readNodeFile("cow.osg"); if (!loadedModel) return 1; } // any option left unread are converted into errors to write out later. arguments.reportRemainingOptionsAsUnrecognized(); // report any errors if they have occurred when parsing the program arguments. if (arguments.errors()) { arguments.writeErrorMessages(std::cout); return 1; } // optimize the scene graph, remove redundant nodes and state etc. osgUtil::Optimizer optimizer; optimizer.optimize(loadedModel.get()); // SWITCH switchNode->addChild(loadedModel.get(),false); // SSAO osg::ref_ptr<osg::Group> grpSSAOModel = new osg::Group; grpSSAOModel->addChild(loadedModel.get()); osg::ref_ptr<SSAO> ssao = new SSAO(grpSSAOModel.get()); ssao->addChild(grpSSAOModel.get()); osg::ref_ptr<osg::Group> grpSSAO = new osg::Group; grpSSAO->addChild(ssao.get()); switchNode->addChild(grpSSAO.get(),true); viewer.setSceneData( switchNode.get() ); viewer.realize(); return viewer.run(); }
_______________________________________________ osg-users mailing list osg-users@lists.openscenegraph.org http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org