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?"
This commit is contained in:
Robert Osfield 2009-01-05 16:53:29 +00:00
parent 1a600c1178
commit 85fffc2e76
6 changed files with 330 additions and 16 deletions

View File

@ -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 <osgGA/MatrixManipulator>
#include <osg/Quat>
#include <osg/CameraView>
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<osg::CameraView> > CameraViewList;
protected:
virtual ~CameraViewSwitchManipulator() {}
osg::ref_ptr<osg::Node> _node;
CameraViewList _cameraViews;
unsigned int _currentView;
};
}
#endif

View File

@ -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}

View File

@ -0,0 +1,111 @@
#include <osgGA/CameraViewSwitchManipulator>
#include <osg/Quat>
#include <osg/Notify>
#include <osg/BoundsChecking>
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."<<std::endl;
}
}
return mat;
}
osg::Matrixd CameraViewSwitchManipulator::getInverseMatrix() const
{
osg::Matrix mat;
if (_currentView < _cameraViews.size())
{
NodePathList parentNodePaths = _cameraViews[_currentView]->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."<<std::endl;
}
}
return mat;
}

View File

@ -24,6 +24,7 @@
#include <osg/Billboard>
#include <osgSim/MultiSwitch>
#include <osg/Sequence>
#include <osg/CameraView>
using namespace osgdae;
@ -484,35 +485,102 @@ osg::Node* daeReader::processLight( domLight *dlight )
// elements:
// 0..1 <asset>
// 1 <optics>
// 1 <technique_common>
// 1 <technique_common>
// 1 <orthographic>, <perspective>
// 0..* <technique>
// 0..* <extra>
// 0..* <imager>
// 1 <technique>
// 1 <technique>
// 0..* <extra>
// 0..* <extra>
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)
{
// <perspective>
// 1 <xfov>, <yfov>, <xfov> and <yfov>, <xfov> and <aspect_ratio>, <yfov> and <aspect_ratio>
// 1 <znear>
// 1 <zfar>
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)
{
// <xfov> and <yfov>
pOsgCameraView->setFieldOfView(pXfov->getValue());
pOsgCameraView->setFieldOfViewMode(osg::CameraView::HORIZONTAL);
if (pAspectRatio)
{
osg::notify(osg::WARN) << "Unexpected <aspectratio> in <camera> '" << dcamera->getId() << "'" << std::endl;
}
}
else if (pAspectRatio)
{
// <xfov> and <aspect_ratio>
pOsgCameraView->setFieldOfView(pXfov->getValue() * pAspectRatio->getValue());
pOsgCameraView->setFieldOfViewMode(osg::CameraView::HORIZONTAL);
}
else
{
// <xfov>
pOsgCameraView->setFieldOfView(pXfov->getValue());
pOsgCameraView->setFieldOfViewMode(osg::CameraView::HORIZONTAL);
}
}
else if (pYfov)
{
if (pAspectRatio)
{
// <yfov> and <aspect_ratio>
pOsgCameraView->setFieldOfView(pYfov->getValue() / pAspectRatio->getValue());
pOsgCameraView->setFieldOfViewMode(osg::CameraView::VERTICAL);
}
else
{
// <yfov>
pOsgCameraView->setFieldOfView(pYfov->getValue());
pOsgCameraView->setFieldOfViewMode(osg::CameraView::VERTICAL);
}
}
else
{
// xfov or yfov expected
osg::notify(osg::WARN) << "Expected <xfov> or <yfov> in <camera> '" << 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)
{
// <orthographic>
// 1 <xmag>, <ymag>, <xmag> and <ymag>, <xmag> and <aspect_ratio>, <ymag> and <aspect_ratio>
// 1 <znear>
// 1 <zfar>
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 <camera> '" << dcamera->getId() << "' not supported" << std::endl;
osg::Switch* svitch = static_cast<osg::Switch*>(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;
}

View File

@ -26,6 +26,7 @@
#include <osgSim/MultiSwitch>
#include <osg/Sequence>
#include <osg/Billboard>
#include <osg/CameraView>
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 <aspect_ratio>, <znear> and <zfar>
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);
}

View File

@ -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)