Files
OpenSceneGraph/src/osgPlugins/dae/daeReader.cpp
Robert Osfield 796ccd14c8 From Cedric Pinson, from three submissions:
"Here a patch that correct like the previous assign collada material name
to stateset."

and

"I changed how the collada reader set object name in osg. Current
implementation use collada ID to setup name. with this patch I use
collada name to setup name in osg object and if collada provide no name
I use as fallback ID. I am not sure we want this fallback.

The motivation of this change is that when an artist set names to its
objects and export to collada, I am not able to use those names in osg
to retrieve the node."

and

"Here the update of the file that fix the light id stuff"
2011-09-12 11:28:14 +00:00

645 lines
22 KiB
C++

/*
* 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);
}
}
}
}
}
}
// Build the actual scene graph based on the visual scene
_rootNode = processVisualScene( _visualScene );
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())
{
std::string name = "";
if (node->getId())
name = node->getId();
if (node->getName())
name = node->getName();
resultNode->setName( name );
}
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;
}