Hi,

Although the DAE Plugin reads the scale (tagged as "unit" in the DAE file)
and stores it in its private member _assetUnitMeter, it doesn't use this
value at all when loading an object.

I've added a little code to scale the original result node by this value
using PositionAttitudeTransform, and then return this PAT as the actual
result node.

The base code for my changes was OSG-3.0.1.

This is my first submission. I hope the code is correct, otherwise let me
know if I am mistaken.

Cheers,

Gus.
/*
 * 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 <dae/domAny.h>
#include <dom/domCOLLADA.h>
#include <dom/domInstanceWithExtra.h>
#include <dom/domConstants.h>
#include <osg/MatrixTransform>
#include <osg/PositionAttitudeTransform>

using namespace osgDAE;

daeReader::Options::Options() :
    strictTransparency(false),
    precisionHint(0),
    usePredefinedTextureUnits(true),
    tessellateMode(TESSELLATE_POLYGONS_AS_TRIFAN)   // Use old tessellation behaviour as default
{
}

daeReader::daeReader(DAE *dae_, const Options * pluginOptions) :
                  _dae(dae_),
				  _rootNode(NULL),
                  _document(NULL),
                  _visualScene(NULL),
                  _numlights(0),
                  _currentInstance_effect(NULL),
                  _currentEffect(NULL),
                  _authoringTool(UNKNOWN),
                  _invertTransparency(false),
                  _pluginOptions(pluginOptions ? *pluginOptions : Options()),
                  _assetUnitName("meter"),
                  _assetUnitMeter(1.0),
                  _assetUp_axis(UPAXISTYPE_Y_UP)
{
}

daeReader::~daeReader()
{
}

bool daeReader::convert( const std::string &fileURI ) 
{
    // Clear caches
    _geometryMap.clear();
    _materialMap.clear();
    _materialMap2.clear();

    daeElement *colladaElement;
    

    daeInt count, result;

    _document = _dae->open(fileURI);
    
    if (!_document) 
    {
        OSG_WARN << "Load failed in COLLADA DOM" << std::endl;
        return false;
    }
    OSG_INFO << "URI loaded: " << fileURI << std::endl;

    if ( !_document->getScene() || !_document->getScene()->getInstance_visual_scene() ) 
    {
        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())
            {
                const char szBlender[] = "Blender";
                const char szDazStudio[] = "DAZ|Studio";
                const char szSketchup[] = "Google SketchUp";
                const char szFbx[] = "FBX";
                const char szMaya[] = "Maya";

                xsString Tool = ContributorArray[CurrentContributor]->getAuthoring_tool()->getValue();

                if (strncmp(Tool, szBlender, strlen(szBlender)) == 0)
                    _authoringTool = BLENDER;
                else if (strncmp(Tool, szDazStudio, strlen(szDazStudio)) == 0)
                    _authoringTool = DAZ_STUDIO;
                else if (strncmp(Tool, szFbx, strlen(szFbx)) == 0)
                    _authoringTool = FBX_CONVERTER;
                else if (strncmp(Tool, szSketchup, strlen(szSketchup)) == 0)
                    _authoringTool = GOOGLE_SKETCHUP;
                else if (strncmp(Tool, szMaya, strlen(szMaya)) == 0)
                    _authoringTool = MAYA;
            }
        }
        if (_document->getAsset()->getUnit())
        {
            if (NULL != _document->getAsset()->getUnit()->getName())
                _assetUnitName = std::string(_document->getAsset()->getUnit()->getName());
            if (0 != _document->getAsset()->getUnit()->getMeter())
                _assetUnitMeter = _document->getAsset()->getUnit()->getMeter();
        }
        if (_document->getAsset()->getUp_axis())
            _assetUp_axis = _document->getAsset()->getUp_axis()->getValue();
    }

    domInstanceWithExtra *ivs = _document->getScene()->getInstance_visual_scene();
    _visualScene = daeSafeCast< domVisual_scene >( getElementFromURI( ivs->getUrl() ) );
    if ( _visualScene == NULL ) 
    {
        OSG_WARN << "Unable to locate visual scene!" << std::endl;
        return false;
    }

    if (daeDatabase* database = _dae->getDatabase()) 
    {
        _invertTransparency = findInvertTransparency(database);

        // build a std::map for lookup if Group or PositionAttitudeTransform should be created, 
        // i.e, make it easy to check if a instance_rigid_body targets a visual node
        domInstance_rigid_body *pDomInstanceRigidBody;
        count = database->getElementCount(NULL, COLLADA_TYPE_INSTANCE_RIGID_BODY, NULL);
        for (int i=0; i<count; i++) 
        {
            result = database->getElement(&colladaElement, i, NULL, COLLADA_TYPE_INSTANCE_RIGID_BODY);

            if (result == DAE_OK) 
            {
                pDomInstanceRigidBody = daeSafeCast<domInstance_rigid_body>(colladaElement);
                if (pDomInstanceRigidBody) 
                {
                    domNode *node = daeSafeCast<domNode>(pDomInstanceRigidBody->getTarget().getElement());
                    if (node && node->getId()) 
                    {
                        _targetMap[ std::string(node->getId()) ] = true;          
                    }
                }
            }
        }

        // Build a map of elements that are targetted by animations
        count = database->getElementCount(NULL, COLLADA_TYPE_CHANNEL, NULL);
        for (int i=0; i<count; i++) 
        {
            result = database->getElement(&colladaElement, i, NULL, COLLADA_TYPE_CHANNEL);

            if (result == DAE_OK) 
            {
                domChannel* pDomChannel = daeSafeCast<domChannel>(colladaElement);
                if (pDomChannel) 
                {
                    std::string target = pDomChannel->getTarget();
                    size_t openparenthesis = target.find_first_of('(');
                    if (openparenthesis != std::string::npos) target.erase(openparenthesis);
                    daeSIDResolver resolver(pDomChannel, target.c_str());
                    daeElement *pDaeElement = resolver.getElement();
                    if (pDaeElement)
                    {
                        _daeElementDomChannelMap.insert(daeElementDomChannelMap::value_type(pDaeElement, pDomChannel));
                    }
                    else
                    {
                        OSG_WARN << "Could not locate <channel> target "  << pDomChannel->getTarget()<< std::endl;
                    }
                }
            }
        }

        // Find all nodes that are used as bones. Note that while many files
        // identify nodes with type="JOINT", some don't do this, while others
        // identify every node as a joint, making it meaningless.
        std::vector<domInstance_controller*> instanceControllers;
        database->typeLookup(instanceControllers);
        for (size_t i = 0; i < instanceControllers.size(); ++i) 
        {
            domInstance_controller* pInstanceController = instanceControllers[i];

            domController *pDomController = daeSafeCast<domController>(getElementFromURI(pInstanceController->getUrl()));
            if (!pDomController)
            {
                OSG_WARN << "Failed to locate controller " << pInstanceController->getUrl().getURI() << std::endl;
                continue;
            }

            const domInstance_controller::domSkeleton_Array& domSkeletonURIs = pInstanceController->getSkeleton_array();
            std::vector<daeElement*> searchIn;

            for (size_t i = 0; i < domSkeletonURIs.getCount(); ++i)
            {
                if (daeElement* el = getElementFromURI(domSkeletonURIs[i]->getValue()))
                {
                    searchIn.push_back(el);
                    if (domNode* pJoint = daeSafeCast<domNode>(el))
                    {
                        _jointSet.insert(pJoint);
                    }
                }
            }

            if (searchIn.empty())
            {
                searchIn.push_back(_visualScene);
            }

            const domSkin* pSkin = pDomController->getSkin();
            if (!pSkin) continue;
            const domSkin::domJoints* pJoints = pSkin->getJoints();
            if (!pJoints) continue;
            const domInputLocal_Array& inputURIs = pJoints->getInput_array();

            domSource* pDomJointsSource = NULL; 
            for (size_t i=0; i < inputURIs.getCount(); i++)
            {
                if (!strcmp(inputURIs[i]->getSemantic(), COMMON_PROFILE_INPUT_JOINT))
                {
                    pDomJointsSource = daeSafeCast<domSource>(getElementFromURI(inputURIs[i]->getSource()));
                    if (!pDomJointsSource)
                    {
                        OSG_WARN << "Could not find skin joints source '" << inputURIs[i]->getSource().getURI() << "'" <<std::endl;
                    }
                }
            }

            if (!pDomJointsSource)
            {
            }
            else if (domIDREF_array* pDomIDREFs = pDomJointsSource->getIDREF_array())
            {
                for (size_t i = 0; i < pDomIDREFs->getCount(); ++i)
                {
                    if (domNode* pJoint = daeSafeCast<domNode>(getElementFromIDRef(pDomIDREFs->getValue().get(i))))
                    {
                        _jointSet.insert(pJoint);
                    }
                }
            }
            else if (domName_array* pDomNames = pDomJointsSource->getName_array())
            {
                for (size_t i = 0; i < pDomNames->getCount(); ++i)
                {
                    daeString target = pDomNames->getValue().get(i);
                    for (size_t j = 0; j < searchIn.size(); ++j)
                    {
                        daeSIDResolver resolver(searchIn[j], target);
                        if (domNode* pJoint = daeSafeCast<domNode>(resolver.getElement()))
                        {
                            _jointSet.insert(pJoint);
                        }
                    }
                }
            }
        }
    }

	// PAT Node to scale the result node
	osg::PositionAttitudeTransform* rootPATNode = new osg::PositionAttitudeTransform;

    // Build the actual scene graph based on the visual scene
	rootPATNode->addChild(processVisualScene( _visualScene ));

	// Apply scale
	rootPATNode->setScale(osg::Vec3d(_assetUnitMeter,_assetUnitMeter,_assetUnitMeter));

    _rootNode = (osg::Node*) rootPATNode;

    osgAnimation::BasicAnimationManager* pOsgAnimationManager = processAnimationLibraries(_document);
    if (pOsgAnimationManager)
    {
		_rootNode->addUpdateCallback(pOsgAnimationManager);
    }
    
    return true;
}

void daeReader::addChild(osg::Group* group, osg::Node* node)
{
    if (dynamic_cast<osgAnimation::Bone*>(node))
    {
        unsigned index = 0;
        while (index < group->getNumChildren() &&
            dynamic_cast<osgAnimation::Bone*>(group->getChild(index)))
        {
            ++index;
        }
        group->insertChild(index, node);
    }
    else
    {
        group->addChild(node);
    }
}

osg::Group* daeReader::turnZUp()
{
    osg::PositionAttitudeTransform* pat = NULL;
    
    // If not Z axis up we need to rotate scene to bring the Z axis up
    if (_assetUp_axis != UPAXISTYPE_Z_UP)
    {
        pat = new osg::PositionAttitudeTransform();
        if (_assetUp_axis == UPAXISTYPE_Y_UP)
        {
            pat->setAttitude(osg::Quat(osg::inDegrees(90.0f), osg::Vec3(1.0f,0.0f,0.0f)));
        }
        else //(m_AssetUp_axis == UPAXISTYPE_X_UP)
        {
            pat->setAttitude(osg::Quat(osg::inDegrees(90.0f), osg::Vec3(0.0f,1.0f,0.0f)));
        }
    }

    _assetUp_axis = UPAXISTYPE_Z_UP;
    return pat;
}

osg::Group* daeReader::processVisualScene( domVisual_scene *scene )
{
    osg::Group *retVal; 
    _rootStateSet = new osg::StateSet();

    unsigned int nbVisualSceneGroup=scene->getNode_array().getCount();
    if (nbVisualSceneGroup==0)
    {
        OSG_WARN << "No visual scene group found !" << std::endl;
        retVal = new osg::Group();
        retVal->setName("Empty Collada scene");
    }
    else
    {
        retVal = turnZUp(); 

        if (!retVal)
        {
            retVal = new osg::Group;
        }

        _skinInstanceControllers.clear();

        const domNode_Array& node_array = scene->getNode_array();
        for (size_t i = 0; i < node_array.getCount(); i++)
        {
            if (osg::Node* node = processNode(node_array[i], false))
            {
                addChild(retVal, node);
            }
        }

        processSkins();

        if (retVal->getName().empty())
        {
            if (retVal->getNumChildren())
            {
                retVal->setName("Collada visual scene group");
            }
            else
            {
                retVal->setName("Empty Collada scene (import failure)");
            }
        }
    }
    retVal->setStateSet(_rootStateSet.get());

    return retVal;
}



osg::Group* daeReader::processExtras(domNode *node)
{
    // See if one of the extras contains OpenSceneGraph specific information
    unsigned int numExtras = node->getExtra_array().getCount();
    for (unsigned int currExtra=0; currExtra < numExtras; currExtra++)
    {
        domExtra* extra = node->getExtra_array()[currExtra];
        domTechnique* teq = NULL;

        daeString extraType = extra->getType();
        if (extraType)
        {
            if (strcmp(extraType, "Switch") == 0)
            {
                teq = getOpenSceneGraphProfile(extra);
                if (teq)
                {
                    return processOsgSwitch(teq);
                }
            }
            else if (strcmp(extraType, "MultiSwitch") == 0)
            {
                teq = getOpenSceneGraphProfile(extra);
                if (teq)
                {
                    return processOsgMultiSwitch(teq);
                }
            }
            else if (strcmp(extraType, "LOD") == 0)
            {
                teq = getOpenSceneGraphProfile(extra);
                if (teq)
                {
                    return processOsgLOD(teq);
                }
            }
            else if (strcmp(extraType, "DOFTransform") == 0)
            {
                teq = getOpenSceneGraphProfile(extra);
                if (teq)
                {
                    return processOsgDOFTransform(teq);
                }
            }
            else if (strcmp(extraType, "Sequence") == 0)
            {
                teq = getOpenSceneGraphProfile(extra);
                if (teq)
                {
                    return processOsgSequence(teq);
                }
            }
        }
    }
    return new osg::Group;
}

void daeReader::processNodeExtra(osg::Node* osgNode, domNode *node)
{
    // See if one of the extras contains OpenSceneGraph specific information
    unsigned int numExtras = node->getExtra_array().getCount();

    for (unsigned int currExtra=0; currExtra < numExtras; currExtra++)
    {
        domExtra* extra = node->getExtra_array()[currExtra];

        daeString extraType = extra->getType();
        if (extraType && (strcmp(extraType, "Node") == 0))
        {
            domTechnique* teq = getOpenSceneGraphProfile(extra);
            if (teq)
            {
                domAny* any = daeSafeCast< domAny >(teq->getChild("Descriptions"));
                if (any)
                {
                    osg::Node::DescriptionList descriptions;
                    unsigned int numChildren = any->getChildren().getCount();
                    for (unsigned int currChild = 0; currChild < numChildren; currChild++)
                    {
                        domAny* child = daeSafeCast<domAny>(any->getChildren()[currChild]);
                        if (child)
                        {
                            if (strcmp(child->getElementName(), "Description" ) == 0 )
                            {
                                std::string value = child->getValue();
                                descriptions.push_back(value);
                            }
                            else
                            {
                                OSG_WARN << "Child of element 'Descriptions' is not of type 'Description'" << std::endl;
                            }
                        }
                        else
                        {
                            OSG_WARN << "Element 'Descriptions' does not contain expected elements." << std::endl;
                        }
                    }
                    osgNode->setDescriptions(descriptions);
                }
                else
                {
                    OSG_WARN << "Expected element 'Descriptions' not found" << std::endl;
                }
            }
        }
    }
}

domTechnique* daeReader::getOpenSceneGraphProfile(domExtra* extra)
{
    unsigned int numTeqs = extra->getTechnique_array().getCount();

    for ( unsigned int currTeq = 0; currTeq < numTeqs; ++currTeq )
    {
        // Only interested in OpenSceneGraph technique
        if (strcmp( extra->getTechnique_array()[currTeq]->getProfile(), "OpenSceneGraph" ) == 0 )
        {
            return extra->getTechnique_array()[currTeq];
        }
    }
    return NULL;
}


// <node>
// attributes:
// id, name, sid, type, layer
// child elements:
// 0..1 <asset>
// 0..* <lookat>, <matrix>, <rotate>, <scale>, <skew>, <translate>
// 0..* <instance_camera>
// 0..* <instance_controller>
// 0..* <instance_geometry>
// 0..* <instance_light>
// 0..* <instance_node>
// 0..* <node>
// 0..* <extra>
osg::Node* daeReader::processNode( domNode *node, bool skeleton)
{
    // First we need to determine what kind of OSG node we need
    // If there exist any of the <lookat>, <matrix>, <rotate>, <scale>, <skew>, <translate> elements
    // or if a COLLADA_TYPE_INSTANCE_RIGID_BODY targets this node we need a MatrixTransform
    int coordcount =    node->getRotate_array().getCount() +
                        node->getScale_array().getCount() +
                        node->getTranslate_array().getCount() +
                        node->getLookat_array().getCount() +
                        node->getMatrix_array().getCount() +
                        node->getSkew_array().getCount();

    // See if it is targeted by an animation
    bool targeted = false;
    if (node->getId()) 
    {
        targeted = _targetMap[std::string(node->getId())];
    }


    osg::Group *resultNode = NULL;

    bool isBone = skeleton || isJoint(node);

    if (coordcount > 0 || targeted || isBone) 
    {
        // TODO
        // single matrix -> MatrixTransform
        // scale, euler, translate -> PositionAttitudeTransform
        // if targeted -> StackedTransform
        // otherwise a flattened -> MatrixTransform
        resultNode = processOsgMatrixTransform(node, isBone);
    }
    else
    {
        // No transform data, determine node type based on it's available extra data
        resultNode = processExtras(node);
    }

    // See if there is generic node info attached as extra
    processNodeExtra(resultNode, node);

    if (resultNode->getName().empty())
    {
        resultNode->setName( node->getId() ? node->getId() : "" );
    }

    osg::Group* attachTo = resultNode;

    if (!skeleton && isJoint(node))
    {
        skeleton = true;
        osgAnimation::Skeleton* pOsgSkeleton = getOrCreateSkeleton(node);
        pOsgSkeleton->addChild(resultNode);
        attachTo = resultNode;
        resultNode = pOsgSkeleton;
    }

    // 0..* <instance_camera>
    const domInstance_camera_Array& cameraInstanceArray = node->getInstance_camera_array();
    for ( size_t i = 0; i < cameraInstanceArray.getCount(); i++ ) 
    {
        daeElement *el = getElementFromURI( cameraInstanceArray[i]->getUrl());
        domCamera *c = daeSafeCast< domCamera >( el );

        if (c)
            addChild(attachTo, processCamera( c ));
        else
            OSG_WARN << "Failed to locate camera " << cameraInstanceArray[i]->getUrl().getURI() << std::endl;
    }

    // 0..* <instance_controller>
    const domInstance_controller_Array& controllerInstanceArray = node->getInstance_controller_array();
    for ( size_t i = 0; i < controllerInstanceArray.getCount(); i++ ) 
    {
        osg::Node* pOsgNode = processInstanceController( controllerInstanceArray[i]);
        
        // A skin controller may return NULL,  since the RigGeometry is added as 
        // child of the skeleton and the skeleton already is added to the scenegraph
        if (pOsgNode)
        {
            addChild(attachTo, pOsgNode);
        }
    }

    // 0..* <instance_geometry>
    const domInstance_geometry_Array& geometryInstanceArray = node->getInstance_geometry_array();
    for ( size_t i = 0; i < geometryInstanceArray.getCount(); i++ ) 
    {
        addChild(attachTo, processInstanceGeometry( geometryInstanceArray[i] ));
    }

    // 0..* <instance_light>
    const domInstance_light_Array& lightInstanceArray = node->getInstance_light_array();
    for ( size_t i = 0; i < lightInstanceArray.getCount(); i++ ) 
    {
        daeElement *el = getElementFromURI( lightInstanceArray[i]->getUrl());
        domLight *pDomLight = daeSafeCast< domLight >( el );
        
        if (pDomLight)
            addChild(attachTo, processLight(pDomLight));
        else
            OSG_WARN << "Failed to locate light " << lightInstanceArray[i]->getUrl().getURI() << std::endl;
    }

    // 0..* <instance_node>
    const domInstance_node_Array& nodeInstanceArray = node->getInstance_node_array();
    for ( size_t i = 0; i < nodeInstanceArray.getCount(); i++ ) 
    {
        daeElement *el = getElementFromURI( nodeInstanceArray[i]->getUrl());
        domNode *n = daeSafeCast< domNode >( el );

        if (n)
            // Recursive call
            addChild(attachTo, processNode( n, skeleton ));
        else
            OSG_WARN << "Failed to locate node " << nodeInstanceArray[i]->getUrl().getURI() << std::endl;
    }

    // 0..* <node>
    const domNode_Array& nodeArray = node->getNode_array();
    for ( size_t i = 0; i < nodeArray.getCount(); i++ ) 
    {
        // Recursive call
        addChild(attachTo, processNode( nodeArray[i], skeleton ));
    }

    return resultNode;
}
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to