From 82ea9597e57e8dec9bf361cf0b2eaff398ce58c2 Mon Sep 17 00:00:00 2001 From: Michael PLATINGS Date: Tue, 8 Jun 2010 17:32:36 +0000 Subject: [PATCH] Added support for Euler angles and step/linear/cubic-bezier interpolation. --- src/osgPlugins/fbx/ReaderWriterFBX.cpp | 84 +++--- src/osgPlugins/fbx/ReaderWriterFBX.h | 2 +- .../fbx/fbxMaterialToOsgStateSet.cpp | 40 ++- src/osgPlugins/fbx/fbxMaterialToOsgStateSet.h | 48 ++-- src/osgPlugins/fbx/fbxRAnimation.cpp | 272 ++++++++++++++++-- src/osgPlugins/fbx/fbxRMesh.cpp | 44 +-- src/osgPlugins/fbx/fbxRNode.cpp | 80 +++++- src/osgPlugins/fbx/fbxReader.h | 100 +++---- 8 files changed, 483 insertions(+), 187 deletions(-) diff --git a/src/osgPlugins/fbx/ReaderWriterFBX.cpp b/src/osgPlugins/fbx/ReaderWriterFBX.cpp index 5e5895f4b..9bc26f322 100644 --- a/src/osgPlugins/fbx/ReaderWriterFBX.cpp +++ b/src/osgPlugins/fbx/ReaderWriterFBX.cpp @@ -255,7 +255,7 @@ ReaderWriterFBX::readNode(const std::string& filenameInit, pScene->SetCurrentTake(pScene->GetCurrentTakeName()); bool useFbxRoot = false; - bool lightmapTextures = false; + bool lightmapTextures = false; if (options) { std::istringstream iss(options->getOptionString()); @@ -288,40 +288,40 @@ ReaderWriterFBX::readNode(const std::string& filenameInit, std::set fbxSkeletons; findLinkedFbxSkeletonNodes(pNode, fbxSkeletons); - OsgFbxReader::AuthoringTool authoringTool = OsgFbxReader::UNKNOWN; - if (KFbxDocumentInfo* pDocInfo = pScene->GetDocumentInfo()) - { - struct ToolName - { - const char* name; - OsgFbxReader::AuthoringTool tool; - }; + OsgFbxReader::AuthoringTool authoringTool = OsgFbxReader::UNKNOWN; + if (KFbxDocumentInfo* pDocInfo = pScene->GetDocumentInfo()) + { + struct ToolName + { + const char* name; + OsgFbxReader::AuthoringTool tool; + }; - ToolName authoringTools[] = { - {"OpenSceneGraph", OsgFbxReader::OPENSCENEGRAPH}, - {"3ds Max", OsgFbxReader::AUTODESK_3DSTUDIO_MAX} - }; + ToolName authoringTools[] = { + {"OpenSceneGraph", OsgFbxReader::OPENSCENEGRAPH}, + {"3ds Max", OsgFbxReader::AUTODESK_3DSTUDIO_MAX} + }; - fbxString appName = pDocInfo->LastSaved_ApplicationName.Get(); + fbxString appName = pDocInfo->LastSaved_ApplicationName.Get(); - for (int i = 0; i < sizeof(authoringTools) / sizeof(authoringTools[0]); ++i) - { - if (0 == _strnicmp(appName, authoringTools[i].name, strlen(authoringTools[i].name))) - { - authoringTool = authoringTools[i].tool; - break; - } - } - } + for (int i = 0; i < sizeof(authoringTools) / sizeof(authoringTools[0]); ++i) + { + if (0 == _strnicmp(appName, authoringTools[i].name, strlen(authoringTools[i].name))) + { + authoringTool = authoringTools[i].tool; + break; + } + } + } - OsgFbxReader reader(*pSdkManager, - *pScene, - fbxMaterialToOsgStateSet, - fbxSkeletons, - *localOptions, - authoringTool, - lightmapTextures); + OsgFbxReader reader(*pSdkManager, + *pScene, + fbxMaterialToOsgStateSet, + fbxSkeletons, + *localOptions, + authoringTool, + lightmapTextures); ReadResult res = reader.readFbxNode(pNode, bIsBone, nLightCount); @@ -473,18 +473,18 @@ osgDB::ReaderWriter::WriteResult ReaderWriterFBX::writeNode( const_cast(node).accept(writerNodeVisitor); } - KFbxDocumentInfo* pDocInfo = pScene->GetDocumentInfo(); - bool needNewDocInfo = pDocInfo != NULL; - if (needNewDocInfo) - { - pDocInfo = KFbxDocumentInfo::Create(pSdkManager, ""); - } - pDocInfo->LastSaved_ApplicationName.Set(fbxString("OpenSceneGraph")); - pDocInfo->LastSaved_ApplicationVersion.Set(fbxString(osgGetVersion())); - if (needNewDocInfo) - { - pScene->SetDocumentInfo(pDocInfo); - } + KFbxDocumentInfo* pDocInfo = pScene->GetDocumentInfo(); + bool needNewDocInfo = pDocInfo != NULL; + if (needNewDocInfo) + { + pDocInfo = KFbxDocumentInfo::Create(pSdkManager, ""); + } + pDocInfo->LastSaved_ApplicationName.Set(fbxString("OpenSceneGraph")); + pDocInfo->LastSaved_ApplicationVersion.Set(fbxString(osgGetVersion())); + if (needNewDocInfo) + { + pScene->SetDocumentInfo(pDocInfo); + } KFbxExporter* lExporter = KFbxExporter::Create(pSdkManager, ""); pScene->GetGlobalSettings().SetAxisSystem(KFbxAxisSystem::eOpenGL); diff --git a/src/osgPlugins/fbx/ReaderWriterFBX.h b/src/osgPlugins/fbx/ReaderWriterFBX.h index a7f059a09..ca91f5ef7 100644 --- a/src/osgPlugins/fbx/ReaderWriterFBX.h +++ b/src/osgPlugins/fbx/ReaderWriterFBX.h @@ -16,7 +16,7 @@ public: supportsExtension("fbx", "FBX format"); supportsOption("Embedded", "(Write option) Embed textures in FBX file"); supportsOption("UseFbxRoot", "(Read/write option) If the source OSG root node is a simple group with no stateset, the writer will put its children directly under the FBX root, and vice-versa for reading"); - supportsOption("LightmapTextures", "(Read option) Interpret texture maps as overriding the lighting. 3D Studio Max may export files that should be interpreted in this way."); + supportsOption("LightmapTextures", "(Read option) Interpret texture maps as overriding the lighting. 3D Studio Max may export files that should be interpreted in this way."); } const char* className() const { return "FBX reader/writer"; } diff --git a/src/osgPlugins/fbx/fbxMaterialToOsgStateSet.cpp b/src/osgPlugins/fbx/fbxMaterialToOsgStateSet.cpp index af8ca9d21..8183e25b8 100644 --- a/src/osgPlugins/fbx/fbxMaterialToOsgStateSet.cpp +++ b/src/osgPlugins/fbx/fbxMaterialToOsgStateSet.cpp @@ -14,8 +14,8 @@ static osg::Texture::WrapMode convertWrap(KFbxTexture::EWrapMode wrap) StateSetContent FbxMaterialToOsgStateSet::convert(const KFbxSurfaceMaterial* pFbxMat) { - KFbxMaterialMap::const_iterator it = _kFbxMaterialMap.find(pFbxMat); - if (it != _kFbxMaterialMap.end()) + FbxMaterialMap::const_iterator it = _fbxMaterialMap.find(pFbxMat); + if (it != _fbxMaterialMap.end()) return it->second; static int nbMat = 0; @@ -31,9 +31,9 @@ FbxMaterialToOsgStateSet::convert(const KFbxSurfaceMaterial* pFbxMat) StateSetContent result; - result.material = pOsgMat; + result.material = pOsgMat; - fbxString shadingModel = pFbxMat->GetShadingModel().Get(); + fbxString shadingModel = pFbxMat->GetShadingModel().Get(); const KFbxSurfaceLambert* pFbxLambert = dynamic_cast(pFbxMat); @@ -67,8 +67,6 @@ FbxMaterialToOsgStateSet::convert(const KFbxSurfaceMaterial* pFbxMat) KFbxTexture* lTexture = KFbxCast(lOpacityProperty.GetSrcObject(KFbxTexture::ClassId, lTextureIndex)); if (lTexture) { - // TODO: if texture image does NOT have an alpha channel, should it be added? - pOsgOpacityTex = fbxTextureToOsgTexture(lTexture); result.opacityTexture = pOsgOpacityTex.release(); result.opacityChannel = lTexture->UVSet.Get(); @@ -120,7 +118,7 @@ FbxMaterialToOsgStateSet::convert(const KFbxSurfaceMaterial* pFbxMat) //For now only allow 1 texture break; - } + } } if (pFbxLambert) @@ -170,19 +168,19 @@ FbxMaterialToOsgStateSet::convert(const KFbxSurfaceMaterial* pFbxMat) } } - if (_lightmapTextures) - { - // if using an emission map then adjust material properties accordingly... - if (result.emissiveTexture) - { - osg::Vec4 diffuse = pOsgMat->getDiffuse(osg::Material::FRONT_AND_BACK); - pOsgMat->setEmission(osg::Material::FRONT_AND_BACK, diffuse); - pOsgMat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0,0,0,diffuse.a())); - pOsgMat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0,0,0,diffuse.a())); - } - } + if (_lightmapTextures) + { + // if using an emission map then adjust material properties accordingly... + if (result.emissiveTexture) + { + osg::Vec4 diffuse = pOsgMat->getDiffuse(osg::Material::FRONT_AND_BACK); + pOsgMat->setEmission(osg::Material::FRONT_AND_BACK, diffuse); + pOsgMat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0,0,0,diffuse.a())); + pOsgMat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0,0,0,diffuse.a())); + } + } - _kFbxMaterialMap.insert(KFbxMaterialMap::value_type(pFbxMat, result)); + _fbxMaterialMap.insert(FbxMaterialMap::value_type(pFbxMat, result)); return result; } @@ -216,7 +214,7 @@ FbxMaterialToOsgStateSet::fbxTextureToOsgTexture(const KFbxTexture* fbx) void FbxMaterialToOsgStateSet::checkInvertTransparency() { int zeroAlpha = 0, oneAlpha = 0; - for (KFbxMaterialMap::const_iterator it = _kFbxMaterialMap.begin(); it != _kFbxMaterialMap.end(); ++it) + for (FbxMaterialMap::const_iterator it = _fbxMaterialMap.begin(); it != _fbxMaterialMap.end(); ++it) { const osg::Material* pMaterial = it->second.material.get(); float alpha = pMaterial->getDiffuse(osg::Material::FRONT).a(); @@ -234,7 +232,7 @@ void FbxMaterialToOsgStateSet::checkInvertTransparency() { //Transparency values seem to be back to front so invert them. - for (KFbxMaterialMap::const_iterator it = _kFbxMaterialMap.begin(); it != _kFbxMaterialMap.end(); ++it) + for (FbxMaterialMap::const_iterator it = _fbxMaterialMap.begin(); it != _fbxMaterialMap.end(); ++it) { osg::Material* pMaterial = it->second.material.get(); osg::Vec4 diffuse = pMaterial->getDiffuse(osg::Material::FRONT); diff --git a/src/osgPlugins/fbx/fbxMaterialToOsgStateSet.h b/src/osgPlugins/fbx/fbxMaterialToOsgStateSet.h index fa70fdd77..b69d2c3e0 100644 --- a/src/osgPlugins/fbx/fbxMaterialToOsgStateSet.h +++ b/src/osgPlugins/fbx/fbxMaterialToOsgStateSet.h @@ -18,20 +18,20 @@ struct StateSetContent { - StateSetContent() - : diffuseFactor(1.0), - opacityFactor(1.0), - reflectionFactor(1.0), - emissiveFactor(1.0) - { - } + StateSetContent() + : diffuseFactor(1.0), + opacityFactor(1.0), + reflectionFactor(1.0), + emissiveFactor(1.0) + { + } - osg::ref_ptr material; + osg::ref_ptr material; - // textures objects... - osg::ref_ptr diffuseTexture; + // textures objects... + osg::ref_ptr diffuseTexture; osg::ref_ptr opacityTexture; - osg::ref_ptr reflectionTexture; + osg::ref_ptr reflectionTexture; osg::ref_ptr emissiveTexture; // more textures types here... @@ -45,23 +45,23 @@ struct StateSetContent // combining factors... double diffuseFactor; double opacityFactor; - double reflectionFactor; + double reflectionFactor; double emissiveFactor; // more combining factors here... // texture units (eventually used for each texture map)... - enum TextureUnit - { - DIFFUSE_TEXTURE_UNIT = 0, - OPACITY_TEXTURE_UNIT, - REFLECTION_TEXTURE_UNIT, - EMISSIVE_TEXTURE_UNIT, - // more texture units here... - }; + enum TextureUnit + { + DIFFUSE_TEXTURE_UNIT = 0, + OPACITY_TEXTURE_UNIT, + REFLECTION_TEXTURE_UNIT, + EMISSIVE_TEXTURE_UNIT, + // more texture units here... + }; }; //We use the pointers set by the importer to not duplicate materials and textures. -typedef std::map KFbxMaterialMap; +typedef std::map FbxMaterialMap; //This map is used to not load the same image more than 1 time. typedef std::map ImageMap; @@ -76,18 +76,18 @@ public: FbxMaterialToOsgStateSet(const std::string& dir, const osgDB::Options* options, bool lightmapTextures) : _options(options), _dir(dir), - _lightmapTextures(lightmapTextures){} + _lightmapTextures(lightmapTextures){} void checkInvertTransparency(); private: //Convert a texture fbx to an osg texture. osg::ref_ptr fbxTextureToOsgTexture(const KFbxTexture* pOsgTex); - KFbxMaterialMap _kFbxMaterialMap; + FbxMaterialMap _fbxMaterialMap; ImageMap _imageMap; const osgDB::Options* _options; const std::string _dir; - bool _lightmapTextures; + bool _lightmapTextures; }; diff --git a/src/osgPlugins/fbx/fbxRAnimation.cpp b/src/osgPlugins/fbx/fbxRAnimation.cpp index 848c7f380..ac3a79115 100644 --- a/src/osgPlugins/fbx/fbxRAnimation.cpp +++ b/src/osgPlugins/fbx/fbxRAnimation.cpp @@ -72,6 +72,109 @@ void readKeys(KFbxAnimCurve* curveX, KFbxAnimCurve* curveY, KFbxAnimCurve* curve } } +void readKeys(KFbxAnimCurve* curveX, KFbxAnimCurve* curveY, KFbxAnimCurve* curveZ, + const fbxDouble3& defaultValue, + std::vector& keyFrameCntr, float scalar = 1.0f) +{ + KFbxAnimCurve* curves[3] = {curveX, curveY, curveZ}; + + typedef std::set TimeSet; + typedef std::map TimeValueMap; + TimeSet times; + TimeValueMap curveTimeMap[3]; + + for (int nCurve = 0; nCurve < 3; ++nCurve) + { + KFbxAnimCurve* pCurve = curves[nCurve]; + + int nKeys = pCurve ? pCurve->KeyGetCount() : 0; + + if (!nKeys) + { + times.insert(0.0); + curveTimeMap[nCurve][0.0] = osgAnimation::FloatCubicBezier(defaultValue[nCurve] * scalar); + } + + for (int i = 0; i < nKeys; ++i) + { + double fTime = pCurve->KeyGetTime(i).GetSecondDouble(); + float val = pCurve->KeyGetValue(i); + times.insert(fTime); + KFCurveTangeantInfo leftTangent = pCurve->KeyGetLeftDerivativeInfo(i); + KFCurveTangeantInfo rightTangent = pCurve->KeyGetRightDerivativeInfo(i); + + if (i > 0) + { + leftTangent.mDerivative *= fTime - pCurve->KeyGetTime(i - 1).GetSecondDouble(); + } + if (i + 1 < pCurve->KeyGetCount()) + { + rightTangent.mDerivative *= pCurve->KeyGetTime(i + 1).GetSecondDouble() - fTime; + } + + osgAnimation::FloatCubicBezier key( + val * scalar, + (val + leftTangent.mDerivative / 3.0) * scalar, + (val + rightTangent.mDerivative / 3.0) * scalar); + + curveTimeMap[nCurve][fTime] = key; + } + } + + for (TimeSet::iterator it = times.begin(); it != times.end(); ++it) + { + double fTime = *it; + osg::Vec3 val, cpIn, cpOut; + for (int i = 0; i < 3; ++i) + { + if (curveTimeMap[i].empty()) continue; + + TimeValueMap::iterator lb = curveTimeMap[i].lower_bound(fTime); + if (lb == curveTimeMap[i].end()) --lb; + val[i] = lb->second.getPosition(); + cpIn[i] = lb->second.getControlPointIn(); + cpOut[i] = lb->second.getControlPointOut(); + } + + keyFrameCntr.push_back(osgAnimation::Vec3CubicBezierKeyframe(fTime, + osgAnimation::Vec3CubicBezier(val, cpIn, cpOut))); + } +} + +// osgAnimation requires control points to be in a weird order. This function +// reorders them from the conventional order to osgAnimation order. +template +void reorderControlPoints(osgAnimation::TemplateKeyframeContainer >& vkfCont) +{ + if (vkfCont.size() <= 1) + { + if (vkfCont.size() == 1) + { + osgAnimation::TemplateCubicBezier tcb = vkfCont.front().getValue(); + T inCP = tcb.getControlPointIn(); + tcb.setControlPointIn(tcb.getControlPointOut()); + tcb.setControlPointOut(inCP); + vkfCont.front().setValue(tcb); + } + return; + } + + osgAnimation::TemplateCubicBezier first = vkfCont.front().getValue(); + + for (unsigned i = 0; i < vkfCont.size() - 1; ++i) + { + osgAnimation::TemplateCubicBezier tcb = vkfCont[i].getValue(); + tcb.setControlPointIn(tcb.getControlPointOut()); + tcb.setControlPointOut(vkfCont[i + 1].getValue().getControlPointIn()); + vkfCont[i].setValue(tcb); + } + + osgAnimation::TemplateCubicBezier last = vkfCont.back().getValue(); + last.setControlPointIn(last.getControlPointOut()); + last.setControlPointOut(first.getControlPointIn()); + vkfCont.back().setValue(last); +} + osgAnimation::Channel* readFbxChannels(KFbxAnimCurve* curveX, KFbxAnimCurve* curveY, KFbxAnimCurve* curveZ, const fbxDouble3& defaultValue, @@ -84,13 +187,44 @@ osgAnimation::Channel* readFbxChannels(KFbxAnimCurve* curveX, KFbxAnimCurve* cur return 0; } - osgAnimation::Vec3LinearChannel* pChannel = new osgAnimation::Vec3LinearChannel; - osgAnimation::Vec3KeyframeContainer* pKeyFrameCntr = - pChannel->getOrCreateSampler()->getOrCreateKeyframeContainer(); + KFbxAnimCurveDef::EInterpolationType interpolationType = KFbxAnimCurveDef::eINTERPOLATION_CONSTANT; + if (curveX && curveX->KeyGetCount()) interpolationType = curveX->KeyGetInterpolation(0); + else if (curveY && curveY->KeyGetCount()) interpolationType = curveY->KeyGetInterpolation(0); + else if (curveZ && curveZ->KeyGetCount()) interpolationType = curveZ->KeyGetInterpolation(0); + + osgAnimation::Channel* pChannel = 0; + + if (interpolationType == KFbxAnimCurveDef::eINTERPOLATION_CUBIC) + { + osgAnimation::Vec3CubicBezierKeyframeContainer* pKeyFrameCntr = new osgAnimation::Vec3CubicBezierKeyframeContainer; + readKeys(curveX, curveY, curveZ, defaultValue, *pKeyFrameCntr); + reorderControlPoints(*pKeyFrameCntr); + + osgAnimation::Vec3CubicBezierChannel* pCubicChannel = new osgAnimation::Vec3CubicBezierChannel; + pCubicChannel->getOrCreateSampler()->setKeyframeContainer(pKeyFrameCntr); + pChannel = pCubicChannel; + } + else + { + osgAnimation::Vec3KeyframeContainer* pKeyFrameCntr = new osgAnimation::Vec3KeyframeContainer; + readKeys(curveX, curveY, curveZ, defaultValue, *pKeyFrameCntr); + + if (interpolationType == KFbxAnimCurveDef::eINTERPOLATION_CONSTANT) + { + osgAnimation::Vec3StepChannel* pStepChannel = new osgAnimation::Vec3StepChannel; + pStepChannel->getOrCreateSampler()->setKeyframeContainer(pKeyFrameCntr); + pChannel = pStepChannel; + } + else + { + osgAnimation::Vec3LinearChannel* pLinearChannel = new osgAnimation::Vec3LinearChannel; + pLinearChannel->getOrCreateSampler()->setKeyframeContainer(pKeyFrameCntr); + pChannel = pLinearChannel; + } + } pChannel->setTargetName(targetName); pChannel->setName(channelName); - readKeys(curveX, curveY, curveZ, defaultValue, *pKeyFrameCntr); return pChannel; } @@ -145,13 +279,15 @@ osgAnimation::Channel* readFbxChannelsQuat( osgAnimation::Animation* addChannels( osgAnimation::Channel* pTranslationChannel, - osgAnimation::Channel* pRotationChannel, + osgAnimation::Channel* pRotationChannels[], osgAnimation::Channel* pScaleChannel, osg::ref_ptr& pAnimManager, const char* pTakeName) { if (pTranslationChannel || - pRotationChannel || + pRotationChannels[0] || + pRotationChannels[1] || + pRotationChannels[2] || pScaleChannel) { if (!pAnimManager) pAnimManager = new osgAnimation::BasicAnimationManager; @@ -174,7 +310,9 @@ osgAnimation::Animation* addChannels( } if (pTranslationChannel) pAnimation->addChannel(pTranslationChannel); - if (pRotationChannel) pAnimation->addChannel(pRotationChannel); + if (pRotationChannels[0]) pAnimation->addChannel(pRotationChannels[0]); + if (pRotationChannels[1]) pAnimation->addChannel(pRotationChannels[1]); + if (pRotationChannels[2]) pAnimation->addChannel(pRotationChannels[2]); if (pScaleChannel) pAnimation->addChannel(pScaleChannel); @@ -184,26 +322,122 @@ osgAnimation::Animation* addChannels( return 0; } -osgAnimation::Animation* readFbxAnimation(KFbxNode* pNode, - KFbxAnimLayer* pAnimLayer, const char* pTakeName, const char* targetName, - osg::ref_ptr& pAnimManager) +void readFbxRotationAnimation(osgAnimation::Channel* channels[3], + KFbxNode* pNode, + KFbxAnimLayer* pAnimLayer, const char* targetName) { + if (!pNode->LclRotation.IsValid()) + { + return; + } + ERotationOrder rotOrder = pNode->RotationOrder.IsValid() ? pNode->RotationOrder.Get() : eEULER_XYZ; - osgAnimation::Channel* pTranslationChannel = 0; - osgAnimation::Channel* pRotationChannel = 0; - - if (pNode->LclRotation.IsValid()) + if (pNode->QuaternionInterpolate.IsValid() && pNode->QuaternionInterpolate.Get()) { - fbxDouble3 fbxBaseValue = pNode->LclRotation.Get(); - - pRotationChannel = readFbxChannelsQuat( + channels[0] = readFbxChannelsQuat( pNode->LclRotation.GetCurve(pAnimLayer, KFCURVENODE_R_X), pNode->LclRotation.GetCurve(pAnimLayer, KFCURVENODE_R_Y), pNode->LclRotation.GetCurve(pAnimLayer, KFCURVENODE_R_Z), pNode->LclRotation.Get(), targetName, rotOrder); } + else + { + char* curveNames[3] = {KFCURVENODE_R_X, KFCURVENODE_R_Y, KFCURVENODE_R_Z}; + + fbxDouble3 fbxPropValue = pNode->LclRotation.Get(); + fbxPropValue[0] = osg::DegreesToRadians(fbxPropValue[0]); + fbxPropValue[1] = osg::DegreesToRadians(fbxPropValue[1]); + fbxPropValue[2] = osg::DegreesToRadians(fbxPropValue[2]); + + for (int i = 0; i < 3; ++i) + { + KFbxAnimCurve* curve = pNode->LclRotation.GetCurve(pAnimLayer, curveNames[i]); + if (!curve) + { + continue; + } + + KFbxAnimCurveDef::EInterpolationType interpolationType = KFbxAnimCurveDef::eINTERPOLATION_CONSTANT; + if (curve && curve->KeyGetCount()) interpolationType = curve->KeyGetInterpolation(0); + + if (interpolationType == KFbxAnimCurveDef::eINTERPOLATION_CUBIC) + { + osgAnimation::FloatCubicBezierKeyframeContainer* pKeyFrameCntr = new osgAnimation::FloatCubicBezierKeyframeContainer; + + for (int j = 0; j < curve->KeyGetCount(); ++j) + { + double fTime = curve->KeyGetTime(j).GetSecondDouble(); + float angle = curve->KeyGetValue(j); + //KFbxAnimCurveDef::EWeightedMode tangentWeightMode = curve->KeyGet(j).GetTangentWeightMode(); + + KFCurveTangeantInfo leftTangent = curve->KeyGetLeftDerivativeInfo(j); + KFCurveTangeantInfo rightTangent = curve->KeyGetRightDerivativeInfo(j); + if (j > 0) + { + leftTangent.mDerivative *= fTime - curve->KeyGetTime(j - 1).GetSecondDouble(); + } + if (j + 1 < curve->KeyGetCount()) + { + rightTangent.mDerivative *= curve->KeyGetTime(j + 1).GetSecondDouble() - fTime; + } + osgAnimation::FloatCubicBezier key( + osg::DegreesToRadians(angle), + osg::DegreesToRadians(angle + leftTangent.mDerivative / 3.0), + osg::DegreesToRadians(angle - rightTangent.mDerivative / 3.0)); + + pKeyFrameCntr->push_back(osgAnimation::FloatCubicBezierKeyframe( + fTime, + key)); + } + + reorderControlPoints(*pKeyFrameCntr); + + osgAnimation::FloatCubicBezierChannel* pCubicChannel = new osgAnimation::FloatCubicBezierChannel; + pCubicChannel->getOrCreateSampler()->setKeyframeContainer(pKeyFrameCntr); + channels[i] = pCubicChannel; + } + else + { + osgAnimation::FloatKeyframeContainer* keys = new osgAnimation::FloatKeyframeContainer; + + for (int j = 0; j < curve->KeyGetCount(); ++j) + { + KFbxAnimCurveKey key = curve->KeyGet(j); + keys->push_back(osgAnimation::FloatKeyframe( + key.GetTime().GetSecondDouble(), + static_cast(osg::DegreesToRadians(key.GetValue())))); + } + + if (interpolationType == KFbxAnimCurveDef::eINTERPOLATION_CONSTANT) + { + osgAnimation::FloatStepChannel* pStepChannel = new osgAnimation::FloatStepChannel(); + pStepChannel->getOrCreateSampler()->setKeyframeContainer(keys); + channels[i] = pStepChannel; + } + else + { + osgAnimation::FloatLinearChannel* pLinearChannel = new osgAnimation::FloatLinearChannel(); + pLinearChannel->getOrCreateSampler()->setKeyframeContainer(keys); + channels[i] = pLinearChannel; + } + } + + channels[i]->setTargetName(targetName); + channels[i]->setName(std::string("rotate") + curveNames[i]); + } + } +} + +osgAnimation::Animation* readFbxAnimation(KFbxNode* pNode, + KFbxAnimLayer* pAnimLayer, const char* pTakeName, const char* targetName, + osg::ref_ptr& pAnimManager) +{ + osgAnimation::Channel* pTranslationChannel = 0; + osgAnimation::Channel* pRotationChannels[3] = {0}; + readFbxRotationAnimation(pRotationChannels, pNode, pAnimLayer, targetName); + if (pNode->LclTranslation.IsValid()) { @@ -218,7 +452,7 @@ osgAnimation::Animation* readFbxAnimation(KFbxNode* pNode, osgAnimation::Channel* pScaleChannel = readFbxChannels( pNode->LclScaling, pAnimLayer, targetName, "scale"); - return addChannels(pTranslationChannel, pRotationChannel, pScaleChannel, pAnimManager, pTakeName); + return addChannels(pTranslationChannel, pRotationChannels, pScaleChannel, pAnimManager, pTakeName); } std::string OsgFbxReader::readFbxAnimation(KFbxNode* pNode, const char* targetName) @@ -239,7 +473,7 @@ std::string OsgFbxReader::readFbxAnimation(KFbxNode* pNode, const char* targetNa { KFbxAnimLayer* pAnimLayer = pAnimStack->GetMember(FBX_TYPE(KFbxAnimLayer), j); - if (osgAnimation::Animation* pAnimation = ::readFbxAnimation( + if (osgAnimation::Animation* pAnimation = ::readFbxAnimation( pNode, pAnimLayer, pTakeName, targetName, pAnimationManager)) { result = targetName; diff --git a/src/osgPlugins/fbx/fbxRMesh.cpp b/src/osgPlugins/fbx/fbxRMesh.cpp index a396d57aa..8052ea548 100644 --- a/src/osgPlugins/fbx/fbxRMesh.cpp +++ b/src/osgPlugins/fbx/fbxRMesh.cpp @@ -148,7 +148,7 @@ osg::Geometry* getGeometry(osg::Geode* pGeode, GeometryMap& geometryMap, // more here... bool bColor, const osgDB::Options& options, - bool lightmapTextures) + bool lightmapTextures) { GeometryMap::iterator it = geometryMap.find(mti); @@ -202,19 +202,19 @@ osg::Geometry* getGeometry(osg::Geode* pGeode, GeometryMap& geometryMap, { stateSet->setTextureAttributeAndModes(StateSetContent::DIFFUSE_TEXTURE_UNIT, ssc.diffuseTexture.get()); - if (lightmapTextures) - { - double factor = ssc.diffuseFactor; - osg::ref_ptr texenv = new osg::TexEnvCombine(); - texenv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); - texenv->setSource0_RGB(osg::TexEnvCombine::TEXTURE); - texenv->setSource1_RGB(osg::TexEnvCombine::PREVIOUS); - texenv->setSource2_RGB(osg::TexEnvCombine::CONSTANT); - texenv->setConstantColor(osg::Vec4(factor, factor, factor, factor)); - stateSet->setTextureAttributeAndModes(StateSetContent::DIFFUSE_TEXTURE_UNIT, texenv.get(), osg::StateAttribute::ON); - } + if (lightmapTextures) + { + double factor = ssc.diffuseFactor; + osg::ref_ptr texenv = new osg::TexEnvCombine(); + texenv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); + texenv->setSource0_RGB(osg::TexEnvCombine::TEXTURE); + texenv->setSource1_RGB(osg::TexEnvCombine::PREVIOUS); + texenv->setSource2_RGB(osg::TexEnvCombine::CONSTANT); + texenv->setConstantColor(osg::Vec4(factor, factor, factor, factor)); + stateSet->setTextureAttributeAndModes(StateSetContent::DIFFUSE_TEXTURE_UNIT, texenv.get(), osg::StateAttribute::ON); + } - // setup transparency + // setup transparency if (!transparent && ssc.diffuseTexture->getImage()) transparent = ssc.diffuseTexture->getImage()->isImageTranslucent(); } @@ -225,8 +225,8 @@ osg::Geometry* getGeometry(osg::Geode* pGeode, GeometryMap& geometryMap, stateSet->setTextureAttributeAndModes(StateSetContent::OPACITY_TEXTURE_UNIT, ssc.opacityTexture.get()); // setup combiner for factor... - //In practice factor will always be zero, hence the RGB of the - //opacity map will be ignored. The alpha will modulate the previous alpha. + //In practice factor will always be zero, hence the RGB of the + //opacity map will be ignored. The alpha will modulate the previous alpha. double factor = ssc.opacityFactor; osg::ref_ptr texenv = new osg::TexEnvCombine(); texenv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); @@ -266,7 +266,7 @@ osg::Geometry* getGeometry(osg::Geode* pGeode, GeometryMap& geometryMap, if (ssc.emissiveTexture) { stateSet->setTextureAttributeAndModes(StateSetContent::EMISSIVE_TEXTURE_UNIT, ssc.emissiveTexture.get()); - } + } // add more texture maps here... @@ -483,8 +483,8 @@ const KFbxLayerElementUV* getUVElementForChannel(std::string pUVChannel, KFbxMes } osgDB::ReaderWriter::ReadResult OsgFbxReader::readMesh( - KFbxNode* pNode, - KFbxMesh* fbxMesh, + KFbxNode* pNode, + KFbxMesh* fbxMesh, std::vector& stateSetList, const char* szName) { @@ -515,7 +515,7 @@ osgDB::ReaderWriter::ReadResult OsgFbxReader::readMesh( pFbxColors = pFbxLayer->GetVertexColors(); if (!pFbxMaterials) pFbxMaterials = pFbxLayer->GetMaterials(); - } + } // look for UV elements (diffuse, opacity, reflection, emissive, ...) and get their channels names... std::string diffuseChannel = getUVChannelForTextureMap(stateSetList, KFbxSurfaceMaterial::sDiffuse); @@ -576,7 +576,7 @@ osgDB::ReaderWriter::ReadResult OsgFbxReader::readMesh( // more UV elements here... pFbxColors != 0, options, - lightmapTextures); + lightmapTextures); osg::Array* pVertices = pGeometry->getVertexArray(); osg::Array* pNormals = pGeometry->getNormalArray(); @@ -636,9 +636,9 @@ osgDB::ReaderWriter::ReadResult OsgFbxReader::readMesh( addVec2ArrayElement(*pTexCoords_opacity, getElement(pFbxUVs_opacity, fbxMesh, i, j, nVertex)); } - // Only spherical reflection maps are supported (so do not add coordinates for the reflection map) + // Only spherical reflection maps are supported (so do not add coordinates for the reflection map) - if (pTexCoords_emissive && (pTexCoords_emissive != pTexCoords_opacity) && (pTexCoords_emissive != pTexCoords_diffuse)) + if (pTexCoords_emissive && (pTexCoords_emissive != pTexCoords_opacity) && (pTexCoords_emissive != pTexCoords_diffuse)) { addVec2ArrayElement(*pTexCoords_emissive, getElement(pFbxUVs_emissive, fbxMesh, i, 0, nVertex0)); addVec2ArrayElement(*pTexCoords_emissive, getElement(pFbxUVs_emissive, fbxMesh, i, j - 1, nVertex - 1)); diff --git a/src/osgPlugins/fbx/fbxRNode.cpp b/src/osgPlugins/fbx/fbxRNode.cpp index 68a76b394..26ba1ee18 100644 --- a/src/osgPlugins/fbx/fbxRNode.cpp +++ b/src/osgPlugins/fbx/fbxRNode.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -168,27 +169,88 @@ void readTranslationElement(KFbxTypedProperty& prop, } } +void getRotationOrder(ERotationOrder fbxRotOrder, int order[/*3*/]) +{ + switch (fbxRotOrder) + { + case eEULER_XZY: + order[0] = 0; order[1] = 2; order[2] = 1; + break; + case eEULER_YZX: + order[0] = 1; order[1] = 2; order[2] = 0; + break; + case eEULER_YXZ: + order[0] = 1; order[1] = 0; order[2] = 2; + break; + case eEULER_ZXY: + order[0] = 2; order[1] = 0; order[2] = 1; + break; + case eEULER_ZYX: + order[0] = 2; order[1] = 1; order[2] = 0; + break; + default: + order[0] = 0; order[1] = 1; order[2] = 2; + } +} + void readRotationElement(KFbxTypedProperty& prop, ERotationOrder fbxRotOrder, + bool quatInterpolate, osgAnimation::UpdateMatrixTransform* pUpdate, osg::Matrix& staticTransform) { - osg::Quat quat = makeQuat(prop.Get(), fbxRotOrder); - if (prop.GetKFCurve(KFCURVENODE_R_X) || prop.GetKFCurve(KFCURVENODE_R_Y) || prop.GetKFCurve(KFCURVENODE_R_Z)) { - if (!staticTransform.isIdentity()) + if (quatInterpolate) { - pUpdate->getStackedTransforms().push_back(new osgAnimation::StackedMatrixElement(staticTransform)); - staticTransform.makeIdentity(); + if (!staticTransform.isIdentity()) + { + pUpdate->getStackedTransforms().push_back( + new osgAnimation::StackedMatrixElement(staticTransform)); + staticTransform.makeIdentity(); + } + pUpdate->getStackedTransforms().push_back(new osgAnimation::StackedQuaternionElement( + "quaternion", makeQuat(prop.Get(), fbxRotOrder))); + } + else + { + char* curveNames[3] = {KFCURVENODE_R_X, KFCURVENODE_R_Y, KFCURVENODE_R_Z}; + osg::Vec3 axes[3] = {osg::Vec3(1,0,0), osg::Vec3(0,1,0), osg::Vec3(0,0,1)}; + + fbxDouble3 fbxPropValue = prop.Get(); + fbxPropValue[0] = osg::DegreesToRadians(fbxPropValue[0]); + fbxPropValue[1] = osg::DegreesToRadians(fbxPropValue[1]); + fbxPropValue[2] = osg::DegreesToRadians(fbxPropValue[2]); + + int order[3] = {0, 1, 2}; + getRotationOrder(fbxRotOrder, order); + + for (int i = 0; i < 3; ++i) + { + int j = order[2-i]; + if (prop.GetKFCurve(curveNames[j])) + { + if (!staticTransform.isIdentity()) + { + pUpdate->getStackedTransforms().push_back(new osgAnimation::StackedMatrixElement(staticTransform)); + staticTransform.makeIdentity(); + } + + pUpdate->getStackedTransforms().push_back(new osgAnimation::StackedRotateAxisElement( + std::string("rotate") + curveNames[j], axes[j], fbxPropValue[j])); + } + else + { + staticTransform.preMultRotate(osg::Quat(fbxPropValue[j], axes[j])); + } + } } - pUpdate->getStackedTransforms().push_back(new osgAnimation::StackedQuaternionElement("quaternion", quat)); } else { - staticTransform.preMultRotate(quat); + staticTransform.preMultRotate(makeQuat(prop.Get(), fbxRotOrder)); } } @@ -244,7 +306,9 @@ void readUpdateMatrixTransform(osgAnimation::UpdateMatrixTransform* pUpdate, KFb staticTransform.preMultRotate(makeQuat(pNode->PreRotation.Get(), fbxRotOrder)); } - readRotationElement(pNode->LclRotation, fbxRotOrder, pUpdate, staticTransform); + readRotationElement(pNode->LclRotation, fbxRotOrder, + pNode->QuaternionInterpolate.IsValid() && pNode->QuaternionInterpolate.Get(), + pUpdate, staticTransform); if (rotationActive) { diff --git a/src/osgPlugins/fbx/fbxReader.h b/src/osgPlugins/fbx/fbxReader.h index 2a2710a64..48c09c00e 100644 --- a/src/osgPlugins/fbx/fbxReader.h +++ b/src/osgPlugins/fbx/fbxReader.h @@ -8,9 +8,9 @@ namespace osgAnimation { - class AnimationManagerBase; - class RigGeometry; - class Skeleton; + class AnimationManagerBase; + class RigGeometry; + class Skeleton; } typedef std::map, osg::Matrix> BindMatrixMap; @@ -18,61 +18,61 @@ typedef std::map, osg::Matrix> class OsgFbxReader { public: - KFbxSdkManager& pSdkManager; - KFbxScene& fbxScene; - osg::ref_ptr pAnimationManager; - FbxMaterialToOsgStateSet& fbxMaterialToOsgStateSet; - std::map nodeMap; - BindMatrixMap boneBindMatrices; - const std::set& fbxSkeletons; - std::map skeletonMap; - const osgDB::Options& options; - bool lightmapTextures; + KFbxSdkManager& pSdkManager; + KFbxScene& fbxScene; + osg::ref_ptr pAnimationManager; + FbxMaterialToOsgStateSet& fbxMaterialToOsgStateSet; + std::map nodeMap; + BindMatrixMap boneBindMatrices; + const std::set& fbxSkeletons; + std::map skeletonMap; + const osgDB::Options& options; + bool lightmapTextures; - enum AuthoringTool - { - UNKNOWN, - OPENSCENEGRAPH, - AUTODESK_3DSTUDIO_MAX - } authoringTool; + enum AuthoringTool + { + UNKNOWN, + OPENSCENEGRAPH, + AUTODESK_3DSTUDIO_MAX + } authoringTool; - OsgFbxReader( - KFbxSdkManager& pSdkManager1, - KFbxScene& fbxScene1, - FbxMaterialToOsgStateSet& fbxMaterialToOsgStateSet1, - const std::set& fbxSkeletons1, - const osgDB::Options& options1, - AuthoringTool authoringTool1, - bool lightmapTextures1) - : pSdkManager(pSdkManager1), - fbxScene(fbxScene1), - fbxMaterialToOsgStateSet(fbxMaterialToOsgStateSet1), - fbxSkeletons(fbxSkeletons1), - options(options1), - authoringTool(authoringTool1), - lightmapTextures(lightmapTextures1) - {} + OsgFbxReader( + KFbxSdkManager& pSdkManager1, + KFbxScene& fbxScene1, + FbxMaterialToOsgStateSet& fbxMaterialToOsgStateSet1, + const std::set& fbxSkeletons1, + const osgDB::Options& options1, + AuthoringTool authoringTool1, + bool lightmapTextures1) + : pSdkManager(pSdkManager1), + fbxScene(fbxScene1), + fbxMaterialToOsgStateSet(fbxMaterialToOsgStateSet1), + fbxSkeletons(fbxSkeletons1), + options(options1), + authoringTool(authoringTool1), + lightmapTextures(lightmapTextures1) + {} - osgDB::ReaderWriter::ReadResult readFbxNode( - KFbxNode*, bool& bIsBone, int& nLightCount); + osgDB::ReaderWriter::ReadResult readFbxNode( + KFbxNode*, bool& bIsBone, int& nLightCount); - std::string readFbxAnimation( - KFbxNode*, const char* targetName); + std::string readFbxAnimation( + KFbxNode*, const char* targetName); - osgDB::ReaderWriter::ReadResult readFbxCamera( - KFbxNode* pNode); + osgDB::ReaderWriter::ReadResult readFbxCamera( + KFbxNode* pNode); - osgDB::ReaderWriter::ReadResult readFbxLight( - KFbxNode* pNode, int& nLightCount); + osgDB::ReaderWriter::ReadResult readFbxLight( + KFbxNode* pNode, int& nLightCount); - osgDB::ReaderWriter::ReadResult readMesh( - KFbxNode* pNode, KFbxMesh* fbxMesh, - std::vector& stateSetList, - const char* szName); + osgDB::ReaderWriter::ReadResult readMesh( + KFbxNode* pNode, KFbxMesh* fbxMesh, + std::vector& stateSetList, + const char* szName); - osgDB::ReaderWriter::ReadResult readFbxMesh( - KFbxNode* pNode, - std::vector&); + osgDB::ReaderWriter::ReadResult readFbxMesh( + KFbxNode* pNode, + std::vector&); }; osgAnimation::Skeleton* getSkeleton(KFbxNode*,