/* OpenSceneGraph example, osganimate. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include class ControlPoints : public osg::Referenced { public: ControlPoints(): bottom_left(-1.0,-1.0), bottom_right(1.0,-1.0), top_left(-1.0,1.0), top_right(1.0,1.0) {} void reset() { bottom_left.set(-1.0,-1.0); bottom_right.set(1.0,-1.0); top_left.set(-1.0,1.0); top_right.set(1.0,1.0); } ControlPoints& operator = (const ControlPoints& rhs) { if (&rhs==this) return *this; bottom_left = rhs.bottom_left; bottom_right = rhs.bottom_right; top_left = rhs.top_left; top_right = rhs.top_right; return *this; } osg::Vec2d bottom_left; osg::Vec2d bottom_right; osg::Vec2d top_left; osg::Vec2d top_right; }; class Keystone : public osg::Referenced { public: Keystone(): translate(0.0,0.0), scale(1.0,1.0), taper(1.0,1.0), angle(0.0) { } double angleBetweenVectors(const osg::Vec2d& v1, const osg::Vec2d& v2) const { osg::Vec2d v3(-v2.y(), v2.x()); double p1 = v1*v2; double p2 = v1*v3; double a = atan2(p2, p1); return a; } osg::Vec2d rotateVector(osg::Vec2d& v, double s, double c) const { return osg::Vec2d(v.x()*c-v.y()*s, v.y()*c+v.x()*s); } void updateKeystone(ControlPoints cp) { // compute translation translate = (cp.bottom_left+cp.bottom_right+cp.top_left+cp.top_right)*0.25; // adjust control points to fit translation cp.top_left -= translate; cp.top_right -= translate; cp.bottom_right -= translate; cp.bottom_left -= translate; angle = (angleBetweenVectors(cp.top_left, osg::Vec2d(-1.0,1.0)) + angleBetweenVectors(cp.top_right, osg::Vec2d(1.0,1.0)) + angleBetweenVectors(cp.bottom_right, osg::Vec2d(1.0,-1.0)) + angleBetweenVectors(cp.bottom_left, osg::Vec2d(-1.0,-1.0)))*0.25; OSG_NOTICE<<"cp.top_left="<getScreenResolution(si, width, height); osg::ref_ptr traits = new osg::GraphicsContext::Traits; traits->hostName = si.hostName; traits->displayNum = si.displayNum; traits->screenNum = si.screenNum; traits->x = 0; traits->y = 0; traits->width = width; traits->height = height; traits->windowDecoration = false; traits->doubleBuffer = true; traits->sharedContext = 0; osg::ref_ptr gc = osg::GraphicsContext::createGraphicsContext(traits.get()); if (!gc) { OSG_NOTICE<<"GraphicsWindow has not been created successfully."<setTextureSize(tex_width, tex_height); texture->setInternalFormat(GL_RGB); texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR); texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR); texture->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE); texture->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE); #if 0 osg::Camera::RenderTargetImplementation renderTargetImplementation = osg::Camera::SEPERATE_WINDOW; GLenum buffer = GL_FRONT; #else osg::Camera::RenderTargetImplementation renderTargetImplementation = osg::Camera::FRAME_BUFFER_OBJECT; GLenum buffer = GL_FRONT; #endif // front face { osg::ref_ptr camera = new osg::Camera; camera->setName("Render to texture camera"); camera->setGraphicsContext(gc.get()); camera->setViewport(new osg::Viewport(0,0,camera_width, camera_height)); camera->setDrawBuffer(buffer); camera->setReadBuffer(buffer); camera->setAllowEventFocus(false); // tell the camera to use OpenGL frame buffer object where supported. camera->setRenderTargetImplementation(renderTargetImplementation); // attach the texture and use it as the color buffer. camera->attach(osg::Camera::COLOR_BUFFER, texture); view->addSlave(camera.get(), osg::Matrixd(), osg::Matrixd()); } // distortion correction set up. { double screenDistance = osg::DisplaySettings::instance()->getScreenDistance(); double screenWidth = osg::DisplaySettings::instance()->getScreenWidth(); double screenHeight = osg::DisplaySettings::instance()->getScreenHeight(); double fovy = osg::RadiansToDegrees(2.0*atan2(screenHeight/2.0,screenDistance)); double aspectRatio = screenWidth/screenHeight; osg::Geode* geode = new osg::Geode(); geode->addDrawable(createKeystoneDistortionMesh(keystone)); // new we need to add the texture to the mesh, we do so by creating a // StateSet to contain the Texture StateAttribute. osg::StateSet* stateset = geode->getOrCreateStateSet(); stateset->setTextureAttributeAndModes(0, texture,osg::StateAttribute::ON); stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF); osg::TexMat* texmat = new osg::TexMat; texmat->setScaleByTextureRectangleSize(true); stateset->setTextureAttributeAndModes(0, texmat, osg::StateAttribute::ON); osg::ref_ptr camera = new osg::Camera; camera->setGraphicsContext(gc.get()); camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT ); camera->setClearColor( osg::Vec4(0.0,0.0,0.0,1.0) ); camera->setViewport(new osg::Viewport(0, 0, width, height)); GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT; camera->setDrawBuffer(buffer); camera->setReadBuffer(buffer); camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); camera->setAllowEventFocus(false); camera->setInheritanceMask(camera->getInheritanceMask() & ~osg::CullSettings::CLEAR_COLOR & ~osg::CullSettings::COMPUTE_NEAR_FAR_MODE); //camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR); camera->setViewMatrix(osg::Matrix::identity()); camera->setProjectionMatrixAsPerspective(fovy, aspectRatio, 0.1, 1000.0); // add subgraph to render camera->addChild(geode); camera->setName("DistortionCorrectionCamera"); view->addSlave(camera.get(), osg::Matrixd(), osg::Matrixd(), false); } } int main( int argc, char **argv ) { osg::ArgumentParser arguments(&argc,argv); // initialize the viewer. osgViewer::Viewer viewer(arguments); osg::ref_ptr keystone = new Keystone; double distance, width, view_angle; if (arguments.read("-p",distance, width, view_angle)) { keystone->taper.x() = (2.0 + (width/distance) * sin(osg::inDegrees(view_angle))) / (2.0 - (width/distance) * sin(osg::inDegrees(view_angle))); //scale.x() = 1.0/cos(osg::inDegrees(view_angle)); OSG_NOTICE<<"scale "<scale<taper<angle)) { OSG_NOTICE<<"angle = "<angle<angle = osg::inDegrees(keystone->angle); } if (arguments.read("-t",keystone->translate.x(), keystone->translate.y())) { OSG_NOTICE<<"translate = "<translate<scale.x(), keystone->scale.y())) { OSG_NOTICE<<"scale = "<scale<taper.x(), keystone->taper.y())) { OSG_NOTICE<<"taper = "<taper< model = osgDB::readNodeFiles(arguments); if (!model) { OSG_NOTICE<<"No models loaded, please specify a model file on the command line"< group = new osg::Group; group->addChild(model.get()); double screenWidth = osg::DisplaySettings::instance()->getScreenWidth(); double screenHeight = osg::DisplaySettings::instance()->getScreenHeight(); double screenDistance = osg::DisplaySettings::instance()->getScreenDistance(); double fovy = osg::RadiansToDegrees(2.0*atan2(screenHeight/2.0,screenDistance)); double aspectRatio = screenWidth/screenHeight; osg::ref_ptr camera = new osg::Camera; camera->setClearMask(0x0); camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); camera->setRenderOrder(osg::Camera::NESTED_RENDER); camera->setProjectionMatrixAsPerspective(fovy, aspectRatio, 0.1, 1000.0); camera->addChild(createGrid(osg::Vec3(-screenWidth*0.5, -screenHeight*0.5, -screenDistance), osg::Vec3(screenWidth, 0.0, 0.0), osg::Vec3(0.0, screenHeight, 0.0), osg::Vec4(1.0,0.0,0.0,1.0))); viewer.setSceneData(group.get()); // add the state manipulator viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) ); // add the stats handler viewer.addEventHandler(new osgViewer::StatsHandler); // add camera manipulator viewer.setCameraManipulator(new osgGA::TrackballManipulator()); if (!oldStyleKeystone) { setUpViewForKeystone(&viewer, keystone); } viewer.realize(); viewer.getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); osg::Matrixd original_pm = viewer.getCamera()->getProjectionMatrix(); osg::Matrixd original_grid_pm = camera->getProjectionMatrix(); group->addChild(camera.get()); // Add keystone handler viewer.addEventHandler(new KeystoneHandler(keystone)); while(!viewer.done()) { viewer.advance(); viewer.eventTraversal(); viewer.updateTraversal(); if (oldStyleKeystone && keystone.valid()) { viewer.getCamera()->setProjectionMatrix(original_pm * keystone->computeKeystoneMatrix()); camera->setProjectionMatrix(original_grid_pm * keystone->computeKeystoneMatrix()); } viewer.renderingTraversals(); } return 0; }