Hi Robert, this is my first implementation test for a wazabee 3D Multiview (fullscreen) display. this implementation has the right interlacer implement as a GLSL shader. i am awar of the fact that the osgFX Effect / Technic wouldn't be the correct place to implement just display support, but it was the fastest way for prototyping of the interlacer. I don't longer need the spatial view interlacing SDK, even under Mac or Linux this should work.
/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/Uniform> #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/Texture2D> #include <osg/PolygonOffset> #include <osgDB/WriteFile> #include <sstream> namespace osgFX { class Wazabee : public Effect { public: Wazabee() {}; Wazabee(osg::Group*); Wazabee(const Wazabee& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); META_Effect(osgFX, Wazabee, "Wazabee : Spatial View Integration : 1440 x 900 (19'') Screen ", "Wazabee : This is just a first hack. ( :-( )", "Adrian Egli"); protected: virtual ~Wazabee() {} Wazabee& operator=(const Wazabee&) { return *this; } bool define_techniques(); osg::ref_ptr<osg::Group> _root; osg::ref_ptr<osg::Group> _baseRoot; }; } using namespace osgFX; namespace { osg::Group* createBase() { osg::ref_ptr<osg::Geode> geode = new osg::Geode; // set up the texture of the base. 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 Wazabee); class DefaultTechnique: public Technique { public: DefaultTechnique(osg::Group* scene,osg::Group* sceneFinal) : Technique(), _scene(scene), _sceneFinal(sceneFinal) { osg::ref_ptr<osg::StateSet> ss = sceneFinal->getOrCreateStateSet(); for (unsigned int iLoop=0;iLoop<5;iLoop++) { // texture resolution _RTTCameras[iLoop]._resolution_x = 1440; _RTTCameras[iLoop]._resolution_y = 900; // texture _RTTCameras[iLoop]._texture = new osg::Texture2D; _RTTCameras[iLoop]._texture->setTextureSize(_RTTCameras[iLoop]._resolution_x, _RTTCameras[iLoop]._resolution_y); _RTTCameras[iLoop]._texture->setInternalFormat(GL_RGBA); _RTTCameras[iLoop]._texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST); _RTTCameras[iLoop]._texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST); _RTTCameras[iLoop]._texture->setResizeNonPowerOfTwoHint(false); // camera _RTTCameras[iLoop]._camera = new osg::Camera; /* // debug interlacing with color coded texture osg::Vec4 cc; switch(iLoop) { case 0: cc.set(1,0,0,1); break; case 1: cc.set(0,1,0,1); break; case 2: cc.set(0,0,1,1); break; case 3: cc.set(1,1,0,1); break; case 4: cc.set(0,1,1,1); break; default: cc.set(0,0,0,1); break; } _RTTCameras[iLoop]._camera->setClearColor(cc); */ _RTTCameras[iLoop]._camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); _RTTCameras[iLoop]._camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); // set viewport _RTTCameras[iLoop]._camera->setViewport(0,0,_RTTCameras[iLoop]._resolution_x,_RTTCameras[iLoop]._resolution_y); // set the camera to render before the main camera. _RTTCameras[iLoop]._camera->setRenderOrder(osg::Camera::PRE_RENDER); // tell the camera to use OpenGL frame buffer object where supported. _RTTCameras[iLoop]._camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); _RTTCameras[iLoop]._camera->attach(osg::Camera::COLOR_BUFFER, _RTTCameras[iLoop]._texture.get()); // add subgraph to render _RTTCameras[iLoop]._camera->addChild(_scene.get()); } for (unsigned int iLoop=0;iLoop<5;iLoop++) { ////////////////////////////////////////////////////////////////////////// // set effect textures....(5 textures) ss->setTextureAttributeAndModes(iLoop,_RTTCameras[iLoop]._texture.get(),osg::StateAttribute::ON); std::stringstream sstrSamplerRTT; sstrSamplerRTT << "samplerRTT" << iLoop; osg::ref_ptr<osg::Uniform> samplerText = new osg::Uniform(osg::Uniform::SAMPLER_2D,sstrSamplerRTT.str().c_str()); samplerText->set((int)iLoop); ss->addUniform(samplerText.get()); } _inter_image=new osg::Image; _inter_image->allocateImage(1440, 900, 1, GL_RGBA, GL_FLOAT); // texture _inter_texture = new osg::Texture2D; _inter_texture->setImage(0,_inter_image.get()); _inter_texture->setTextureSize(1440, 900); _inter_texture->setInternalFormat(GL_RGBA); _inter_texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST); _inter_texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST); _inter_texture->setResizeNonPowerOfTwoHint(false); ss->setTextureAttributeAndModes(5,_inter_texture.get(),osg::StateAttribute::ON); osg::ref_ptr<osg::Uniform> samplerText = new osg::Uniform(osg::Uniform::SAMPLER_2D,"samplerSelectText"); samplerText->set(5); ss->addUniform(samplerText.get()); // fill in the image data. const int interSchemaS[5] = {1,4,2,0,3}; const int interSchemaT[5] = {4,3,2,1,0}; for (unsigned int t=0;t<900;t++){ for (unsigned int s=0;s<1440;s++){ int ms = s % 5; int mt = t % 5; double v = ((double)( (interSchemaS[ms]+interSchemaT[mt]) % 5) )/5.0; //if ( t < 5 && s < 5) std::cout << "(" << (v*5) << ")"; osg::Vec4 color(v,v,v,v); osg::Vec4* dataPtr = (osg::Vec4*)_inter_image->data(s,t); *dataPtr = color; } //if ( t < 5 ) std::cout << std::endl; } osg::ref_ptr<osg::Program> program = new osg::Program; ss->setAttribute(program.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 samplerRTT0;"\ "uniform sampler2D samplerRTT1;"\ "uniform sampler2D samplerRTT2;"\ "uniform sampler2D samplerRTT3;"\ "uniform sampler2D samplerRTT4;"\ "uniform sampler2D samplerSelectText;"\ "varying vec2 vTexCoord;"\ "void main(void)"\ "{"\ " float modS = step(mod(vTexCoord.s*512.0,5.0),0.0);"\ " float modT = step(mod(vTexCoord.t*512.0,5.0),0.0);"\ " vec4 cS = texture2D(samplerSelectText,vTexCoord.st);"\ " vec4 final = vec4(1,1,1,1);"\ " vec4 c0 = texture2D(samplerRTT0,vTexCoord.st);"\ " vec4 c1 = texture2D(samplerRTT1,vTexCoord.st);"\ " vec4 c2 = texture2D(samplerRTT2,vTexCoord.st);"\ " vec4 c3 = texture2D(samplerRTT3,vTexCoord.st);"\ " vec4 c4 = texture2D(samplerRTT4,vTexCoord.st);"\ " float sel = 0.0;"\ " float selTmp = 0.0;"\ " sel = step(cS.x,0.01);"\ " final = sel*c0;"\ " selTmp = clamp((1.0-sel)*step(cS.x,0.21),0.0,1.0);"\ " sel = clamp(sel+selTmp,0.0,1.0);"\ " final = final + selTmp*c1;"\ " selTmp = clamp((1.0-sel)*step(cS.x,0.41),0.0,1.0);"\ " sel = clamp(sel+selTmp,0.0,1.0);"\ " final = final + selTmp*c2;"\ " selTmp = clamp((1.0-sel)*step(cS.x,0.61),0.0,1.0);"\ " sel = clamp(sel+selTmp,0.0,1.0);"\ " final = final + selTmp*c3;"\ " selTmp = clamp((1.0-sel)*step(cS.x,0.81),0.0,1.0);"\ " sel = clamp(sel+selTmp,0.0,1.0);"\ " final = final + selTmp*c4;"\ " gl_FragColor = final;"\ "}" ); 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; return true; } /** optional: return a node that overrides the child node on a specified pass */ inline virtual osg::Node* getOverrideChild(int passNum) { if ( passNum < 5 ) { return _RTTCameras[passNum]._camera.get(); } return _sceneFinal.get(); } 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(); for (unsigned int iLoop=0;iLoop<5;iLoop++) { _RTTCameras[iLoop]._camera->setViewMatrix(cv->getRenderInfo().getView()->getCamera()->getViewMatrix()); _RTTCameras[iLoop]._camera->setProjectionMatrix(cv->getRenderInfo().getView()->getCamera()->getProjectionMatrix()); osg::ref_ptr<osg::Viewport> vp = cv->getRenderInfo().getView()->getCamera()->getViewport(); osg::ref_ptr<osg::Viewport> vpCam = _RTTCameras[iLoop]._camera->getViewport(); if ( vpCam->width()!=vp->width() || vpCam->height()!=vp->height() ) { _RTTCameras[iLoop]._camera->getViewport()->setViewport( 0, 0, std::min((unsigned int)vp->width(),_RTTCameras[iLoop]._resolution_x), std::min((unsigned int)vp->height(),_RTTCameras[iLoop]._resolution_y) ); } double fusionDistance = 1.0;//cv->getRenderInfo().getView()->getCameraManipulator()->getFusionDistanceValue(); double eyeSeparation = osg::DisplaySettings::instance()->getEyeSeparation();//cv->getRenderInfo().getView()->getDisplaySettings()->getEyeSeparation(); double screenDistance = osg::DisplaySettings::instance()->getScreenDistance();//cv->getRenderInfo().getView()->getDisplaySettings()->getScreenDistance(); std::cout << eyeSeparation << "," << screenDistance << std::endl; osg::Matrixd masterProjection = cv->getRenderInfo().getView()->getCamera()->getProjectionMatrix(); int cameraCount = 5; double es = (eyeSeparation/screenDistance); double start = 0.5 * (es * (cameraCount - 1)); osg::Matrix offsetP; offsetP.ptr()[8] = start - (es * iLoop); _RTTCameras[iLoop]._camera->setProjectionMatrix(offsetP * masterProjection); osg::Matrixd masterView = cv->getRenderInfo().getView()->getCamera()->getViewMatrix(); es = fusionDistance * (eyeSeparation/screenDistance); start = 0.5 * (es * (cameraCount - 1)); osg::Matrix offsetV; offsetV.ptr()[12] = start - (es * iLoop); _RTTCameras[iLoop]._camera->setViewMatrix(masterView * offsetV); } } traverse_implementation(nv, fx); } protected: void define_passes() { for (unsigned int iLoop=0;iLoop<5+1;iLoop++) { // 5 + 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::Texture2D> _texture; osg::ref_ptr<osg::StateSet> _stateset; osg::ref_ptr<osg::Image> _image; unsigned int _resolution_x; unsigned int _resolution_y; }; RTTInfo _RTTCameras[5]; osg::ref_ptr<osg::Group> _scene; osg::ref_ptr<osg::Group> _sceneFinal; osg::ref_ptr<osg::Texture2D> _inter_texture; osg::ref_ptr<osg::Image> _inter_image; }; } Wazabee::Wazabee(osg::Group* rootGrp) : Effect(),_root(rootGrp) { int resolution_x = 1440; int resolution_y = 900; // camera osg::ref_ptr<osg::Camera> camera = new osg::Camera; camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); // set viewport camera->setViewport(0,0,resolution_x,resolution_y); camera->setViewMatrixAsLookAt(osg::Vec3(0.5,0.5,1),osg::Vec3(0.5,0.5,0),osg::Vec3(0,1,0)); camera->setProjectionMatrixAsOrtho2D(-0.5,0.5,-0.5,0.5); osg::Group* base = createBase(); osg::PolygonMode* polyModeObj = new osg::PolygonMode; polyModeObj->setMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::FILL ); base->getOrCreateStateSet()->setAttribute(polyModeObj); _baseRoot = camera.get(); camera->addChild(base); } Wazabee::Wazabee(const Wazabee& copy, const osg::CopyOp& copyop) : Effect(copy, copyop){ } bool Wazabee::define_techniques() { addTechnique(new DefaultTechnique(_root.get(),_baseRoot)); return true; } 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); // 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()); // Wazabee osg::ref_ptr<osg::Group> grpWazabeeModel = new osg::Group; grpWazabeeModel->addChild(loadedModel.get()); osg::ref_ptr<Wazabee> wazabee = new Wazabee(grpWazabeeModel.get()); wazabee->addChild(loadedModel.get()); osg::ref_ptr<osg::Group> grpWazabee = new osg::Group; grpWazabee->addChild(wazabee.get()); viewer.setSceneData( grpWazabee.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