FBXModel::VertexCollection FBXModel::getVertices(KFbxMesh* mesh)
{
	const KFbxLayer* layer = mesh->GetLayer(0);
	
	const KFbxLayerElementNormal* normals = layer->GetNormals();
	const KFbxLayerElementUV* texCoord = layer->GetUVs();

	VertexCollection vertices = VertexCollection(mesh->GetControlPointsCount());

	// positions
	for (unsigned i = 0; i < vertices.size(); i++)
		vertices[i].position = convert(mesh->GetControlPointAt(i));

	// normals
	//if (normals)
	//{
	//	for (unsigned i = 0; i < vertices.size(); i++)
	//		vertices[i].normal = Vector3::normalize(convert(normals->GetDirectArray().GetAt(i)));
	//}

	// UV
	if (texCoord)
	{
		for (int i = 0; i < mesh->GetPolygonCount(); ++i)
			for (int j = 0; j < mesh->GetPolygonSize(i); ++j)
				vertices[mesh->GetPolygonVertex(i, j)].texCoord = convert(texCoord->GetDirectArray().GetAt(mesh->GetTextureUVIndex(i,j)));
	}
	
	// skin weights
	std::vector<int> blendCount(vertices.size(), 0);

	for (int i = 0; i < mesh->GetDeformerCount(KFbxDeformer::eSKIN); ++i)
	{
		KFbxSkin* skin = (KFbxSkin*)mesh->GetDeformer(i, KFbxDeformer::eSKIN);

		for (int j = 0; j < skin->GetClusterCount(); ++j)
		{
			KFbxCluster* cluster = skin->GetCluster(j);
			unsigned boneIndex = bones[cluster->GetLink()->GetName()].index;

			int* vertexIndices = cluster->GetControlPointIndices();
			double* vertexBlendWeights = cluster->GetControlPointWeights();

			for (int k = 0; k < cluster->GetControlPointIndicesCount(); ++k)
			{
				int index = vertexIndices[k];
				int blendIndex = blendCount[index]++;

				vertices[index].blendWeights[blendIndex] = (float)vertexBlendWeights[k];
				vertices[index].blendIndices[blendIndex] = (unsigned char)boneIndex;
			}
		}
	}

	return vertices;
}
예제 #2
0
파일: ParseMesh.cpp 프로젝트: KNeal/Oculus
BOOL ParseMeshSkinning( KFbxMesh* pMesh, SkinData* pSkinData )
{
    DWORD dwDeformerCount = pMesh->GetDeformerCount( KFbxDeformer::eSKIN );
    if( dwDeformerCount == 0 )
        return FALSE;

    ExportLog::LogMsg( 4, "Parsing skin weights on mesh %s", pMesh->GetName() );

    const DWORD dwVertexCount = pMesh->GetControlPointsCount();
    const DWORD dwStride = 4;
    pSkinData->Alloc( dwVertexCount, dwStride );

    for( DWORD dwDeformerIndex = 0; dwDeformerIndex < dwDeformerCount; ++dwDeformerIndex )
    {
        KFbxSkin* pSkin = (KFbxSkin*)pMesh->GetDeformer( dwDeformerIndex, KFbxDeformer::eSKIN );
        DWORD dwClusterCount = pSkin->GetClusterCount();

        for( DWORD dwClusterIndex = 0; dwClusterIndex < dwClusterCount; ++dwClusterIndex )
        {
            KFbxCluster* pCluster = pSkin->GetCluster( dwClusterIndex );
            DWORD dwClusterSize = pCluster->GetControlPointIndicesCount();
            if( dwClusterSize == 0 )
                continue;

            KFbxNode* pLink = pCluster->GetLink();

            DWORD dwBoneIndex = pSkinData->GetBoneCount();
            pSkinData->InfluenceNodes.push_back( pLink );
            ExportLog::LogMsg( 4, "Influence %d: %s", dwBoneIndex, pLink->GetName() );
            
            KFbxXMatrix matXBindPose;
            pCluster->GetTransformLinkMatrix( matXBindPose );
            KFbxMatrix matBindPose = matXBindPose;
            CaptureBindPoseMatrix( pLink, matBindPose );

            INT* pIndices = pCluster->GetControlPointIndices();
            DOUBLE* pWeights = pCluster->GetControlPointWeights();

            for( DWORD i = 0; i < dwClusterSize; ++i )
            {
                pSkinData->InsertWeight( pIndices[i], dwBoneIndex, (FLOAT)pWeights[i] );
            }
        }
    }

    return TRUE;
}
예제 #3
0
파일: fbxRMesh.cpp 프로젝트: BodyViz/osg
osgDB::ReaderWriter::ReadResult OsgFbxReader::readMesh(
    KFbxNode* pNode,
    KFbxMesh* fbxMesh,
    std::vector<StateSetContent>& stateSetList,
    const char* szName)
{
    GeometryMap geometryMap;

    osg::Geode* pGeode = new osg::Geode;
    pGeode->setName(szName);

    const KFbxLayerElementNormal* pFbxNormals = 0;
    const KFbxLayerElementVertexColor* pFbxColors = 0;
    const KFbxLayerElementMaterial* pFbxMaterials = 0;

    const KFbxVector4* pFbxVertices = fbxMesh->GetControlPoints();

    // scan layers for Normals, Colors and Materials elements (this will get the first available elements)...
    for (int cLayerIndex = 0; cLayerIndex < fbxMesh->GetLayerCount(); cLayerIndex++)
    {
        const KFbxLayer* pFbxLayer = fbxMesh->GetLayer(cLayerIndex);
        if (!pFbxLayer)
            continue;

        // 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, KFbxLayerElement::eDIFFUSE_TEXTURES, fbxMesh);
    const KFbxLayerElementUV* pFbxUVs_opacity = getUVElementForChannel(opacityChannel, KFbxLayerElement::eTRANSPARENT_TEXTURES, fbxMesh);
    const KFbxLayerElementUV* pFbxUVs_emissive = getUVElementForChannel(emissiveChannel, KFbxLayerElement::eEMISSIVE_TEXTURES, 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();

    int nDeformerCount = fbxMesh->GetDeformerCount(KFbxDeformer::eSKIN);
    int nDeformerBlendShapeCount = fbxMesh->GetDeformerCount(KFbxDeformer::eBLENDSHAPE);

    GeometryType geomType = GEOMETRY_STATIC;

    //determine the type of geometry
    if (nDeformerCount)
    {
        geomType = GEOMETRY_RIG;
    }
    else if (nDeformerBlendShapeCount)
    {
        geomType = GEOMETRY_MORPH;
    }

    FbxToOsgVertexMap fbxToOsgVertMap;
    OsgToFbxNormalMap osgToFbxNormMap;

    // First add only triangles and quads (easy to split into triangles without
    // more processing)
    // This is the reason we store polygons references:

    PolygonRefList polygonRefList;

    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,
            stateSetList, geomType, materialIndex,
            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();

        // 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();

        if (lPolygonSize == 3)
        {
            // Triangle
            readMeshTriangle(fbxMesh, i,
                0, 1, 2,
                nVertex, nVertex+1, nVertex+2,
                fbxToOsgVertMap, osgToFbxNormMap,
                pFbxVertices, pFbxNormals, pFbxUVs_diffuse, pFbxUVs_opacity, pFbxUVs_emissive, pFbxColors,
                pGeometry,
                pVertices, pNormals, pTexCoords_diffuse, pTexCoords_opacity, pTexCoords_emissive, pColors);
            nVertex += 3;
        }
        else if (lPolygonSize == 4)
        {
            // Quad - Convert to triangles
            // Use some fast specialized code to see how the should be decomposed
            // Two cases : Split at '02' (012 and 023), or split at '13 (013 and 123)
            bool split02 = quadSplit02(fbxMesh, i, 0, 1, 2, 3, pFbxVertices);
            int p02 = split02 ? 2 : 3; // Triangle 0, point 2
            int p10 = split02 ? 0 : 1; // Triangle 1, point 0
            readMeshTriangle(fbxMesh, i,
                0, 1, p02,
                nVertex, nVertex+1, nVertex+p02,
                fbxToOsgVertMap, osgToFbxNormMap,
                pFbxVertices, pFbxNormals, pFbxUVs_diffuse, pFbxUVs_opacity, pFbxUVs_emissive, pFbxColors,
                pGeometry,
                pVertices, pNormals, pTexCoords_diffuse, pTexCoords_opacity, pTexCoords_emissive, pColors);
            readMeshTriangle(fbxMesh, i,
                p10, 2, 3,
                nVertex+p10, nVertex+2, nVertex+3,
                fbxToOsgVertMap, osgToFbxNormMap,
                pFbxVertices, pFbxNormals, pFbxUVs_diffuse, pFbxUVs_opacity, pFbxUVs_emissive, pFbxColors,
                pGeometry,
                pVertices, pNormals, pTexCoords_diffuse, pTexCoords_opacity, pTexCoords_emissive, pColors);
            nVertex += 4;
        }
        else if (tessellatePolygons)
        {
            // Polygons - Store to add after triangles
            polygonRefList.push_back(PolygonRef(pGeometry, i, nVertex));
            nVertex += lPolygonSize;
        }
        else
        {
            int nVertex0 = nVertex;
            nVertex += (std::min)(2, lPolygonSize);

            for (int j = 2; j < lPolygonSize; ++j, ++nVertex)
            {
                readMeshTriangle(fbxMesh, i,
                    0, j - 1, j,
                    nVertex0, nVertex - 1, nVertex,
                    fbxToOsgVertMap, osgToFbxNormMap,
                    pFbxVertices, pFbxNormals, pFbxUVs_diffuse, pFbxUVs_opacity, pFbxUVs_emissive, pFbxColors,
                    pGeometry,
                    pVertices, pNormals, pTexCoords_diffuse, pTexCoords_opacity, pTexCoords_emissive, pColors);
            }
        }
    }

    for (unsigned i = 0; i < pGeode->getNumDrawables(); ++i)
    {
        osg::Geometry* pGeometry = pGeode->getDrawable(i)->asGeometry();
        osg::DrawArrays* pDrawArrays = new osg::DrawArrays(
            GL_TRIANGLES, 0, pGeometry->getVertexArray()->getNumElements());
        pGeometry->addPrimitiveSet(pDrawArrays);
    }

    // Now add polygons - Convert to triangles
    // We put vertices in their own PrimitiveSet with Mode=POLYGON; then run the
    // Tessellator on the Geometry which should tessellate the polygons
    // automagically.
    for (PolygonRefList::iterator it = polygonRefList.begin(), itEnd=polygonRefList.end();
        it != itEnd; ++it)
    {
        int i = it->numPoly;
        int lPolygonSize = fbxMesh->GetPolygonSize(i);
        //int materialIndex = getPolygonIndex(pFbxMaterials, i);
        osg::Geometry* pGeometry = it->pGeometry;

        osg::Array* pVertices = pGeometry->getVertexArray();
        osg::Array* pNormals = pGeometry->getNormalArray();
        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);
        osg::Array* pColors = pGeometry->getColorArray();
        // Index of the 1st vertex of the polygon in the geometry
        int osgVertex0 = pVertices->getNumElements();

        for (int j = 0, nVertex = it->nVertex; j<lPolygonSize; ++j, ++nVertex)
        {
            int v0 = fbxMesh->GetPolygonVertex(i, j);
            fbxToOsgVertMap.insert(FbxToOsgVertexMap::value_type(v0, GIPair(pGeometry, pVertices->getNumElements())));
            addVec3ArrayElement(*pVertices, pFbxVertices[v0]);
            if (pNormals)
            {
                int n0 = getVertexIndex(pFbxNormals, fbxMesh, i, j, nVertex);
                osgToFbxNormMap.insert(OsgToFbxNormalMap::value_type(GIPair(pGeometry, pNormals->getNumElements()), n0));
                addVec3ArrayElement(*pNormals, pFbxNormals->GetDirectArray().GetAt(n0));
            }

            // add texture maps data (avoid duplicates)...
            if (pTexCoords_diffuse)
            {
                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, 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, j, nVertex));
            }
            // add more texture maps here...

            if (pColors)
            {
                addColorArrayElement(*pColors, getElement(pFbxColors, fbxMesh, i, j, nVertex));
            }
        }

        osg::DrawArrays* pDrawArrays = new osg::DrawArrays(
            GL_POLYGON, osgVertex0, pGeometry->getVertexArray()->getNumElements() - osgVertex0);
        pGeometry->addPrimitiveSet(pDrawArrays);
    }

    for (unsigned i = 0; i < pGeode->getNumDrawables(); ++i)
    {
        osg::Geometry* pGeometry = pGeode->getDrawable(i)->asGeometry();

        // Now split polygons if necessary
        osgUtil::Tessellator tessellator;
        tessellator.retessellatePolygons(*pGeometry);

        if (pGeode->getNumDrawables() > 1)
        {
            std::stringstream ss;
            ss << pGeode->getName() << " " << i + 1;
            pGeometry->setName(ss.str());
        }
        else
        {
            pGeometry->setName(pGeode->getName());
        }
    }

    if (geomType == GEOMETRY_RIG)
    {
        typedef std::map<osg::ref_ptr<osg::Geometry>,
            osg::ref_ptr<osgAnimation::RigGeometry> > GeometryRigGeometryMap;
        GeometryRigGeometryMap old2newGeometryMap;

        for (unsigned i = 0; i < pGeode->getNumDrawables(); ++i)
        {
            osg::Geometry* pGeometry = pGeode->getDrawable(i)->asGeometry();

            osgAnimation::RigGeometry* pRig = new osgAnimation::RigGeometry;
            pRig->setSourceGeometry(pGeometry);
            pRig->copyFrom(*pGeometry);
            old2newGeometryMap.insert(GeometryRigGeometryMap::value_type(
                pGeometry, pRig));
            pRig->setDataVariance(osg::Object::DYNAMIC);
            pRig->setUseDisplayList( false );
            pGeode->setDrawable(i, pRig);

            pRig->setInfluenceMap(new osgAnimation::VertexInfluenceMap);
            pGeometry = pRig;
        }

        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);
                //assert(KFbxCluster::eNORMALIZE == pCluster->GetLinkMode());
                KFbxNode* pBone = pCluster->GetLink();

                KFbxXMatrix transformLink;
                pCluster->GetTransformLinkMatrix(transformLink);
                KFbxXMatrix transformLinkInverse = transformLink.Inverse();
                const double* pTransformLinkInverse = transformLinkInverse;
                osg::Matrix bindMatrix(pTransformLinkInverse);

                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<float>(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<osgAnimation::RigGeometry&>(
                            *old2newGeometryMap[gi.first]);
                        addBindMatrix(boneBindMatrices, pBone, bindMatrix, &rig);
                        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)
    {
        for (unsigned i = 0; i < pGeode->getNumDrawables(); ++i)
        {
            osg::Geometry* pGeometry = pGeode->getDrawable(i)->asGeometry();

            osgAnimation::MorphGeometry& morph = dynamic_cast<osgAnimation::MorphGeometry&>(*pGeometry);

            pGeode->addUpdateCallback(new osgAnimation::UpdateMorph(morph.getName()));

            //read morph geometry
            for (int nBlendShape = 0; nBlendShape < nDeformerBlendShapeCount; ++nBlendShape)
            {
                KFbxBlendShape* pBlendShape = KFbxCast<KFbxBlendShape>(fbxMesh->GetDeformer(nBlendShape, KFbxDeformer::eBLENDSHAPE));
                const int nBlendShapeChannelCount = pBlendShape->GetBlendShapeChannelCount();

                for (int nBlendShapeChannel = 0; nBlendShapeChannel < nBlendShapeChannelCount; ++nBlendShapeChannel)
                {
                    KFbxBlendShapeChannel* pBlendShapeChannel = pBlendShape->GetBlendShapeChannel(nBlendShapeChannel);
                    if (!pBlendShapeChannel->GetTargetShapeCount()) continue;

                    //Assume one shape
                    if (pBlendShapeChannel->GetTargetShapeCount() > 1)
                    {
                        OSG_WARN << "Multiple FBX Target Shapes, only the first will be used" << std::endl;
                    }
                    const KFbxGeometryBase* pMorphShape = pBlendShapeChannel->GetTargetShape(0);

                    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<osg::Array*>(
                        pMorphTarget->getVertexArray()->clone(osg::CopyOp::DEEP_COPY_ARRAYS)));
                    if (pFbxShapeNormals)
                    {
                        if (osg::Array* pNormals = pMorphTarget->getNormalArray())
                        {
                            pMorphTarget->setNormalArray(static_cast<osg::Array*>(
                                pNormals->clone(osg::CopyOp::DEEP_COPY_ARRAYS)));
                        }
                    }
                    pMorphTarget->setName(pMorphShape->GetName());
                    morph.addMorphTarget(pMorphTarget, 0.0f);

                    readAnimation(pNode, fbxScene, morph.getName(), pAnimationManager, fbxMesh,
                        nBlendShape, nBlendShapeChannel, (int)morph.getMorphTargetList().size() - 1);
                }
            }
        }

        int nMorphTarget = 0;
        for (int nBlendShape = 0; nBlendShape < nDeformerBlendShapeCount; ++nBlendShape)
        {
            KFbxBlendShape* pBlendShape = KFbxCast<KFbxBlendShape>(fbxMesh->GetDeformer(nBlendShape, KFbxDeformer::eBLENDSHAPE));
            const int nBlendShapeChannelCount = pBlendShape->GetBlendShapeChannelCount();

            for (int nBlendShapeChannel = 0; nBlendShapeChannel < nBlendShapeChannelCount; ++nBlendShapeChannel)
            {
                KFbxBlendShapeChannel* pBlendShapeChannel = pBlendShape->GetBlendShapeChannel(nBlendShapeChannel);
                if (!pBlendShapeChannel->GetTargetShapeCount()) continue;

                //Assume one shape again
                const KFbxGeometryBase* pMorphShape = pBlendShapeChannel->GetTargetShape(0);

                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::Vec3d 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<osgAnimation::MorphGeometry&>(*gi.first);
                        osg::Geometry* pGeometry = morphGeom.getMorphTarget(nMorphTarget).getGeometry();

                        if (pGeometry->getVertexArray()->getType() == osg::Array::Vec3dArrayType)
                        {
                            osg::Vec3dArray* pVertices = static_cast<osg::Vec3dArray*>(pGeometry->getVertexArray());
                            (*pVertices)[gi.second] = vPos;
                        }
                        else
                        {
                            osg::Vec3Array* pVertices = static_cast<osg::Vec3Array*>(pGeometry->getVertexArray());
                            (*pVertices)[gi.second] = vPos;
                        }

                        if (pFbxShapeNormals && pGeometry->getNormalArray())
                        {
                            if (pGeometry->getNormalArray()->getType() == osg::Array::Vec3dArrayType)
                            {
                                osg::Vec3dArray* pNormals = static_cast<osg::Vec3dArray*>(pGeometry->getNormalArray());
                                (*pNormals)[gi.second] = convertVec3(
                                    pFbxShapeNormals->GetDirectArray().GetAt(osgToFbxNormMap[gi]));
                            }
                            else
                            {
                                osg::Vec3Array* pNormals = static_cast<osg::Vec3Array*>(pGeometry->getNormalArray());
                                (*pNormals)[gi.second] = convertVec3(
                                    pFbxShapeNormals->GetDirectArray().GetAt(osgToFbxNormMap[gi]));
                            }
                        }
                    }
                }

                //don't put this in the for loop as we don't want to do it if the loop continues early
                ++nMorphTarget;
            }
        }
    }

    KFbxXMatrix fbxGeometricTransform;
    fbxGeometricTransform.SetTRS(
        pNode->GeometricTranslation.Get(),
        pNode->GeometricRotation.Get(),
        pNode->GeometricScaling.Get());
    const double* pGeometricMat = fbxGeometricTransform;
    osg::Matrix osgGeometricTransform(pGeometricMat);

    if (geomType == GEOMETRY_RIG)
    {
        KFbxSkin* pSkin = (KFbxSkin*)fbxMesh->GetDeformer(0, KFbxDeformer::eSKIN);
        if (pSkin->GetClusterCount())
        {
            KFbxXMatrix fbxTransformMatrix;
            pSkin->GetCluster(0)->GetTransformMatrix(fbxTransformMatrix);
            const double* pTransformMatrix = fbxTransformMatrix;
            osgGeometricTransform.postMult(osg::Matrix(pTransformMatrix));
        }
    }

    osg::Node* pResult = pGeode;

    if (!osgGeometricTransform.isIdentity())
    {
        osg::MatrixTransform* pMatTrans = new osg::MatrixTransform(osgGeometricTransform);
        pMatTrans->addChild(pGeode);
        pResult = pMatTrans;
    }

    if (geomType == GEOMETRY_RIG)
    {
        //Add the geometry to the skeleton ancestor of one of the bones.
        KFbxSkin* pSkin = (KFbxSkin*)fbxMesh->GetDeformer(0, KFbxDeformer::eSKIN);
        if (pSkin->GetClusterCount())
        {
            osgAnimation::Skeleton* pSkeleton = getSkeleton(
                pSkin->GetCluster(0)->GetLink(), fbxSkeletons, skeletonMap);
            pSkeleton->addChild(pResult);
            return osgDB::ReaderWriter::ReadResult::FILE_LOADED;
        }
    }

    return osgDB::ReaderWriter::ReadResult(pResult);
}