diff --git a/src/osgPlugins/fbx/CMakeLists.txt b/src/osgPlugins/fbx/CMakeLists.txt index df997b4bd..4cd4bbb6c 100644 --- a/src/osgPlugins/fbx/CMakeLists.txt +++ b/src/osgPlugins/fbx/CMakeLists.txt @@ -13,15 +13,11 @@ SET(TARGET_SRC ) SET(TARGET_H - fbxRAnimation.h - fbxRCamera.h - fbxRLight.h - fbxRMesh.h - fbxRNode.h + fbxMaterialToOsgStateSet.h + fbxReader.h ReaderWriterFBX.h WriterCompareTriangle.h WriterNodeVisitor.h - fbxMaterialToOsgStateSet.h ) ADD_DEFINITIONS(-DKFBX_PLUGIN -DKFBX_FBXSDK -DKFBX_NODLL) diff --git a/src/osgPlugins/fbx/ReaderWriterFBX.cpp b/src/osgPlugins/fbx/ReaderWriterFBX.cpp index 165c14d47..5e5895f4b 100644 --- a/src/osgPlugins/fbx/ReaderWriterFBX.cpp +++ b/src/osgPlugins/fbx/ReaderWriterFBX.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -23,8 +24,7 @@ #include #include "ReaderWriterFBX.h" -#include "fbxRNode.h" -#include "fbxMaterialToOsgStateSet.h" +#include "fbxReader.h" #include "WriterNodeVisitor.h" /// Returns true if the given node is a basic root group with no special information. @@ -255,6 +255,7 @@ ReaderWriterFBX::readNode(const std::string& filenameInit, pScene->SetCurrentTake(pScene->GetCurrentTakeName()); bool useFbxRoot = false; + bool lightmapTextures = false; if (options) { std::istringstream iss(options->getOptionString()); @@ -265,10 +266,13 @@ ReaderWriterFBX::readNode(const std::string& filenameInit, { useFbxRoot = true; } + if (opt == "LightmapTextures") + { + lightmapTextures = true; + } } } - osg::ref_ptr pAnimationManager; bool bIsBone = false; int nLightCount = 0; osg::ref_ptr localOptions = NULL; @@ -279,29 +283,59 @@ ReaderWriterFBX::readNode(const std::string& filenameInit, localOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_IMAGES); std::string filePath = osgDB::getFilePath(filename); - FbxMaterialToOsgStateSet fbxMaterialToOsgStateSet(filePath, localOptions.get()); + FbxMaterialToOsgStateSet fbxMaterialToOsgStateSet(filePath, localOptions.get(), lightmapTextures); std::set fbxSkeletons; findLinkedFbxSkeletonNodes(pNode, fbxSkeletons); - std::map nodeMap; - BindMatrixMap boneBindMatrices; - std::map skeletonMap; - ReadResult res = readFbxNode(*pSdkManager, *pScene, pNode, pAnimationManager, - bIsBone, nLightCount, fbxMaterialToOsgStateSet, nodeMap, - boneBindMatrices, fbxSkeletons, skeletonMap, *localOptions); + 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} + }; + + 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; + } + } + } + + + OsgFbxReader reader(*pSdkManager, + *pScene, + fbxMaterialToOsgStateSet, + fbxSkeletons, + *localOptions, + authoringTool, + lightmapTextures); + + ReadResult res = reader.readFbxNode(pNode, bIsBone, nLightCount); if (res.success()) { fbxMaterialToOsgStateSet.checkInvertTransparency(); - resolveBindMatrices(*res.getNode(), boneBindMatrices, nodeMap); + resolveBindMatrices(*res.getNode(), reader.boneBindMatrices, reader.nodeMap); osg::Node* osgNode = res.getNode(); osgNode->getOrCreateStateSet()->setMode(GL_RESCALE_NORMAL,osg::StateAttribute::ON); osgNode->getOrCreateStateSet()->setMode(GL_NORMALIZE,osg::StateAttribute::ON); - if (pAnimationManager.valid()) + if (reader.pAnimationManager.valid()) { if (osgNode->getUpdateCallback()) { @@ -311,8 +345,8 @@ ReaderWriterFBX::readNode(const std::string& filenameInit, } //because the animations may be altered after registering - pAnimationManager->buildTargetReference(); - osgNode->setUpdateCallback(pAnimationManager.get()); + reader.pAnimationManager->buildTargetReference(); + osgNode->setUpdateCallback(reader.pAnimationManager.get()); } KFbxAxisSystem fbxAxis = pScene->GetGlobalSettings().GetAxisSystem(); @@ -439,6 +473,19 @@ 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); + } + 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 add68c84d..a7f059a09 100644 --- a/src/osgPlugins/fbx/ReaderWriterFBX.h +++ b/src/osgPlugins/fbx/ReaderWriterFBX.h @@ -16,6 +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."); } const char* className() const { return "FBX reader/writer"; } diff --git a/src/osgPlugins/fbx/fbxMaterialToOsgStateSet.cpp b/src/osgPlugins/fbx/fbxMaterialToOsgStateSet.cpp index 9a1d2d83e..af8ca9d21 100644 --- a/src/osgPlugins/fbx/fbxMaterialToOsgStateSet.cpp +++ b/src/osgPlugins/fbx/fbxMaterialToOsgStateSet.cpp @@ -18,12 +18,26 @@ FbxMaterialToOsgStateSet::convert(const KFbxSurfaceMaterial* pFbxMat) if (it != _kFbxMaterialMap.end()) return it->second; static int nbMat = 0; + osg::ref_ptr pOsgMat = new osg::Material; - osg::ref_ptr pOsgTex = NULL; pOsgMat->setName(pFbxMat->GetName()); + + // texture maps... + osg::ref_ptr pOsgDiffuseTex = NULL; + osg::ref_ptr pOsgReflectionTex = NULL; + osg::ref_ptr pOsgOpacityTex = NULL; + osg::ref_ptr pOsgEmissiveTex = NULL; + // add more maps here... + + StateSetContent result; + + result.material = pOsgMat; + + fbxString shadingModel = pFbxMat->GetShadingModel().Get(); const KFbxSurfaceLambert* pFbxLambert = dynamic_cast(pFbxMat); + // diffuse map... const KFbxProperty lProperty = pFbxMat->FindProperty(KFbxSurfaceMaterial::sDiffuse); if (lProperty.IsValid()) { @@ -33,13 +47,82 @@ FbxMaterialToOsgStateSet::convert(const KFbxSurfaceMaterial* pFbxMat) KFbxTexture* lTexture = KFbxCast(lProperty.GetSrcObject(KFbxTexture::ClassId, lTextureIndex)); if (lTexture) { - pOsgTex = fbxTextureToOsgTexture(lTexture); + pOsgDiffuseTex = fbxTextureToOsgTexture(lTexture); + result.diffuseTexture = pOsgDiffuseTex.release(); + result.diffuseChannel = lTexture->UVSet.Get(); } //For now only allow 1 texture break; } } + + // opacity map... + const KFbxProperty lOpacityProperty = pFbxMat->FindProperty(KFbxSurfaceMaterial::sTransparentColor); + if (lOpacityProperty.IsValid()) + { + int lNbTex = lOpacityProperty.GetSrcObjectCount(KFbxTexture::ClassId); + for (int lTextureIndex = 0; lTextureIndex < lNbTex; lTextureIndex++) + { + 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(); + } + + //For now only allow 1 texture + break; + } + } + + // reflection map... + const KFbxProperty lReflectionProperty = pFbxMat->FindProperty(KFbxSurfaceMaterial::sReflection); + if (lReflectionProperty.IsValid()) + { + int lNbTex = lReflectionProperty.GetSrcObjectCount(KFbxTexture::ClassId); + for (int lTextureIndex = 0; lTextureIndex < lNbTex; lTextureIndex++) + { + KFbxTexture* lTexture = KFbxCast(lReflectionProperty.GetSrcObject(KFbxTexture::ClassId, lTextureIndex)); + if (lTexture) + { + // support only spherical reflection maps... + if (KFbxTexture::eUMT_ENVIRONMENT == lTexture->GetMappingType()) + { + pOsgReflectionTex = fbxTextureToOsgTexture(lTexture); + result.reflectionTexture = pOsgReflectionTex.release(); + result.reflectionChannel = lTexture->UVSet.Get(); + } + } + + //For now only allow 1 texture + break; + } + } + + // emissive map... + const KFbxProperty lEmissiveProperty = pFbxMat->FindProperty(KFbxSurfaceMaterial::sEmissive); + if (lEmissiveProperty.IsValid()) + { + int lNbTex = lEmissiveProperty.GetSrcObjectCount(KFbxTexture::ClassId); + for (int lTextureIndex = 0; lTextureIndex < lNbTex; lTextureIndex++) + { + KFbxTexture* lTexture = KFbxCast(lEmissiveProperty.GetSrcObject(KFbxTexture::ClassId, lTextureIndex)); + if (lTexture) + { + pOsgEmissiveTex = fbxTextureToOsgTexture(lTexture); + result.emissiveTexture = pOsgEmissiveTex.release(); + result.emissiveChannel = lTexture->UVSet.Get(); + } + + //For now only allow 1 texture + break; + } + } + if (pFbxLambert) { fbxDouble3 color = pFbxLambert->GetDiffuseColor().Get(); @@ -78,10 +161,28 @@ FbxMaterialToOsgStateSet::convert(const KFbxSurfaceMaterial* pFbxMat) pOsgMat->setShininess(osg::Material::FRONT_AND_BACK, static_cast(pFbxPhong->GetShininess().Get())); + + // get maps factors... + result.diffuseFactor = pFbxPhong->GetDiffuseFactor().Get(); + result.reflectionFactor = pFbxPhong->GetReflectionFactor().Get(); + result.opacityFactor = pFbxPhong->GetTransparencyFactor().Get(); + // get more factors here... } } - StateSetContent result(pOsgMat.release(), pOsgTex.release()); - _kFbxMaterialMap.insert(KFbxMaterialMap::value_type(pFbxMat, result)); + + 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)); return result; } @@ -117,7 +218,7 @@ void FbxMaterialToOsgStateSet::checkInvertTransparency() int zeroAlpha = 0, oneAlpha = 0; for (KFbxMaterialMap::const_iterator it = _kFbxMaterialMap.begin(); it != _kFbxMaterialMap.end(); ++it) { - const osg::Material* pMaterial = it->second.first; + const osg::Material* pMaterial = it->second.material.get(); float alpha = pMaterial->getDiffuse(osg::Material::FRONT).a(); if (alpha > 0.999f) { @@ -135,7 +236,7 @@ void FbxMaterialToOsgStateSet::checkInvertTransparency() for (KFbxMaterialMap::const_iterator it = _kFbxMaterialMap.begin(); it != _kFbxMaterialMap.end(); ++it) { - osg::Material* pMaterial = it->second.first; + osg::Material* pMaterial = it->second.material.get(); osg::Vec4 diffuse = pMaterial->getDiffuse(osg::Material::FRONT); diffuse.a() = 1.0f - diffuse.a(); pMaterial->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); diff --git a/src/osgPlugins/fbx/fbxMaterialToOsgStateSet.h b/src/osgPlugins/fbx/fbxMaterialToOsgStateSet.h index c89da51e0..fa70fdd77 100644 --- a/src/osgPlugins/fbx/fbxMaterialToOsgStateSet.h +++ b/src/osgPlugins/fbx/fbxMaterialToOsgStateSet.h @@ -15,9 +15,52 @@ //The only things we need to create a new StateSet are texture and materials. So we store that in a pair. //We Don't store directly in stateSet because getOrCreateStateSet function set some parameters. -typedef std::pair StateSetContent; -//We use the pointers setted by the importer to not duplicate materials and textures. +struct StateSetContent +{ + StateSetContent() + : diffuseFactor(1.0), + opacityFactor(1.0), + reflectionFactor(1.0), + emissiveFactor(1.0) + { + } + + osg::ref_ptr material; + + // textures objects... + osg::ref_ptr diffuseTexture; + osg::ref_ptr opacityTexture; + osg::ref_ptr reflectionTexture; + osg::ref_ptr emissiveTexture; + // more textures types here... + + // textures maps channels names... + std::string diffuseChannel; + std::string opacityChannel; + std::string reflectionChannel; + std::string emissiveChannel; + // more channels names here... + + // combining factors... + double diffuseFactor; + double opacityFactor; + 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... + }; +}; + +//We use the pointers set by the importer to not duplicate materials and textures. typedef std::map KFbxMaterialMap; //This map is used to not load the same image more than 1 time. @@ -30,9 +73,10 @@ public: StateSetContent convert(const KFbxSurfaceMaterial* pFbxMat); //dir is the directory where fbx is stored (for relative path). - FbxMaterialToOsgStateSet(const std::string& dir, const osgDB::Options* options) : + FbxMaterialToOsgStateSet(const std::string& dir, const osgDB::Options* options, bool lightmapTextures) : _options(options), - _dir(dir) {} + _dir(dir), + _lightmapTextures(lightmapTextures){} void checkInvertTransparency(); private: @@ -43,6 +87,7 @@ private: ImageMap _imageMap; const osgDB::Options* _options; const std::string _dir; + bool _lightmapTextures; }; diff --git a/src/osgPlugins/fbx/fbxRAnimation.cpp b/src/osgPlugins/fbx/fbxRAnimation.cpp index 17189fc52..848c7f380 100644 --- a/src/osgPlugins/fbx/fbxRAnimation.cpp +++ b/src/osgPlugins/fbx/fbxRAnimation.cpp @@ -11,6 +11,8 @@ #include #include +#include "fbxReader.h" + osg::Quat makeQuat(const fbxDouble3&, ERotationOrder); osg::Quat makeQuat(const osg::Vec3& radians, ERotationOrder fbxRotOrder) @@ -219,10 +221,7 @@ osgAnimation::Animation* readFbxAnimation(KFbxNode* pNode, return addChannels(pTranslationChannel, pRotationChannel, pScaleChannel, pAnimManager, pTakeName); } -std::string readFbxAnimation(KFbxNode* pNode, - KFbxScene& fbxScene, - osg::ref_ptr& pAnimManager, - const char* targetName) +std::string OsgFbxReader::readFbxAnimation(KFbxNode* pNode, const char* targetName) { std::string result; for (int i = 0; i < fbxScene.GetSrcObjectCount(FBX_TYPE(KFbxAnimStack)); ++i) @@ -240,8 +239,8 @@ std::string readFbxAnimation(KFbxNode* pNode, { KFbxAnimLayer* pAnimLayer = pAnimStack->GetMember(FBX_TYPE(KFbxAnimLayer), j); - if (osgAnimation::Animation* pAnimation = readFbxAnimation( - pNode, pAnimLayer, pTakeName, targetName, pAnimManager)) + if (osgAnimation::Animation* pAnimation = ::readFbxAnimation( + pNode, pAnimLayer, pTakeName, targetName, pAnimationManager)) { result = targetName; } diff --git a/src/osgPlugins/fbx/fbxRAnimation.h b/src/osgPlugins/fbx/fbxRAnimation.h deleted file mode 100644 index f44c85bed..000000000 --- a/src/osgPlugins/fbx/fbxRAnimation.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef FBXRANIMATION_H -#define FBXRANIMATION_H - -#include - -std::string readFbxAnimation( - KFbxNode*, - KFbxScene& fbxScene, - osg::ref_ptr&, - const char* targetName); - -#endif diff --git a/src/osgPlugins/fbx/fbxRCamera.cpp b/src/osgPlugins/fbx/fbxRCamera.cpp index 87de1200d..a9814d905 100644 --- a/src/osgPlugins/fbx/fbxRCamera.cpp +++ b/src/osgPlugins/fbx/fbxRCamera.cpp @@ -8,9 +8,9 @@ #endif #include -#include "fbxRCamera.h" +#include "fbxReader.h" -osgDB::ReaderWriter::ReadResult readFbxCamera(KFbxNode* pNode) +osgDB::ReaderWriter::ReadResult OsgFbxReader::readFbxCamera(KFbxNode* pNode) { const KFbxCamera* fbxCamera = dynamic_cast(pNode->GetNodeAttribute()); diff --git a/src/osgPlugins/fbx/fbxRCamera.h b/src/osgPlugins/fbx/fbxRCamera.h deleted file mode 100644 index ea9a1a6b6..000000000 --- a/src/osgPlugins/fbx/fbxRCamera.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef FBXRCAMERA_H -#define FBXRCAMERA_H - -#include -#include - -osgDB::ReaderWriter::ReadResult readFbxCamera( - KFbxNode* pNode); - -#endif diff --git a/src/osgPlugins/fbx/fbxRLight.cpp b/src/osgPlugins/fbx/fbxRLight.cpp index f643f6090..6f06f112b 100644 --- a/src/osgPlugins/fbx/fbxRLight.cpp +++ b/src/osgPlugins/fbx/fbxRLight.cpp @@ -7,9 +7,9 @@ #endif #include -#include "fbxRLight.h" +#include "fbxReader.h" -osgDB::ReaderWriter::ReadResult readFbxLight(KFbxNode* pNode, int& nLightCount) +osgDB::ReaderWriter::ReadResult OsgFbxReader::readFbxLight(KFbxNode* pNode, int& nLightCount) { const KFbxLight* fbxLight = dynamic_cast(pNode->GetNodeAttribute()); diff --git a/src/osgPlugins/fbx/fbxRLight.h b/src/osgPlugins/fbx/fbxRLight.h deleted file mode 100644 index ff74d0134..000000000 --- a/src/osgPlugins/fbx/fbxRLight.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef FBXRLIGHT_H -#define FBXRLIGHT_H - -#include -#include - -osgDB::ReaderWriter::ReadResult readFbxLight( - KFbxNode* pNode, int& nLightCount); - -#endif diff --git a/src/osgPlugins/fbx/fbxRMesh.cpp b/src/osgPlugins/fbx/fbxRMesh.cpp index d57a6a1a5..a396d57aa 100644 --- a/src/osgPlugins/fbx/fbxRMesh.cpp +++ b/src/osgPlugins/fbx/fbxRMesh.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include @@ -19,8 +21,7 @@ #endif #include -#include "fbxRMesh.h" -#include "fbxRNode.h" +#include "fbxReader.h" enum GeometryType { @@ -138,7 +139,16 @@ osg::Array* createVec4Array(bool doublePrecision) osg::Geometry* getGeometry(osg::Geode* pGeode, GeometryMap& geometryMap, std::vector& stateSetList, - GeometryType gt, unsigned int mti, bool bNormal, bool bTexCoord, bool bColor, const osgDB::Options& options) + GeometryType gt, + unsigned int mti, + bool bNormal, + bool useDiffuseMap, + bool useOpacityMap, + bool useEmissiveMap, + // more here... + bool bColor, + const osgDB::Options& options, + bool lightmapTextures) { GeometryMap::iterator it = geometryMap.find(mti); @@ -161,30 +171,109 @@ osg::Geometry* getGeometry(osg::Geode* pGeode, GeometryMap& geometryMap, pGeometry->setVertexData(osg::Geometry::ArrayData(createVec3Array((precision & osgDB::Options::DOUBLE_PRECISION_VERTEX) != 0), osg::Geometry::BIND_PER_VERTEX)); if (bNormal) pGeometry->setNormalData(osg::Geometry::ArrayData(createVec3Array((precision & osgDB::Options::DOUBLE_PRECISION_NORMAL) != 0), osg::Geometry::BIND_PER_VERTEX)); - if (bTexCoord) pGeometry->setTexCoordData(0, osg::Geometry::ArrayData(createVec2Array((precision & osgDB::Options::DOUBLE_PRECISION_TEX_COORD) != 0), osg::Geometry::BIND_PER_VERTEX)); + + // create as much textures coordinates as needed... + if (useDiffuseMap) + pGeometry->setTexCoordData(StateSetContent::DIFFUSE_TEXTURE_UNIT, osg::Geometry::ArrayData(createVec2Array((precision & osgDB::Options::DOUBLE_PRECISION_TEX_COORD) != 0), osg::Geometry::BIND_PER_VERTEX)); + if (useOpacityMap) + pGeometry->setTexCoordData(StateSetContent::OPACITY_TEXTURE_UNIT, osg::Geometry::ArrayData(createVec2Array((precision & osgDB::Options::DOUBLE_PRECISION_TEX_COORD) != 0), osg::Geometry::BIND_PER_VERTEX)); + if (useEmissiveMap) + pGeometry->setTexCoordData(StateSetContent::EMISSIVE_TEXTURE_UNIT, osg::Geometry::ArrayData(createVec2Array((precision & osgDB::Options::DOUBLE_PRECISION_TEX_COORD) != 0), osg::Geometry::BIND_PER_VERTEX)); + // create more textures coordinates here... + if (bColor) pGeometry->setColorData(osg::Geometry::ArrayData(createVec4Array((precision & osgDB::Options::DOUBLE_PRECISION_COLOR) != 0), osg::Geometry::BIND_PER_VERTEX)); if (mti < stateSetList.size()) { + osg::StateSet* stateSet = pGeometry->getOrCreateStateSet(); + bool transparent = false; - const StateSetContent& ss = stateSetList[mti]; - if (osg::Material* pMaterial = ss.first) + const StateSetContent& ssc = stateSetList[mti]; + + // set material... + if (osg::Material* pMaterial = ssc.material.get()) { - pGeometry->getOrCreateStateSet()->setAttributeAndModes(pMaterial); + stateSet->setAttributeAndModes(pMaterial); transparent = pMaterial->getDiffuse(osg::Material::FRONT).w() < 1.0f; } - if (osg::Texture2D* pTexture = ss.second) + + // diffuse texture map... + if (ssc.diffuseTexture) { - pGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, pTexture); - if (!transparent && pTexture->getImage()) - { - transparent = pTexture->getImage()->isImageTranslucent(); - } + 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); + } + + // setup transparency + if (!transparent && ssc.diffuseTexture->getImage()) + transparent = ssc.diffuseTexture->getImage()->isImageTranslucent(); } + // opacity texture map... + if (ssc.opacityTexture) + { + 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. + double factor = ssc.opacityFactor; + 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::OPACITY_TEXTURE_UNIT, texenv.get(), osg::StateAttribute::ON); + + // setup transparency... + if (!transparent && ssc.opacityTexture->getImage()) + transparent = ssc.opacityTexture->getImage()->isImageTranslucent(); + } + + // reflection texture map... + if (ssc.reflectionTexture) + { + stateSet->setTextureAttributeAndModes(StateSetContent::REFLECTION_TEXTURE_UNIT, ssc.reflectionTexture.get()); + + // setup spherical map... + osg::ref_ptr texgen = new osg::TexGen(); + texgen->setMode(osg::TexGen::SPHERE_MAP); + stateSet->setTextureAttributeAndModes(StateSetContent::REFLECTION_TEXTURE_UNIT, texgen.get(), osg::StateAttribute::ON); + + // setup combiner for factor... + double factor = ssc.reflectionFactor; + 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::REFLECTION_TEXTURE_UNIT, texenv.get(), osg::StateAttribute::ON); + } + + // emissive texture map + if (ssc.emissiveTexture) + { + stateSet->setTextureAttributeAndModes(StateSetContent::EMISSIVE_TEXTURE_UNIT, ssc.emissiveTexture.get()); + } + + // add more texture maps here... + if (transparent) { - pGeometry->getOrCreateStateSet()->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + stateSet->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); } } @@ -348,41 +437,106 @@ void addColorArrayElement(osg::Array& a, const KFbxColor& c) } } -osgDB::ReaderWriter::ReadResult readMesh(KFbxSdkManager& pSdkManager, - KFbxScene& fbxScene, - KFbxNode* pNode, KFbxMesh* fbxMesh, - osg::ref_ptr& pAnimationManager, +// scans StateSetList looking for the (first) channel name for the specified map type... +std::string getUVChannelForTextureMap(std::vector& stateSetList, const char* pName) +{ + // will return the first occurrence in the state set list... + // TODO: what if more than one channel for the same map type? + for (unsigned int i=0; i < stateSetList.size(); i++) + { + if (0 == strcmp(pName, KFbxSurfaceMaterial::sDiffuse)) + return stateSetList[i].diffuseChannel; + if (0 == strcmp(pName, KFbxSurfaceMaterial::sTransparentColor)) + return stateSetList[i].opacityChannel; + if (0 == strcmp(pName, KFbxSurfaceMaterial::sReflection)) + return stateSetList[i].reflectionChannel; + if (0 == strcmp(pName, KFbxSurfaceMaterial::sEmissive)) + return stateSetList[i].emissiveChannel; + // more here... + } + + return ""; +} + +// scans mesh layers looking for the UV element corrensponding to the specified channel name... +const KFbxLayerElementUV* getUVElementForChannel(std::string pUVChannel, KFbxMesh* pFbxMesh) +{ + const KFbxLayer* pFbxLayer = 0; + const KFbxLayerElementUV* uv = 0; + + // scan layers for specified UV channel... + for (int cLayerIndex=0; cLayerIndex < pFbxMesh->GetLayerCount(); cLayerIndex++) + { + pFbxLayer = pFbxMesh->GetLayer(cLayerIndex); + if (!pFbxLayer) + continue; + + uv = pFbxLayer->GetUVs(); + if (uv) + { + if (0 == pUVChannel.compare(uv->GetName())) + return uv; + } + } + + return 0; +} + +osgDB::ReaderWriter::ReadResult OsgFbxReader::readMesh( + KFbxNode* pNode, + KFbxMesh* fbxMesh, std::vector& stateSetList, - const char* szName, - BindMatrixMap& boneBindMatrices, - const std::set& fbxSkeletons, - std::map& skeletonMap, - const osgDB::Options& options) + const char* szName) { GeometryMap geometryMap; osg::Geode* pGeode = new osg::Geode; pGeode->setName(szName); - const KFbxLayer* pFbxLayer = fbxMesh->GetLayer(0); + 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) + // scan layers for Normals, Colors and Materials elements (this will get the first available elements)... + for (int cLayerIndex=0; cLayerIndex < fbxMesh->GetLayerCount(); cLayerIndex++) { - pFbxNormals = pFbxLayer->GetNormals(); - pFbxColors = pFbxLayer->GetVertexColors(); - pFbxUVs = pFbxLayer->GetUVs(); - pFbxMaterials = pFbxLayer->GetMaterials(); + pFbxLayer = fbxMesh->GetLayer(cLayerIndex); + if (!pFbxLayer) + continue; - if (!layerElementValid(pFbxNormals)) pFbxNormals = 0; - if (!layerElementValid(pFbxColors)) pFbxColors = 0; - if (!layerElementValid(pFbxUVs)) pFbxUVs = 0; - } + // get normals, colors and materials... + if (!pFbxNormals) + pFbxNormals = pFbxLayer->GetNormals(); + if (!pFbxColors) + 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); + std::string opacityChannel = getUVChannelForTextureMap(stateSetList, KFbxSurfaceMaterial::sTransparentColor); + std::string emissiveChannel = getUVChannelForTextureMap(stateSetList, KFbxSurfaceMaterial::sEmissive);; + // look for more UV elements here... + + // UV elements... + const KFbxLayerElementUV* pFbxUVs_diffuse = getUVElementForChannel(diffuseChannel, fbxMesh); + const KFbxLayerElementUV* pFbxUVs_opacity = getUVElementForChannel(opacityChannel, fbxMesh); + const KFbxLayerElementUV* pFbxUVs_emissive = getUVElementForChannel(emissiveChannel, fbxMesh); + // more UV elements here... + + // check elements validity... + if (!layerElementValid(pFbxNormals)) pFbxNormals = 0; + if (!layerElementValid(pFbxColors)) pFbxColors = 0; + + if (!layerElementValid(pFbxUVs_diffuse)) pFbxUVs_diffuse = 0; + if (!layerElementValid(pFbxUVs_opacity)) pFbxUVs_opacity = 0; + if (!layerElementValid(pFbxUVs_emissive)) pFbxUVs_emissive = 0; + // more here... int nPolys = fbxMesh->GetPolygonCount(); @@ -415,11 +569,24 @@ osgDB::ReaderWriter::ReadResult readMesh(KFbxSdkManager& pSdkManager, osg::Geometry* pGeometry = getGeometry(pGeode, geometryMap, stateSetList, geomType, materialIndex, - pFbxNormals != 0, pFbxUVs != 0, pFbxColors != 0, options); + pFbxNormals != 0, + pFbxUVs_diffuse != 0, + pFbxUVs_opacity != 0, + pFbxUVs_emissive != 0, + // more UV elements here... + pFbxColors != 0, + options, + lightmapTextures); osg::Array* pVertices = pGeometry->getVertexArray(); osg::Array* pNormals = pGeometry->getNormalArray(); - osg::Array* pTexCoords = pGeometry->getTexCoordArray(0); + + // get texture coordinates... + osg::Array* pTexCoords_diffuse = pGeometry->getTexCoordArray(StateSetContent::DIFFUSE_TEXTURE_UNIT); + osg::Array* pTexCoords_opacity = pGeometry->getTexCoordArray(StateSetContent::OPACITY_TEXTURE_UNIT); + osg::Array* pTexCoords_emissive = pGeometry->getTexCoordArray(StateSetContent::EMISSIVE_TEXTURE_UNIT); + // more texture coordinates here... + osg::Array* pColors = pGeometry->getColorArray(); int nVertex0 = nVertex; @@ -455,12 +622,29 @@ osgDB::ReaderWriter::ReadResult readMesh(KFbxSdkManager& pSdkManager, addVec3ArrayElement(*pNormals, pFbxNormals->GetDirectArray().GetAt(n2)); } - if (pTexCoords) + // add texture maps data (avoid duplicates)... + if (pTexCoords_diffuse) { - addVec2ArrayElement(*pTexCoords, getElement(pFbxUVs, fbxMesh, i, 0, nVertex0)); - addVec2ArrayElement(*pTexCoords, getElement(pFbxUVs, fbxMesh, i, j - 1, nVertex - 1)); - addVec2ArrayElement(*pTexCoords, getElement(pFbxUVs, fbxMesh, i, j, nVertex)); + addVec2ArrayElement(*pTexCoords_diffuse, getElement(pFbxUVs_diffuse, fbxMesh, i, 0, nVertex0)); + addVec2ArrayElement(*pTexCoords_diffuse, getElement(pFbxUVs_diffuse, fbxMesh, i, j - 1, nVertex - 1)); + addVec2ArrayElement(*pTexCoords_diffuse, getElement(pFbxUVs_diffuse, fbxMesh, i, j, nVertex)); } + if (pTexCoords_opacity && (pTexCoords_opacity != pTexCoords_diffuse)) + { + addVec2ArrayElement(*pTexCoords_opacity, getElement(pFbxUVs_opacity, fbxMesh, i, 0, nVertex0)); + addVec2ArrayElement(*pTexCoords_opacity, getElement(pFbxUVs_opacity, fbxMesh, i, j - 1, nVertex - 1)); + 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) + + 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)); + addVec2ArrayElement(*pTexCoords_emissive, getElement(pFbxUVs_emissive, fbxMesh, i, j, nVertex)); + } + // add more texture maps here... if (pColors) { @@ -701,15 +885,8 @@ osgDB::ReaderWriter::ReadResult readMesh(KFbxSdkManager& pSdkManager, return osgDB::ReaderWriter::ReadResult(pResult); } -osgDB::ReaderWriter::ReadResult readFbxMesh(KFbxSdkManager& pSdkManager, - KFbxScene& fbxScene, - KFbxNode* pNode, - osg::ref_ptr& pAnimationManager, - std::vector& stateSetList, - BindMatrixMap& boneBindMatrices, - const std::set& fbxSkeletons, - std::map& skeletonMap, - const osgDB::Options& options) +osgDB::ReaderWriter::ReadResult OsgFbxReader::readFbxMesh(KFbxNode* pNode, + std::vector& stateSetList) { KFbxMesh* lMesh = dynamic_cast(pNode->GetNodeAttribute()); @@ -718,6 +895,6 @@ osgDB::ReaderWriter::ReadResult readFbxMesh(KFbxSdkManager& pSdkManager, return osgDB::ReaderWriter::ReadResult::ERROR_IN_READING_FILE; } - return readMesh(pSdkManager, fbxScene, pNode, lMesh, pAnimationManager, stateSetList, - pNode->GetName(), boneBindMatrices, fbxSkeletons, skeletonMap, options); -} + return readMesh(pNode, lMesh, stateSetList, + pNode->GetName()); +} \ No newline at end of file diff --git a/src/osgPlugins/fbx/fbxRMesh.h b/src/osgPlugins/fbx/fbxRMesh.h deleted file mode 100644 index 3601f4651..000000000 --- a/src/osgPlugins/fbx/fbxRMesh.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef FBXRMESH_H -#define FBXRMESH_H - -#include -#include -#include -#include "fbxRNode.h" -osgDB::ReaderWriter::ReadResult readFbxMesh( - KFbxSdkManager& pSdkManager, - KFbxScene& fbxScene, - KFbxNode* pNode, - osg::ref_ptr& pAnimationManager, - std::vector&, - BindMatrixMap& boneBindMatrices, - const std::set& fbxSkeletons, - std::map& skeletonMap, - const osgDB::Options&); - -#endif diff --git a/src/osgPlugins/fbx/fbxRNode.cpp b/src/osgPlugins/fbx/fbxRNode.cpp index f80f496a2..a269fdd9c 100644 --- a/src/osgPlugins/fbx/fbxRNode.cpp +++ b/src/osgPlugins/fbx/fbxRNode.cpp @@ -25,12 +25,7 @@ #endif #include -#include "fbxRAnimation.h" -#include "fbxRCamera.h" -#include "fbxRLight.h" -#include "fbxRMesh.h" -#include "fbxRNode.h" -#include "fbxMaterialToOsgStateSet.h" +#include "fbxReader.h" osg::Quat makeQuat(const fbxDouble3& degrees, ERotationOrder fbxRotOrder) { @@ -317,18 +312,9 @@ osg::Group* createGroupNode(KFbxSdkManager& pSdkManager, KFbxNode* pNode, } } -osgDB::ReaderWriter::ReadResult readFbxNode( - KFbxSdkManager& pSdkManager, - KFbxScene& fbxScene, +osgDB::ReaderWriter::ReadResult OsgFbxReader::readFbxNode( KFbxNode* pNode, - osg::ref_ptr& pAnimationManager, - bool& bIsBone, int& nLightCount, - FbxMaterialToOsgStateSet& fbxMaterialToOsgStateSet, - std::map& nodeMap, - BindMatrixMap& boneBindMatrices, - const std::set& fbxSkeletons, - std::map& skeletonMap, - const osgDB::Options& options) + bool& bIsBone, int& nLightCount) { if (KFbxNodeAttribute* lNodeAttribute = pNode->GetNodeAttribute()) { @@ -383,9 +369,7 @@ osgDB::ReaderWriter::ReadResult readFbxNode( bool bChildIsBone = false; osgDB::ReaderWriter::ReadResult childResult = readFbxNode( - pSdkManager, fbxScene, pChildNode, pAnimationManager, - bChildIsBone, nLightCount, fbxMaterialToOsgStateSet, nodeMap, - boneBindMatrices, fbxSkeletons, skeletonMap, options); + pChildNode, bChildIsBone, nLightCount); if (childResult.error()) { return childResult; @@ -404,7 +388,7 @@ osgDB::ReaderWriter::ReadResult readFbxNode( } } - std::string animName = readFbxAnimation(pNode, fbxScene, pAnimationManager, pNode->GetName()); + std::string animName = readFbxAnimation(pNode, pNode->GetName()); osg::Matrix localMatrix; makeLocalMatrix(pNode, localMatrix); @@ -419,9 +403,7 @@ osgDB::ReaderWriter::ReadResult readFbxNode( case KFbxNodeAttribute::eMESH: { size_t bindMatrixCount = boneBindMatrices.size(); - osgDB::ReaderWriter::ReadResult meshRes = readFbxMesh(pSdkManager, fbxScene, - pNode, pAnimationManager, stateSetList, boneBindMatrices, - fbxSkeletons, skeletonMap, options); + osgDB::ReaderWriter::ReadResult meshRes = readFbxMesh(pNode, stateSetList); if (meshRes.error()) { return meshRes; @@ -485,7 +467,7 @@ osgDB::ReaderWriter::ReadResult readFbxNode( osg::Group* pAddChildrenTo = osgGroup.get(); if (bCreateSkeleton) - { + { osgAnimation::Skeleton* osgSkeleton = getSkeleton(pNode, fbxSkeletons, skeletonMap); osgSkeleton->setDefaultUpdateCallback(); pAddChildrenTo->addChild(osgSkeleton); diff --git a/src/osgPlugins/fbx/fbxRNode.h b/src/osgPlugins/fbx/fbxRNode.h deleted file mode 100644 index 6eb3e1538..000000000 --- a/src/osgPlugins/fbx/fbxRNode.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef FBXRNODE_H -#define FBXRNODE_H - -#include "fbxMaterialToOsgStateSet.h" -namespace osgAnimation -{ - class AnimationManagerBase; - class RigGeometry; -} - -typedef std::map, osg::Matrix> BindMatrixMap; - -osgAnimation::Skeleton* getSkeleton(KFbxNode*, - const std::set& fbxSkeletons, - std::map&); - -osgDB::ReaderWriter::ReadResult readFbxNode( - KFbxSdkManager& pSdkManager, - KFbxScene& fbxScene, - KFbxNode* pNode, - osg::ref_ptr& pAnimationManager, - bool& bIsBone, - int& nLightCount, - FbxMaterialToOsgStateSet& fbxMaterialToOsgStateSet, - std::map& nodeMap, - BindMatrixMap& boneBindMatrices, - const std::set& fbxSkeletons, - std::map& skeletonMap, - const osgDB::Options&); - -#endif diff --git a/src/osgPlugins/fbx/fbxReader.h b/src/osgPlugins/fbx/fbxReader.h new file mode 100644 index 000000000..2a2710a64 --- /dev/null +++ b/src/osgPlugins/fbx/fbxReader.h @@ -0,0 +1,82 @@ +#ifndef FBXRANIMATION_H +#define FBXRANIMATION_H + +#include +#include +#include +#include "fbxMaterialToOsgStateSet.h" + +namespace osgAnimation +{ + class AnimationManagerBase; + class RigGeometry; + class Skeleton; +} + +typedef std::map, osg::Matrix> BindMatrixMap; + +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; + + 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) + {} + + osgDB::ReaderWriter::ReadResult readFbxNode( + KFbxNode*, bool& bIsBone, int& nLightCount); + + std::string readFbxAnimation( + KFbxNode*, const char* targetName); + + osgDB::ReaderWriter::ReadResult readFbxCamera( + KFbxNode* pNode); + + 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 readFbxMesh( + KFbxNode* pNode, + std::vector&); +}; + +osgAnimation::Skeleton* getSkeleton(KFbxNode*, + const std::set& fbxSkeletons, + std::map&); + +#endif