From 2e11c49742dc8a1830b1633b1edb1e437d3cec16 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 19 Nov 2009 11:44:44 +0000 Subject: [PATCH] From Michael Platings, "This plugin adds support for the Autodesk FBX file format. It imports animations, including skeletal and morph animations, hence all my previous submissions to osgAnimation. The plugin won't build without the changes made in the "osgAnimation small additions" submission (14th August). The plugin requires the FBX SDK to be installed, available from http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=6837478" --- CMakeLists.txt | 1 + CMakeModules/FindFBX.cmake | 51 ++ src/osgPlugins/CMakeLists.txt | 4 + src/osgPlugins/fbx/CMakeLists.txt | 31 + src/osgPlugins/fbx/ReaderWriterFBX.cpp | 168 ++++++ src/osgPlugins/fbx/ReaderWriterFBX.h | 30 + src/osgPlugins/fbx/fbxRAnimation.cpp | 310 ++++++++++ src/osgPlugins/fbx/fbxRAnimation.h | 16 + src/osgPlugins/fbx/fbxRCamera.cpp | 53 ++ src/osgPlugins/fbx/fbxRCamera.h | 10 + src/osgPlugins/fbx/fbxRLight.cpp | 96 ++++ src/osgPlugins/fbx/fbxRLight.h | 10 + src/osgPlugins/fbx/fbxRMesh.cpp | 547 ++++++++++++++++++ src/osgPlugins/fbx/fbxRMesh.h | 14 + src/osgPlugins/fbx/fbxRNode.cpp | 560 +++++++++++++++++++ src/osgPlugins/fbx/fbxRNode.h | 17 + src/osgWrappers/osgWidget/EventInterface.cpp | 44 +- src/osgWrappers/osgWidget/Widget.cpp | 36 +- 18 files changed, 1958 insertions(+), 40 deletions(-) create mode 100644 CMakeModules/FindFBX.cmake create mode 100644 src/osgPlugins/fbx/CMakeLists.txt create mode 100644 src/osgPlugins/fbx/ReaderWriterFBX.cpp create mode 100644 src/osgPlugins/fbx/ReaderWriterFBX.h create mode 100644 src/osgPlugins/fbx/fbxRAnimation.cpp create mode 100644 src/osgPlugins/fbx/fbxRAnimation.h create mode 100644 src/osgPlugins/fbx/fbxRCamera.cpp create mode 100644 src/osgPlugins/fbx/fbxRCamera.h create mode 100644 src/osgPlugins/fbx/fbxRLight.cpp create mode 100644 src/osgPlugins/fbx/fbxRLight.h create mode 100644 src/osgPlugins/fbx/fbxRMesh.cpp create mode 100644 src/osgPlugins/fbx/fbxRMesh.h create mode 100644 src/osgPlugins/fbx/fbxRNode.cpp create mode 100644 src/osgPlugins/fbx/fbxRNode.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 667421266..dd35e4799 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -350,6 +350,7 @@ FIND_PACKAGE(Inventor) FIND_PACKAGE(Jasper) FIND_PACKAGE(OpenEXR) FIND_PACKAGE(COLLADA) +FIND_PACKAGE(FBX) FIND_PACKAGE(ZLIB) FIND_PACKAGE(Xine) FIND_PACKAGE(OpenVRML) diff --git a/CMakeModules/FindFBX.cmake b/CMakeModules/FindFBX.cmake new file mode 100644 index 000000000..7716e885d --- /dev/null +++ b/CMakeModules/FindFBX.cmake @@ -0,0 +1,51 @@ +# Locate FBX +# This module defines: +# FBX_INCLUDE_DIR, where to find the headers +# +# FBX_LIBRARY, FBX_LIBRARY_DEBUG +# FBX_FOUND +# +# $FBX_DIR is an environment variable that would +# correspond to the ./configure --prefix=$FBX_DIR + +IF(WIN32) +SET(FBX_ROOT "$ENV{PROGRAMFILES}/Autodesk/FBX/FbxSdk/2010.2" CACHE PATH "Location of FBX SDK directory") +ELSE(WIN32) +SET(FBX_ROOT $ENV{FBX_DIR} CACHE PATH "Location of FBX SDK directory") +ENDIF(WIN32) + +IF(APPLE) + SET(FBX_LIBNAME "libfbxsdk_gcc4_ub") +ELSEIF(CMAKE_COMPILER_IS_GNUCXX) + SET(FBX_LIBNAME "libfbxsdk_gcc4")#TODO: libs are provided for GCC 3.4 & 4.0 in both 32 and 64 bit versions, but I don't know how to confgure that here. +ELSEIF(MSVC71) + SET(FBX_LIBNAME "fbxsdk_md2003") +ELSEIF(MSVC80) + SET(FBX_LIBNAME "fbxsdk_md2005") +ELSEIF(MSVC90 OR MSVC_VER>1500) + SET(FBX_LIBNAME "fbxsdk_md2008") +ENDIF(APPLE) + +IF(CMAKE_CL_64) + SET(FBX_LIBNAME ${FBX_LIBNAME}_amd64) +ENDIF(CMAKE_CL_64) + +IF(APPLE) +SET(FBX_LIBNAME_DEBUG ${FBX_LIBNAME}) +ELSE(APPLE) +SET(FBX_LIBNAME_DEBUG ${FBX_LIBNAME}d) +ENDIF(APPLE) + +FIND_PATH(FBX_INCLUDE_DIR fbxsdk.h + ${FBX_ROOT}/include +) + +FIND_LIBRARY(FBX_LIBRARY ${FBX_LIBNAME} ${FBX_ROOT}/lib) + +FIND_LIBRARY(FBX_LIBRARY_DEBUG ${FBX_LIBNAME_DEBUG} ${FBX_ROOT}/lib) + +IF(FBX_LIBRARY AND FBX_LIBRARY_DEBUG AND FBX_INCLUDE_DIR) + SET(FBX_FOUND "YES") +ELSE(FBX_LIBRARY AND FBX_LIBRARY_DEBUG AND FBX_INCLUDE_DIR) + SET(FBX_FOUND "NO") +ENDIF(FBX_LIBRARY AND FBX_LIBRARY_DEBUG AND FBX_INCLUDE_DIR) diff --git a/src/osgPlugins/CMakeLists.txt b/src/osgPlugins/CMakeLists.txt index 4bc8b365f..10feaf03b 100644 --- a/src/osgPlugins/CMakeLists.txt +++ b/src/osgPlugins/CMakeLists.txt @@ -157,6 +157,10 @@ IF(COLLADA_FOUND) ADD_SUBDIRECTORY(dae) ENDIF() +IF(FBX_FOUND) + ADD_SUBDIRECTORY(fbx) +ENDIF() + IF(OSG_GLU_AVAILABLE) ADD_SUBDIRECTORY(lwo) ADD_SUBDIRECTORY(dw) diff --git a/src/osgPlugins/fbx/CMakeLists.txt b/src/osgPlugins/fbx/CMakeLists.txt new file mode 100644 index 000000000..858fa1822 --- /dev/null +++ b/src/osgPlugins/fbx/CMakeLists.txt @@ -0,0 +1,31 @@ +INCLUDE_DIRECTORIES(${FBX_ROOT}/include) + +SET(TARGET_SRC + fbxRAnimation.cpp + fbxRCamera.cpp + fbxRLight.cpp + fbxRMesh.cpp + fbxRNode.cpp + ReaderWriterFBX.cpp +) + +SET(TARGET_H + fbxRAnimation.h + fbxRCamera.h + fbxRLight.h + fbxRMesh.h + fbxRNode.h + ReaderWriterFBX.h +) + +ADD_DEFINITIONS(-DKFBX_PLUGIN -DKFBX_FBXSDK -DKFBX_NODLL) + +IF(WIN32) + SET(TARGET_EXTERNAL_LIBRARIES wininet) +ENDIF(WIN32) + +SET(TARGET_LIBRARIES_VARS FBX_LIBRARY) +SET(TARGET_ADDED_LIBRARIES osgAnimation) + +#### end var setup ### +SETUP_PLUGIN(fbx) diff --git a/src/osgPlugins/fbx/ReaderWriterFBX.cpp b/src/osgPlugins/fbx/ReaderWriterFBX.cpp new file mode 100644 index 000000000..612dbf0c4 --- /dev/null +++ b/src/osgPlugins/fbx/ReaderWriterFBX.cpp @@ -0,0 +1,168 @@ +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#if defined(_MSC_VER) + #pragma warning( disable : 4505 ) +#endif +#include + +#include "ReaderWriterFBX.h" +#include "fbxRNode.h" + +osgDB::ReaderWriter::ReadResult +ReaderWriterFBX::readNode(const std::string& utf8filename, + const osgDB::ReaderWriter::Options* options) const +{ + OpenThreads::ScopedLock lock(_serializerMutex); + + try + { + std::string ext(osgDB::getLowerCaseFileExtension(utf8filename)); + if(!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; + + std::string fileName(osgDB::findDataFile(utf8filename, options)); + if( fileName.empty()) return ReadResult::FILE_NOT_FOUND; + + KFbxSdkManager* pSdkManager = KFbxSdkManager::Create(); + + if (!pSdkManager) + { + return ReadResult::ERROR_IN_READING_FILE; + } + + class CleanUpFbx + { + KFbxSdkManager* m_pSdkManager; + public: + CleanUpFbx(KFbxSdkManager* pSdkManager) : m_pSdkManager(pSdkManager) + {} + + ~CleanUpFbx() + { + KFbxIOSettings::IOSettingsRef().FreeIOSettings(); + m_pSdkManager->Destroy(); + } + } cleanUpFbx(pSdkManager); + + KFbxScene* pScene = KFbxScene::Create(pSdkManager,""); + + int fileFormat; + if (!pSdkManager->GetIOPluginRegistry()->DetectFileFormat(utf8filename.c_str(), fileFormat)) + { + return ReadResult::FILE_NOT_HANDLED; + } + + KFbxImporter* lImporter = KFbxImporter::Create(pSdkManager,""); + lImporter->SetFileFormat(fileFormat); + + if (!lImporter->Initialize(utf8filename.c_str())) + { + return std::string(lImporter->GetLastErrorString()); + } + + if (!lImporter->IsFBX()) + { + return ReadResult::ERROR_IN_READING_FILE; + } + + for(int i = 0; i < lImporter->GetTakeCount(); i++) + { + KFbxTakeInfo* lTakeInfo = lImporter->GetTakeInfo(i); + + lTakeInfo->mSelect = true; + } + + if (!lImporter->Import(pScene)) + { + return std::string(lImporter->GetLastErrorString()); + } + + if (KFbxNode* pNode = pScene->GetRootNode()) + { + osg::ref_ptr pAnimationManager; + bool bNeedSkeleton = false; + int nLightCount = 0; + ReadResult res = readFbxNode(*pSdkManager, pNode, pAnimationManager, + osgDB::getFilePath(fileName), bNeedSkeleton, nLightCount); + if (res.success()) + { + osg::Node* osgNode = res.getNode(); + if (bNeedSkeleton) + { + osgAnimation::Skeleton* osgSkeleton = new osgAnimation::Skeleton; + osgSkeleton->setDefaultUpdateCallback(); + osgSkeleton->addChild(osgNode); + osgNode = osgSkeleton; + } + if (pAnimationManager.valid()) + { + if (osgNode->getUpdateCallback()) + { + osg::Group* osgGroup = new osg::Group; + osgGroup->addChild(osgNode); + osgNode = osgGroup; + } + + //because the animations may be altered after registering + pAnimationManager->buildTargetReference(); + + osgNode->setUpdateCallback(pAnimationManager.get()); + } + + KFbxAxisSystem fbxAxis = pScene->GetGlobalSettings().GetAxisSystem(); + int upSign; + KFbxAxisSystem::eUpVector eUp = fbxAxis.GetUpVector(upSign); + bool bLeftHanded = fbxAxis.GetCoorSystem() == KFbxAxisSystem::LeftHanded; + if (eUp != KFbxAxisSystem::YAxis || upSign < 0 || bLeftHanded) + { + float fSign = upSign < 0 ? -1.0f : 1.0f; + float zScale = bLeftHanded ? -1.0f : 1.0f; + + osg::Matrix mat; + switch (eUp) + { + case KFbxAxisSystem::XAxis: + mat.set(0,fSign,0,0,-fSign,0,0,0,0,0,zScale,0,0,0,0,1); + break; + case KFbxAxisSystem::YAxis: + mat.set(1,0,0,0,0,fSign,0,0,0,0,fSign*zScale,0,0,0,0,1); + break; + case KFbxAxisSystem::ZAxis: + mat.set(1,0,0,0,0,0,-fSign*zScale,0,0,fSign,0,0,0,0,0,1); + break; + } + osg::MatrixTransform* pTransform = new osg::MatrixTransform(mat); + pTransform->addChild(osgNode); + osgNode = pTransform; + } + + return osgNode; + } + } + } + catch (...) + { + } + + return ReadResult::ERROR_IN_READING_FILE; +} + +/////////////////////////////////////////////////////////////////////////// +// Add ourself to the Registry to instantiate the reader/writer. + +REGISTER_OSGPLUGIN(fbx, ReaderWriterFBX) diff --git a/src/osgPlugins/fbx/ReaderWriterFBX.h b/src/osgPlugins/fbx/ReaderWriterFBX.h new file mode 100644 index 000000000..3055304a7 --- /dev/null +++ b/src/osgPlugins/fbx/ReaderWriterFBX.h @@ -0,0 +1,30 @@ +#ifndef READERWRITERFBX_H +#define READERWRITERFBX_H + +#include +#include + +/////////////////////////////////////////////////////////////////////////// +// OSG reader plugin for the ".fbx" format. +// See http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=6837478 + +class ReaderWriterFBX : public osgDB::ReaderWriter +{ +public: + ReaderWriterFBX() + { + supportsExtension("fbx", "FBX format"); + } + + const char* className() const { return "FBX reader/writer"; } + + /// The FBX SDK interprets the filename as UTF-8 + ReadResult readNode(const std::string& utf8filename, const Options*) const; + +private: + mutable OpenThreads::ReentrantMutex _serializerMutex; +}; + +/////////////////////////////////////////////////////////////////////////// + +#endif diff --git a/src/osgPlugins/fbx/fbxRAnimation.cpp b/src/osgPlugins/fbx/fbxRAnimation.cpp new file mode 100644 index 000000000..01bdeda63 --- /dev/null +++ b/src/osgPlugins/fbx/fbxRAnimation.cpp @@ -0,0 +1,310 @@ +#include + +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) + #pragma warning( disable : 4505 ) +#endif +#include +#include + +osg::Quat makeQuat(const fbxDouble3&, ERotationOrder); + +osg::Quat makeQuat(const osg::Vec3& radians, ERotationOrder fbxRotOrder) +{ + fbxDouble3 degrees( + osg::RadiansToDegrees(radians.x()), + osg::RadiansToDegrees(radians.y()), + osg::RadiansToDegrees(radians.z())); + return makeQuat(degrees, fbxRotOrder); +} + +void readKeys(KFCurve* curveX, KFCurve* curveY, KFCurve* curveZ, + float scalar, const osg::Vec3& baseValue, bool multiply, + std::vector >& keyFrameCntr) +{ + KFCurve* curves[3] = {curveX, curveY, curveZ}; + + typedef std::set TimeSet; + typedef std::map TimeFloatMap; + TimeSet times; + TimeFloatMap curveTimeMap[3]; + + for (int nCurve = 0; nCurve < 3; ++nCurve) + { + KFCurve* pCurve = curves[nCurve]; + + int nKeys = pCurve->KeyGetCount(); + + if (!nKeys) + { + times.insert(0.0f); + curveTimeMap[nCurve][0.0f] = static_cast(pCurve->GetValue()) * scalar; + } + + for (int i = 0; i < nKeys; ++i) + { + KFCurveKey key = pCurve->KeyGet(i); + float fTime = static_cast(key.GetTime().GetSecondDouble()); + times.insert(fTime); + curveTimeMap[nCurve][fTime] = static_cast(key.GetValue()) * scalar; + } + } + + for (TimeSet::iterator it = times.begin(); it != times.end(); ++it) + { + float fTime = *it; + osg::Vec3 val(baseValue); + for (int i = 0; i < 3; ++i) + { + if (curveTimeMap[i].empty()) continue; + + TimeFloatMap::iterator lb = curveTimeMap[i].lower_bound(fTime); + if (lb == curveTimeMap[i].end()) --lb; + if (multiply) + { + val[i] *= lb->second; + } + else + { + val[i] += lb->second; + } + } + keyFrameCntr.push_back(osgAnimation::Vec3Keyframe(fTime, val)); + } +} + +osgAnimation::Channel* readFbxChannels(KFCurve* curveX, KFCurve* curveY, + KFCurve* curveZ, const char* targetName, const char* channelName, + float scalar, const osg::Vec3& baseValue, bool multiply) +{ + if (!curveX && !curveY && !curveZ) + { + return 0; + } + + if (!curveX->KeyGetCount() && !curveY->KeyGetCount() && !curveZ->KeyGetCount()) + { + return 0; + } + + osgAnimation::Vec3LinearChannel* pChannel = new osgAnimation::Vec3LinearChannel; + osgAnimation::Vec3KeyframeContainer* pKeyFrameCntr = + pChannel->getOrCreateSampler()->getOrCreateKeyframeContainer(); + + pChannel->setTargetName(targetName); + pChannel->setName(channelName); + readKeys(curveX, curveY, curveZ, scalar, baseValue, multiply, *pKeyFrameCntr); + + return pChannel; +} + +osgAnimation::Channel* readFbxChannels( + KFbxTypedProperty& fbxProp, const char* pTakeName, + const char* targetName, const char* channelName, const osg::Vec3& baseValue, float scalar, bool multiply) +{ + if (!fbxProp.IsValid()) return 0; + + return readFbxChannels( + fbxProp.GetKFCurve("X", pTakeName), + fbxProp.GetKFCurve("Y", pTakeName), + fbxProp.GetKFCurve("Z", pTakeName), + targetName, channelName, scalar, + baseValue * scalar, multiply); +} + +osgAnimation::Channel* readFbxChannelsQuat( + KFCurve* curveX, KFCurve* curveY, KFCurve* curveZ, const char* targetName, + const osg::Quat& baseQuat, ERotationOrder rotOrder) +{ + if (!curveX && !curveY && !curveZ) + { + return 0; + } + + osgAnimation::QuatSphericalLinearChannel* pChannel = new osgAnimation::QuatSphericalLinearChannel; + pChannel->setTargetName(targetName); + pChannel->setName("quaternion"); + typedef std::vector > KeyFrameCntr; + KeyFrameCntr eulerFrameCntr; + readKeys(curveX, curveY, curveZ, static_cast(osg::PI / 180.0), osg::Vec3(0,0,0), false, eulerFrameCntr); + + osgAnimation::QuatSphericalLinearSampler::KeyframeContainerType& quatFrameCntr = + *pChannel->getOrCreateSampler()->getOrCreateKeyframeContainer(); + quatFrameCntr.reserve(eulerFrameCntr.size()); + + for (KeyFrameCntr::iterator it = eulerFrameCntr.begin(), end = eulerFrameCntr.end(); + it != end; ++it) + { + const osg::Vec3& euler = it->getValue(); + quatFrameCntr.push_back(osgAnimation::QuatKeyframe( + it->getTime(), makeQuat(euler, rotOrder) * baseQuat)); + } + + return pChannel; +} + +osgAnimation::Animation* addChannels( + osgAnimation::Channel* pTranslationChannel, + osgAnimation::Channel* pRotationChannel, + osgAnimation::Channel* pScaleChannel, + osg::ref_ptr &pAnimManager, + const char* pTakeName) +{ + if (pTranslationChannel || + pRotationChannel || + pScaleChannel) + { + if (!pAnimManager) pAnimManager = new osgAnimation::BasicAnimationManager; + + osgAnimation::Animation* pAnimation = 0; + const osgAnimation::AnimationList& anims = pAnimManager->getAnimationList(); + for (size_t i = 0; i < anims.size(); ++i) + { + if (anims[i]->getName() == pTakeName) + { + pAnimation = anims[i].get(); + } + } + + if (!pAnimation) + { + pAnimation = new osgAnimation::Animation; + pAnimation->setName(pTakeName); + pAnimManager->registerAnimation(pAnimation); + } + + if (pTranslationChannel) pAnimation->addChannel(pTranslationChannel); + if (pRotationChannel) pAnimation->addChannel(pRotationChannel); + if (pScaleChannel) pAnimation->addChannel(pScaleChannel); + + + return pAnimation; + } + + return 0; +} + +osgAnimation::Animation* readFbxBoneAnimation(KFbxNode* pNode, + const char* pTakeName, const char* targetName, + osg::ref_ptr& pAnimManager) +{ + if (!pTakeName) + { + return 0; + } + + ERotationOrder rotOrder = pNode->RotationOrder.IsValid() ? pNode->RotationOrder.Get() : eEULER_XYZ; + osg::Quat inverseRot; + + osgAnimation::Channel* pTranslationChannel = 0; + osgAnimation::Channel* pRotationChannel = 0; + + if (pNode->LclRotation.IsValid()) + { + inverseRot = makeQuat(pNode->LclRotation.Get(), rotOrder).inverse(); + + pRotationChannel = readFbxChannelsQuat( + pNode->LclRotation.GetKFCurve(KFCURVENODE_R_X, pTakeName), + pNode->LclRotation.GetKFCurve(KFCURVENODE_R_Y, pTakeName), + pNode->LclRotation.GetKFCurve(KFCURVENODE_R_Z, pTakeName), + targetName, inverseRot, rotOrder); + } + + if (pNode->LclTranslation.IsValid()) + { + fbxDouble3 fbxBaseValue = pNode->LclTranslation.Get(); + osg::Vec3 offsetTranslation( + -static_cast(fbxBaseValue[0]), + -static_cast(fbxBaseValue[1]), + -static_cast(fbxBaseValue[2])); + + pTranslationChannel = readFbxChannels( + pNode->LclTranslation.GetKFCurve(KFCURVENODE_T_X, pTakeName), + pNode->LclTranslation.GetKFCurve(KFCURVENODE_T_Y, pTakeName), + pNode->LclTranslation.GetKFCurve(KFCURVENODE_T_Z, pTakeName), + targetName, "position", 1.0f, offsetTranslation, false); + + if (pTranslationChannel) + { + osgAnimation::Vec3KeyframeContainer& keyFrameCntr = + dynamic_cast( + *pTranslationChannel->getSampler()->getKeyframeContainer()); + + for (int i = 0; i < keyFrameCntr.size(); ++i) + { + keyFrameCntr[i].setValue(inverseRot * keyFrameCntr[i].getValue()); + } + } + } + + osgAnimation::Channel* pScaleChannel = readFbxChannels( + pNode->LclScaling, pTakeName, targetName, "scale", osg::Vec3(0,0,0), 1.0f, true); + + return addChannels(pTranslationChannel, pRotationChannel, pScaleChannel, pAnimManager, pTakeName); +} + +osgAnimation::Animation* readFbxAnimation(KFbxNode* pNode, + const char* pTakeName, const char* targetName, + osg::ref_ptr& pAnimManager) +{ + if (!pTakeName) return 0; + + osgAnimation::Channel* pTranslationChannel = readFbxChannels( + pNode->LclTranslation, pTakeName, targetName, "position", osg::Vec3(0,0,0), 1.0f, false); + + //TODO: This will break if there are rotations in more than one of + // Pre/Lcl/Post so really they should each get their own MatrixTransform. + fbxDouble3 fbxPreRot = pNode->PreRotation.Get(); + fbxDouble3 fbxPostRot = pNode->PostRotation.Get(); + osg::Vec3 eulerOffset( + static_cast(fbxPreRot[0] + fbxPostRot[0]), + static_cast(fbxPreRot[1] + fbxPostRot[1]), + static_cast(fbxPreRot[2] + fbxPostRot[2])); + + osgAnimation::Channel* pRotationChannel = readFbxChannels( + pNode->LclRotation, pTakeName, targetName, "euler", eulerOffset, static_cast(osg::PI / 180.0), false); + + osgAnimation::Channel* pScaleChannel = readFbxChannels( + pNode->LclScaling, pTakeName, targetName, "scale", osg::Vec3(1,1,1), 1.0f, true); + + return addChannels(pTranslationChannel, pRotationChannel, pScaleChannel, pAnimManager, pTakeName); +} + +std::string readFbxBoneAnimation(KFbxNode* pNode, + osg::ref_ptr& pAnimManager, + const char* targetName) +{ + std::string result; + for (int i = 1; i < pNode->GetTakeNodeCount(); ++i) + { + const char* pTakeName = pNode->GetTakeNodeName(i); + if (osgAnimation::Animation* pAnimation = readFbxBoneAnimation( + pNode, pTakeName, targetName, pAnimManager)) + { + result = targetName; + } + } + return result; +} + +std::string readFbxAnimation(KFbxNode* pNode, + osg::ref_ptr& pAnimManager, + const char* targetName) +{ + std::string result; + for (int i = 1; i < pNode->GetTakeNodeCount(); ++i) + { + const char* pTakeName = pNode->GetTakeNodeName(i); + if (osgAnimation::Animation* pAnimation = readFbxAnimation( + pNode, pTakeName, targetName, pAnimManager)) + { + result = targetName; + } + } + return result; +} diff --git a/src/osgPlugins/fbx/fbxRAnimation.h b/src/osgPlugins/fbx/fbxRAnimation.h new file mode 100644 index 000000000..60a9f152e --- /dev/null +++ b/src/osgPlugins/fbx/fbxRAnimation.h @@ -0,0 +1,16 @@ +#ifndef FBXRANIMATION_H +#define FBXRANIMATION_H + +#include + +std::string readFbxBoneAnimation( + FBXFILESDK_NAMESPACE::KFbxNode*, + osg::ref_ptr&, + const char* targetName); + +std::string readFbxAnimation( + FBXFILESDK_NAMESPACE::KFbxNode*, + osg::ref_ptr&, + const char* targetName); + +#endif diff --git a/src/osgPlugins/fbx/fbxRCamera.cpp b/src/osgPlugins/fbx/fbxRCamera.cpp new file mode 100644 index 000000000..9607352a8 --- /dev/null +++ b/src/osgPlugins/fbx/fbxRCamera.cpp @@ -0,0 +1,53 @@ +#include +#include + +#include + +#if defined(_MSC_VER) +#pragma warning( disable : 4505 ) +#endif +#include + +#include "fbxRCamera.h" + +osgDB::ReaderWriter::ReadResult readFbxCamera(KFbxNode* pNode) +{ + const KFbxCamera* fbxCamera = dynamic_cast(pNode->GetNodeAttribute()); + + if (!fbxCamera) + { + return osgDB::ReaderWriter::ReadResult::ERROR_IN_READING_FILE; + } + + osg::CameraView* osgCameraView = new osg::CameraView; + + if (fbxCamera->FieldOfView.IsValid()) + { + osgCameraView->setFieldOfView(fbxCamera->FieldOfView.Get()); + } + + if (fbxCamera->FocalLength.IsValid()) + { + osgCameraView->setFocalLength(fbxCamera->FocalLength.Get()); + } + + if (fbxCamera->ApertureMode.IsValid()) + { + switch (fbxCamera->ApertureMode.Get()) + { + case KFbxCamera::eHORIZONTAL: + osgCameraView->setFieldOfViewMode(osg::CameraView::HORIZONTAL); + break; + case KFbxCamera::eVERTICAL: + osgCameraView->setFieldOfViewMode(osg::CameraView::VERTICAL); + break; + case KFbxCamera::eHORIZONTAL_AND_VERTICAL: + case KFbxCamera::eFOCAL_LENGTH: + default: + osg::notify(osg::WARN) << "readFbxCamera: Unsupported Camera aperture mode." << std::endl; + break; + } + } + + return osgDB::ReaderWriter::ReadResult(osgCameraView); +} diff --git a/src/osgPlugins/fbx/fbxRCamera.h b/src/osgPlugins/fbx/fbxRCamera.h new file mode 100644 index 000000000..09c65946f --- /dev/null +++ b/src/osgPlugins/fbx/fbxRCamera.h @@ -0,0 +1,10 @@ +#ifndef FBXRCAMERA_H +#define FBXRCAMERA_H + +#include +#include + +osgDB::ReaderWriter::ReadResult readFbxCamera( + FBXFILESDK_NAMESPACE::KFbxNode* pNode); + +#endif diff --git a/src/osgPlugins/fbx/fbxRLight.cpp b/src/osgPlugins/fbx/fbxRLight.cpp new file mode 100644 index 000000000..f643f6090 --- /dev/null +++ b/src/osgPlugins/fbx/fbxRLight.cpp @@ -0,0 +1,96 @@ +#include + +#include + +#if defined(_MSC_VER) +#pragma warning( disable : 4505 ) +#endif +#include + +#include "fbxRLight.h" + +osgDB::ReaderWriter::ReadResult readFbxLight(KFbxNode* pNode, int& nLightCount) +{ + const KFbxLight* fbxLight = dynamic_cast(pNode->GetNodeAttribute()); + + if (!fbxLight) + { + return osgDB::ReaderWriter::ReadResult::ERROR_IN_READING_FILE; + } + + osg::Light* osgLight = new osg::Light; + osg::LightSource* osgLightSource = new osg::LightSource; + + osgLightSource->setLight(osgLight); + osgLight->setLightNum(nLightCount++); + + KFbxLight::ELightType fbxLightType = fbxLight->LightType.IsValid() ? + fbxLight->LightType.Get() : KFbxLight::ePOINT; + + osgLight->setPosition(osg::Vec4(0,0,0,fbxLightType != KFbxLight::eDIRECTIONAL)); + + if (fbxLightType == KFbxLight::eSPOT) + { + double coneAngle = fbxLight->ConeAngle.IsValid() ? fbxLight->ConeAngle.Get() : 45.0; + double hotSpot = fbxLight->HotSpot.IsValid() ? fbxLight->HotSpot.Get() : 45.0; + const float MIN_HOTSPOT = 0.467532f; + + osgLight->setSpotCutoff(static_cast(coneAngle)); + + //Approximate the hotspot using the GL light exponent. + //This formula maps a hotspot of 180° to exponent 0 (uniform light + // distribution) and a hotspot of 45° to exponent 1 (effective light + // intensity is attenuated by the cosine of the angle between the + // direction of the light and the direction from the light to the vertex + // being lighted). A hotspot close to 0° maps to exponent 128 (maximum). + float exponent = (180.0f / (std::max)(static_cast(hotSpot), + MIN_HOTSPOT) - 1.0f) / 3.0f; + osgLight->setSpotExponent(exponent); + } + + if (fbxLight->DecayType.IsValid() && + fbxLight->DecayStart.IsValid()) + { + double fbxDecayStart = fbxLight->DecayStart.Get(); + + switch (fbxLight->DecayType.Get()) + { + case KFbxLight::eLINEAR: + osgLight->setLinearAttenuation(fbxDecayStart); + break; + case KFbxLight::eQUADRATIC: + case KFbxLight::eCUBIC: + osgLight->setQuadraticAttenuation(fbxDecayStart); + break; + } + } + + osg::Vec3f osgDiffuseSpecular(1.0f, 1.0f, 1.0f); + osg::Vec3f osgAmbient(0.0f, 0.0f, 0.0f); + if (fbxLight->Color.IsValid()) + { + fbxDouble3 fbxColor = fbxLight->Color.Get(); + osgDiffuseSpecular.set( + static_cast(fbxColor[0]), + static_cast(fbxColor[1]), + static_cast(fbxColor[2])); + } + if (fbxLight->Intensity.IsValid()) + { + osgDiffuseSpecular *= static_cast(fbxLight->Intensity.Get()) * 0.01f; + } + if (fbxLight->ShadowColor.IsValid()) + { + fbxDouble3 fbxShadowColor = fbxLight->ShadowColor.Get(); + osgAmbient.set( + static_cast(fbxShadowColor[0]), + static_cast(fbxShadowColor[1]), + static_cast(fbxShadowColor[2])); + } + + osgLight->setDiffuse(osg::Vec4f(osgDiffuseSpecular, 1.0f)); + osgLight->setSpecular(osg::Vec4f(osgDiffuseSpecular, 1.0f)); + osgLight->setAmbient(osg::Vec4f(osgAmbient, 1.0f)); + + return osgDB::ReaderWriter::ReadResult(osgLightSource); +} diff --git a/src/osgPlugins/fbx/fbxRLight.h b/src/osgPlugins/fbx/fbxRLight.h new file mode 100644 index 000000000..96872cb96 --- /dev/null +++ b/src/osgPlugins/fbx/fbxRLight.h @@ -0,0 +1,10 @@ +#ifndef FBXRLIGHT_H +#define FBXRLIGHT_H + +#include +#include + +osgDB::ReaderWriter::ReadResult readFbxLight( + FBXFILESDK_NAMESPACE::KFbxNode* pNode, int& nLightCount); + +#endif diff --git a/src/osgPlugins/fbx/fbxRMesh.cpp b/src/osgPlugins/fbx/fbxRMesh.cpp new file mode 100644 index 000000000..26bfb4271 --- /dev/null +++ b/src/osgPlugins/fbx/fbxRMesh.cpp @@ -0,0 +1,547 @@ +#include +#include + +#include + +#include + +#include +#include +#include + +#if defined(_MSC_VER) +#pragma warning( disable : 4505 ) +#endif +#include + +#include "fbxRMesh.h" + +enum GeometryType +{ + GEOMETRY_STATIC, + GEOMETRY_RIG, + GEOMETRY_MORPH +}; + +osg::Vec3 convertVec3(const KFbxVector4& v) +{ + return osg::Vec3( + static_cast(v[0]), + static_cast(v[1]), + static_cast(v[2])); +} + +osg::Vec2 convertVec2(const KFbxVector2& v) +{ + return osg::Vec2( + static_cast(v[0]), + static_cast(v[1])); +} + +osg::Vec4 convertColor(const KFbxColor& color) +{ + return osg::Vec4( + static_cast(color.mRed), + static_cast(color.mGreen), + static_cast(color.mBlue), + static_cast(color.mAlpha)); +} + +template +bool layerElementValid(const KFbxLayerElementTemplate* pLayerElement) +{ + if (!pLayerElement) + return false; + + switch (pLayerElement->GetMappingMode()) + { + case KFbxLayerElement::eBY_CONTROL_POINT: + case KFbxLayerElement::eBY_POLYGON_VERTEX: + case KFbxLayerElement::eBY_POLYGON: + break; + default: + return false; + } + + switch (pLayerElement->GetReferenceMode()) + { + case KFbxLayerElement::eDIRECT: + case KFbxLayerElement::eINDEX_TO_DIRECT: + return true; + } + + return false; +} + +template +int getVertexIndex(const KFbxLayerElementTemplate* pLayerElement, + KFbxMesh* fbxMesh, + int nPolygon, int nPolyVertex, int nMeshVertex) +{ + int index = 0; + + switch (pLayerElement->GetMappingMode()) + { + case KFbxLayerElement::eBY_CONTROL_POINT: + index = fbxMesh->GetPolygonVertex(nPolygon, nPolyVertex); + break; + case KFbxLayerElement::eBY_POLYGON_VERTEX: + index = nMeshVertex; + break; + case KFbxLayerElement::eBY_POLYGON: + index = nPolygon; + break; + } + + if (pLayerElement->GetReferenceMode() == KFbxLayerElement::eDIRECT) + { + return index; + } + + return pLayerElement->GetIndexArray().GetAt(index); +} + +template +int getPolygonIndex(const KFbxLayerElementTemplate* pLayerElement, int nPolygon) +{ + if (pLayerElement && + pLayerElement->GetMappingMode() == KFbxLayerElement::eBY_POLYGON) + { + switch (pLayerElement->GetReferenceMode()) + { + case KFbxLayerElement::eDIRECT: + return nPolygon; + case KFbxLayerElement::eINDEX_TO_DIRECT: + return pLayerElement->GetIndexArray().GetAt(nPolygon); + } + } + + return 0; +} + +template +FbxT getElement(const KFbxLayerElementTemplate* pLayerElement, + KFbxMesh* fbxMesh, + int nPolygon, int nPolyVertex, int nMeshVertex) +{ + return pLayerElement->GetDirectArray().GetAt(getVertexIndex( + pLayerElement, fbxMesh, nPolygon, nPolyVertex, nMeshVertex)); +} + +typedef std::map > GeometryMap; + +osg::Geometry* getGeometry(osg::Geode* pGeode, GeometryMap& geometryMap, + const std::vector>& materialList, + const std::vector>& textureList, + GeometryType gt, unsigned mti, bool bNormal, bool bTexCoord, bool bColor) +{ + GeometryMap::iterator it = geometryMap.find(mti); + + if (it != geometryMap.end()) + { + return it->second.get(); + } + + osg::ref_ptr pGeometry; + if (gt == GEOMETRY_RIG) + { + osgAnimation::RigGeometry* pRig = new osgAnimation::RigGeometry; + pRig->setInfluenceMap(new osgAnimation::VertexInfluenceMap); + pGeometry = pRig; + } + else if (gt == GEOMETRY_MORPH) + { + pGeometry = new osgAnimation::MorphGeometry; + } + else + { + pGeometry = new osg::Geometry; + } + + pGeometry->setVertexData(osg::Geometry::ArrayData(new osg::Vec3Array, osg::Geometry::BIND_PER_VERTEX)); + if (bNormal) pGeometry->setNormalData(osg::Geometry::ArrayData(new osg::Vec3Array, osg::Geometry::BIND_PER_VERTEX)); + if (bTexCoord) pGeometry->setTexCoordData(0, osg::Geometry::ArrayData(new osg::Vec2Array, osg::Geometry::BIND_PER_VERTEX)); + if (bColor) pGeometry->setColorData(osg::Geometry::ArrayData(new osg::Vec4Array, osg::Geometry::BIND_PER_VERTEX)); + + if (mti < materialList.size()) + { + pGeometry->getOrCreateStateSet()->setAttributeAndModes(materialList[mti].get()); + } + + if (mti < textureList.size()) + { + pGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, textureList[mti].get()); + } + + geometryMap.insert(std::pair>(mti, pGeometry)); + pGeode->addDrawable(pGeometry.get()); + + return pGeometry.get(); +} + +osgAnimation::VertexInfluence& getVertexInfluence( + osgAnimation::VertexInfluenceMap& vim, const std::string& name) +{ + osgAnimation::VertexInfluenceMap::iterator it = vim.lower_bound(name); + if (it == vim.end() || name != it->first) + { + it = vim.insert(it, osgAnimation::VertexInfluenceMap::value_type( + name, osgAnimation::VertexInfluence())); + it->second.setName(name); + } + return it->second; +} + +void addChannel( + osgAnimation::Channel* pChannel, + osg::ref_ptr &pAnimManager, + const char* pTakeName) +{ + if (!pChannel) + { + return; + } + + if (!pAnimManager) pAnimManager = new osgAnimation::BasicAnimationManager; + + osgAnimation::Animation* pAnimation = 0; + const osgAnimation::AnimationList& anims = pAnimManager->getAnimationList(); + for (size_t i = 0; i < anims.size(); ++i) + { + if (anims[i]->getName() == pTakeName) + { + pAnimation = anims[i].get(); + } + } + + if (!pAnimation) + { + pAnimation = new osgAnimation::Animation; + pAnimation->setName(pTakeName); + pAnimManager->registerAnimation(pAnimation); + } + + pAnimation->addChannel(pChannel); +} + +void readAnimation(KFbxNode* pNode, osg::Geode* pGeode, + osg::ref_ptr& pAnimationManager, + KFbxMesh* pMesh, int nShape) +{ + for (int i = 1; i < pNode->GetTakeNodeCount(); ++i) + { + const char* pTakeName = pNode->GetTakeNodeName(i); + + KFCurve* pCurve = pMesh->GetShapeChannel(nShape, true, pTakeName); + + osgAnimation::FloatLinearChannel* pChannel = new osgAnimation::FloatLinearChannel; + std::vector >& keyFrameCntr = *pChannel->getOrCreateSampler()->getOrCreateKeyframeContainer(); + + int nKeys = pCurve->KeyGetCount(); + if (!nKeys) + { + float fValue = static_cast(pCurve->GetValue() * 0.01); + keyFrameCntr.push_back(osgAnimation::FloatKeyframe(0.0f,fValue)); + } + + for (int k = 0; k < nKeys; ++k) + { + KFCurveKey key = pCurve->KeyGet(k); + float fTime = static_cast(key.GetTime().GetSecondDouble()); + float fValue = static_cast(key.GetValue() * 0.01); + keyFrameCntr.push_back(osgAnimation::FloatKeyframe(fTime,fValue)); + } + + pChannel->setTargetName(pGeode->getName()); + pChannel->setName(pMesh->GetShapeName(nShape)); + addChannel(pChannel, pAnimationManager, pTakeName); + } +} + +osgDB::ReaderWriter::ReadResult readMesh(KFbxNode* pNode, KFbxMesh* fbxMesh, + osg::ref_ptr& pAnimationManager, + const std::vector>& materialList, + const std::vector>& textureList, + const char* szName) +{ + GeometryMap geometryMap; + + osg::Geode* pGeode = new osg::Geode; + pGeode->setName(szName); + + const KFbxLayer* pFbxLayer = 0; + const KFbxLayerElementNormal* pFbxNormals = 0; + const KFbxLayerElementUV* pFbxUVs = 0; + const KFbxLayerElementVertexColor* pFbxColors = 0; + const KFbxLayerElementMaterial* pFbxMaterials = 0; + + const KFbxVector4* pFbxVertices = fbxMesh->GetControlPoints(); + + if (pFbxLayer = fbxMesh->GetLayer(0)) + { + pFbxNormals = pFbxLayer->GetNormals(); + pFbxColors = pFbxLayer->GetVertexColors(); + pFbxUVs = pFbxLayer->GetUVs(); + pFbxMaterials = pFbxLayer->GetMaterials(); + + if (!layerElementValid(pFbxNormals)) pFbxNormals = 0; + if (!layerElementValid(pFbxColors)) pFbxColors = 0; + if (!layerElementValid(pFbxUVs)) pFbxUVs = 0; + } + + int nPolys = fbxMesh->GetPolygonCount(); + + int nDeformerCount = fbxMesh->GetDeformerCount(KFbxDeformer::eSKIN); + int nMorphShapeCount = 0; + + GeometryType geomType = GEOMETRY_STATIC; + + //determine the type of geometry + if (nDeformerCount) + { + geomType = GEOMETRY_RIG; + } + else if (nMorphShapeCount = fbxMesh->GetShapeCount()) + { + geomType = GEOMETRY_MORPH; + } + + typedef std::pair GIPair; + typedef std::multimap FbxToOsgVertexMap; + typedef std::map OsgToFbxNormalMap; + FbxToOsgVertexMap fbxToOsgVertMap; + OsgToFbxNormalMap osgToFbxNormMap; + + for (int i = 0, nVertex = 0; i < nPolys; ++i) + { + int lPolygonSize = fbxMesh->GetPolygonSize(i); + + int materialIndex = getPolygonIndex(pFbxMaterials, i); + + osg::Geometry* pGeometry = getGeometry(pGeode, geometryMap, + materialList, textureList, geomType, materialIndex, + pFbxNormals != 0, pFbxUVs != 0, pFbxColors != 0); + + osg::Vec3Array* pVertices = static_cast( + pGeometry->getVertexArray()); + osg::Vec3Array* pNormals = static_cast( + pGeometry->getNormalArray()); + osg::Vec2Array* pTexCoords = static_cast( + pGeometry->getTexCoordArray(0)); + osg::Vec4Array* pColors = static_cast( + pGeometry->getColorArray()); + + int nVertex0 = nVertex; + nVertex += (std::min)(2, lPolygonSize); + + //convert polygon to triangles + for (int j = 2; j < lPolygonSize; ++j, ++nVertex) + { + int v0 = fbxMesh->GetPolygonVertex(i, 0), + v1 = fbxMesh->GetPolygonVertex(i, j - 1), + v2 = fbxMesh->GetPolygonVertex(i, j); + + fbxToOsgVertMap.insert(FbxToOsgVertexMap::value_type(v0, GIPair(pGeometry, pVertices->size()))); + fbxToOsgVertMap.insert(FbxToOsgVertexMap::value_type(v1, GIPair(pGeometry, pVertices->size() + 1))); + fbxToOsgVertMap.insert(FbxToOsgVertexMap::value_type(v2, GIPair(pGeometry, pVertices->size() + 2))); + + + pVertices->push_back(convertVec3(pFbxVertices[v0])); + pVertices->push_back(convertVec3(pFbxVertices[v1])); + pVertices->push_back(convertVec3(pFbxVertices[v2])); + + if (pNormals) + { + int n0 = getVertexIndex(pFbxNormals, fbxMesh, i, 0, nVertex0); + int n1 = getVertexIndex(pFbxNormals, fbxMesh, i, j - 1, nVertex - 1); + int n2 = getVertexIndex(pFbxNormals, fbxMesh, i, j, nVertex); + + osgToFbxNormMap.insert(OsgToFbxNormalMap::value_type(GIPair(pGeometry, pNormals->size()), n0)); + osgToFbxNormMap.insert(OsgToFbxNormalMap::value_type(GIPair(pGeometry, pNormals->size() + 1), n1)); + osgToFbxNormMap.insert(OsgToFbxNormalMap::value_type(GIPair(pGeometry, pNormals->size() + 2), n2)); + + pNormals->push_back(convertVec3(pFbxNormals->GetDirectArray().GetAt(n0))); + pNormals->push_back(convertVec3(pFbxNormals->GetDirectArray().GetAt(n1))); + pNormals->push_back(convertVec3(pFbxNormals->GetDirectArray().GetAt(n2))); + } + + if (pTexCoords) + { + pTexCoords->push_back(convertVec2(getElement(pFbxUVs, fbxMesh, i, 0, nVertex0))); + pTexCoords->push_back(convertVec2(getElement(pFbxUVs, fbxMesh, i, j - 1, nVertex - 1))); + pTexCoords->push_back(convertVec2(getElement(pFbxUVs, fbxMesh, i, j, nVertex))); + } + + if (pColors) + { + pColors->push_back(convertColor(getElement(pFbxColors, fbxMesh, i, 0, nVertex0))); + pColors->push_back(convertColor(getElement(pFbxColors, fbxMesh, i, j - 1, nVertex - 1))); + pColors->push_back(convertColor(getElement(pFbxColors, fbxMesh, i, j, nVertex))); + } + } + } + + for (int i = 0; i < pGeode->getNumDrawables(); ++i) + { + osg::Geometry* pGeometry = pGeode->getDrawable(i)->asGeometry(); + pGeometry->setName(pGeode->getName()); + + osg::DrawArrays* pDrawArrays = new osg::DrawArrays( + GL_TRIANGLES, 0, pGeometry->getVertexArray()->getNumElements()); + pGeometry->addPrimitiveSet(pDrawArrays); + } + + if (geomType == GEOMETRY_RIG) + { + for (int i = 0; i < nDeformerCount; ++i) + { + KFbxSkin* pSkin = (KFbxSkin*)fbxMesh->GetDeformer(i, KFbxDeformer::eSKIN); + int nClusters = pSkin->GetClusterCount(); + for (int j = 0; j < nClusters; ++j) + { + KFbxCluster* pCluster = (KFbxCluster*)pSkin->GetCluster(j); + KFbxNode* pBone = pCluster->GetLink(); + + int nIndices = pCluster->GetControlPointIndicesCount(); + int* pIndices = pCluster->GetControlPointIndices(); + double* pWeights = pCluster->GetControlPointWeights(); + + for (int k = 0; k < nIndices; ++k) + { + int fbxIndex = pIndices[k]; + float weight = static_cast(pWeights[k]); + + for (FbxToOsgVertexMap::const_iterator it = + fbxToOsgVertMap.find(fbxIndex); + it != fbxToOsgVertMap.end() && + it->first == fbxIndex; ++it) + { + GIPair gi = it->second; + osgAnimation::RigGeometry& rig = dynamic_cast(*gi.first); + osgAnimation::VertexInfluenceMap& vim = *rig.getInfluenceMap(); + osgAnimation::VertexInfluence& vi = getVertexInfluence(vim, pBone->GetName()); + vi.push_back(osgAnimation::VertexIndexWeight( + gi.second, weight)); + } + } + } + } + } + else if (geomType == GEOMETRY_MORPH) + { + pGeode->addUpdateCallback(new osgAnimation::UpdateMorph(pGeode->getName())); + + + for (int i = 0; i < pGeode->getNumDrawables(); ++i) + { + osg::Geometry* pGeometry = pGeode->getDrawable(i)->asGeometry(); + + osgAnimation::MorphGeometry& morph = dynamic_cast(*pGeometry); + + //read morph geometry + for (int j = 0; j < nMorphShapeCount; ++j) + { + const KFbxGeometryBase* pMorphShape = fbxMesh->GetShape(i); + + const KFbxLayerElementNormal* pFbxShapeNormals = 0; + if (const KFbxLayer* pFbxShapeLayer = pMorphShape->GetLayer(0)) + { + pFbxShapeNormals = pFbxShapeLayer->GetNormals(); + if (!layerElementValid(pFbxShapeNormals)) pFbxShapeNormals = 0; + } + + osg::Geometry* pMorphTarget = new osg::Geometry(morph); + pMorphTarget->setVertexArray(static_cast( + pMorphTarget->getVertexArray()->clone(osg::CopyOp::DEEP_COPY_ARRAYS))); + if (pFbxShapeNormals) + { + if (osg::Array* pNormals = pMorphTarget->getNormalArray()) + { + pMorphTarget->setNormalArray(static_cast( + pNormals->clone(osg::CopyOp::DEEP_COPY_ARRAYS))); + } + } + pMorphTarget->setName(fbxMesh->GetShapeName(j)); + KFCurve* pCurve = fbxMesh->GetShapeChannel(j); + double defaultWeight = pCurve->GetValue() * 0.01; + morph.addMorphTarget(pMorphTarget, static_cast(defaultWeight)); + + readAnimation(pNode, pGeode, pAnimationManager, fbxMesh, j); + } + } + + for (int i = 0; i < nMorphShapeCount; ++i) + { + const KFbxGeometryBase* pMorphShape = fbxMesh->GetShape(i); + + const KFbxLayerElementNormal* pFbxShapeNormals = 0; + if (const KFbxLayer* pFbxShapeLayer = pMorphShape->GetLayer(0)) + { + pFbxShapeNormals = pFbxShapeLayer->GetNormals(); + if (!layerElementValid(pFbxShapeNormals)) pFbxShapeNormals = 0; + } + + const KFbxVector4* pControlPoints = pMorphShape->GetControlPoints(); + int nControlPoints = pMorphShape->GetControlPointsCount(); + for (int fbxIndex = 0; fbxIndex < nControlPoints; ++fbxIndex) + { + osg::Vec3 vPos = convertVec3(pControlPoints[fbxIndex]); + for (FbxToOsgVertexMap::const_iterator it = + fbxToOsgVertMap.find(fbxIndex); + it != fbxToOsgVertMap.end() && + it->first == fbxIndex; ++it) + { + GIPair gi = it->second; + osgAnimation::MorphGeometry& morphGeom = + dynamic_cast(*gi.first); + osg::Geometry* pGeometry = morphGeom.getMorphTarget(i).getGeometry(); + osg::Vec3Array* pVertices = static_cast(pGeometry->getVertexArray()); + (*pVertices)[gi.second] = vPos; + + if (pFbxShapeNormals) + { + if (osg::Vec3Array* pNormals = static_cast(pGeometry->getNormalArray())) + { + (*pNormals)[gi.second] = convertVec3( + pFbxShapeNormals->GetDirectArray().GetAt(osgToFbxNormMap[gi])); + } + } + } + } + } + } + + KFbxXMatrix fbxVertexTransform; + fbxVertexTransform.SetTRS( + pNode->GetGeometricTranslation(KFbxNode::eSOURCE_SET), + pNode->GetGeometricRotation(KFbxNode::eSOURCE_SET), + pNode->GetGeometricScaling(KFbxNode::eSOURCE_SET)); + const double* pVertexMat = fbxVertexTransform; + osg::Matrix vertexMat(pVertexMat); + + if (vertexMat.isIdentity()) + { + return osgDB::ReaderWriter::ReadResult(pGeode); + } + else + { + osg::MatrixTransform* pMatTrans = new osg::MatrixTransform(vertexMat); + pMatTrans->addChild(pGeode); + return osgDB::ReaderWriter::ReadResult(pMatTrans); + } +} + +osgDB::ReaderWriter::ReadResult readFbxMesh(KFbxNode* pNode, + osg::ref_ptr& pAnimationManager, + const std::vector>& materialList, + const std::vector>& textureList) +{ + KFbxMesh* lMesh = dynamic_cast(pNode->GetNodeAttribute()); + + if (!lMesh) + { + return osgDB::ReaderWriter::ReadResult::ERROR_IN_READING_FILE; + } + + return readMesh(pNode, lMesh, pAnimationManager, materialList, textureList, pNode->GetName()); +} diff --git a/src/osgPlugins/fbx/fbxRMesh.h b/src/osgPlugins/fbx/fbxRMesh.h new file mode 100644 index 000000000..20a9d5c95 --- /dev/null +++ b/src/osgPlugins/fbx/fbxRMesh.h @@ -0,0 +1,14 @@ +#ifndef FBXRMESH_H +#define FBXRMESH_H + +#include +#include +#include + +osgDB::ReaderWriter::ReadResult readFbxMesh( + FBXFILESDK_NAMESPACE::KFbxNode* pNode, + osg::ref_ptr& pAnimationManager, + const std::vector>&, + const std::vector>&); + +#endif diff --git a/src/osgPlugins/fbx/fbxRNode.cpp b/src/osgPlugins/fbx/fbxRNode.cpp new file mode 100644 index 000000000..cd48f97ce --- /dev/null +++ b/src/osgPlugins/fbx/fbxRNode.cpp @@ -0,0 +1,560 @@ +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#if defined(_MSC_VER) + #pragma warning( disable : 4505 ) +#endif +#include + +#include "fbxRAnimation.h" +#include "fbxRCamera.h" +#include "fbxRLight.h" +#include "fbxRMesh.h" + +template +class FbxToOsgMap +{ + std::map> m_map; +public: + ConvertFunc m_convertFunc; + + FbxToOsgMap(ConvertFunc convertFunc) : m_convertFunc(convertFunc) {} + + osg::ref_ptr Get(const FbxT* fbx) + { + if (!fbx) + return 0; + std::map>::iterator it = m_map.find(fbx); + if (it != m_map.end()) + { + return it->second; + } + osg::ref_ptr osgObj = m_convertFunc(fbx); + m_map.insert(std::pair>(fbx, osgObj)); + return osgObj; + } +}; + +struct GetOsgTexture +{ + const std::string& m_dir; + + GetOsgTexture(const std::string& dir) : m_dir(dir) {} + + static osg::Texture::WrapMode convertWrap(KFbxTexture::EWrapMode wrap) + { + return wrap == KFbxTexture::eREPEAT ? + osg::Texture2D::REPEAT : osg::Texture2D::CLAMP_TO_EDGE; + } + + osg::ref_ptr operator () (const KFbxTexture* fbx) + { + osg::Image* pImage; + if ((pImage = osgDB::readImageFile(osgDB::concatPaths(m_dir, fbx->GetRelativeFileName()))) || + (pImage = osgDB::readImageFile(osgDB::concatPaths(m_dir, fbx->GetFileName())))) + { + osg::ref_ptr pOsgTex = new osg::Texture2D; + + pOsgTex->setImage(pImage); + pOsgTex->setWrap(osg::Texture2D::WRAP_S, convertWrap(fbx->GetWrapModeU())); + pOsgTex->setWrap(osg::Texture2D::WRAP_T, convertWrap(fbx->GetWrapModeV())); + + return pOsgTex; + } + else + { + return 0; + } + } +}; + +struct GetOsgMaterial +{ + typedef FbxToOsgMap TextureMap; + TextureMap m_textureMap; + +public: + osg::ref_ptr m_pTexture; + + GetOsgMaterial(const std::string& dir) : m_textureMap(GetOsgTexture(dir)){} + + osg::ref_ptr operator () (const KFbxSurfaceMaterial* pFbxMat) + { + osg::ref_ptr pOsgMat = new osg::Material; + + const KFbxSurfaceLambert* pFbxLambert = dynamic_cast(pFbxMat); + + const KFbxProperty lProperty = pFbxMat->FindProperty(KFbxSurfaceMaterial::sDiffuse); + if(lProperty.IsValid()){ + int lNbTex = lProperty.GetSrcObjectCount(KFbxTexture::ClassId); + for (int lTextureIndex = 0; lTextureIndex < lNbTex; lTextureIndex++) + { + const KFbxTexture* lTexture = KFbxCast(lProperty.GetSrcObject(KFbxTexture::ClassId, lTextureIndex)); + if(lTexture) + { + m_pTexture = m_textureMap.Get(lTexture); + } + + //For now only allow 1 texture + break; + } + } + + if (pFbxLambert) + { + fbxDouble3 color = pFbxLambert->GetDiffuseColor().Get(); + double factor = pFbxLambert->GetDiffuseFactor().Get(); + pOsgMat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4( + static_cast(color[0] * factor), + static_cast(color[1] * factor), + static_cast(color[2] * factor), + static_cast(1.0 - pFbxLambert->GetTransparencyFactor().Get()))); + + color = pFbxLambert->GetAmbientColor().Get(); + factor = pFbxLambert->GetAmbientFactor().Get(); + pOsgMat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4( + static_cast(color[0] * factor), + static_cast(color[1] * factor), + static_cast(color[2] * factor), + 1.0f)); + + color = pFbxLambert->GetEmissiveColor().Get(); + factor = pFbxLambert->GetEmissiveFactor().Get(); + pOsgMat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4( + static_cast(color[0] * factor), + static_cast(color[1] * factor), + static_cast(color[2] * factor), + 1.0f)); + + if (const KFbxSurfacePhong* pFbxPhong = dynamic_cast(pFbxLambert)) + { + color = pFbxPhong->GetSpecularColor().Get(); + factor = pFbxPhong->GetSpecularFactor().Get(); + pOsgMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4( + static_cast(color[0] * factor), + static_cast(color[1] * factor), + static_cast(color[2] * factor), + 1.0f)); + + pOsgMat->setShininess(osg::Material::FRONT_AND_BACK, + static_cast(pFbxPhong->GetShininess().Get())); + } + } + + return pOsgMat; + } +}; + +osg::Quat makeQuat(const fbxDouble3& degrees, ERotationOrder fbxRotOrder) +{ + double radiansX = osg::DegreesToRadians(degrees[0]); + double radiansY = osg::DegreesToRadians(degrees[1]); + double radiansZ = osg::DegreesToRadians(degrees[2]); + + switch (fbxRotOrder) + { + case eEULER_XYZ: + return osg::Quat( + radiansX, osg::Vec3d(1,0,0), + radiansY, osg::Vec3d(0,1,0), + radiansZ, osg::Vec3d(0,0,1)); + case eEULER_XZY: + return osg::Quat( + radiansX, osg::Vec3d(1,0,0), + radiansY, osg::Vec3d(0,0,1), + radiansZ, osg::Vec3d(0,1,0)); + case eEULER_YZX: + return osg::Quat( + radiansX, osg::Vec3d(0,1,0), + radiansY, osg::Vec3d(0,0,1), + radiansZ, osg::Vec3d(1,0,0)); + case eEULER_YXZ: + return osg::Quat( + radiansX, osg::Vec3d(0,1,0), + radiansY, osg::Vec3d(1,0,0), + radiansZ, osg::Vec3d(0,0,1)); + case eEULER_ZXY: + return osg::Quat( + radiansX, osg::Vec3d(0,0,1), + radiansY, osg::Vec3d(1,0,0), + radiansZ, osg::Vec3d(0,1,0)); + case eEULER_ZYX: + return osg::Quat( + radiansX, osg::Vec3d(0,0,1), + radiansY, osg::Vec3d(0,1,0), + radiansZ, osg::Vec3d(1,0,0)); + case eSPHERIC_XYZ: + { + //I don't know what eSPHERIC_XYZ means, so this is a complete guess. + osg::Quat quat; + quat.makeRotate(osg::Vec3d(1.0, 0.0, 0.0), osg::Vec3d(degrees[0], degrees[1], degrees[2])); + return quat; + } + default: + osg::notify(osg::WARN) << "Invalid FBX rotation mode." << std::endl; + return osg::Quat(); + } +} + +void makeLocalMatrix(const KFbxNode* pNode, osg::Matrix& m) +{ + /*From http://area.autodesk.com/forum/autodesk-fbx/fbx-sdk/the-makeup-of-the-local-matrix-of-an-kfbxnode/ + + Local Matrix = LclTranslation * RotationOffset * RotationPivot * + PreRotation * LclRotation * PostRotation * RotationPivotInverse * + ScalingOffset * ScalingPivot * LclScaling * ScalingPivotInverse + + LocalTranslation : translate (xform -query -translation) + RotationOffset: translation compensates for the change in the rotate pivot point (xform -q -rotateTranslation) + RotationPivot: current rotate pivot position (xform -q -rotatePivot) + PreRotation : joint orientation(pre rotation) + LocalRotation: rotate transform (xform -q -rotation & xform -q -rotateOrder) + PostRotation : rotate axis (xform -q -rotateAxis) + RotationPivotInverse: inverse of RotationPivot + ScalingOffset: translation compensates for the change in the scale pivot point (xform -q -scaleTranslation) + ScalingPivot: current scale pivot position (xform -q -scalePivot) + LocalScaling: scale transform (xform -q -scale) + ScalingPivotInverse: inverse of ScalingPivot + */ + + ERotationOrder fbxRotOrder = pNode->RotationOrder.Get(); + + fbxDouble3 fbxLclPos = pNode->LclTranslation.Get(); + fbxDouble3 fbxRotOff = pNode->RotationOffset.Get(); + fbxDouble3 fbxRotPiv = pNode->RotationPivot.Get(); + fbxDouble3 fbxPreRot = pNode->PreRotation.Get(); + fbxDouble3 fbxLclRot = pNode->LclRotation.Get(); + fbxDouble3 fbxPostRot = pNode->PostRotation.Get(); + fbxDouble3 fbxSclOff = pNode->ScalingOffset.Get(); + fbxDouble3 fbxSclPiv = pNode->ScalingPivot.Get(); + fbxDouble3 fbxLclScl = pNode->LclScaling.Get(); + + m.makeTranslate(osg::Vec3d( + fbxLclPos[0] + fbxRotOff[0] + fbxRotPiv[0], + fbxLclPos[1] + fbxRotOff[1] + fbxRotPiv[1], + fbxLclPos[2] + fbxRotOff[2] + fbxRotPiv[2])); + m.preMultRotate( + makeQuat(fbxPostRot, fbxRotOrder) * + makeQuat(fbxLclRot, fbxRotOrder) * + makeQuat(fbxPreRot, fbxRotOrder)); + m.preMultTranslate(osg::Vec3d( + fbxSclOff[0] + fbxSclPiv[0] - fbxRotPiv[0], + fbxSclOff[1] + fbxSclPiv[1] - fbxRotPiv[1], + fbxSclOff[2] + fbxSclPiv[2] - fbxRotPiv[2])); + m.preMultScale(osg::Vec3d(fbxLclScl[0], fbxLclScl[1], fbxLclScl[2])); + m.preMultTranslate(osg::Vec3d( + -fbxSclPiv[0], + -fbxSclPiv[1], + -fbxSclPiv[2])); +} + +void getApproximateTransform(const KFbxNode* pNode, osg::Vec3& trans, osg::Quat& quat, osg::Vec3& scale) +{ + ERotationOrder fbxRotOrder = pNode->RotationOrder.Get(); + + fbxDouble3 fbxLclPos = pNode->LclTranslation.Get(); + //fbxDouble3 fbxRotOff = pNode->RotationOffset.Get(); + //fbxDouble3 fbxRotPiv = pNode->RotationPivot.Get(); + fbxDouble3 fbxPreRot = pNode->PreRotation.Get(); + fbxDouble3 fbxLclRot = pNode->LclRotation.Get(); + fbxDouble3 fbxPostRot = pNode->PostRotation.Get(); + //fbxDouble3 fbxSclOff = pNode->ScalingOffset.Get(); + //fbxDouble3 fbxSclPiv = pNode->ScalingPivot.Get(); + fbxDouble3 fbxLclScl = pNode->LclScaling.Get(); + + trans.set( + static_cast(fbxLclPos[0]), + static_cast(fbxLclPos[1]), + static_cast(fbxLclPos[2])); + + quat = + makeQuat(fbxPostRot, fbxRotOrder) * + makeQuat(fbxLclRot, fbxRotOrder) * + makeQuat(fbxPreRot, fbxRotOrder); + + scale.set( + static_cast(fbxLclScl[0]), + static_cast(fbxLclScl[1]), + static_cast(fbxLclScl[2])); +} + +void getApproximateTransform(const KFbxNode* pNode, osg::Vec3& trans, osg::Vec3& euler, osg::Vec3& scale) +{ + //ERotationOrder fbxRotOrder = pNode->RotationOrder.Get(); + + fbxDouble3 fbxLclPos = pNode->LclTranslation.Get(); + //fbxDouble3 fbxRotOff = pNode->RotationOffset.Get(); + //fbxDouble3 fbxRotPiv = pNode->RotationPivot.Get(); + fbxDouble3 fbxPreRot = pNode->PreRotation.Get(); + fbxDouble3 fbxLclRot = pNode->LclRotation.Get(); + fbxDouble3 fbxPostRot = pNode->PostRotation.Get(); + //fbxDouble3 fbxSclOff = pNode->ScalingOffset.Get(); + //fbxDouble3 fbxSclPiv = pNode->ScalingPivot.Get(); + fbxDouble3 fbxLclScl = pNode->LclScaling.Get(); + + trans.set( + static_cast(fbxLclPos[0]), + static_cast(fbxLclPos[1]), + static_cast(fbxLclPos[2])); + + //TODO: Convert each rotation to a quaternion, concatenate them and extract euler from that. + euler.set( + osg::DegreesToRadians(static_cast(fbxPreRot[0] + fbxLclRot[0] + fbxPostRot[0])), + osg::DegreesToRadians(static_cast(fbxPreRot[1] + fbxLclRot[1] + fbxPostRot[1])), + osg::DegreesToRadians(static_cast(fbxPreRot[2] + fbxLclRot[2] + fbxPostRot[2]))); + + scale.set( + static_cast(fbxLclScl[0]), + static_cast(fbxLclScl[1]), + static_cast(fbxLclScl[2])); +} + +bool readBindPose(KFbxSdkManager& pManager, KFbxNode* pNode, + osgAnimation::Bone* osgBone) +{ + KArrayTemplate pPoseList; + KArrayTemplate pIndex; + if (!pNode || !KFbxPose::GetBindPoseContaining( + pManager, pNode, pPoseList, pIndex)) + { + return false; + } + + const double* pMat = pPoseList[0]->GetMatrix(pIndex[0]); + osgBone->setBindMatrixInBoneSpace(osg::Matrix(pMat)); + return true; +} + +osg::Group* createGroupNode(KFbxSdkManager& pSdkManager, KFbxNode* pNode, + const std::string& animName, const osg::Matrix& localMatrix, bool bNeedSkeleton) +{ + if (bNeedSkeleton) + { + osgAnimation::Bone* osgBone = new osgAnimation::Bone; + osgBone->setDataVariance(osg::Object::DYNAMIC); + osgBone->setName(pNode->GetName()); + osgBone->setDefaultUpdateCallback(animName); + + readBindPose(pSdkManager, pNode, osgBone); + + return osgBone; + } + else + { + bool bAnimated = !animName.empty(); + if (!bAnimated && localMatrix.isIdentity()) + { + osg::Group* pGroup = new osg::Group; + pGroup->setName(pNode->GetName()); + return pGroup; + } + + osg::MatrixTransform* pTransform = new osg::MatrixTransform(localMatrix); + pTransform->setName(pNode->GetName()); + if (bAnimated) + { + osgAnimation::UpdateTransform* pUpdate = new osgAnimation::UpdateTransform(animName); + + osg::Vec3 trans, rot, scale; + getApproximateTransform(pNode, trans, rot, scale); + + pUpdate->getPosition()->setValue(trans); + pUpdate->getEuler()->setValue(rot); + pUpdate->getScale()->setValue(scale); + pTransform->setUpdateCallback(pUpdate); + } + return pTransform; + } +} + +osgDB::ReaderWriter::ReadResult readFbxNode( + KFbxSdkManager& pSdkManager, KFbxNode* pNode, + osg::ref_ptr& pAnimationManager, + const std::string& dir, bool& bNeedSkeleton, int& nLightCount) +{ + if (KFbxNodeAttribute* lNodeAttribute = pNode->GetNodeAttribute()) + { + if (lNodeAttribute->GetAttributeType() == KFbxNodeAttribute::eNURB || + lNodeAttribute->GetAttributeType() == KFbxNodeAttribute::ePATCH) + { + KFbxGeometryConverter lConverter(&pSdkManager); + lConverter.TriangulateInPlace(pNode); + } + } + + KFbxNodeAttribute::EAttributeType lAttributeType = KFbxNodeAttribute::eUNIDENTIFIED; + if (pNode->GetNodeAttribute()) + { + lAttributeType = pNode->GetNodeAttribute()->GetAttributeType(); + if (lAttributeType == KFbxNodeAttribute::eSKELETON) + { + bNeedSkeleton = true; + } + } + + unsigned nMaterials = pNode->GetMaterialCount(); + std::vector> materialList; + std::vector> textureList; + materialList.reserve(nMaterials); + + typedef FbxToOsgMap MaterialMap; + MaterialMap materialMap(dir); + + for (unsigned i = 0; i < nMaterials; ++i) + { + materialList.push_back(materialMap.Get(pNode->GetMaterial(i))); + textureList.push_back(materialMap.m_convertFunc.m_pTexture); + } + + osg::NodeList skeletal, children; + + int nChildCount = pNode->GetChildCount(); + for (int i = 0; i < nChildCount; ++i) + { + KFbxNode* pChildNode = pNode->GetChild(i); + + if (pChildNode->GetParent() != pNode) + { + //workaround for bug that occurs in some files exported from Blender + continue; + } + + bool bChildNeedSkeleton = false; + osgDB::ReaderWriter::ReadResult childResult = readFbxNode( + pSdkManager, pChildNode, pAnimationManager, dir, + bChildNeedSkeleton, nLightCount); + if (childResult.error()) + { + return childResult; + } + else if (osg::Node* osgChild = childResult.getNode()) + { + if (bChildNeedSkeleton) + { + bNeedSkeleton = true; + skeletal.push_back(osgChild); + } + else + { + children.push_back(osgChild); + } + } + } + + std::string animName; + + if (bNeedSkeleton) + { + animName = readFbxBoneAnimation(pNode, pAnimationManager, + pNode->GetName()); + } + else + { + animName = readFbxAnimation(pNode, pAnimationManager, pNode->GetName()); + } + + osg::Matrix localMatrix; + makeLocalMatrix(pNode, localMatrix); + bool bLocalMatrixIdentity = localMatrix.isIdentity(); + + osg::ref_ptr osgGroup; + + bool bEmpty = children.empty() && !bNeedSkeleton; + + switch (lAttributeType) + { + case KFbxNodeAttribute::eUNIDENTIFIED: + if (children.size() + skeletal.size() == 1) + { + if (children.size() == 1) + { + return osgDB::ReaderWriter::ReadResult(children.front().get()); + } + else + { + return osgDB::ReaderWriter::ReadResult(skeletal.front().get()); + } + } + break; + case KFbxNodeAttribute::eMESH: + { + osgDB::ReaderWriter::ReadResult meshRes = readFbxMesh(pNode, + pAnimationManager, materialList, textureList); + if (meshRes.error()) + { + return meshRes; + } + else if (osg::Node* node = meshRes.getNode()) + { + bEmpty = false; + if (animName.empty() && + children.empty() && + skeletal.empty() && + bLocalMatrixIdentity) + { + return osgDB::ReaderWriter::ReadResult(node); + } + osgGroup = createGroupNode(pSdkManager, pNode, animName, localMatrix, bNeedSkeleton); + osgGroup->getOrCreateStateSet()->setMode(GL_RESCALE_NORMAL,osg::StateAttribute::ON); + + osgGroup->addChild(node); + } + } + break; + case KFbxNodeAttribute::eCAMERA: + case KFbxNodeAttribute::eLIGHT: + { + osgDB::ReaderWriter::ReadResult res = + lAttributeType == KFbxNodeAttribute::eCAMERA ? + readFbxCamera(pNode) : readFbxLight(pNode, nLightCount); + if (res.error()) + { + return res; + } + else if (osg::Group* resGroup = dynamic_cast(res.getObject())) + { + bEmpty = false; + if (animName.empty() && + bLocalMatrixIdentity) + { + osgGroup = resGroup; + } + else + { + osgGroup = createGroupNode(pSdkManager, pNode, animName, + localMatrix, bNeedSkeleton); + osgGroup->addChild(resGroup); + } + } + } + break; + } + + if (bEmpty) + { + osgDB::ReaderWriter::ReadResult(0); + } + + if (!osgGroup) osgGroup = createGroupNode(pSdkManager, pNode, animName, localMatrix, bNeedSkeleton); + for (osg::NodeList::iterator it = skeletal.begin(); it != skeletal.end(); ++it) + { + osgGroup->addChild(it->get()); + } + for (osg::NodeList::iterator it = children.begin(); it != children.end(); ++it) + { + osgGroup->addChild(it->get()); + } + + return osgDB::ReaderWriter::ReadResult(osgGroup.get()); +} diff --git a/src/osgPlugins/fbx/fbxRNode.h b/src/osgPlugins/fbx/fbxRNode.h new file mode 100644 index 000000000..a00ad2afe --- /dev/null +++ b/src/osgPlugins/fbx/fbxRNode.h @@ -0,0 +1,17 @@ +#ifndef FBXRNODE_H +#define FBXRNODE_H + +namespace osgAnimation +{ + class AnimationManagerBase; +} + +osgDB::ReaderWriter::ReadResult readFbxNode( + FBXFILESDK_NAMESPACE::KFbxSdkManager& pSdkManager, + FBXFILESDK_NAMESPACE::KFbxNode* pNode, + osg::ref_ptr& pAnimationManager, + const std::string& dir, + bool& bNeedSkeleton, + int& nLightCount); + +#endif diff --git a/src/osgWrappers/osgWidget/EventInterface.cpp b/src/osgWrappers/osgWidget/EventInterface.cpp index bbc488099..aa0154074 100644 --- a/src/osgWrappers/osgWidget/EventInterface.cpp +++ b/src/osgWrappers/osgWidget/EventInterface.cpp @@ -164,59 +164,59 @@ BEGIN_VALUE_REFLECTOR(osgWidget::EventInterface) ____EventInterface__C5_EventInterface_R1, "", ""); - I_Method1(bool, focus, IN, osgWidget::WindowManager *, x, + I_Method1(bool, focus, IN, const osgWidget::WindowManager *, x, Properties::VIRTUAL, - __bool__focus__WindowManager_P1, + __bool__focus__C5_WindowManager_P1, "", ""); - I_Method1(bool, unfocus, IN, osgWidget::WindowManager *, x, + I_Method1(bool, unfocus, IN, const osgWidget::WindowManager *, x, Properties::VIRTUAL, - __bool__unfocus__WindowManager_P1, + __bool__unfocus__C5_WindowManager_P1, "", ""); - I_Method3(bool, mouseEnter, IN, double, x, IN, double, x, IN, osgWidget::WindowManager *, x, + I_Method3(bool, mouseEnter, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, Properties::VIRTUAL, - __bool__mouseEnter__double__double__WindowManager_P1, + __bool__mouseEnter__double__double__C5_WindowManager_P1, "", ""); - I_Method3(bool, mouseOver, IN, double, x, IN, double, x, IN, osgWidget::WindowManager *, x, + I_Method3(bool, mouseOver, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, Properties::VIRTUAL, - __bool__mouseOver__double__double__WindowManager_P1, + __bool__mouseOver__double__double__C5_WindowManager_P1, "", ""); - I_Method3(bool, mouseLeave, IN, double, x, IN, double, x, IN, osgWidget::WindowManager *, x, + I_Method3(bool, mouseLeave, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, Properties::VIRTUAL, - __bool__mouseLeave__double__double__WindowManager_P1, + __bool__mouseLeave__double__double__C5_WindowManager_P1, "", ""); - I_Method3(bool, mouseDrag, IN, double, x, IN, double, x, IN, osgWidget::WindowManager *, x, + I_Method3(bool, mouseDrag, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, Properties::VIRTUAL, - __bool__mouseDrag__double__double__WindowManager_P1, + __bool__mouseDrag__double__double__C5_WindowManager_P1, "", ""); - I_Method3(bool, mousePush, IN, double, x, IN, double, x, IN, osgWidget::WindowManager *, x, + I_Method3(bool, mousePush, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, Properties::VIRTUAL, - __bool__mousePush__double__double__WindowManager_P1, + __bool__mousePush__double__double__C5_WindowManager_P1, "", ""); - I_Method3(bool, mouseRelease, IN, double, x, IN, double, x, IN, osgWidget::WindowManager *, x, + I_Method3(bool, mouseRelease, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, Properties::VIRTUAL, - __bool__mouseRelease__double__double__WindowManager_P1, + __bool__mouseRelease__double__double__C5_WindowManager_P1, "", ""); - I_Method3(bool, mouseScroll, IN, double, x, IN, double, x, IN, osgWidget::WindowManager *, x, + I_Method3(bool, mouseScroll, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, Properties::VIRTUAL, - __bool__mouseScroll__double__double__WindowManager_P1, + __bool__mouseScroll__double__double__C5_WindowManager_P1, "", ""); - I_Method3(bool, keyDown, IN, int, x, IN, int, x, IN, osgWidget::WindowManager *, x, + I_Method3(bool, keyDown, IN, int, x, IN, int, x, IN, const osgWidget::WindowManager *, x, Properties::VIRTUAL, - __bool__keyDown__int__int__WindowManager_P1, + __bool__keyDown__int__int__C5_WindowManager_P1, "", ""); - I_Method3(bool, keyUp, IN, int, x, IN, int, x, IN, osgWidget::WindowManager *, x, + I_Method3(bool, keyUp, IN, int, x, IN, int, x, IN, const osgWidget::WindowManager *, x, Properties::VIRTUAL, - __bool__keyUp__int__int__WindowManager_P1, + __bool__keyUp__int__int__C5_WindowManager_P1, "", ""); I_Method1(void, setEventMask, IN, unsigned int, mask, diff --git a/src/osgWrappers/osgWidget/Widget.cpp b/src/osgWrappers/osgWidget/Widget.cpp index 9dbb81cd3..13d866080 100644 --- a/src/osgWrappers/osgWidget/Widget.cpp +++ b/src/osgWrappers/osgWidget/Widget.cpp @@ -64,47 +64,47 @@ BEGIN_OBJECT_REFLECTOR(osgWidget::NotifyWidget) "", ""); I_Method1(bool, focus, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__focus__C5_WindowManager_P1, "", ""); I_Method1(bool, unfocus, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__unfocus__C5_WindowManager_P1, "", ""); I_Method3(bool, mouseEnter, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__mouseEnter__double__double__C5_WindowManager_P1, "", ""); I_Method3(bool, mouseOver, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__mouseOver__double__double__C5_WindowManager_P1, "", ""); I_Method3(bool, mouseLeave, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__mouseLeave__double__double__C5_WindowManager_P1, "", ""); I_Method3(bool, mouseDrag, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__mouseDrag__double__double__C5_WindowManager_P1, "", ""); I_Method3(bool, mousePush, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__mousePush__double__double__C5_WindowManager_P1, "", ""); I_Method3(bool, mouseRelease, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__mouseRelease__double__double__C5_WindowManager_P1, "", ""); I_Method3(bool, mouseScroll, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__mouseScroll__double__double__C5_WindowManager_P1, "", ""); @@ -157,47 +157,47 @@ BEGIN_OBJECT_REFLECTOR(osgWidget::NullWidget) "", ""); I_Method1(bool, focus, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__focus__C5_WindowManager_P1, "", ""); I_Method1(bool, unfocus, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__unfocus__C5_WindowManager_P1, "", ""); I_Method3(bool, mouseEnter, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__mouseEnter__double__double__C5_WindowManager_P1, "", ""); I_Method3(bool, mouseOver, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__mouseOver__double__double__C5_WindowManager_P1, "", ""); I_Method3(bool, mouseLeave, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__mouseLeave__double__double__C5_WindowManager_P1, "", ""); I_Method3(bool, mouseDrag, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__mouseDrag__double__double__C5_WindowManager_P1, "", ""); I_Method3(bool, mousePush, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__mousePush__double__double__C5_WindowManager_P1, "", ""); I_Method3(bool, mouseRelease, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__mouseRelease__double__double__C5_WindowManager_P1, "", ""); I_Method3(bool, mouseScroll, IN, double, x, IN, double, x, IN, const osgWidget::WindowManager *, x, - Properties::NON_VIRTUAL, + Properties::VIRTUAL, __bool__mouseScroll__double__double__C5_WindowManager_P1, "", "");