[osg-submissions] some changes to osgdb_dae (Collada plugin)

Mattias Linde linde at acc.umu.se
Tue Aug 28 06:39:46 PDT 2007


Hello,

We are using Collada and OpenSceneGraph and how the current plugin handles nodes makes
the visual stuff hard to control. 


Collada is a xml-based file format for content exchange. In the files (named .dae) one can
have <node> .. </node>.  These nodes can have zero or more rotate, scale and translate tags 
inside them. Nodes can also contain nodes.


The node hierarchy returned from the plugin is deeper than it should be (and loading and saving the 
same scene a couple of time will make a real mess out of things).

I'll give an example to show the problem (some xml remove to make it more readable):

<node layer="L1" id="Cube" name="Cube">
	<translate sid="translate">0.00000 0.00000 0.00000</translate>
        <rotate sid="rotateZ">0 0 1 0.00000</rotate>
        <rotate sid="rotateY">0 1 0 -0.00000</rotate>
        <rotate sid="rotateX">1 0 0 0.00000</rotate>
        <scale sid="scale">1.00000 1.00000 1.00000</scale>
	(removed stuff)
</node>


This will be read in as: (name and node-types)

   Cube (Group) 
      translate (PositionAttitudeTransform) 
         rotateZ (PositionAttitudeTransform) 
            rotateY (PositionAttitudeTransform) 
               rotateX (PositionAttitudeTransform) 
                  scale (PositionAttitudeTransform) 
                     Cube-Geometry (Group) 
                        Material (Geode) 


If one also wants to use the physics part of collada there can be rigid_body-tags which specify the 
position of a (visual) node. Now that the node rotation and translation are split into several different 
PositionAttitudeTransforms there are some problems updating the visual node so it has the same position and 
rotation as the rigid body. (there is also a comment in the code, "TODO: I am doing transforms wrong. ...")


With the changes made to the plugin the example above would be read in as:

   Cube (PositionAttitudeTransform) 
      Cube-Geometry (Group) 
         Material (Geode) 



I've attached the changes for review.

The code have been tested with a some different collada files.

/ Mattias


-------------- next part --------------
/*
 * Copyright 2006 Sony Computer Entertainment Inc.
 *
 * Licensed under the SCEA Shared Source License, Version 1.0 (the "License"); you may not use this 
 * file except in compliance with the License. You may obtain a copy of the License at:
 * http://research.scea.com/scea_shared_source_license.html
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License 
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
 * implied. See the License for the specific language governing permissions and limitations under the 
 * License. 
 */

#include "daeReader.h"
#include <dae.h>
#include <dom/domCOLLADA.h>
#include <dom/domInstanceWithExtra.h>

using namespace osgdae;

daeReader::daeReader(DAE *dae_) : dae(dae_),
                  rootNode(NULL),
                  m_numlights(0),
                  currentEffect(NULL),
                  geometryMap(),
                  materialMap(),
                  m_AuthoringTool(UNKNOWN)
{
}

daeReader::~daeReader()
{
}

bool daeReader::convert( const std::string &fileURI ) 
{
    std::string fURI;
    if ( fileURI[1] == ':' )
    {
        fURI = "/" + fileURI;
    }
    else
    {
        fURI = fileURI;
    }
    daeInt res = dae->load( fURI.c_str() );
    
    if( res != DAE_OK && res != DAE_ERR_COLLECTION_ALREADY_EXISTS) 
    {
        osg::notify( osg::WARN ) << "Load failed in COLLADA DOM" << std::endl;
        return false;
    }
    osg::notify( osg::INFO ) << "URI loaded: " << fURI << std::endl;

    domCOLLADA* document = dae->getDom( fURI.c_str() );

    if ( !document->getScene() || !document->getScene()->getInstance_visual_scene() ) 
    {
        osg::notify( osg::WARN ) << "No scene found!" << std::endl;
        return false;
    }

    if (document->getAsset())
    {
        const domAsset::domContributor_Array& ContributorArray = document->getAsset()->getContributor_array();
        size_t NumberOfContributors = ContributorArray.getCount();
        size_t CurrentContributor;
        for (CurrentContributor = 0; CurrentContributor < NumberOfContributors; CurrentContributor++)
        {
            if (ContributorArray[CurrentContributor]->getAuthoring_tool())
            {
                xsString Tool = ContributorArray[CurrentContributor]->getAuthoring_tool()->getValue();
                if (strncmp(Tool, "Google SketchUp", 15) == 0)
                    m_AuthoringTool = GOOGLE_SKETCHUP;
            }
        }
    }


    domInstanceWithExtra *ivs = document->getScene()->getInstance_visual_scene();
    domVisual_scene *vs = daeSafeCast< domVisual_scene >( getElementFromURI( ivs->getUrl() ) );
    if ( vs == NULL ) 
    {
        osg::notify( osg::WARN ) << "Unable to locate visual scene!" << std::endl;
        return false;
    }
    rootNode = processVisualScene( vs );

    return true;
}

osg::Node* daeReader::processVisualScene( domVisual_scene *scene )
{
    osg::Node *retVal; 
    //### do not add an empty group if there is only one
    unsigned int nbVisualSceneGroup=scene->getNode_array().getCount();
    if (nbVisualSceneGroup==0)
    {
        osg::notify( osg::WARN ) << "No visual scene group found !" << std::endl;
        retVal = new osg::Group();
        retVal->setName("Empty Collada scene");
    }
    else if (nbVisualSceneGroup==1)
    {
        osg::Node *node = processNode( scene->getNode_array()[0] );
        if ( node != NULL )
           retVal = node;
        else
        {
           retVal = new osg::Group();
           retVal->setName("Empty Collada scene (import failure)");
        }
    }
    else
    { 
       retVal = new osg::Group();
       retVal->setName("Collada visual scene group");
       for ( size_t i = 0; i < scene->getNode_array().getCount(); i++ )
       {
          osg::Node *node = processNode( scene->getNode_array()[i] );
          if ( node != NULL )
          {
              retVal->asGroup()->addChild( node );
          }
       }
    }
    return retVal;
    
}

osg::Node* daeReader::processNode( domNode *node )
{
    osg::PositionAttitudeTransform *retVal = new osg::PositionAttitudeTransform();
    osg::Node *current = retVal;

    retVal->setName( node->getId() ? node->getId() : "" );


	// Handle rotate, translate and scale first..
	// will make the hierarchy less deep

    // <rotate>
    osg::Quat osgRot;
    for (int i=0; i<node->getRotate_array().getCount(); i++) {
	    daeSmartRef<domRotate> rot = node->getRotate_array().get(i);
        if (rot->getValue().getCount() != 4 ) {
            osg::notify(osg::WARN)<<"Data is wrong size for rotate"<<std::endl;
            continue;
        }

        domFloat4& r = rot->getValue();

        osg::Vec3 axis;
        axis.set(r[0],r[1],r[2]);
        osgRot =  osg::Quat(osg::DegreesToRadians(r[3]),axis) * osgRot;
        retVal->setAttitude(osgRot);
     }

    // <scale>
    osg::Vec3 osgScale = osg::Vec3(1.0, 1.0, 1.0);
    for (int i=0; i<node->getScale_array().getCount(); i++) {
	    daeSmartRef<domScale> scale = node->getScale_array().get(i);

        if (scale->getValue().getCount() != 3 ) {
            osg::notify(osg::WARN)<<"Data is wrong size for scale"<<std::endl;
	        continue;
    	}
    	domFloat3& s = scale->getValue();
	
	   osgScale[0] *= s[0];
	   osgScale[1] *= s[1];
	   osgScale[2] *= s[2];
       retVal->setScale(osgScale);
    }

    // <translate>
    osg::Vec3 osgTrans = osg::Vec3(0.0, 0.0, 0.0);
    for (int i=0; i<node->getTranslate_array().getCount(); i++) {
	    daeSmartRef<domTranslate> trans = node->getTranslate_array().get(i);

    	if (trans->getValue().getCount() != 3 ) {
            osg::notify(osg::WARN)<<"Data is wrong size for translate"<<std::endl;
            continue;
        }

    	domFloat3& t = trans->getValue();
    	osgTrans += osg::Vec3(t[0],t[1],t[2]);
        retVal->setPosition(osgTrans);
    }




    size_t count = node->getContents().getCount();
    for ( size_t i = 0; i < count; i++ ) 
    {
        osg::Node *trans = NULL;

        //I'm using daeSafeCast to check type because the pointer comparisons are a lot faster
        //than a strcmp

        domTranslate * t = daeSafeCast< domTranslate >( node->getContents()[i] );
        if ( t != NULL )
        {
            continue;
        }

        domRotate * r = daeSafeCast< domRotate >( node->getContents()[i] );
        if ( r != NULL ) {
            continue;
        }

        domScale * s = daeSafeCast< domScale >( node->getContents()[i] );
        if ( s != NULL ) {
            continue;
        }

        domMatrix * m = daeSafeCast< domMatrix >( node->getContents()[i] );
        if ( m != NULL ) {
            trans = processMatrix( m );
            if ( trans != NULL )
            {
                current->asGroup()->addChild( trans );
                current = trans;
            }
            continue;
        }

        domSkew *sk = daeSafeCast< domSkew >( node->getContents()[i] );
        if ( sk != NULL ) {
            trans = processSkew( sk );
            if ( trans != NULL )
            {
                current->asGroup()->addChild( trans );
                current = trans;
            }
            continue;
        }

        domInstance_geometry *ig = daeSafeCast< domInstance_geometry >( node->getContents()[i] );
        if ( ig != NULL )
        {
            trans = processInstance_geometry( ig );
            if ( trans != NULL )
            {
                current->asGroup()->addChild( trans );
            }
            continue;
        }
        
        domInstance_controller *ictrl = daeSafeCast< domInstance_controller >( node->getContents()[i] );
        if ( ictrl != NULL )
        {
            trans = processInstance_controller( ictrl );
            if ( trans != NULL )
            {
                current->asGroup()->addChild( trans );
            }
            continue;
        }

        domInstance_camera *ic = daeSafeCast< domInstance_camera >( node->getContents()[i] );
        if ( ic != NULL )
        {
            daeElement *el = getElementFromURI( ic->getUrl() );
            domCamera *c = daeSafeCast< domCamera >( el );
            if ( c == NULL )
            {
                osg::notify( osg::WARN ) << "Failed to locate camera " << ic->getUrl().getURI() << std::endl;
            }
            trans = processCamera( c );
            if ( trans != NULL )
            {
                current->asGroup()->addChild( trans );
            }
            continue;
        }
        
        domInstance_light *il = daeSafeCast< domInstance_light >( node->getContents()[i] );
        if ( il != NULL )
        {
            daeElement *el = getElementFromURI( il->getUrl() );
            domLight *l = daeSafeCast< domLight >( el );
            if ( l == NULL )
            {
                osg::notify( osg::WARN ) << "Failed to locate light " << il->getUrl().getURI() << std::endl;
            }
            trans = processLight( l );
            if ( trans != NULL )
            {
                current->asGroup()->addChild( trans );
            }
            continue;
        }

        domInstance_node *instn = daeSafeCast< domInstance_node >( node->getContents()[i] );
        if ( instn != NULL )
        {
            daeElement *el = getElementFromURI( instn->getUrl() );
            domNode *n = daeSafeCast< domNode >( el );
            if ( n == NULL )
            {
                osg::notify( osg::WARN ) << "Failed to locate camera " << ic->getUrl().getURI() << std::endl;
            }
            trans = processNode( n );
            if ( trans != NULL )
            {
                current->asGroup()->addChild( trans );
            }
            continue;
        }

        domNode *n = daeSafeCast< domNode >( node->getContents()[i] );
        if ( n != NULL )
        {
            trans = processNode( n );
            if ( trans != NULL )
            {
                current->asGroup()->addChild( trans );
            }
            continue;
        }

        const char *name = node->getContents()[i]->getElementName();
        if ( name == NULL ) name = node->getContents()[i]->getTypeName();
        osg::notify( osg::WARN ) << "Unsupported element type: " << name << " in COLLADA scene!" << std::endl;

    }

    return retVal;
}


More information about the osg-submissions mailing list