void fbxLoader2::computeMesh(FbxNode* pNode, FbxTime& pTime, FbxAnimLayer* pAnimLayer, FbxAMatrix& pGlobalPosition, FbxPose* pPose, int frame) { FbxMesh* lMesh = pNode->GetMesh(); const int lVertexCount = lMesh->GetControlPointsCount(); // No vertex to draw. if (lVertexCount == 0) { return; } // If it has some defomer connection, update the vertices position const bool lHasVertexCache = lMesh->GetDeformerCount(FbxDeformer::eVertexCache) && (static_cast<FbxVertexCacheDeformer*>(lMesh->GetDeformer(0, FbxDeformer::eVertexCache)))->IsActive(); const bool lHasShape = lMesh->GetShapeCount() > 0; const bool lHasSkin = lMesh->GetDeformerCount(FbxDeformer::eSkin) > 0; const bool lHasDeformation = lHasVertexCache || lHasShape || lHasSkin; if (lHasDeformation) { //we need to get the number of clusters const int lSkinCount = lMesh->GetDeformerCount(FbxDeformer::eSkin); int lClusterCount = 0; for (int lSkinIndex = 0; lSkinIndex < lSkinCount; ++lSkinIndex) { lClusterCount += ((FbxSkin *)(lMesh->GetDeformer(lSkinIndex, FbxDeformer::eSkin)))->GetClusterCount(); } if (lClusterCount) { // Deform the vertex array with the skin deformer. ComputeSkinDeformation(pGlobalPosition, lMesh, pTime, pPose, frame); } } }
void fbxLoader2::setBindPoseCluster(FbxNode *node) { if( node->GetNodeAttribute()) { switch(node->GetNodeAttribute()->GetAttributeType()) { case FbxNodeAttribute::eMesh: FbxMesh *mesh = node->GetMesh(); for (int j = 0; j<mesh->GetDeformerCount(); j++) { FbxSkin *skin = (FbxSkin*) mesh->GetDeformer(j,FbxDeformer::eSkin); int clusters = skin->GetClusterCount(); for(int k = 0; k<clusters; k++) { FbxCluster* cluster = skin->GetCluster(k); FbxNode* boneLink = cluster->GetLink(); if(boneLink) { std::string nameLink = boneLink->GetName(); FbxAMatrix translationM; FbxAMatrix invert; cluster->GetTransformLinkMatrix(translationM); cluster->GetTransformMatrix(invert); translationM = translationM * invert.Inverse(); D3DXMATRIX mat = D3DXMATRIX((float)translationM.mData[0].mData[0], (float)translationM.mData[0].mData[1], (float)translationM.mData[0].mData[2], (float)translationM.mData[3].mData[0], (float)translationM.mData[1].mData[0], (float)translationM.mData[1].mData[1], (float)translationM.mData[1].mData[2], (float)translationM.mData[3].mData[1], (float)translationM.mData[2].mData[0], (float)translationM.mData[2].mData[1], (float)translationM.mData[2].mData[2], (float)translationM.mData[3].mData[2], 0,0,0,1); skeleton->GetBone(skeleton->GetBoneByName(nameLink))->SetTransformation(mat); } } } break; } } for (int i = 0; i<node->GetChildCount(); i++) { FbxNode* child = node->GetChild(i); setBindPoseCluster(child); } }
void FBXConverter::processAnimations( FbxNode* node , std::vector<JointData> &skeleton , std::vector<VertexData> &verts , std::vector<IndexData> &indices ) { FbxMesh* theMesh = node->GetMesh(); FbxAnimStack* animationStack = node->GetScene()->GetSrcObject<FbxAnimStack>(); FbxAnimLayer* animationLayer = animationStack->GetMember<FbxAnimLayer>(); std::vector<FbxTime> frames; for ( int curveNodeIndex = 0; curveNodeIndex < animationLayer->GetMemberCount(); ++curveNodeIndex ) { FbxAnimCurveNode* currentCurve = animationLayer->GetMember<FbxAnimCurveNode>( curveNodeIndex ); for ( unsigned int channelIndex = 0; channelIndex < currentCurve->GetChannelsCount(); ++channelIndex ) { for ( int curve = 0; curve < currentCurve->GetCurveCount( channelIndex ); ++curve ) { FbxAnimCurve* theCurveVictim = currentCurve->GetCurve( channelIndex , curve ); for ( int keyIndex = 0; keyIndex < theCurveVictim->KeyGetCount(); ++keyIndex ) { bool alreadyIn = false; for ( unsigned int frameIndex = 0; frameIndex < frames.size(); ++frameIndex ) { if ( ( unsigned int ) frames[frameIndex].GetFrameCount() == ( unsigned int ) theCurveVictim->KeyGet( keyIndex ).GetTime().GetFrameCount() ) { alreadyIn = true; //std::cout << frames[frameIndex].GetFrameCount() << " " << theCurveVictim->KeyGet( keyIndex ).GetTime().GetFrameCount() << " " << alreadyIn << std::endl; break; } } std::cout << theCurveVictim->KeyGet( keyIndex ).GetTime().GetFrameCount() << " " << alreadyIn << std::endl; if(!alreadyIn) frames.push_back(theCurveVictim->KeyGet( keyIndex ).GetTime()); } } } } std::sort( frames.begin() , frames.end() , frameCompare ); FbxAMatrix geoTransform( node->GetGeometricTranslation( FbxNode::eSourcePivot ) , node->GetGeometricRotation( FbxNode::eSourcePivot ) , node->GetGeometricScaling( FbxNode::eSourcePivot ) ); for ( int i = 0; i < theMesh->GetDeformerCount(); ++i ) { FbxSkin* theSkin = reinterpret_cast< FbxSkin* >( theMesh->GetDeformer( i , FbxDeformer::eSkin ) ); if ( !theSkin ) continue; for ( int j = 0; j < theSkin->GetClusterCount(); ++j ) { FbxCluster* cluster = theSkin->GetCluster( j ); std::string jointName = cluster->GetLink()->GetName(); int currentJointIndex = -1; for ( unsigned int k = 0; k < skeleton.size(); ++k ) { if ( !skeleton[k].name.compare( jointName ) ) { currentJointIndex = k; break; } } if ( currentJointIndex < 0 ) { std::cout << "wrong bone" << std::endl; continue; } FbxAMatrix transformMatrix, transformLinkMatrix, offsetMatrix; cluster->GetTransformMatrix( transformMatrix ); cluster->GetTransformLinkMatrix( transformLinkMatrix ); //offsetMatrix = transformLinkMatrix.Inverse() * transformMatrix * geoTransform; FbxMatrix realMatrix( transformLinkMatrix.Inverse() * transformMatrix ); for ( unsigned int row = 0; row < 4; ++row ) { for ( unsigned int column = 0; column < 4; ++column ) { skeleton[currentJointIndex].offsetMatrix[row][column] = (float)realMatrix.Get( row , column ); } } for ( int k = 0; k < cluster->GetControlPointIndicesCount(); ++k ) { BlendingIndexWeightPair weightPair; weightPair.blendingIndex = currentJointIndex; weightPair.blendingWeight = (float)cluster->GetControlPointWeights()[k]; unsigned int controlPoint = cluster->GetControlPointIndices()[k]; for ( unsigned int z = 0; z < indices.size(); ++z ) { if ( indices[z].oldControlPoint == controlPoint ) { if ( verts[indices[z].index].blendingInfo.size() > 4 ) { std::cout << "Warning: vert has more than 4 bones connected, ignoring additional bone." << std::endl; } //else verts[indices[z].index].blendingInfo.push_back( weightPair ); bool found = false; for ( unsigned int omg = 0; omg < verts[indices[z].index].blendingInfo.size(); ++omg ) { if ( verts[indices[z].index].blendingInfo[omg].blendingIndex == weightPair.blendingIndex ) { found = true; break; } } if ( !found ) verts[indices[z].index].blendingInfo.push_back( weightPair ); } } } for ( unsigned int frameIndex = 0; frameIndex < frames.size(); ++frameIndex ) { FbxVector4 translation = cluster->GetLink()->EvaluateLocalTranslation( frames[frameIndex] ); FbxVector4 rotation = cluster->GetLink()->EvaluateLocalRotation( frames[frameIndex] ); FbxVector4 scale = cluster->GetLink()->EvaluateLocalScaling( frames[frameIndex] ); AnimationData animData; animData.frame = (int)frames[frameIndex].GetFrameCount(); animData.translation = glm::vec3(translation[0],translation[1],translation[2]); animData.rotation = glm::angleAxis( glm::radians( (float)rotation[2] ), glm::vec3(0,0,1)) * glm::angleAxis(glm::radians((float) rotation[1]), glm::vec3(0,1,0)) * glm::angleAxis(glm::radians((float)rotation[0]), glm::vec3(1,0,0)); animData.scale = glm::vec3(scale[0],scale[1],scale[2]); skeleton[currentJointIndex].animation.push_back( animData ); } } } }
int main(int argc, char **argv) { #ifndef _DEBUG if (argc != 2) { printf("invalid arg"); return 0; } const char* filename = argv[1]; #else const char* filename = "*****@*****.**"; #endif output.open("output.txt", ios::out | ios::trunc); output2.open("output2.txt", ios::out | ios::trunc); output3.open("output3.txt", ios::out | ios::trunc); if (!output.is_open()) { exit(1); } FbxManager* fm = FbxManager::Create(); FbxIOSettings *ios = FbxIOSettings::Create(fm, IOSROOT); //ios->SetBoolProp(EXP_FBX_ANIMATION, false); ios->SetIntProp(EXP_FBX_COMPRESS_LEVEL, 9); ios->SetAllObjectFlags(true); fm->SetIOSettings(ios); FbxImporter* importer = FbxImporter::Create(fm, ""); if (!importer->Initialize(filename, -1, fm->GetIOSettings())) { printf("error returned : %s\n", importer->GetStatus().GetErrorString()); exit(-1); } FbxScene* scene = FbxScene::Create(fm, "myscene"); importer->Import(scene); importer->Destroy(); output << "some\n"; output << "charcnt : " << scene->GetCharacterCount() << endl << "node cnt : " << scene->GetNodeCount() << endl; int animstackcnt = scene->GetSrcObjectCount<FbxAnimStack>(); output << "animstackcnt : " << animstackcnt << endl; output << "------------" << endl; vector<FbxNode*> removableNodes; for (int i = 0; i < scene->GetNodeCount(); i++) { FbxNode* node = scene->GetNode(i); output << "scene's node " << i << " : " << node->GetName() << ", childcnt : " << node->GetChildCount(); if (node->GetNodeAttribute()) { output <<", att type : " << node->GetNodeAttribute()->GetAttributeType(); if (node->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::EType::eMesh) { FbxMesh* mesh = node->GetMesh(); output << ", mem usage : " << mesh->MemoryUsage() << ", deformer cnt : " << mesh->GetDeformerCount(FbxDeformer::EDeformerType::eSkin) << endl; collapseMesh(mesh); FbxSkin* skin = (FbxSkin*) (mesh->GetDeformer(0, FbxDeformer::EDeformerType::eSkin)); if (skin) { for (int cli = 0; cli < skin->GetClusterCount(); cli++) { FbxCluster* cluster = skin->GetCluster(cli); output << "\tcluster no." << cli << " has " << cluster->GetControlPointIndicesCount() << " connected verts" << endl; if (cluster->GetControlPointIndicesCount() == 0) removableNodes.push_back( cluster->GetLink() ); //cluster-> //skin->RemoveCluster(cluster);효과없음 } } if (mesh->IsTriangleMesh()) { output << "\tit's triangle mesh" << endl; } //mesh->RemoveDeformer(0);효과없음 } else output << endl; } else { output << ", att type : none" << endl; } } for (int rni = 0; rni < removableNodes.size(); rni++) { FbxNode* rnd = removableNodes[rni]; if (rnd && rnd->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::EType::eSkeleton) { output3 << rnd->GetName() << " node with no vert attached's curve : " << rnd->GetSrcObjectCount<FbxAnimCurve>() << "," << rnd->GetSrcObjectCount<FbxAnimCurveNode>() << endl; } } output << "-----------animinfo" << endl; int cubic = 0, linear = 0, cons = 0; for (int si = 0; si < animstackcnt; si++) { FbxAnimStack* stack = scene->GetSrcObject<FbxAnimStack>(si); for (int i = 0; i < stack->GetMemberCount<FbxAnimLayer>(); i++) { FbxAnimLayer* layer = stack->GetMember<FbxAnimLayer>(i); int curvenodecnt = layer->GetMemberCount<FbxAnimCurveNode>(); int compositcnt = 0; for (int j = 0; j < curvenodecnt; j++) { FbxAnimCurveNode* cnode = layer->GetMember<FbxAnimCurveNode>(j); compositcnt += (cnode->IsComposite() ? 1 : 0); } output << "\tanimstack's layer " << i << " : " << layer->GetName() << ", curve node cnt : " << curvenodecnt << ", composit node cnt : " << compositcnt << endl; vector<FbxAnimCurveNode*> nodes2del; for (int j = 0; j < curvenodecnt; j++) { FbxAnimCurveNode* cnode = layer->GetMember<FbxAnimCurveNode>(j); output << "\t\tcurvenode " << j << " channel cnt : " << cnode->GetChannelsCount() << ", dst obj cnt " << cnode->GetDstObjectCount() << "("; for (int dsti = 0; dsti < cnode->GetDstObjectCount(); dsti++) { output << "," << cnode->GetDstObject(dsti)->GetName(); if (cnode->GetDstObject(dsti)->GetSrcObjectCount() > 0) output << "<" << cnode->GetDstObject(dsti)->GetSrcObjectCount<FbxSkeleton>() << ">"; } output << ")"; FbxTimeSpan interval; if (cnode->GetAnimationInterval(interval)) { output << ", start : " << interval.GetStart().GetTimeString() << ", end : " << interval.GetStop().GetTimeString() << endl; } else { nodes2del.push_back(cnode); output << ", no interval" << endl; } for (int chi = 0; chi < cnode->GetChannelsCount(); chi++) { int curvecnt = cnode->GetCurveCount(chi); output << "\t\t\tchannel." << chi << " curvecnt : " << curvecnt << endl; for (int ci = 0; ci < curvecnt; ci++) { FbxAnimCurve* curve = cnode->GetCurve(chi, ci); int keycnt = curve->KeyGetCount(); output << "\t\t\t\tcurve no." << ci << " : key count : " << keycnt; output2 << "curve " << ci << endl; vector<int> keys2Remove; for (int cki = 0; cki < keycnt; cki++) { FbxAnimCurveKey prevkey, currkey, nextkey; if (cki == 0 || cki == keycnt - 1) continue; currkey = curve->KeyGet(cki); prevkey = curve->KeyGet(cki-1); nextkey = curve->KeyGet(cki + 1); bool keepit = true; output2 << ci << "-" << cki; // keepit = keepTestHorizon(curve, prevkey, currkey, nextkey); // if (keepit) // keepit = slopkeepTest(curve, prevkey, currkey, nextkey); if (!keepit) { if (!(currkey.GetInterpolation() == FbxAnimCurveDef::EInterpolationType::eInterpolationConstant && nextkey.GetInterpolation() != FbxAnimCurveDef::EInterpolationType::eInterpolationConstant)) keys2Remove.push_back(cki); } } for (int kri = keys2Remove.size() - 1; kri >= 0; kri--) { //curve->KeyRemove(keys2Remove[kri]); } output2 << endl; //output << ", cubic:linear:const : " << cubic << ":" << linear << ":" << cons << endl; if (keys2Remove.size() > 0) output << ", " << keys2Remove.size() << " keys removed"; keycnt = curve->KeyGetCount(); } } } //이부분은 별로 효과없음 /* for (int di = 0; di < nodes2del.size(); di++) { layer->RemoveMember(nodes2del[di]); } */ } } output << "cubic:linear:const " << cubic << ":" << linear << ":" << cons << endl; FbxExporter* exporter = FbxExporter::Create(fm, ""); const char* outFBXName = "after.fbx"; bool exportstatus = exporter->Initialize(outFBXName, -1, fm->GetIOSettings()); if (exportstatus == false) { puts("err export fail"); } exporter->Export(scene); exporter->Destroy(); scene->Destroy(); ios->Destroy(); fm->Destroy(); output.close(); output2.close(); output3.close(); return 0; }
void FVertexAnimTools::ImportVertexAnimtion(UnFbx::FFbxImporter* FFbxImporter, USkeletalMesh * SkelMesh, UPackage * Package, FString& Filename) { check(SkelMesh); check(SkelMesh->GetImportedResource()->LODModels.Num() > 0); FStaticLODModel& Model = SkelMesh->GetImportedResource()->LODModels[0]; if(Model.MeshToImportVertexMap.Num() == 0) { UE_LOG(LogFbx, Warning, TEXT("ImportVertexAnimtion: Mesh does not contain necessary vertex anim mapping.")); return; } FbxNode* RootNodeToImport = FFbxImporter->Scene->GetRootNode(); /* Exporting from Maya with skin and vertex cache seems to throw away the skin deformer, so not sure how to find the 'right' mesh... TArray<FbxNode*> MeshArray; FName RootBoneName = (SkelMesh->Skeleton)? SkelMesh->Skeleton->GetBoneName(0) : SkelMesh->RefSkeleton.RefBoneInfo(0).Name; FFbxImporter->FindFBXMeshesByBone(RootBoneName, false, MeshArray); */ // Find mesh with vertex deformer TArray<FbxMesh*> VertexCacheMeshes; RecursiveFindVertexAnimMeshes(RootNodeToImport, VertexCacheMeshes); if(VertexCacheMeshes.Num() == 0) { UE_LOG(LogFbx, Warning, TEXT("ImportVertexAnimtion: No vertex cache deformed mesh found.")); return; } // Get deformer and open cache FbxMesh* Mesh = VertexCacheMeshes[0]; FbxVertexCacheDeformer* Deformer = static_cast<FbxVertexCacheDeformer*>(Mesh->GetDeformer(0, FbxDeformer::eVertexCache)); check(Deformer != NULL); // tested in RecursiveFindVertexAnimMeshes FbxCache* Cache = Deformer->GetCache(); bool bOpenSuccess = Cache->OpenFileForRead(); if(!bOpenSuccess) { UE_LOG(LogFbx, Warning, TEXT("ImportVertexAnimtion: Unable to open cache file.")); return; } // Check cache format if(Cache->GetCacheFileFormat() != FbxCache::eMayaCache) { UE_LOG(LogFbx, Warning, TEXT("ImportVertexAnimtion: Only Maya vertex animation supported.")); return; } // Get channel FbxString DeformerChannelName = Deformer->Channel.Get(); int ChannelIndex = Cache->GetChannelIndex(DeformerChannelName); if(ChannelIndex == -1) { UE_LOG(LogFbx, Warning, TEXT("ImportVertexAnimtion: No Cache channel for deformer.")); return; } // Get data type FbxCache::EMCDataType DataType; bool bGetDataTypeOk = Cache->GetChannelDataType(ChannelIndex, DataType); check(bGetDataTypeOk); if(DataType != FbxCache::EMCDataType::eDoubleVectorArray) { UE_LOG(LogFbx, Warning, TEXT("ImportVertexAnimtion: Only double array format supported at the moment.")); return; } // Get other info about anim FbxTime StartTime, DeltaTime; int32 NumFrames, NumAnimatedPoints; bool bInfoOk = GetVertexAnimInfo(Cache, ChannelIndex, StartTime, DeltaTime, NumFrames, NumAnimatedPoints); if(!bInfoOk) { UE_LOG(LogFbx, Warning, TEXT("ImportVertexAnimtion: Invalid vertex animation.")); return; } UVertexAnimation* NewVertexAnim = UnFbx::FFbxImporter::CreateAsset<UVertexAnimation>( Package->GetName(), *FPaths::GetBaseFilename(Filename) ); if (NewVertexAnim != NULL) { // Save the mesh we are importing for NewVertexAnim->BaseSkelMesh = SkelMesh; NewVertexAnim->NumAnimatedVerts = NumAnimatedPoints; ConvertCacheToAnim(Cache, ChannelIndex, NewVertexAnim, StartTime, DeltaTime, NumFrames); UE_LOG(LogFbx, Log, TEXT("ImportVertexAnimtion: Success! %d frames."), NewVertexAnim->GetNumFrames()); } }
//=============================================================================================================================== void FBXLoader::LoadJointsAndAnimation(FbxNode* inNode) { // This is how each subset gets its bone/joint for animation FBXSubsets* subset = mSubsets[iCurrentSubset]; FbxMesh* mesh = inNode->GetMesh(); uint32 numOfDeformers = mesh->GetDeformerCount(); FbxAMatrix geomTrans = ZShadeSandboxMesh::FBXHelper::GetGeometryTransformation(inNode); // A deformer contains clusters. // A cluster contains a link, which is a joint. // Normally, There is only one deformer in a mesh but Maya has many types. for (uint32 deformerIndex = 0; deformerIndex < numOfDeformers; ++deformerIndex) { // Lets see if this deformer is a skin FbxSkin* skin = reinterpret_cast<FbxSkin*>(mesh->GetDeformer(deformerIndex, FbxDeformer::eSkin)); if (!skin) continue; uint32 numOfClusters = skin->GetClusterCount(); for (uint32 clusterIndex = 0; clusterIndex < numOfClusters; ++clusterIndex) { FbxCluster* cluster = skin->GetCluster(clusterIndex); string jointName = cluster->GetLink()->GetName(); uint32 jointIndex = FindJointIndexUsingName(jointName); subset->mJoints.push_back(jointIndex); FbxAMatrix transform; FbxAMatrix transformLink; FbxAMatrix globalBindposeInverse; // The transformation of the mesh at binding time cluster->GetTransformMatrix(transform); // The transformation of the cluster (joint) at binding time from joint space to world space cluster->GetTransformLinkMatrix(transformLink); globalBindposeInverse = transformLink.Inverse() * transform * geomTrans; // Update skeletal information mSkeleton.joints[jointIndex].globalBindposeInverse = globalBindposeInverse; mSkeleton.joints[jointIndex].node = cluster->GetLink(); // Associate each joint with the control points it affects uint32 numOfIndices = cluster->GetControlPointIndicesCount(); for (uint32 i = 0; i < numOfIndices; ++i) { ZShadeSandboxMesh::BlendingIndexWeightPair currBlendingIndexWeightPair; currBlendingIndexWeightPair.blendingIndex = jointIndex; currBlendingIndexWeightPair.blendingWeight = cluster->GetControlPointWeights()[i]; mControlPoints[cluster->GetControlPointIndices()[i]]->blendingInfo.push_back(currBlendingIndexWeightPair); } // Animation information FbxAnimStack* animStack = m_pFbxScene->GetSrcObject<FbxAnimStack>(0); FbxString animStackName = animStack->GetName(); mAnimationName = animStackName.Buffer(); FbxTakeInfo* takeInfo = m_pFbxScene->GetTakeInfo(animStackName); FbxTime start = takeInfo->mLocalTimeSpan.GetStart(); FbxTime end = takeInfo->mLocalTimeSpan.GetStop(); mAnimationLength = end.GetFrameCount(FbxTime::eFrames24) - start.GetFrameCount(FbxTime::eFrames24) + 1; FBXKeyframe** anim = &mSkeleton.joints[jointIndex].animation; for (FbxLongLong i = start.GetFrameCount(FbxTime::eFrames24); i <= end.GetFrameCount(FbxTime::eFrames24); ++i) { FbxTime time; time.SetFrame(i, FbxTime::eFrames24); *anim = new FBXKeyframe(); (*anim)->frameNum = i; FbxAMatrix currentTransformOffset = inNode->EvaluateGlobalTransform(time) * geomTrans; (*anim)->globalTransform = currentTransformOffset.Inverse() * cluster->GetLink()->EvaluateGlobalTransform(time); anim = &((*anim)->next); } } } // Some control points have less than 4 joints // For a normal renderer, there are usually 4 joints ZShadeSandboxMesh::BlendingIndexWeightPair currBlendingIndexWeightPair; currBlendingIndexWeightPair.blendingIndex = 0; currBlendingIndexWeightPair.blendingWeight = 0; for (auto itr = mControlPoints.begin(); itr != mControlPoints.end(); ++itr) { for (unsigned int i = itr->second->blendingInfo.size(); i <= 4; ++i) { itr->second->blendingInfo.push_back(currBlendingIndexWeightPair); } } }
bool FillData(ModelData* someData,FbxNode* aNode, AnimationData* aAnimation) { FbxMesh* mesh = aNode->GetMesh(); if (mesh == nullptr || !aNode) return false; const int lPolygonCount = mesh->GetPolygonCount(); // Count the polygon count of each material FbxLayerElementArrayTemplate<int>* lMaterialIndice = NULL; FbxGeometryElement::EMappingMode lMaterialMappingMode = FbxGeometryElement::eNone; if (mesh->GetElementMaterial()) { lMaterialIndice = &mesh->GetElementMaterial()->GetIndexArray(); lMaterialMappingMode = mesh->GetElementMaterial()->GetMappingMode(); if (lMaterialIndice && lMaterialMappingMode == FbxGeometryElement::eByPolygon) { FBX_ASSERT(lMaterialIndice->GetCount() == lPolygonCount); if (lMaterialIndice->GetCount() == lPolygonCount) { // Count the faces of each material for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex) { const int lMaterialIndex = lMaterialIndice->GetAt(lPolygonIndex); lMaterialIndex; /*if (someData->mSubMeshes[lMaterialIndex] == NULL) { someData->mSubMeshes[lMaterialIndex] = new ModelData::SubMesh; } someData->mSubMeshes[lMaterialIndex]->TriangleCount += 1;*/ } // Make sure we have no "holes" (NULL) in the mSubMeshes table. This can happen // if, in the loop above, we resized the mSubMeshes by more than one slot. /*for (int i = 0; i < someData->mSubMeshes.Count(); i++) { if (someData->mSubMeshes[i] == NULL) someData->mSubMeshes[i] = new ModelData::SubMesh; }*/ // Record the offset (how many vertex) const int lMaterialCount = someData->mSubMeshes.Size(); lMaterialCount; int lOffset = 0; /*for (int lIndex = 0; lIndex < lMaterialCount; ++lIndex) { someData->mSubMeshes[lIndex]->IndexOffset = lOffset; lOffset += someData->mSubMeshes[lIndex]->TriangleCount * 3; // This will be used as counter in the following procedures, reset to zero someData->mSubMeshes[lIndex]->TriangleCount = 0; }*/ FBX_ASSERT(lOffset == lPolygonCount * 3); } } } // All faces will use the same material. if (someData->mSubMeshes.Size() == 0) { if (someData->mSubMeshes.GetCapacity() == 0) { someData->mSubMeshes.Init(1); } someData->mSubMeshes.RemoveAll(); someData->mSubMeshes.AddEmptyObject(); someData->mSubMeshes[0] = new ModelData::SubMesh(); } bool hasNormalMap = false; const int lMaterialCount = aNode->GetMaterialCount(); for (int lMaterialIndex = 0; lMaterialIndex < lMaterialCount; ++lMaterialIndex) { FbxSurfaceMaterial * lMaterial = aNode->GetMaterial(lMaterialIndex); if (lMaterial && !lMaterial->GetUserDataPtr()) { TextureInfo diffuseInfo; GetMaterialProperty(lMaterial,FbxSurfaceMaterial::sDiffuse,FbxSurfaceMaterial::sDiffuseFactor,diffuseInfo.myFileName); diffuseInfo.myType = DIFFUSE; if(diffuseInfo.myFileName.empty() == false) { someData->myTextures.push_back(diffuseInfo); } TextureInfo normalInfo; GetMaterialProperty(lMaterial,FbxSurfaceMaterial::sNormalMap,FbxSurfaceMaterial::sBumpFactor,normalInfo.myFileName); hasNormalMap = normalInfo.myFileName.empty() == false; normalInfo.myType = NORMALMAP; if(normalInfo.myFileName.empty() == false) { someData->myTextures.push_back(normalInfo); hasNormalMap = true; } TextureInfo roughnessInfo; GetMaterialProperty(lMaterial,FbxSurfaceMaterial::sSpecular,FbxSurfaceMaterial::sSpecularFactor,roughnessInfo.myFileName); roughnessInfo.myType = ROUGHNESS; if(roughnessInfo.myFileName.empty() == false) { someData->myTextures.push_back(roughnessInfo); } TextureInfo substanceInfo; GetMaterialProperty(lMaterial,FbxSurfaceMaterial::sReflection,FbxSurfaceMaterial::sReflectionFactor,substanceInfo.myFileName); substanceInfo.myType = SUBSTANCE; if(substanceInfo.myFileName.empty() == false) { someData->myTextures.push_back(substanceInfo); } TextureInfo ambientInfo; GetMaterialProperty(lMaterial, FbxSurfaceMaterial::sAmbient, FbxSurfaceMaterial::sAmbientFactor, ambientInfo.myFileName); ambientInfo.myType = AO; if (substanceInfo.myFileName.empty() == false) { someData->myTextures.push_back(ambientInfo); } } } // Congregate all the data of a mesh to be cached in VBOs. // If normal or UV is by polygon vertex, record all vertex attributes by polygon vertex.' someData->mHasNormal = mesh->GetElementNormalCount() > 0; someData->mHasUV = mesh->GetElementUVCount() > 0; someData->myHasBiNormal = mesh->GetElementBinormalCount() > 0; FbxSkin * lSkinDeformer = (FbxSkin *)mesh->GetDeformer(0, FbxDeformer::eSkin); someData->myHasSkinweights = lSkinDeformer != nullptr; if(hasNormalMap && someData->myHasBiNormal == false) { mesh->GenerateTangentsDataForAllUVSets(); someData->myHasBiNormal = mesh->GetElementBinormalCount() > 0; } someData->myHasTangents = mesh->GetElementTangentCount() > 0; FbxGeometryElement::EMappingMode lNormalMappingMode = FbxGeometryElement::eNone; FbxGeometryElement::EMappingMode lUVMappingMode = FbxGeometryElement::eNone; if (someData->mHasNormal) { lNormalMappingMode = mesh->GetElementNormal(0)->GetMappingMode(); if (lNormalMappingMode == FbxGeometryElement::eNone) { someData->mHasNormal = false; } if (someData->mHasNormal && lNormalMappingMode != FbxGeometryElement::eByControlPoint) { someData->mAllByControlPoint = false; } } if (someData->mHasUV) { lUVMappingMode = mesh->GetElementUV(0)->GetMappingMode(); if (lUVMappingMode == FbxGeometryElement::eNone) { someData->mHasUV = false; } if (someData->mHasUV && lUVMappingMode != FbxGeometryElement::eByControlPoint) { someData->mAllByControlPoint = false; } } // Allocate the array memory, by control point or by polygon vertex. int lPolygonVertexCount = mesh->GetControlPointsCount(); //if (!someData->my) { ModelData::Layout newLayout; newLayout.myType = ModelData::VERTEX_POS; newLayout.mySize = VERTEX_STRIDE; newLayout.myOffset = 0; someData->myLayout.Add(newLayout); lPolygonVertexCount = lPolygonCount * TRIANGLE_VERTEX_COUNT; } int stride = VERTEX_STRIDE; size_t size = lPolygonVertexCount * VERTEX_STRIDE; //float * lVertices = new float[lPolygonVertexCount * VERTEX_STRIDE]; unsigned int * lIndices = new unsigned int[lPolygonCount * TRIANGLE_VERTEX_COUNT]; someData->myIndexCount = lPolygonCount * TRIANGLE_VERTEX_COUNT; //float * lNormals = NULL; if (someData->mHasNormal) { ModelData::Layout newLayout; newLayout.myType = ModelData::VERTEX_NORMAL; newLayout.mySize = NORMAL_STRIDE; newLayout.myOffset = stride*4; someData->myLayout.Add(newLayout); stride += NORMAL_STRIDE; size += lPolygonVertexCount * NORMAL_STRIDE; //lNormals = new float[lPolygonVertexCount * NORMAL_STRIDE]; } //float * lUVs = NULL; FbxStringList lUVNames; mesh->GetUVSetNames(lUVNames); const char * lUVName = NULL; if (someData->mHasUV && lUVNames.GetCount()) { ModelData::Layout newLayout; newLayout.myType = ModelData::VERTEX_UV; newLayout.mySize = UV_STRIDE; newLayout.myOffset = stride*4; someData->myLayout.Add(newLayout); stride += UV_STRIDE; size += lPolygonVertexCount * UV_STRIDE; //lUVs = new float[lPolygonVertexCount * UV_STRIDE]; lUVName = lUVNames[0]; } if (someData->myHasBiNormal) { ModelData::Layout newLayout; newLayout.myType = ModelData::VERTEX_BINORMAL; newLayout.mySize = BINORMAL_STRIDE; newLayout.myOffset = stride*4; someData->myLayout.Add(newLayout); stride += BINORMAL_STRIDE; size += lPolygonVertexCount * BINORMAL_STRIDE; //lUVs = new float[lPolygonVertexCount * UV_STRIDE]; } if (someData->myHasTangents) { ModelData::Layout newLayout; newLayout.myType = ModelData::VERTEX_TANGENT; newLayout.mySize = TANGENT_STRIDE; newLayout.myOffset = stride*4; someData->myLayout.Add(newLayout); stride += TANGENT_STRIDE; size += lPolygonVertexCount * TANGENT_STRIDE; //lUVs = new float[lPolygonVertexCount * UV_STRIDE]; } if (someData->myHasSkinweights) { ModelData::Layout newLayout; newLayout.myType = ModelData::VERTEX_SKINWEIGHTS; newLayout.mySize = SKINWEIGHT_STRIDE; newLayout.myOffset = stride*4; someData->myLayout.Add(newLayout); stride += SKINWEIGHT_STRIDE; size += lPolygonVertexCount * SKINWEIGHT_STRIDE; newLayout.myType = ModelData::VERTEX_BONEID; newLayout.mySize = BONEID_STRIDE; newLayout.myOffset = stride*4; someData->myLayout.Add(newLayout); stride += BONEID_STRIDE; size += lPolygonVertexCount * BONEID_STRIDE; //lUVs = new float[lPolygonVertexCount * UV_STRIDE]; } float * lVertices = new float[size]; FbxAMatrix globalPos; FbxVector4* weights = nullptr; FbxVectorTemplate4<int>* bones = nullptr; FbxTime time = static_cast<FbxTime>(0.0f); if(someData->myHasSkinweights) { weights = new FbxVector4[mesh->GetControlPointsCount()]; bones = new FbxVectorTemplate4<int>[mesh->GetControlPointsCount()]; ComputeLinearDeformation(globalPos,mesh,weights,bones,aAnimation); } const FbxGeometryElementBinormal * lBiNormalElement = NULL; const FbxGeometryElementTangent * lTangentElement = NULL; if (someData->myHasBiNormal) { lBiNormalElement = mesh->GetElementBinormal(0); } if (someData->myHasTangents) { lTangentElement = mesh->GetElementTangent(0); } // Populate the array with vertex attribute, if by control point. const FbxVector4 * lControlPoints = mesh->GetControlPoints(); FbxVector4 lCurrentVertex; FbxVector4 lCurrentNormal; FbxVector4 lCurrentBiNormal; FbxVector4 lCurrentTangent; FbxVector2 lCurrentUV; if (someData->mAllByControlPoint) { const FbxGeometryElementNormal * lNormalElement = NULL; const FbxGeometryElementUV * lUVElement = NULL; if (someData->mHasNormal) { lNormalElement = mesh->GetElementNormal(0); } if (someData->mHasUV) { lUVElement = mesh->GetElementUV(0); } for (int lIndex = 0; lIndex < lPolygonVertexCount; ++lIndex) { int currentIndex = lIndex * stride; int addedSize = VERTEX_STRIDE; // Save the vertex position. lCurrentVertex = lControlPoints[lIndex]; CU::Vector4f position(static_cast<float>(lCurrentVertex[0]), static_cast<float>(lCurrentVertex[1]), static_cast<float>(lCurrentVertex[2]), 1); CU::Matrix44f fixMatrix; fixMatrix = CU::Matrix44<float>::CreateReflectionMatrixAboutAxis(CU::Vector3f(1,0,0)); position = position*fixMatrix; lVertices[currentIndex] = position.x; lVertices[currentIndex + 1] = position.y; lVertices[currentIndex + 2] = position.z; lVertices[currentIndex + 3] = 1; // Save the normal. if (someData->mHasNormal) { int lNormalIndex = lIndex; if (lNormalElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lNormalIndex = lNormalElement->GetIndexArray().GetAt(lIndex); } lCurrentNormal = lNormalElement->GetDirectArray().GetAt(lNormalIndex); CU::Vector3f normal( static_cast<float>(lCurrentNormal[0]), static_cast<float>(lCurrentNormal[1]), static_cast<float>(lCurrentNormal[2])); normal = normal*CU::Matrix33<float>::CreateReflectionMatrixAboutAxis(CU::Vector3f(1, 0, 0)); lVertices[currentIndex + addedSize] = normal.x; lVertices[currentIndex + addedSize + 1] = normal.y; lVertices[currentIndex + addedSize + 2] = normal.z; lVertices[currentIndex + addedSize + 3] = 0; addedSize += NORMAL_STRIDE; } // Save the UV. if (someData->mHasUV) { int lUVIndex = lIndex; if (lUVElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lUVIndex = lUVElement->GetIndexArray().GetAt(lIndex); } lCurrentUV = lUVElement->GetDirectArray().GetAt(lUVIndex); lVertices[currentIndex + addedSize] = static_cast<float>(lCurrentUV[0]); lVertices[currentIndex + addedSize + 1] = static_cast<float>(lCurrentUV[1])*-1.0f; addedSize += 2; } if (someData->myHasBiNormal) { int lBinormIndexIndex = lIndex; if (lBiNormalElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lBinormIndexIndex = lBiNormalElement->GetIndexArray().GetAt(lIndex); } lCurrentBiNormal = lBiNormalElement->GetDirectArray().GetAt(lBinormIndexIndex); //mesh->GetElementBinormal(lPolygonIndex, lVerticeIndex, lCurrentNormal); //lCurrentNormal = lCurrentNormal CU::Vector3f normal( static_cast<float>(lCurrentBiNormal[0]), static_cast<float>(lCurrentBiNormal[1]), static_cast<float>(lCurrentBiNormal[2])); normal = normal*CU::Matrix33<float>::CreateReflectionMatrixAboutAxis(CU::Vector3f(1, 0, 0)); if (CU::Length(normal) != 0.f) CU::Normalize(normal); lVertices[currentIndex + addedSize] = normal.x; lVertices[currentIndex + addedSize + 1] = normal.y; lVertices[currentIndex + addedSize + 2] = normal.z; lVertices[currentIndex + addedSize + 3] = 0; addedSize += BINORMAL_STRIDE; } if (someData->myHasTangents) { int lBinormIndexIndex = lIndex; if (lTangentElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lBinormIndexIndex = lTangentElement->GetIndexArray().GetAt(lIndex); } lCurrentTangent = lTangentElement->GetDirectArray().GetAt(lBinormIndexIndex); //lCurrentNormal = lCurrentNormal CU::Vector3f normal( static_cast<float>(lCurrentTangent[0]), static_cast<float>(lCurrentTangent[1]), static_cast<float>(lCurrentTangent[2])); normal = normal*CU::Matrix33<float>::CreateReflectionMatrixAboutAxis(CU::Vector3f(1, 0, 0)); if (CU::Length(normal) != 0.f) CU::Normalize(normal); lVertices[currentIndex + addedSize] = normal.x; lVertices[currentIndex + addedSize + 1] = normal.y; lVertices[currentIndex + addedSize + 2] = normal.z; lVertices[currentIndex + addedSize + 3] = 0; addedSize += TANGENT_STRIDE; } if(someData->myHasSkinweights) { FbxVector4 currentWeights = weights[lIndex]; //currentWeights.Normalize(); lVertices[currentIndex + addedSize] = static_cast<float>(currentWeights[0]); lVertices[currentIndex + addedSize + 1] = static_cast<float>(currentWeights[1]); lVertices[currentIndex + addedSize + 2] = static_cast<float>(currentWeights[2]); lVertices[currentIndex + addedSize + 3] = static_cast<float>(currentWeights[3]); addedSize += SKINWEIGHT_STRIDE; FbxVectorTemplate4<int> currentBones = bones[lIndex]; lVertices[currentIndex + addedSize] = static_cast<float>(currentBones[0]); lVertices[currentIndex + addedSize + 1] = static_cast<float>(currentBones[1]); lVertices[currentIndex + addedSize + 2] = static_cast<float>(currentBones[2]); lVertices[currentIndex + addedSize + 3] = static_cast<float>(currentBones[3]); addedSize += BONEID_STRIDE; } } } int lVertexCount = 0; for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex) { // The material for current face. int lMaterialIndex = 0; if (lMaterialIndice && lMaterialMappingMode == FbxGeometryElement::eByPolygon) { lMaterialIndex = lMaterialIndice->GetAt(lPolygonIndex); } // Where should I save the vertex attribute index, according to the material const int lIndexOffset = someData->mSubMeshes[lMaterialIndex]->IndexOffset + someData->mSubMeshes[lMaterialIndex]->TriangleCount * 3; for (int lVerticeIndex = TRIANGLE_VERTEX_COUNT-1; lVerticeIndex > -1; --lVerticeIndex) { const int lControlPointIndex = mesh->GetPolygonVertex(lPolygonIndex, lVerticeIndex); int vertexIndex = lIndexOffset + (TRIANGLE_VERTEX_COUNT-1) - lVerticeIndex; if (someData->mAllByControlPoint) { lIndices[vertexIndex] = static_cast<unsigned int>(lControlPointIndex); } // Populate the array with vertex attribute, if by polygon vertex. else { lIndices[vertexIndex] = static_cast<unsigned int>(lVertexCount); lCurrentVertex = lControlPoints[lControlPointIndex]; int addedSize = VERTEX_STRIDE; int currentIndex = lVertexCount * stride; CU::Vector4f position(static_cast<float>(lCurrentVertex[0]), static_cast<float>(lCurrentVertex[1]), static_cast<float>(lCurrentVertex[2]), 1); //fixMatrix CU::Matrix44f fixMatrix; fixMatrix = CU::Matrix44<float>::CreateReflectionMatrixAboutAxis(CU::Vector3f(1, 0, 0)); position = position*fixMatrix; lVertices[currentIndex] = position.x; lVertices[currentIndex + 1] = position.y; lVertices[currentIndex + 2] = position.z; lVertices[currentIndex + 3] = 0; if (someData->mHasNormal) { mesh->GetPolygonVertexNormal(lPolygonIndex, lVerticeIndex, lCurrentNormal); CU::Vector3f normal( static_cast<float>(lCurrentNormal[0]), static_cast<float>(lCurrentNormal[1]), static_cast<float>(lCurrentNormal[2])); normal = normal*CU::Matrix33<float>::CreateReflectionMatrixAboutAxis(CU::Vector3f(1, 0, 0)); if (CU::Length(normal) != 0.f) CU::Normalize(normal); lVertices[currentIndex + addedSize] = normal.x; lVertices[currentIndex + addedSize + 1] = normal.y; lVertices[currentIndex + addedSize + 2] = normal.z; lVertices[currentIndex + addedSize + 3] = 0; addedSize += NORMAL_STRIDE; } if (someData->mHasUV) { bool lUnmappedUV; mesh->GetPolygonVertexUV(lPolygonIndex, lVerticeIndex, lUVName, lCurrentUV, lUnmappedUV); lVertices[currentIndex + addedSize] = static_cast<float>(lCurrentUV[0]); lVertices[currentIndex + addedSize + 1] = static_cast<float>(lCurrentUV[1])*-1.0f; addedSize += UV_STRIDE; } if (someData->myHasBiNormal) { int lBinormIndexIndex = lVerticeIndex; if (lBiNormalElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lBinormIndexIndex = lBiNormalElement->GetIndexArray().GetAt(lVerticeIndex); } lCurrentBiNormal = lBiNormalElement->GetDirectArray().GetAt(lBinormIndexIndex); CU::Vector3f normal( static_cast<float>(lCurrentBiNormal[0]), static_cast<float>(lCurrentBiNormal[1]), static_cast<float>(lCurrentBiNormal[2])); normal = normal*CU::Matrix33<float>::CreateReflectionMatrixAboutAxis(CU::Vector3f(1, 0, 0)); if (CU::Length(normal) != 0.f) CU::Normalize(normal); lVertices[currentIndex + addedSize] = normal.x; lVertices[currentIndex + addedSize + 1] = normal.y; lVertices[currentIndex + addedSize + 2] = normal.z; lVertices[currentIndex + addedSize + 3] = 0; addedSize += BINORMAL_STRIDE; } if (someData->myHasTangents) { int lBinormIndexIndex = lVerticeIndex; if (lTangentElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { lBinormIndexIndex = lTangentElement->GetIndexArray().GetAt(lVerticeIndex); } lCurrentTangent = lTangentElement->GetDirectArray().GetAt(lBinormIndexIndex); mesh->GetPolygonVertexNormal(lPolygonIndex, lVerticeIndex, lCurrentNormal); CU::Vector3f normal( static_cast<float>(lCurrentTangent[0]), static_cast<float>(lCurrentTangent[1]), static_cast<float>(lCurrentTangent[2])); normal = normal*CU::Matrix33<float>::CreateReflectionMatrixAboutAxis(CU::Vector3f(1, 0, 0)); if (CU::Length(normal) != 0.f) CU::Normalize(normal); lVertices[currentIndex + addedSize] = normal.x; lVertices[currentIndex + addedSize + 1] = normal.y; lVertices[currentIndex + addedSize + 2] = normal.z; lVertices[currentIndex + addedSize + 3] = 0; addedSize += TANGENT_STRIDE; } if(someData->myHasSkinweights) { FbxVector4 currentWeights = weights[lControlPointIndex]; FbxVectorTemplate4<int> currentBones = bones[lControlPointIndex]; for(int l = 0;l < 4;++l) { if(currentBones[l] == -1) { currentWeights[l] = 0.0f; } } currentWeights.Normalize(); lVertices[currentIndex + addedSize] = static_cast<float>(currentWeights[0]); lVertices[currentIndex + addedSize + 1] = static_cast<float>(currentWeights[1]); lVertices[currentIndex + addedSize + 2] = static_cast<float>(currentWeights[2]); lVertices[currentIndex + addedSize + 3] = static_cast<float>(currentWeights[3]); addedSize += SKINWEIGHT_STRIDE; lVertices[currentIndex + addedSize] = *(float*)¤tBones[0]; lVertices[currentIndex + addedSize + 1] = *(float*)¤tBones[1]; lVertices[currentIndex + addedSize + 2] = *(float*)¤tBones[2]; lVertices[currentIndex + addedSize + 3] = *(float*)¤tBones[3]; addedSize += BONEID_STRIDE; } } ++lVertexCount; } someData->mSubMeshes[lMaterialIndex]->TriangleCount += 1; } someData->myVertexCount = lVertexCount; someData->myVertexStride = stride; someData->myVertexBuffer = lVertices; someData->myIndicies = lIndices; if(weights) { delete [] weights; delete [] bones; } return true; }