improved model export

This commit is contained in:
Perfare 2019-07-16 04:33:37 +08:00
parent e001dff3de
commit 50c17c2ec4
5 changed files with 317 additions and 418 deletions

View File

@ -1,5 +1,4 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -29,6 +28,21 @@ namespace AssetStudio
public int Count => children.Count; public int Count => children.Count;
public string Path
{
get
{
var frame = this;
var path = frame.Name;
while (frame.Parent != null)
{
frame = frame.Parent;
path = frame.Name + "/" + path;
}
return path;
}
}
public ImportedFrame(int childrenCount = 0) public ImportedFrame(int childrenCount = 0)
{ {
children = new List<ImportedFrame>(childrenCount); children = new List<ImportedFrame>(childrenCount);
@ -48,19 +62,15 @@ namespace AssetStudio
public ImportedFrame FindFrameByPath(string path) public ImportedFrame FindFrameByPath(string path)
{ {
var splitPath = path.Split('/'); var name = path.Substring(path.LastIndexOf('/') + 1);
if (Name != splitPath[0]) foreach (var frame in FindChilds(name))
throw new Exception($"Couldn't find path {path}");
var curFrame = this;
for (int i = 1; i < splitPath.Length; i++)
{ {
curFrame = curFrame.FindChild(splitPath[i], false); if (frame.Path.EndsWith(path, StringComparison.Ordinal))
if (curFrame == null)
{ {
throw new Exception($"Couldn't find path {path}"); return frame;
} }
} }
return curFrame; return null;
} }
public ImportedFrame FindFrame(string name) public ImportedFrame FindFrame(string name)
@ -265,27 +275,6 @@ namespace AssetStudio
return null; return null;
} }
public static ImportedMesh FindMesh(ImportedFrame frame, List<ImportedMesh> importedMeshList)
{
var framePath = frame.Name;
var root = frame;
while (root.Parent != null)
{
root = root.Parent;
framePath = root.Name + "/" + framePath;
}
foreach (var mesh in importedMeshList)
{
if (mesh.Path == framePath)
{
return mesh;
}
}
return null;
}
public static ImportedMaterial FindMaterial(string name, List<ImportedMaterial> importedMats) public static ImportedMaterial FindMaterial(string name, List<ImportedMaterial> importedMats)
{ {
foreach (var mat in importedMats) foreach (var mat in importedMats)

View File

@ -1,5 +1,3 @@
#include <fbxsdk.h>
#include <fbxsdk/fileio/fbxiosettings.h>
#include "AssetStudioFBX.h" #include "AssetStudioFBX.h"
namespace AssetStudio namespace AssetStudio

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <fbxsdk.h>
#ifdef IOS_REF #ifdef IOS_REF
#undef IOS_REF #undef IOS_REF
#define IOS_REF (*(pSdkManager->GetIOSettings())) #define IOS_REF (*(pSdkManager->GetIOSettings()))
@ -48,14 +50,14 @@ namespace AssetStudio {
{ {
public: public:
static void Export(String^ path, IImported^ imported, bool eulerFilter, float filterPrecision, bool allFrames, bool allBones, bool skins, float boneSize, float scaleFactor, bool flatInbetween, int versionIndex, bool isAscii); static void Export(String^ path, IImported^ imported, bool eulerFilter, float filterPrecision, bool allFrames, bool allBones, bool skins, float boneSize, float scaleFactor, bool flatInbetween, int versionIndex, bool isAscii);
static void ExportMorph(String^ path, IImported^ imported, bool morphMask, bool flatInbetween, bool skins, float boneSize, float scaleFactor, int versionIndex, bool isAscii);
private: private:
HashSet<String^>^ frameNames;
bool exportSkins; bool exportSkins;
float boneSize; float boneSize;
IImported^ imported; IImported^ imported;
HashSet<String^>^ framePaths;
Dictionary<ImportedFrame^, size_t>^ frameToNode;
List<ImportedFrame^>^ meshFrames;
char* cDest; char* cDest;
FbxManager* pSdkManager; FbxManager* pSdkManager;
@ -63,24 +65,22 @@ namespace AssetStudio {
FbxExporter* pExporter; FbxExporter* pExporter;
FbxArray<FbxSurfacePhong*>* pMaterials; FbxArray<FbxSurfacePhong*>* pMaterials;
FbxArray<FbxFileTexture*>* pTextures; FbxArray<FbxFileTexture*>* pTextures;
FbxArray<FbxNode*>* pMeshNodes;
FbxPose* pBindPose; FbxPose* pBindPose;
Exporter(String^ path, IImported^ imported, bool allFrames, bool allBones, bool skins, float boneSize, float scaleFactor, int versionIndex, bool isAscii, bool normals); Exporter(String^ path, IImported^ imported, bool allFrames, bool allBones, bool skins, float boneSize, float scaleFactor, int versionIndex, bool isAscii);
~Exporter(); ~Exporter();
void Exporter::LinkTexture(ImportedMaterialTexture^ texture, FbxFileTexture* pTexture, FbxProperty& prop); void Exporter::LinkTexture(ImportedMaterialTexture^ texture, FbxFileTexture* pTexture, FbxProperty& prop);
void SetJointsNode(FbxNode* pNode, HashSet<String^>^ boneNames, bool allBones); void SetJointsNode(ImportedFrame^ frame, HashSet<String^>^ bonePaths, bool allBones);
HashSet<String^>^ SearchHierarchy(); HashSet<String^>^ SearchHierarchy();
void SearchHierarchy(ImportedFrame^ frame, HashSet<String^>^ exportFrames); void SearchHierarchy(ImportedFrame^ frame, HashSet<String^>^ exportFrames);
void SetJointsFromImportedMeshes(bool allBones); void SetJointsFromImportedMeshes(bool allBones);
void ExportFrame(FbxNode* pParentNode, ImportedFrame^ frame); void ExportFrame(FbxNode* pParentNode, ImportedFrame^ frame);
void ExportMesh(FbxNode* pFrameNode, ImportedMesh^ meshList, bool normals); void ExportMesh(FbxNode* pFrameNode, ImportedMesh^ meshList);
FbxNode* FindNodeByPath(String ^ path);
FbxFileTexture* ExportTexture(ImportedTexture^ matTex); FbxFileTexture* ExportTexture(ImportedTexture^ matTex);
void ExportAnimations(bool eulerFilter, float filterValue, bool flatInbetween); void ExportAnimations(bool eulerFilter, float filterValue, bool flatInbetween);
void ExportKeyframedAnimation(ImportedKeyframedAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* eulerFilter, float filterPrecision, bool flatInbetween); void ExportKeyframedAnimation(ImportedKeyframedAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* eulerFilter, float filterPrecision, bool flatInbetween);
void ExportMorphs(IImported^ imported, bool morphMask, bool flatInbetween); void ExportMorphs(bool morphMask, bool flatInbetween);
}; };
}; };
} }

View File

@ -1,5 +1,3 @@
#include <fbxsdk.h>
#include <fbxsdk/fileio/fbxiosettings.h>
#include "AssetStudioFBX.h" #include "AssetStudioFBX.h"
namespace AssetStudio namespace AssetStudio
@ -16,8 +14,8 @@ namespace AssetStudio
Directory::SetCurrentDirectory(dir->FullName); Directory::SetCurrentDirectory(dir->FullName);
path = Path::GetFileName(path); path = Path::GetFileName(path);
Exporter^ exporter = gcnew Exporter(path, imported, allFrames, allBones, skins, boneSize, scaleFactor, versionIndex, isAscii, true); Exporter^ exporter = gcnew Exporter(path, imported, allFrames, allBones, skins, boneSize, scaleFactor, versionIndex, isAscii);
exporter->ExportMorphs(imported, false, flatInbetween); //TODO exporter->ExportMorphs(false, flatInbetween);
exporter->ExportAnimations(eulerFilter, filterPrecision, flatInbetween); exporter->ExportAnimations(eulerFilter, filterPrecision, flatInbetween);
exporter->pExporter->Export(exporter->pScene); exporter->pExporter->Export(exporter->pScene);
delete exporter; delete exporter;
@ -25,27 +23,7 @@ namespace AssetStudio
Directory::SetCurrentDirectory(currentDir); Directory::SetCurrentDirectory(currentDir);
} }
void Fbx::Exporter::ExportMorph(String^ path, IImported^ imported, bool morphMask, bool flatInbetween, bool skins, float boneSize, float scaleFactor, int versionIndex, bool isAscii) Fbx::Exporter::Exporter(String^ path, IImported^ imported, bool allFrames, bool allBones, bool skins, float boneSize, float scaleFactor, int versionIndex, bool isAscii)
{
FileInfo^ file = gcnew FileInfo(path);
DirectoryInfo^ dir = file->Directory;
if (!dir->Exists)
{
dir->Create();
}
String^ currentDir = Directory::GetCurrentDirectory();
Directory::SetCurrentDirectory(dir->FullName);
path = Path::GetFileName(path);
Exporter^ exporter = gcnew Exporter(path, imported, false, true, skins, boneSize, scaleFactor, versionIndex, isAscii, false);
exporter->ExportMorphs(imported, morphMask, flatInbetween);
exporter->pExporter->Export(exporter->pScene);
delete exporter;
Directory::SetCurrentDirectory(currentDir);
}
Fbx::Exporter::Exporter(String^ path, IImported^ imported, bool allFrames, bool allBones, bool skins, float boneSize, float scaleFactor, int versionIndex, bool isAscii, bool normals)
{ {
this->imported = imported; this->imported = imported;
exportSkins = skins; exportSkins = skins;
@ -57,7 +35,6 @@ namespace AssetStudio
pExporter = NULL; pExporter = NULL;
pMaterials = NULL; pMaterials = NULL;
pTextures = NULL; pTextures = NULL;
pMeshNodes = NULL;
pin_ptr<FbxManager*> pSdkManagerPin = &pSdkManager; pin_ptr<FbxManager*> pSdkManagerPin = &pSdkManager;
pin_ptr<FbxScene*> pScenePin = &pScene; pin_ptr<FbxScene*> pScenePin = &pScene;
@ -100,19 +77,21 @@ namespace AssetStudio
throw gcnew Exception(gcnew String("Failed to initialize FbxExporter: ") + gcnew String(pExporter->GetStatus().GetErrorString())); throw gcnew Exception(gcnew String("Failed to initialize FbxExporter: ") + gcnew String(pExporter->GetStatus().GetErrorString()));
} }
frameNames = nullptr; framePaths = nullptr;
if (!allFrames) if (!allFrames)
{ {
frameNames = SearchHierarchy(); framePaths = SearchHierarchy();
if (!frameNames) if (!framePaths)
{ {
return; return;
} }
} }
pMeshNodes = imported->MeshList != nullptr ? new FbxArray<FbxNode*>(imported->MeshList->Count) : NULL;
pBindPose = FbxPose::Create(pScene, "BindPose"); pBindPose = FbxPose::Create(pScene, "BindPose");
pBindPose->SetIsBindPose(true); pBindPose->SetIsBindPose(true);
frameToNode = gcnew Dictionary<ImportedFrame^, size_t>();
meshFrames = imported->MeshList != nullptr ? gcnew List<ImportedFrame^>() : nullptr;
ExportFrame(pScene->GetRootNode(), imported->RootFrame); ExportFrame(pScene->GetRootNode(), imported->RootFrame);
if (imported->MeshList != nullptr) if (imported->MeshList != nullptr)
@ -124,31 +103,36 @@ namespace AssetStudio
pMaterials->Reserve(imported->MaterialList->Count); pMaterials->Reserve(imported->MaterialList->Count);
pTextures->Reserve(imported->TextureList->Count); pTextures->Reserve(imported->TextureList->Count);
for (int i = 0; i < pMeshNodes->GetCount(); i++) for (int i = 0; i < meshFrames->Count; i++)
{ {
FbxNode* meshNode = pMeshNodes->GetAt(i); auto meshFram = meshFrames[i];
String^ meshPath = gcnew String(meshNode->GetName()); FbxNode* meshNode = (FbxNode*)frameToNode[meshFram];
FbxNode* rootNode = meshNode; ImportedMesh^ mesh = ImportedHelpers::FindMesh(meshFram->Path, imported->MeshList);
while ((rootNode = rootNode->GetParent()) != pScene->GetRootNode()) ExportMesh(meshNode, mesh);
{
meshPath = gcnew String(rootNode->GetName()) + "/" + meshPath;
}
ImportedMesh^ mesh = ImportedHelpers::FindMesh(meshPath, imported->MeshList);
ExportMesh(meshNode, mesh, normals);
} }
} }
else else
{ {
SetJointsNode(pScene->GetRootNode()->GetChild(0), nullptr, true); SetJointsNode(imported->RootFrame, nullptr, true);
} }
} }
Fbx::Exporter::~Exporter() Fbx::Exporter::~Exporter()
{ {
if (pMeshNodes != NULL) imported = nullptr;
if (framePaths != nullptr)
{ {
delete pMeshNodes; framePaths->Clear();
} }
if (frameToNode != nullptr)
{
frameToNode->Clear();
}
if (meshFrames != nullptr)
{
meshFrames->Clear();
}
if (pMaterials != NULL) if (pMaterials != NULL)
{ {
delete pMaterials; delete pMaterials;
@ -175,30 +159,33 @@ namespace AssetStudio
} }
} }
void Fbx::Exporter::SetJointsNode(FbxNode* pNode, HashSet<String^>^ boneNames, bool allBones) void Fbx::Exporter::SetJointsNode(ImportedFrame^ frame, HashSet<String^>^ bonePaths, bool allBones)
{ {
String^ nodeName = gcnew String(pNode->GetName()); size_t pointer;
if (allBones || boneNames->Contains(nodeName)) if (frameToNode->TryGetValue(frame, pointer))
{ {
FbxSkeleton* pJoint = FbxSkeleton::Create(pSdkManager, ""); auto pNode = (FbxNode*)pointer;
pJoint->Size.Set((double)boneSize); if (allBones || bonePaths->Contains(frame->Path))
pJoint->SetSkeletonType(FbxSkeleton::eLimbNode);
pNode->SetNodeAttribute(pJoint);
}
else
{
FbxNull* pNull = FbxNull::Create(pSdkManager, "");
if (pNode->GetChildCount() > 0)
{ {
pNull->Look.Set(FbxNull::eNone); FbxSkeleton* pJoint = FbxSkeleton::Create(pScene, "");
pJoint->Size.Set(FbxDouble(boneSize));
pJoint->SetSkeletonType(FbxSkeleton::eLimbNode);
pNode->SetNodeAttribute(pJoint);
} }
else
{
FbxNull* pNull = FbxNull::Create(pScene, "");
if (pNode->GetChildCount() > 0)
{
pNull->Look.Set(FbxNull::eNone);
}
pNode->SetNodeAttribute(pNull); pNode->SetNodeAttribute(pNull);
}
} }
for (int i = 0; i < frame->Count; i++)
for (int i = 0; i < pNode->GetChildCount(); i++)
{ {
SetJointsNode(pNode->GetChild(i), boneNames, allBones); SetJointsNode(frame[i], bonePaths, allBones);
} }
} }
@ -215,13 +202,13 @@ namespace AssetStudio
void Fbx::Exporter::SearchHierarchy(ImportedFrame^ frame, HashSet<String^>^ exportFrames) void Fbx::Exporter::SearchHierarchy(ImportedFrame^ frame, HashSet<String^>^ exportFrames)
{ {
ImportedMesh^ meshListSome = ImportedHelpers::FindMesh(frame, imported->MeshList); ImportedMesh^ meshListSome = ImportedHelpers::FindMesh(frame->Path, imported->MeshList);
if (meshListSome != nullptr) if (meshListSome != nullptr)
{ {
ImportedFrame^ parent = frame; ImportedFrame^ parent = frame;
while (parent != nullptr) while (parent != nullptr)
{ {
exportFrames->Add(parent->Name); exportFrames->Add(parent->Path);
parent = parent->Parent; parent = parent->Parent;
} }
@ -230,13 +217,12 @@ namespace AssetStudio
{ {
for (int i = 0; i < boneList->Count; i++) for (int i = 0; i < boneList->Count; i++)
{ {
String^ boneName = boneList[i]->Path->Substring(boneList[i]->Path->LastIndexOf('/') + 1); if (!exportFrames->Contains(boneList[i]->Path))
if (!exportFrames->Contains(boneName))
{ {
ImportedFrame^ boneParent = imported->RootFrame->FindFrameByPath(boneList[i]->Path); ImportedFrame^ boneParent = imported->RootFrame->FindFrameByPath(boneList[i]->Path);
while (boneParent != nullptr) while (boneParent != nullptr)
{ {
exportFrames->Add(boneParent->Name); exportFrames->Add(boneParent->Path);
boneParent = boneParent->Parent; boneParent = boneParent->Parent;
} }
} }
@ -256,7 +242,7 @@ namespace AssetStudio
{ {
return; return;
} }
HashSet<String^>^ boneNames = gcnew HashSet<String^>(); HashSet<String^>^ bonePaths = gcnew HashSet<String^>();
for (int i = 0; i < imported->MeshList->Count; i++) for (int i = 0; i < imported->MeshList->Count; i++)
{ {
ImportedMesh^ meshList = imported->MeshList[i]; ImportedMesh^ meshList = imported->MeshList[i];
@ -266,24 +252,23 @@ namespace AssetStudio
for (int j = 0; j < boneList->Count; j++) for (int j = 0; j < boneList->Count; j++)
{ {
ImportedBone^ bone = boneList[j]; ImportedBone^ bone = boneList[j];
boneNames->Add(bone->Path); bonePaths->Add(bone->Path);
} }
} }
} }
SetJointsNode(pScene->GetRootNode()->GetChild(0), boneNames, allBones); SetJointsNode(imported->RootFrame, bonePaths, allBones);
} }
void Fbx::Exporter::ExportFrame(FbxNode* pParentNode, ImportedFrame^ frame) void Fbx::Exporter::ExportFrame(FbxNode* pParentNode, ImportedFrame^ frame)
{ {
String^ frameName = frame->Name; if (framePaths == nullptr || framePaths->Contains(frame->Path))
if ((frameNames == nullptr) || frameNames->Contains(frameName))
{ {
FbxNode* pFrameNode = NULL; FbxNode* pFrameNode;
WITH_MARSHALLED_STRING WITH_MARSHALLED_STRING
( (
pName, pName,
frameName, frame->Name,
pFrameNode = FbxNode::Create(pScene, pName); pFrameNode = FbxNode::Create(pScene, pName);
); );
@ -294,11 +279,13 @@ namespace AssetStudio
pParentNode->AddChild(pFrameNode); pParentNode->AddChild(pFrameNode);
pBindPose->Add(pFrameNode, pFrameNode->EvaluateGlobalTransform()); pBindPose->Add(pFrameNode, pFrameNode->EvaluateGlobalTransform());
if (imported->MeshList != nullptr && ImportedHelpers::FindMesh(frame, imported->MeshList) != nullptr) if (imported->MeshList != nullptr && ImportedHelpers::FindMesh(frame->Path, imported->MeshList) != nullptr)
{ {
pMeshNodes->Add(pFrameNode); meshFrames->Add(frame);
} }
frameToNode->Add(frame, (size_t)pFrameNode);
for (int i = 0; i < frame->Count; i++) for (int i = 0; i < frame->Count; i++)
{ {
ExportFrame(pFrameNode, frame[i]); ExportFrame(pFrameNode, frame[i]);
@ -306,10 +293,8 @@ namespace AssetStudio
} }
} }
void Fbx::Exporter::ExportMesh(FbxNode* pFrameNode, ImportedMesh^ meshList, bool normals) void Fbx::Exporter::ExportMesh(FbxNode* pFrameNode, ImportedMesh^ meshList)
{ {
int lastSlash = meshList->Path->LastIndexOf('/');
String^ frameName = lastSlash < 0 ? meshList->Path : meshList->Path->Substring(lastSlash + 1);
List<ImportedBone^>^ boneList = meshList->BoneList; List<ImportedBone^>^ boneList = meshList->BoneList;
bool hasBones; bool hasBones;
if (exportSkins && boneList != nullptr) if (exportSkins && boneList != nullptr)
@ -321,7 +306,9 @@ namespace AssetStudio
hasBones = false; hasBones = false;
} }
FbxArray<FbxNode*>* pBoneNodeList = NULL; FbxArray<FbxNode*>* pBoneNodeList = nullptr;
FbxArray<FbxCluster*>* pClusterArray = nullptr;
try try
{ {
if (hasBones) if (hasBones)
@ -330,280 +317,242 @@ namespace AssetStudio
pBoneNodeList->Reserve(boneList->Count); pBoneNodeList->Reserve(boneList->Count);
for (int i = 0; i < boneList->Count; i++) for (int i = 0; i < boneList->Count; i++)
{ {
ImportedBone^ bone = boneList[i]; auto bone = boneList[i];
FbxNode* lFrame = FindNodeByPath(bone->Path); auto frame = imported->RootFrame->FindFrameByPath(bone->Path);
pBoneNodeList->Add(lFrame); auto frameNode = (FbxNode*)frameToNode[frame];
pBoneNodeList->Add(frameNode);
}
pClusterArray = new FbxArray<FbxCluster*>();
pClusterArray->Reserve(boneList->Count);
for (int i = 0; i < boneList->Count; i++)
{
FbxNode* pNode = pBoneNodeList->GetAt(i);
FbxString lClusterName = pNode->GetNameOnly() + FbxString("Cluster");
FbxCluster* pCluster = FbxCluster::Create(pScene, lClusterName.Buffer());
pCluster->SetLink(pNode);
pCluster->SetLinkMode(FbxCluster::eTotalOne);
pClusterArray->Add(pCluster);
} }
} }
FbxMesh* pMesh = FbxMesh::Create(pScene, "");
pFrameNode->SetNodeAttribute(pMesh);
int vertexCount = 0;
for (int i = 0; i < meshList->SubmeshList->Count; i++) for (int i = 0; i < meshList->SubmeshList->Count; i++)
{ {
char* pName = NULL; vertexCount += meshList->SubmeshList[i]->VertexList->Count;
FbxArray<FbxCluster*>* pClusterArray = NULL; }
try
pMesh->InitControlPoints(vertexCount);
FbxVector4* pControlPoints = pMesh->GetControlPoints();
FbxGeometryElementNormal* lGeometryElementNormal = pMesh->CreateElementNormal();
lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect);
FbxGeometryElementUV* lGeometryElementUV = pMesh->CreateElementUV("UV0");
lGeometryElementUV->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementUV->SetReferenceMode(FbxGeometryElement::eDirect);
FbxGeometryElementTangent* lGeometryElementTangent = pMesh->CreateElementTangent();
lGeometryElementTangent->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementTangent->SetReferenceMode(FbxGeometryElement::eDirect);
FbxGeometryElementVertexColor* lGeometryElementVertexColor = nullptr;
bool vertexColours = vertexCount > 0 && dynamic_cast<ImportedVertexWithColour^>(meshList->SubmeshList[0]->VertexList[0]) != nullptr;
if (vertexColours)
{
lGeometryElementVertexColor = pMesh->CreateElementVertexColor();
lGeometryElementVertexColor->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementVertexColor->SetReferenceMode(FbxGeometryElement::eDirect);
}
FbxGeometryElementMaterial* lGeometryElementMaterial = pMesh->CreateElementMaterial();
lGeometryElementMaterial->SetMappingMode(FbxGeometryElement::eByPolygon);
lGeometryElementMaterial->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
int firstVertex = 0;
for (int i = 0; i < meshList->SubmeshList->Count; i++)
{
ImportedSubmesh^ meshObj = meshList->SubmeshList[i];
List<ImportedVertex^>^ vertexList = meshObj->VertexList;
List<ImportedFace^>^ faceList = meshObj->FaceList;
int materialIndex = 0;
ImportedMaterial^ mat = ImportedHelpers::FindMaterial(meshObj->Material, imported->MaterialList);
if (mat != nullptr)
{ {
pName = StringToCharArray(frameName + "_" + i); char* pMatName = NULL;
FbxMesh* pMesh = FbxMesh::Create(pScene, ""); try
if (hasBones)
{ {
pClusterArray = new FbxArray<FbxCluster*>(); pMatName = StringToCharArray(mat->Name);
pClusterArray->Reserve(boneList->Count); int foundMat = -1;
for (int j = 0; j < pMaterials->GetCount(); j++)
for (int i = 0; i < boneList->Count; i++)
{ {
FbxNode* pNode = pBoneNodeList->GetAt(i); FbxSurfacePhong* pMatTemp = pMaterials->GetAt(j);
FbxString lClusterName = pNode->GetNameOnly() + FbxString("Cluster"); if (strcmp(pMatTemp->GetName(), pMatName) == 0)
FbxCluster* pCluster = FbxCluster::Create(pSdkManager, lClusterName.Buffer()); {
pCluster->SetLink(pNode); foundMat = j;
pCluster->SetLinkMode(FbxCluster::eTotalOne); break;
pClusterArray->Add(pCluster); }
}
FbxSurfacePhong* pMat;
if (foundMat >= 0)
{
pMat = pMaterials->GetAt(foundMat);
}
else
{
FbxString lShadingName = "Phong";
Color diffuse = mat->Diffuse;
Color ambient = mat->Ambient;
Color emissive = mat->Emissive;
Color specular = mat->Specular;
Color reflection = mat->Reflection;
pMat = FbxSurfacePhong::Create(pScene, pMatName);
pMat->Diffuse.Set(FbxDouble3(diffuse.R, diffuse.G, diffuse.B));
pMat->DiffuseFactor.Set(FbxDouble(diffuse.A));
pMat->Ambient.Set(FbxDouble3(ambient.R, ambient.G, ambient.B));
pMat->AmbientFactor.Set(FbxDouble(ambient.A));
pMat->Emissive.Set(FbxDouble3(emissive.R, emissive.G, emissive.B));
pMat->EmissiveFactor.Set(FbxDouble(emissive.A));
pMat->Specular.Set(FbxDouble3(specular.R, specular.G, specular.B));
pMat->SpecularFactor.Set(FbxDouble(specular.A));
pMat->Reflection.Set(FbxDouble3(reflection.R, reflection.G, reflection.B));
pMat->ReflectionFactor.Set(FbxDouble(reflection.A));
pMat->Shininess.Set(FbxDouble(mat->Shininess));
pMat->TransparencyFactor.Set(FbxDouble(mat->Transparency));
pMat->ShadingModel.Set(lShadingName);
pMaterials->Add(pMat);
}
materialIndex = pFrameNode->AddMaterial(pMat);
bool hasTexture = false;
for each (ImportedMaterialTexture^ texture in mat->Textures)
{
auto pTexture = ExportTexture(ImportedHelpers::FindTexture(texture->Name, imported->TextureList));
if (pTexture != NULL)
{
if (texture->Dest == 0)
{
LinkTexture(texture, pTexture, pMat->Diffuse);
hasTexture = true;
}
else if (texture->Dest == 1)
{
LinkTexture(texture, pTexture, pMat->NormalMap);
hasTexture = true;
}
else if (texture->Dest == 2)
{
LinkTexture(texture, pTexture, pMat->Specular);
hasTexture = true;
}
else if (texture->Dest == 3)
{
LinkTexture(texture, pTexture, pMat->Bump);
hasTexture = true;
}
}
}
if (hasTexture)
{
pFrameNode->SetShadingMode(FbxNode::eTextureShading);
} }
} }
finally
ImportedSubmesh^ meshObj = meshList->SubmeshList[i];
List<ImportedFace^>^ faceList = meshObj->FaceList;
List<ImportedVertex^>^ vertexList = meshObj->VertexList;
pMesh->InitControlPoints(vertexList->Count);
FbxVector4* pControlPoints = pMesh->GetControlPoints();
FbxGeometryElementNormal* lGeometryElementNormal = NULL;
//if (normals)
{ {
lGeometryElementNormal = pMesh->GetElementNormal(); Marshal::FreeHGlobal((IntPtr)pMatName);
if (!lGeometryElementNormal) }
{ }
lGeometryElementNormal = pMesh->CreateElementNormal();
} for (int j = 0; j < vertexList->Count; j++)
lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint); {
lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect); ImportedVertex^ vertex = vertexList[j];
Vector3 coords = vertex->Position;
pControlPoints[j + firstVertex] = FbxVector4(coords.X, coords.Y, coords.Z, 0);
Vector3 normal = vertex->Normal;
lGeometryElementNormal->GetDirectArray().Add(FbxVector4(normal.X, normal.Y, normal.Z, 0));
array<float>^ uv = vertex->UV;
if (uv != nullptr)
{
lGeometryElementUV->GetDirectArray().Add(FbxVector2(uv[0], uv[1]));
} }
FbxGeometryElementUV* lGeometryElementUV = pMesh->GetElementUV(); Vector4 tangent = vertex->Tangent;
if (!lGeometryElementUV) lGeometryElementTangent->GetDirectArray().Add(FbxVector4(tangent.X, tangent.Y, tangent.Z, tangent.W));
{
lGeometryElementUV = pMesh->CreateElementUV("");
}
lGeometryElementUV->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementUV->SetReferenceMode(FbxGeometryElement::eDirect);
FbxGeometryElementTangent* lGeometryElementTangent = NULL;
if (normals)
{
lGeometryElementTangent = pMesh->GetElementTangent();
if (!lGeometryElementTangent)
{
lGeometryElementTangent = pMesh->CreateElementTangent();
}
lGeometryElementTangent->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementTangent->SetReferenceMode(FbxGeometryElement::eDirect);
}
bool vertexColours = vertexList->Count > 0 && dynamic_cast<ImportedVertexWithColour^>(vertexList[0]) != nullptr;
if (vertexColours) if (vertexColours)
{ {
FbxGeometryElementVertexColor* lGeometryElementVertexColor = pMesh->CreateElementVertexColor(); ImportedVertexWithColour^ vert = (ImportedVertexWithColour^)vertexList[j];
lGeometryElementVertexColor->SetMappingMode(FbxGeometryElement::eByControlPoint); lGeometryElementVertexColor->GetDirectArray().Add(FbxColor(vert->Colour.R, vert->Colour.G, vert->Colour.B, vert->Colour.A));
lGeometryElementVertexColor->SetReferenceMode(FbxGeometryElement::eDirect);
for (int j = 0; j < vertexList->Count; j++)
{
ImportedVertexWithColour^ vert = (ImportedVertexWithColour^)vertexList[j];
lGeometryElementVertexColor->GetDirectArray().Add(FbxColor(vert->Colour.R, vert->Colour.G, vert->Colour.B, vert->Colour.A));
}
} }
FbxNode* pMeshNode = FbxNode::Create(pScene, pName); if (hasBones && vertex->BoneIndices != nullptr)
if (hasBones)
{ {
pBindPose->Add(pMeshNode, pMeshNode->EvaluateGlobalTransform()); auto boneIndices = vertex->BoneIndices;
} auto weights4 = vertex->Weights;
pMeshNode->SetNodeAttribute(pMesh); for (int k = 0; k < 4; k++)
pFrameNode->AddChild(pMeshNode);
ImportedMaterial^ mat = ImportedHelpers::FindMaterial(meshObj->Material, imported->MaterialList);
if (mat != nullptr)
{
FbxGeometryElementMaterial* lGeometryElementMaterial = pMesh->GetElementMaterial();
if (!lGeometryElementMaterial)
{ {
lGeometryElementMaterial = pMesh->CreateElementMaterial(); if (boneIndices[k] < boneList->Count && weights4[k] > 0)
}
lGeometryElementMaterial->SetMappingMode(FbxGeometryElement::eByPolygon);
lGeometryElementMaterial->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
char* pMatName = NULL;
try
{
pMatName = StringToCharArray(mat->Name);
int foundMat = -1;
for (int j = 0; j < pMaterials->GetCount(); j++)
{ {
FbxSurfacePhong* pMatTemp = pMaterials->GetAt(j); FbxCluster* pCluster = pClusterArray->GetAt(boneIndices[k]);
if (strcmp(pMatTemp->GetName(), pMatName) == 0) pCluster->AddControlPointIndex(j + firstVertex, weights4[k]);
{
foundMat = j;
break;
}
} }
FbxSurfacePhong* pMat;
if (foundMat >= 0)
{
pMat = pMaterials->GetAt(foundMat);
}
else
{
FbxString lShadingName = "Phong";
Color diffuse = mat->Diffuse;
Color ambient = mat->Ambient;
Color emissive = mat->Emissive;
Color specular = mat->Specular;
Color reflection = mat->Reflection;
pMat = FbxSurfacePhong::Create(pScene, pMatName);
pMat->Diffuse.Set(FbxDouble3(diffuse.R, diffuse.G, diffuse.B));
pMat->DiffuseFactor.Set(FbxDouble(diffuse.A));
pMat->Ambient.Set(FbxDouble3(ambient.R, ambient.G, ambient.B));
pMat->AmbientFactor.Set(FbxDouble(ambient.A));
pMat->Emissive.Set(FbxDouble3(emissive.R, emissive.G, emissive.B));
pMat->EmissiveFactor.Set(FbxDouble(emissive.A));
pMat->Specular.Set(FbxDouble3(specular.R, specular.G, specular.B));
pMat->SpecularFactor.Set(FbxDouble(specular.A));
pMat->Reflection.Set(FbxDouble3(reflection.R, reflection.G, reflection.B));
pMat->ReflectionFactor.Set(FbxDouble(reflection.A));
pMat->Shininess.Set(FbxDouble(mat->Shininess));
pMat->TransparencyFactor.Set(FbxDouble(mat->Transparency));
pMat->ShadingModel.Set(lShadingName);
foundMat = pMaterials->GetCount();
pMaterials->Add(pMat);
}
pMeshNode->AddMaterial(pMat);
bool hasTexture = false;
for each (ImportedMaterialTexture^ texture in mat->Textures)
{
auto pTexture = ExportTexture(ImportedHelpers::FindTexture(texture->Name, imported->TextureList));
if (pTexture != NULL)
{
if (texture->Dest == 0)
{
LinkTexture(texture, pTexture, pMat->Diffuse);
hasTexture = true;
}
else if (texture->Dest == 1)
{
LinkTexture(texture, pTexture, pMat->NormalMap);
hasTexture = true;
}
else if (texture->Dest == 2)
{
LinkTexture(texture, pTexture, pMat->Specular);
hasTexture = true;
}
else if (texture->Dest == 3)
{
LinkTexture(texture, pTexture, pMat->Bump);
hasTexture = true;
}
}
}
if (hasTexture)
{
pMeshNode->SetShadingMode(FbxNode::eTextureShading);
}
}
finally
{
Marshal::FreeHGlobal((IntPtr)pMatName);
}
}
for (int j = 0; j < vertexList->Count; j++)
{
ImportedVertex^ vertex = vertexList[j];
Vector3 coords = vertex->Position;
pControlPoints[j] = FbxVector4(coords.X, coords.Y, coords.Z, 0);
//if (normals)
{
Vector3 normal = vertex->Normal;
lGeometryElementNormal->GetDirectArray().Add(FbxVector4(normal.X, normal.Y, normal.Z, 0));
}
array<float>^ uv = vertex->UV;
if (uv != nullptr)
lGeometryElementUV->GetDirectArray().Add(FbxVector2(uv[0], uv[1]));
if (normals)
{
Vector4 tangent = vertex->Tangent;
lGeometryElementTangent->GetDirectArray().Add(FbxVector4(tangent.X, tangent.Y, tangent.Z, tangent.W));
}
if (hasBones && vertex->BoneIndices != nullptr)
{
auto boneIndices = vertex->BoneIndices;
auto weights4 = vertex->Weights;
for (int k = 0; k < weights4->Length; k++)
{
if (boneIndices[k] < boneList->Count && weights4[k] > 0)
{
FbxCluster* pCluster = pClusterArray->GetAt(boneIndices[k]);
pCluster->AddControlPointIndex(j, weights4[k]);
}
}
}
}
for (int j = 0; j < faceList->Count; j++)
{
ImportedFace^ face = faceList[j];
pMesh->BeginPolygon(0);
pMesh->AddPolygon(face->VertexIndices[0]);
pMesh->AddPolygon(face->VertexIndices[1]);
pMesh->AddPolygon(face->VertexIndices[2]);
pMesh->EndPolygon();
}
if (hasBones)
{
FbxAMatrix lMeshMatrix = pFrameNode->EvaluateGlobalTransform();
FbxSkin* pSkin = FbxSkin::Create(pScene, "");
for (int j = 0; j < boneList->Count; j++)
{
FbxCluster* pCluster = pClusterArray->GetAt(j);
if (pCluster->GetControlPointIndicesCount() > 0)
{
auto boneMatrix = boneList[j]->Matrix;
FbxAMatrix lBoneMatrix;
for (int m = 0; m < 4; m++)
{
for (int n = 0; n < 4; n++)
{
lBoneMatrix.mData[m][n] = boneMatrix[m, n];
}
}
pCluster->SetTransformMatrix(lMeshMatrix);
pCluster->SetTransformLinkMatrix(lMeshMatrix * lBoneMatrix.Inverse());
pSkin->AddCluster(pCluster);
}
}
if (pSkin->GetClusterCount() > 0)
{
pMesh->AddDeformer(pSkin);
} }
} }
} }
finally
for (int j = 0; j < faceList->Count; j++)
{ {
if (pClusterArray != NULL) ImportedFace^ face = faceList[j];
pMesh->BeginPolygon(materialIndex);
pMesh->AddPolygon(face->VertexIndices[0] + firstVertex);
pMesh->AddPolygon(face->VertexIndices[1] + firstVertex);
pMesh->AddPolygon(face->VertexIndices[2] + firstVertex);
pMesh->EndPolygon();
}
firstVertex += vertexList->Count;
}
if (hasBones)
{
FbxSkin* pSkin = FbxSkin::Create(pScene, "");
FbxAMatrix lMeshMatrix = pFrameNode->EvaluateGlobalTransform();
for (int j = 0; j < boneList->Count; j++)
{
FbxCluster* pCluster = pClusterArray->GetAt(j);
if (pCluster->GetControlPointIndicesCount() > 0)
{ {
delete pClusterArray; auto boneMatrix = boneList[j]->Matrix;
FbxAMatrix lBoneMatrix;
for (int m = 0; m < 4; m++)
{
for (int n = 0; n < 4; n++)
{
lBoneMatrix.mData[m][n] = boneMatrix[m, n];
}
}
pCluster->SetTransformMatrix(lMeshMatrix);
pCluster->SetTransformLinkMatrix(lMeshMatrix * lBoneMatrix.Inverse());
pSkin->AddCluster(pCluster);
} }
Marshal::FreeHGlobal((IntPtr)pName); }
if (pSkin->GetClusterCount() > 0)
{
pMesh->AddDeformer(pSkin);
} }
} }
} }
@ -613,33 +562,11 @@ namespace AssetStudio
{ {
delete pBoneNodeList; delete pBoneNodeList;
} }
} if (pClusterArray != NULL)
}
FbxNode* Fbx::Exporter::FindNodeByPath(String ^ path)
{
array<String^>^ splitPath = path->Split('/');
FbxNode* lNode = pScene->GetRootNode();
for (int i = 0; i < splitPath->Length; i++)
{
String^ frameName = splitPath[i];
char* pNodeName = NULL;
try
{ {
pNodeName = StringToCharArray(frameName); delete pClusterArray;
FbxNode* foundNode = lNode->FindChild(pNodeName, false);
if (foundNode == NULL)
{
throw gcnew Exception(gcnew String("Couldn't find path ") + path);
}
lNode = foundNode;
}
finally
{
Marshal::FreeHGlobal((IntPtr)pNodeName);
} }
} }
return lNode;
} }
FbxFileTexture* Fbx::Exporter::ExportTexture(ImportedTexture^ matTex) FbxFileTexture* Fbx::Exporter::ExportTexture(ImportedTexture^ matTex)
@ -761,9 +688,11 @@ namespace AssetStudio
{ {
continue; continue;
} }
FbxNode* pNode = FindNodeByPath(keyframeList->Path); auto frame = imported->RootFrame->FindFrameByPath(keyframeList->Path);
if (pNode != nullptr) if (frame != nullptr)
{ {
FbxNode* pNode = (FbxNode*)frameToNode[frame];
FbxAnimCurve* lCurveSX = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true); FbxAnimCurve* lCurveSX = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true);
FbxAnimCurve* lCurveSY = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true); FbxAnimCurve* lCurveSY = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true);
FbxAnimCurve* lCurveSZ = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true); FbxAnimCurve* lCurveSZ = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true);
@ -835,9 +764,9 @@ namespace AssetStudio
} }
} }
void Fbx::Exporter::ExportMorphs(IImported^ imported, bool morphMask, bool flatInbetween) void Fbx::Exporter::ExportMorphs(bool morphMask, bool flatInbetween)
{ {
if (imported->MeshList == nullptr) /*if (imported->MeshList == nullptr)
{ {
return; return;
} }
@ -885,7 +814,7 @@ namespace AssetStudio
WITH_MARSHALLED_STRING WITH_MARSHALLED_STRING
( (
pShapeName, pShapeName,
morph->ClipName + (meshList->SubmeshList->Count > 1 ? "_" + meshObjIdx : String::Empty) /*+ "_BlendShape"*/, morph->ClipName + (meshList->SubmeshList->Count > 1 ? "_" + meshObjIdx : String::Empty),
lBlendShape = FbxBlendShape::Create(pScene, pShapeName); lBlendShape = FbxBlendShape::Create(pScene, pShapeName);
); );
FbxProperty rootGroupProp = FbxProperty::Create(lBlendShape, FbxStringDT, "RootGroup"); FbxProperty rootGroupProp = FbxProperty::Create(lBlendShape, FbxStringDT, "RootGroup");
@ -1035,6 +964,6 @@ namespace AssetStudio
meshVertexIndex += meshList->SubmeshList[meshObjIdx]->VertexList->Count; meshVertexIndex += meshList->SubmeshList[meshObjIdx]->VertexList->Count;
} }
} }
} }*/
} }
} }

View File

@ -507,34 +507,15 @@ namespace AssetStudio
{ {
if (transformDictionary.TryGetValue(transform, out var frame)) if (transformDictionary.TryGetValue(transform, out var frame))
{ {
return GetFramePath(frame); return frame.Path;
} }
return null; return null;
} }
private static string GetFramePath(ImportedFrame frame)
{
var path = frame.Name;
while (frame.Parent != null)
{
frame = frame.Parent;
path = frame.Name + "/" + path;
}
return path;
}
private string FixBonePath(string path) private string FixBonePath(string path)
{ {
var name = path.Substring(path.LastIndexOf('/') + 1); var frame = RootFrame.FindFrameByPath(path);
foreach (var frame in RootFrame.FindChilds(name)) return frame?.Path;
{
var fullPath = GetFramePath(frame);
if (fullPath.EndsWith(path))
{
return fullPath;
}
}
return null;
} }
private static string GetTransformPathByFather(Transform transform) private static string GetTransformPathByFather(Transform transform)
@ -962,6 +943,8 @@ namespace AssetStudio
transformName = strs.Last(); transformName = strs.Last();
var parentFrameName = strs[strs.Length - 2]; var parentFrameName = strs[strs.Length - 2];
parentFrame = RootFrame.FindChild(parentFrameName); parentFrame = RootFrame.FindChild(parentFrameName);
//var parentFramePath = path.Substring(0, path.LastIndexOf('/'));
//parentFrame = RootFrame.FindFrameByPath(parentFramePath);
} }
var skeletonPose = avatar.m_Avatar.m_DefaultPose; var skeletonPose = avatar.m_Avatar.m_DefaultPose;