void CameraOrbit(KFbxScene* pScene, KFbxVector4 lOrigCamPos, double OrigRoll, int dX, int dY) { KFbxCamera* lCamera = GetCurrentCamera(pScene); if (!lCamera) return; KFbxGlobalCameraSettings& lGlobalCameraSettings = pScene->GlobalCameraSettings(); if (lCamera != lGlobalCameraSettings.GetCameraProducerPerspective()) return; if (lCamera->LockMode.Get()) return; if (dX == 0 && dY == 0) return; KFbxVector4 lRotationVector, lNewPosition, lCurPosition; KFbxXMatrix lRotation; KFbxVector4 lCenter = lCamera->InterestPosition.Get(); KFbxVector4 lPosition = lCamera->Position.Get(); lCurPosition = lPosition-lCenter; lNewPosition = lOrigCamPos-lCenter; int rotX; if (lNewPosition[2] == 0) { rotX = 90; } else { rotX = (int) (180.0* atan((double)lNewPosition[0]/(double)lNewPosition[2]) / 3.14159); } bool bRoll = (((int)OrigRoll % 360) != 0); if ( (lNewPosition[2] < 0 && !bRoll) || (lNewPosition[2] > 0 && bRoll) ) { dY = -dY; } if (bRoll) dX = -dX; lRotationVector[1] = -rotX; lRotation.SetR(lRotationVector); lNewPosition = lRotation.MultT(lNewPosition); lRotationVector[1] = 0; lRotationVector[0] = dY; lRotation.SetR(lRotationVector); lNewPosition = lRotation.MultT(lNewPosition); lRotationVector[0] = 0; lRotationVector[1] = rotX; lRotation.SetR(lRotationVector); lNewPosition = lRotation.MultT(lNewPosition); lRotationVector[1] = -dX; lRotation.SetR(lRotationVector); lNewPosition = lRotation.MultT(lNewPosition); if ( lNewPosition[0]*lCurPosition[0] < 0 && lNewPosition[2]*lCurPosition[2] < 0) { double lRoll = lCamera->Roll.Get(); lRoll = 180.0-lRoll; lCamera->Roll.Set(lRoll); } lNewPosition = lNewPosition + lCenter; lCamera->Position.Set(lNewPosition); }
// Get the geometry deformation local to a node. It is never inherited by the // children. KFbxXMatrix GetGeometry(KFbxNode* pNode) { KFbxVector4 lT, lR, lS; KFbxXMatrix lGeometry; lT = pNode->GetGeometricTranslation(KFbxNode::eSOURCE_SET); lR = pNode->GetGeometricRotation(KFbxNode::eSOURCE_SET); lS = pNode->GetGeometricScaling(KFbxNode::eSOURCE_SET); lGeometry.SetT(lT); lGeometry.SetR(lR); lGeometry.SetS(lS); return lGeometry; }
KFbxXMatrix FilmboxNode::GetGeometricTransform() const { KFbxXMatrix value; value.SetIdentity(); if( m_node ) { KFbxVector4 translation = m_node->GeometricTranslation.Get(); KFbxVector4 rotation = m_node->GeometricRotation.Get(); KFbxVector4 scale = m_node->GeometricScaling.Get(); value.SetS( scale ); value.SetR( rotation ); value.SetT( translation ); } return value; }
KFbxXMatrix FilmboxNode::GetParentWorldTransform( int frame ) const { KFbxXMatrix value; value.SetIdentity(); if( m_node ) { KFbxNode* fbx_parent_node = m_node->GetParent(); if( fbx_parent_node ) { MCE::FBX::FilmboxNode mce_parent_node( fbx_parent_node ); value = mce_parent_node.GetWorldTransform( frame ); } } return value; }
Matrix FBXModel::convert(const KFbxXMatrix& matrix) { Matrix m; for (int row = 0; row < 4; ++row) for (int col = 0; col < 4; ++col) m[row * 4 + col] = (float)matrix.Get(row, col); return m; }
// Set the view to the current camera settings. void SetCamera(KFbxScene* pScene, KTime& pTime, KFbxAnimLayer* pAnimLayer, KArrayTemplate<KFbxNode*>& pCameraArray) { KFbxCamera* lCamera = GetCurrentCamera(pScene, pTime, pCameraArray); KFbxNode* lCameraNode = lCamera ? lCamera->GetNode() : NULL; KFbxVector4 lEye(0,0,1); KFbxVector4 lCenter(0,0,0); KFbxVector4 lUp(0,1,0); KFbxVector4 lForward, lRight; if (lCamera) { lEye = lCamera->Position.Get(); lUp = lCamera->UpVector.Get(); } if (lCameraNode && lCameraNode->GetTarget()) { lCenter = GetGlobalPosition(lCameraNode->GetTarget(), pTime).GetT(); } else { if (!lCameraNode || IsProducerCamera(pScene, lCamera)) { if (lCamera) lCenter = lCamera->InterestPosition.Get(); } else { KFbxXMatrix lGlobalRotation; KFbxVector4 lRotationVector(GetGlobalPosition(lCameraNode, pTime).GetR()); lGlobalRotation.SetR(lRotationVector); KFbxVector4 lInterestPosition(lCamera->InterestPosition.Get()); KFbxVector4 lCameraGlobalPosition(GetGlobalPosition(lCameraNode, pTime).GetT()); double lLength = (KFbxVector4(lInterestPosition - lCameraGlobalPosition).Length()); lRotationVector = KFbxVector4(1.0,0,0); lCenter = lGlobalRotation.MultT(lRotationVector); lCenter *= lLength; lCenter += lEye; lRotationVector = KFbxVector4(0,1.0,0); lUp = lGlobalRotation.MultT(lRotationVector); } } lForward = lCenter - lEye; lForward.Normalize(); lRight = lForward.CrossProduct(lUp); lRight.Normalize(); lUp = lRight.CrossProduct(lForward); lUp.Normalize(); double lRadians = 0; if (lCamera) lRadians = 3.1416 * lCamera->Roll.Get() / 180.0; lUp *= cos(lRadians); lRight *= sin(lRadians); lUp = lUp + lRight; double lNearPlane = 0.01; if (lCamera) lNearPlane = lCamera->GetNearPlane(); double lFarPlane = 1000.0; if (lCamera) lFarPlane = lCamera->GetFarPlane(); if (lCamera && lCamera->ProjectionType.Get() == KFbxCamera::ePERSPECTIVE) { double lFieldOfViewY=0.0; double lAspect = lCamera->GetApertureWidth() * lCamera->GetSqueezeRatio() / lCamera->GetApertureHeight(); if (lCamera->GetApertureMode() == KFbxCamera::eHORIZONTAL || lCamera->GetApertureMode() == KFbxCamera::eVERTICAL) { lFieldOfViewY = lCamera->FieldOfView.Get(); if (lCamera->GetApertureMode() == KFbxCamera::eHORIZONTAL) lFieldOfViewY /= lAspect; } else if (lCamera->GetApertureMode() == KFbxCamera::eFOCAL_LENGTH) { lFieldOfViewY = lCamera->ComputeFieldOfView(lCamera->FocalLength.Get()); lFieldOfViewY /= lAspect; } else if (lCamera->GetApertureMode() == KFbxCamera::eHORIZONTAL_AND_VERTICAL) { lFieldOfViewY = lCamera->FieldOfViewY.Get(); } GlSetCameraPerspective(lFieldOfViewY, lAspect, lNearPlane, lFarPlane, lEye, lCenter, lUp); } else { double lPixelRatio = 1.0; if (lCamera) lPixelRatio = lCamera->GetPixelRatio(); int lWidth, lHeight; double lLeftPlane, lRightPlane, lBottomPlane, lTopPlane; GlGetWindowSize(lWidth, lHeight); if(lWidth < lHeight) { lLeftPlane = -gsOrthoCameraScale * lPixelRatio; lRightPlane = gsOrthoCameraScale * lPixelRatio; lBottomPlane = -gsOrthoCameraScale * lHeight / lWidth; lTopPlane = gsOrthoCameraScale * lHeight / lWidth; } else { lWidth *= (int) lPixelRatio; lLeftPlane = -gsOrthoCameraScale * lWidth / lHeight; lRightPlane = gsOrthoCameraScale * lWidth / lHeight; lBottomPlane = -gsOrthoCameraScale; lTopPlane = gsOrthoCameraScale; } GlSetCameraOrthogonal(lLeftPlane, lRightPlane, lBottomPlane, lTopPlane, lNearPlane, lFarPlane, lEye, lCenter, lUp); } }
KFbxXMatrix FilmboxNode::GetWorldTransform( int frame ) const { KFbxXMatrix value; value.SetIdentity(); if( m_node ) { KFbxScene* scene = m_node->GetScene(); KFbxAnimEvaluator* evaluator = scene->GetEvaluator(); KTime frame_time; if( frame == 0xFFFFFFFF ) { frame_time = KTIME_INFINITE; } else { frame_time.SetTime( 0, 0, 0, frame ); } value = evaluator->GetNodeGlobalTransform( m_node, frame_time ); if( m_type == MCE::FBX::SceneObjectType::CAMERA ) { KFbxNode* fbx_target_node = m_node->GetTarget(); if( fbx_target_node ) { // For target cameras we need to manually replace the rotation to point towards the target KFbxVector4 camera_position = value.GetT(); MCE::FBX::FilmboxNode mce_target_node( fbx_target_node ); KFbxXMatrix target_transform = mce_target_node.GetWorldTransform( frame ); KFbxVector4 target_position = target_transform.GetT(); KFbxVector4 up_vector( 0.0, 1.0, 0.0, 0.0 ); KFbxVector4 look_axis = -( target_position - camera_position ); look_axis.Normalize(); KFbxVector4 right_axis = up_vector.CrossProduct( look_axis ); KFbxVector4 up_axis = look_axis.CrossProduct( right_axis ); KFbxMatrix rotation_matrix; rotation_matrix.SetRow( 0, right_axis ); rotation_matrix.SetRow( 1, up_axis ); rotation_matrix.SetRow( 2, look_axis ); rotation_matrix.SetRow( 3, KFbxVector4( 0.0, 0.0, 0.0, 1.0 ) ); KFbxQuaternion camera_rotation; double determinant; rotation_matrix.GetElements( KFbxVector4(), camera_rotation, KFbxVector4(), KFbxVector4(), determinant ); KFbxVector4 camera_scale( 1.0, 1.0, 1.0, 0.0 ); value.SetTQS( camera_position, camera_rotation, camera_scale ); } else { // Even though the SDK docs say that GetNodeGlobalTransform takes all transforms into account // For cameras it appears that you have to manually apply post-rotation KFbxVector4 post_rotation = m_node->GetPostRotation( KFbxNode::eSOURCE_SET ); KFbxXMatrix fbx_to_mce_camera; fbx_to_mce_camera.SetR( post_rotation ); value *= fbx_to_mce_camera; } } } return value; }
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); }