Hi Robert, i implement a first version of SSAO effect and i have only one issue left in the implementation. the whole thing works nicely with GLSL shader, mutlipass-rendering when we don't resize the window, actually 512x512. so what sould i do, to replace this issue. ?
Another thing is to remove the last pass GLSL shader, is there a way to solve it under common openGL textureing? Mutlitextureing? Or any other idea. This version supports: (Transparant faces: just disable for transparent faces like window, glass the detph writing, the depth buffer will hold only un-transparent z-values (alpha > 0.9) ) toggle ssao on/off with key 'a' have a look and i will be happy to get any ideas to improve the stuff. FPS is about 30. /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> struct WriteCameraPostDrawCallback : public osg::Camera::DrawCallback { WriteCameraPostDrawCallback(osg::Image* image,std::string filename, bool write): _image(image), _filename(filename), _write(write) { char* write_file = getenv("SSAO_WRITE_FILE"); if ( write_file ) _write = true; } virtual void operator () (const osg::Camera& /*camera*/) const { _image->dirty(); if ( _write ) { std::cout << "write " << _filename << std::endl; osgDB::writeImageFile(*(_image.get()),_filename); } } osg::ref_ptr<osg::Image> _image; std::string _filename; bool _write; }; 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) { // texture resolution _RTTInfoDepth._resolution_x = 512; _RTTInfoDepth._resolution_y = 512; // texture _RTTInfoDepth._texture = new osg::Texture2D; _RTTInfoDepth._texture->setTextureSize(_RTTInfoDepth._resolution_x, _RTTInfoDepth._resolution_y); _RTTInfoDepth._texture->setInternalFormat(GL_RGB); _RTTInfoDepth._texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST); _RTTInfoDepth._texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST); // camera _RTTInfoDepth._camera = new osg::Camera; _RTTInfoDepth._camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); _RTTInfoDepth._camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); _RTTInfoDepth._camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); // set viewport _RTTInfoDepth._camera->setViewport(0,0,_RTTInfoDepth._resolution_x,_RTTInfoDepth._resolution_y); // set the camera to render before the main camera. _RTTInfoDepth._camera->setRenderOrder(osg::Camera::PRE_RENDER); // tell the camera to use OpenGL frame buffer object where supported. _RTTInfoDepth._camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); // image (SSAO filter) _RTTInfoDepth._image=new osg::Image; _RTTInfoDepth._image->allocateImage(_RTTInfoDepth._resolution_x, _RTTInfoDepth._resolution_y, 1, GL_RGB, GL_UNSIGNED_BYTE); _RTTInfoDepth._camera->attach(osg::Camera::COLOR_BUFFER, _RTTInfoDepth._image.get(),0,0); _RTTInfoDepth._camera->setPostDrawCallback(new WriteCameraPostDrawCallback(_RTTInfoDepth._image.get(),"RTTInfoDepth.png",false)); _RTTInfoDepth._texture->setImage(0,_RTTInfoDepth._image.get()); // add subgraph to render _RTTInfoDepth._camera->addChild(_scene.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(_RTTInfoDepth._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 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(_RTTInfoDepth._texture.get() ,_RTTInfoGaussianH._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,_RTTInfoSSAO._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));"\ " float lenRGB = length(ssao.rgb);"\ " lenRGB = 0.25*lenRGB + 0.75*(1.0f-(1.0f-lenRGB)*(1.0f-lenRGB));"\ " gl_FragColor = text*gl_Color - vec4(lenRGB,lenRGB,lenRGB,1.0);"\ "}" ); 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 _RTTInfoDepth._camera.get(); } if ( passNum == 1 ) { // Gaussian V return _RTTInfoGaussianV._camera.get(); } if ( passNum == 2 ) { // Gaussian H return _RTTInfoGaussianH._camera.get(); } if ( passNum == 3 ) { // SSAO return _RTTInfoSSAO._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(); _RTTInfoDepth._camera->setViewMatrix(cv->getRenderInfo().getView()->getCamera()->getViewMatrix()); _RTTInfoDepth._camera->setProjectionMatrix(cv->getRenderInfo().getView()->getCamera()->getProjectionMatrix()); osg::ref_ptr<osg::Viewport> vp = cv->getRenderInfo().getView()->getCamera()->getViewport(); osg::ref_ptr<osg::Viewport> vpCam = _RTTInfoDepth._camera->getViewport(); if ( vpCam->width()!=vp->width() || vpCam->height()!=vp->height() ) { _RTTInfoDepth._camera->getViewport()->setViewport( 0, 0, std::min((unsigned int)vp->width(),_RTTInfoDepth._resolution_x), std::min((unsigned int)vp->height(),_RTTInfoDepth._resolution_y) ); } double f,a,zn,zf; cv->getRenderInfo().getView()->getCamera()->getProjectionMatrix().getPerspective(f,a,zn,zf); if ( nearUniform.valid() ) nearUniform->set((float)zn); if ( farUniform.valid() ) farUniform->set((float)zf); } traverse_implementation(nv, fx); } protected: void define_passes() { { // 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()); nearUniform = new osg::Uniform("nearUniform",FLT_MIN); farUniform = new osg::Uniform("farUniform",FLT_MAX); ss->addUniform(nearUniform.get()); ss->addUniform(farUniform.get()); osg::ref_ptr<osg::Shader> vertex_shader = new osg::Shader(osg::Shader::VERTEX, "varying float intensity;"\ "void main(void)"\ "{"\ " intensity = 0.5*(1.0+dot(vec3(0,0,1),gl_Normal));"\ " 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 float intensity;"\ "void main() {"\ " float c = 0.5+0.5*intensity;"\ " float z = (gl_FragCoord.z/gl_FragCoord.w) / ( farUniform);"\ " gl_FragColor = c*vec4(z,z,z,step(0.9,gl_FrontMaterial.diffuse.a));"\ "} " ); program->addShader(fragment_shader.get()); addPass(ss.get()); } { // Gaussian V 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> 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 - 4.0*blurSize, vTexCoord.y)) * 1.0/50.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x - 3.0*blurSize, vTexCoord.y)) * 2.0/50.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x - 2.0*blurSize, vTexCoord.y)) * 4.0/50.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x - blurSize , vTexCoord.y)) * 7.0/50.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x , vTexCoord.y)) * 22.0/50.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x + blurSize , vTexCoord.y)) * 7.0/50.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x + 2.0*blurSize, vTexCoord.y)) * 4.0/50.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x + 3.0*blurSize, vTexCoord.y)) * 2.0/50.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x + 4.0*blurSize, vTexCoord.y)) * 1.0/50.0;"\ " gl_FragColor = sum;"\ "}" ); program->addShader(fragment_shader.get()); addPass(ss.get()); } { // Gaussian H 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, vTexCoord.y - 4.0*blurSize)) * 1.0/50.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y - 3.0*blurSize)) * 2.0/50.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y - 2.0*blurSize)) * 4.0/50.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y - blurSize )) * 7.0/50.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y )) * 22.0/50.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y + blurSize )) * 7.0/50.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y + 2.0*blurSize)) * 4.0/50.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y + 3.0*blurSize)) * 2.0/50.0;"\ " sum += texture2D(samplerRTScene, vec2(vTexCoord.x, vTexCoord.y + 4.0*blurSize)) * 1.0/50.0;"\ " gl_FragColor = sum;"\ "}" ); program->addShader(fragment_shader.get()); addPass(ss.get()); } { // SSAO 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> samplerD = new osg::Uniform("samplerD",0); ss->addUniform(samplerD.get()); osg::ref_ptr<osg::Uniform> samplerH = new osg::Uniform("samplerH",1); ss->addUniform(samplerH.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 samplerD;"\ "uniform sampler2D samplerH;"\ "varying vec2 vTexCoord;"\ "void main(void)"\ "{"\ " vec4 sum = vec4(0.0,0.0,0.0,0.0);"\ " sum += texture2D(samplerD, vec2(vTexCoord.x, vTexCoord.y));"\ " sum -= texture2D(samplerH, vec2(vTexCoord.x, vTexCoord.y));"\ " gl_FragColor = clamp(sum,0.0,1.0);"\ "}" ); 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 _RTTInfoDepth; RTTInfo _RTTInfoSSAO; RTTInfo _RTTInfoGaussianH; RTTInfo _RTTInfoGaussianV; osg::ref_ptr<osg::Group> _scene; osg::ref_ptr<osg::Uniform> nearUniform; osg::ref_ptr<osg::Uniform> farUniform; }; } 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; } } 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