From 85fffc2e768c3bd8cacf6dd8da4990344276bad0 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 5 Jan 2009 16:53:29 +0000 Subject: [PATCH] From Roland Smeenk, "Attached you will find an improved Collada plugin to properly support camera's. A Collada camera will be added to the scenegraph as osg::CameraView. This allows the user to create a set of predefined camera viewpoints. I also added a new MatrixManipulator to osgGA called CameraViewSwitchManipulator and added usage of this to the osgviewer example. This manipulator allows switching between the predefined camera viewpoints. The current design limition I ran into is that a MatrixManipulator only manipulates the ViewMatrix, but for this particular manipulator I also want to update the projectionMatrix of the camera when switching to a new viewpoint. This is not implemented because I don't know what would be the best way to design it. Any ideas? Furthermore Collada also supports orthographic camera's, where an osg::CameraView only supports a perspective camera. Would it be useful to create a CameraView with customizable optics for this?" --- include/osgGA/CameraViewSwitchManipulator | 79 +++++++++++++++ src/osgGA/CMakeLists.txt | 2 + src/osgGA/CameraViewSwitchManipulator.cpp | 111 ++++++++++++++++++++++ src/osgPlugins/dae/daeRSceneObjects.cpp | 98 ++++++++++++++++--- src/osgPlugins/dae/daeWSceneObjects.cpp | 54 +++++++++++ src/osgPlugins/dae/daeWriter.h | 2 +- 6 files changed, 330 insertions(+), 16 deletions(-) create mode 100644 include/osgGA/CameraViewSwitchManipulator create mode 100644 src/osgGA/CameraViewSwitchManipulator.cpp diff --git a/include/osgGA/CameraViewSwitchManipulator b/include/osgGA/CameraViewSwitchManipulator new file mode 100644 index 000000000..0d5e20417 --- /dev/null +++ b/include/osgGA/CameraViewSwitchManipulator @@ -0,0 +1,79 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library 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. See the + * OpenSceneGraph Public License for more details. +*/ + +#ifndef OSGGA_VIEWLISTMANIPULATOR +#define OSGGA_VIEWLISTMANIPULATOR 1 + +#include +#include +#include + +namespace osgGA{ + +class OSGGA_EXPORT CameraViewSwitchManipulator : public MatrixManipulator +{ + public: + CameraViewSwitchManipulator() {} + + virtual const char* className() const { return "CameraViewSwitcher"; } + + /** set the position of the matrix manipulator using a 4x4 Matrix.*/ + virtual void setByMatrix(const osg::Matrixd& matrix) {} + + /** set the position of the matrix manipulator using a 4x4 Matrix.*/ + virtual void setByInverseMatrix(const osg::Matrixd& matrix) {} + + /** get the position of the manipulator as 4x4 Matrix.*/ + virtual osg::Matrixd getMatrix() const; + + /** get the position of the manipulator as a inverse matrix of the manipulator, typically used as a model view matrix.*/ + virtual osg::Matrixd getInverseMatrix() const; + + + /** Attach a node to the manipulator. + Automatically detaches previously attached node. + setNode(NULL) detaches previously nodes. + Is ignored by manipulators which do not require a reference model.*/ + virtual void setNode(osg::Node*); + + /** Return node if attached.*/ + virtual const osg::Node* getNode() const { return _node.get();} + + /** Return node if attached.*/ + virtual osg::Node* getNode() { return _node.get();} + + /** Start/restart the manipulator.*/ + virtual void init(const GUIEventAdapter& ea,GUIActionAdapter& us) { _currentView = 0; } + + /** handle events, return true if handled, false otherwise.*/ + virtual bool handle(const GUIEventAdapter& ea,GUIActionAdapter& us); + + /** Get the keyboard and mouse usage of this manipulator.*/ + virtual void getUsage(osg::ApplicationUsage& usage) const; + + typedef std::vector< osg::ref_ptr > CameraViewList; + + protected: + + virtual ~CameraViewSwitchManipulator() {} + + osg::ref_ptr _node; + + CameraViewList _cameraViews; + unsigned int _currentView; +}; + +} + +#endif + diff --git a/src/osgGA/CMakeLists.txt b/src/osgGA/CMakeLists.txt index ced211cd1..059c09182 100644 --- a/src/osgGA/CMakeLists.txt +++ b/src/osgGA/CMakeLists.txt @@ -25,6 +25,7 @@ SET(LIB_PUBLIC_HEADERS ${HEADER_PATH}/TrackballManipulator ${HEADER_PATH}/UFOManipulator ${HEADER_PATH}/Version + ${HEADER_PATH}/CameraViewSwitchManipulator ) # FIXME: For OS X, need flag for Framework or dylib @@ -46,6 +47,7 @@ ADD_LIBRARY(${LIB_NAME} TrackballManipulator.cpp UFOManipulator.cpp Version.cpp + CameraViewSwitchManipulator.cpp ) LINK_INTERNAL(${LIB_NAME} diff --git a/src/osgGA/CameraViewSwitchManipulator.cpp b/src/osgGA/CameraViewSwitchManipulator.cpp new file mode 100644 index 000000000..ad45da407 --- /dev/null +++ b/src/osgGA/CameraViewSwitchManipulator.cpp @@ -0,0 +1,111 @@ +#include +#include +#include +#include + + +using namespace osg; +using namespace osgGA; + +class CollectCameraViewsNodeVisitor : public osg::NodeVisitor +{ +public: + CollectCameraViewsNodeVisitor(CameraViewSwitchManipulator::CameraViewList* cameraViews): + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), + _cameraViews(cameraViews) + {} + + virtual void apply(CameraView& node) + { + _cameraViews->push_back(&node); + } + + CameraViewSwitchManipulator::CameraViewList* _cameraViews; +}; + +void CameraViewSwitchManipulator::setNode(osg::Node* node) +{ + _node = node; + + _cameraViews.clear(); + CollectCameraViewsNodeVisitor visitor(&_cameraViews); + + _node->accept(visitor); +} + +void CameraViewSwitchManipulator::getUsage(osg::ApplicationUsage& usage) const +{ + usage.addKeyboardMouseBinding("CameraViewSwitcher: [","Decrease current camera number"); + usage.addKeyboardMouseBinding("CameraViewSwitcher: ]","Increase current camera number"); +} + +bool CameraViewSwitchManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us) +{ + if (ea.getHandled()) return false; + + switch(ea.getEventType()) + { + + case(GUIEventAdapter::KEYDOWN): + if (ea.getKey()=='[') + { + if (_currentView == 0) + _currentView = _cameraViews.size()-1; + else + _currentView--; + return true; + } + else if (ea.getKey()==']') + { + _currentView++; + if (_currentView >= _cameraViews.size()) + _currentView = 0; + return true; + } + return false; + + default: + return false; + } + return false; +} + +osg::Matrixd CameraViewSwitchManipulator::getMatrix() const +{ + osg::Matrix mat; + if (_currentView < _cameraViews.size()) + { + NodePathList parentNodePaths = _cameraViews[_currentView]->getParentalNodePaths(); + + if (!parentNodePaths.empty()) + { + mat = osg::computeLocalToWorld(parentNodePaths[0]); + // TODO take into account the position and attitude of the CameraView + } + else + { + osg::notify(osg::NOTICE)<<"CameraViewSwitchManipulator::getMatrix(): Unable to calculate matrix due to empty parental path."<getParentalNodePaths(); + + if (!parentNodePaths.empty()) + { + mat = osg::computeWorldToLocal(parentNodePaths[0]); + // TODO take into account the position and attitude of the CameraView + } + else + { + osg::notify(osg::NOTICE)<<"CameraViewSwitchManipulator::getInverseMatrix(): Unable to calculate matrix due to empty parental path."< #include #include +#include using namespace osgdae; @@ -484,35 +485,102 @@ osg::Node* daeReader::processLight( domLight *dlight ) // elements: // 0..1 // 1 -// 1 +// 1 // 1 , // 0..* // 0..* // 0..* -// 1 +// 1 // 0..* // 0..* osg::Node* daeReader::processCamera( domCamera * dcamera ) { - osg::Node *node = new osg::Switch(); + osg::CameraView* pOsgCameraView = new osg::CameraView; + pOsgCameraView->setName(dcamera->getId()); - //TODO: Make the camera actually make a camera to view from. Not just draw a cone. - osg::Cone* cone = new osg::Cone(); + domCamera::domOptics::domTechnique_common *pDomTechniqueCommon = dcamera->getOptics()->getTechnique_common(); + domCamera::domOptics::domTechnique_common::domPerspective *pDomPerspective = pDomTechniqueCommon->getPerspective(); + domCamera::domOptics::domTechnique_common::domOrthographic *pDomOrthographic = pDomTechniqueCommon->getOrthographic(); + if (pDomPerspective) + { + // + // 1 , , and , and , and + // 1 + // 1 + domTargetableFloat *pXfov = daeSafeCast< domTargetableFloat >(pDomPerspective->getXfov()); + domTargetableFloat *pYfov = daeSafeCast< domTargetableFloat >(pDomPerspective->getYfov()); + domTargetableFloat *pAspectRatio = daeSafeCast< domTargetableFloat >(pDomPerspective->getAspect_ratio()); - osg::ShapeDrawable* sd = new osg::ShapeDrawable(cone); + if (pXfov) + { + if (pYfov) + { + // and + pOsgCameraView->setFieldOfView(pXfov->getValue()); + pOsgCameraView->setFieldOfViewMode(osg::CameraView::HORIZONTAL); + + if (pAspectRatio) + { + osg::notify(osg::WARN) << "Unexpected in '" << dcamera->getId() << "'" << std::endl; + } + } + else if (pAspectRatio) + { + // and + pOsgCameraView->setFieldOfView(pXfov->getValue() * pAspectRatio->getValue()); + pOsgCameraView->setFieldOfViewMode(osg::CameraView::HORIZONTAL); + } + else + { + // + pOsgCameraView->setFieldOfView(pXfov->getValue()); + pOsgCameraView->setFieldOfViewMode(osg::CameraView::HORIZONTAL); + } + } + else if (pYfov) + { + if (pAspectRatio) + { + // and + pOsgCameraView->setFieldOfView(pYfov->getValue() / pAspectRatio->getValue()); + pOsgCameraView->setFieldOfViewMode(osg::CameraView::VERTICAL); + } + else + { + // + pOsgCameraView->setFieldOfView(pYfov->getValue()); + pOsgCameraView->setFieldOfViewMode(osg::CameraView::VERTICAL); + } + } + else + { + // xfov or yfov expected + osg::notify(osg::WARN) << "Expected or in '" << dcamera->getId() << "'" << std::endl; + } - cone->setRadius(0.3); - cone->setHeight(1.0); + domTargetableFloat *pZnear = daeSafeCast< domTargetableFloat >(pDomPerspective->getZnear()); + domTargetableFloat *pZfar = daeSafeCast< domTargetableFloat >(pDomPerspective->getZfar()); - osg::Geode* geode = new osg::Geode(); + // TODO The current osg::CameraView does not support storage of near far + } + else if (pDomOrthographic) + { + // + // 1 , , and , and , and + // 1 + // 1 + domTargetableFloat *pXmag = daeSafeCast< domTargetableFloat >(pDomOrthographic->getXmag()); + domTargetableFloat *pYmag = daeSafeCast< domTargetableFloat >(pDomOrthographic->getYmag()); + domTargetableFloat *pAspectRatio = daeSafeCast< domTargetableFloat >(pDomOrthographic->getAspect_ratio()); - geode->addDrawable(sd); - geode->setName("camera"); + // TODO The current osg::CameraView does not support an orthographic view + osg::notify(osg::WARN) << "Orthographic in '" << dcamera->getId() << "' not supported" << std::endl; - osg::Switch* svitch = static_cast(node); + domTargetableFloat *pZnear = daeSafeCast< domTargetableFloat >(pDomOrthographic->getZnear()); + domTargetableFloat *pZfar = daeSafeCast< domTargetableFloat >(pDomOrthographic->getZfar()); - // Switched of by default to avoid excessively large scene bound - svitch->addChild(geode,false); + // TODO The current osg::CameraView does not support storage of near far + } - return node; + return pOsgCameraView; } diff --git a/src/osgPlugins/dae/daeWSceneObjects.cpp b/src/osgPlugins/dae/daeWSceneObjects.cpp index ae11cb886..f42395a84 100644 --- a/src/osgPlugins/dae/daeWSceneObjects.cpp +++ b/src/osgPlugins/dae/daeWSceneObjects.cpp @@ -26,6 +26,7 @@ #include #include #include +#include using namespace osgdae; @@ -393,3 +394,56 @@ void daeWriter::apply( osg::Camera &node ) traverse( node ); } + +void daeWriter::apply( osg::CameraView &node) +{ + debugPrint( node ); + + domInstance_camera *ic = daeSafeCast< domInstance_camera >( currentNode->add( "instance_camera" ) ); + std::string name = node.getName(); + if ( name.empty() ) + { + name = uniquify( "camera" ); + } + std::string url = "#" + name; + ic->setUrl( url.c_str() ); + + if ( lib_cameras == NULL ) + { + lib_cameras = daeSafeCast< domLibrary_cameras >( dom->add( COLLADA_ELEMENT_LIBRARY_CAMERAS ) ); + } + domCamera *cam = daeSafeCast< domCamera >( lib_cameras->add( COLLADA_ELEMENT_CAMERA ) ); + cam->setId( name.c_str() ); + + domCamera::domOptics *optics = daeSafeCast< domCamera::domOptics >( cam->add( COLLADA_ELEMENT_OPTICS ) ); + domCamera::domOptics::domTechnique_common *techniqueCommon = daeSafeCast< domCamera::domOptics::domTechnique_common >( optics->add( COLLADA_ELEMENT_TECHNIQUE_COMMON ) ); + domCamera::domOptics::domTechnique_common::domPerspective *pDomPerspective = daeSafeCast< domCamera::domOptics::domTechnique_common::domPerspective >( techniqueCommon->add( COLLADA_ELEMENT_PERSPECTIVE ) ); + + domTargetableFloat *pXfov = NULL; + domTargetableFloat *pYfov = NULL; + switch(node.getFieldOfViewMode()) + { + case(osg::CameraView::UNCONSTRAINED): + pXfov = daeSafeCast< domTargetableFloat >( pDomPerspective->add( COLLADA_ELEMENT_XFOV ) ); + pXfov->setValue(node.getFieldOfView()); + break; + case(osg::CameraView::HORIZONTAL): + pXfov = daeSafeCast< domTargetableFloat >( pDomPerspective->add( COLLADA_ELEMENT_XFOV ) ); + pXfov->setValue(node.getFieldOfView()); + break; + case(osg::CameraView::VERTICAL): + pYfov = daeSafeCast< domTargetableFloat >( pDomPerspective->add( COLLADA_ELEMENT_YFOV ) ); + pYfov->setValue(node.getFieldOfView()); + break; + } + + // Using hardcoded values for , and + domTargetableFloat *pAspectRatio = daeSafeCast< domTargetableFloat >( pDomPerspective->add( COLLADA_ELEMENT_ASPECT_RATIO ) ); + pAspectRatio->setValue(1.0); + + domTargetableFloat *pNear = daeSafeCast< domTargetableFloat >( pDomPerspective->add( COLLADA_ELEMENT_ZNEAR ) ); + pNear->setValue(1); + + domTargetableFloat *pFar = daeSafeCast< domTargetableFloat >( pDomPerspective->add( COLLADA_ELEMENT_ZFAR ) ); + pFar->setValue(1000); +} diff --git a/src/osgPlugins/dae/daeWriter.h b/src/osgPlugins/dae/daeWriter.h index ab833783b..3687d4717 100644 --- a/src/osgPlugins/dae/daeWriter.h +++ b/src/osgPlugins/dae/daeWriter.h @@ -110,7 +110,7 @@ public: //virtual void apply( osg::ClipNode &node) //virtual void apply( osg::TexGenNode &node) virtual void apply( osg::Transform &node ); - //virtual void apply( osg::CameraView &node) + virtual void apply( osg::CameraView &node); //virtual void apply( osg::PagedLOD &node) //virtual void apply( osg::ClearNode &node) //virtual void apply( osg::OccluderNode &node)