Merge d96da9434e
into ed43cacb33
This commit is contained in:
commit
662b55d328
|
@ -1,4 +1,4 @@
|
|||
# FBX2glTF
|
||||
# FBX2glTF
|
||||
|
||||
[](https://opensource.org/licenses/BSD-3-Clause)
|
||||
|
||||
|
@ -56,6 +56,7 @@ Options:
|
|||
--flip-v Flip all V texture coordinates.
|
||||
--no-flip-v Don't flip V texture coordinates.
|
||||
--no-khr-lights-punctual Don't use KHR_lights_punctual extension to export FBX lights.
|
||||
--animation-files Read multiple fbx animation files.
|
||||
--user-properties Transcribe FBX User Properties into glTF node and material 'extras'.
|
||||
--blend-shape-normals Include blend shape normals, if reported present by the FBX SDK.
|
||||
--blend-shape-tangents Include blend shape tangents, if reported present by the FBX SDK.
|
||||
|
@ -97,6 +98,10 @@ Some of these switches are not obvious:
|
|||
Your FBX is likely constructed with the assumption that `(0, 0)` is bottom
|
||||
left, whereas glTF has `(0, 0)` as top left. To produce spec-compliant glTF,
|
||||
we must flip the texcoords. To request unflipped coordinates:
|
||||
- '--animation-files' will try to read in additional animations from multiple
|
||||
fbx files with numbers added to the base name (eg. test1.fbx, test2.fbx, ...).
|
||||
It will apply animations to geometry in the base file by matching the node
|
||||
names, so make sure all nodes have a unique name.
|
||||
- `--long-indices` lets you force the use of either 16-bit or 32-bit indices.
|
||||
The default option is auto, which make the choice on a per-mesh-size basis.
|
||||
- `--compute-normals` controls when automatic vertex normals should be computed
|
||||
|
|
|
@ -137,6 +137,11 @@ int main(int argc, char* argv[]) {
|
|||
[&](size_t count) { gltfOptions.useKHRLightsPunctual = (count == 0); },
|
||||
"Don't use KHR_lights_punctual extension to export FBX lights.");
|
||||
|
||||
app.add_flag(
|
||||
"--animation-files",
|
||||
gltfOptions.readAnimationFiles,
|
||||
"Read multiple fbx animation files.");
|
||||
|
||||
app.add_flag(
|
||||
"--user-properties",
|
||||
gltfOptions.enableUserProperties,
|
||||
|
@ -314,6 +319,7 @@ int main(int argc, char* argv[]) {
|
|||
if (verboseOutput) {
|
||||
fmt::printf("Loading FBX File: %s\n", inputPath);
|
||||
}
|
||||
|
||||
if (!LoadFBXFile(raw, inputPath, {"png", "jpg", "jpeg"}, gltfOptions)) {
|
||||
fmt::fprintf(stderr, "ERROR:: Failed to parse FBX: %s\n", inputPath);
|
||||
return 1;
|
||||
|
|
|
@ -112,6 +112,9 @@ struct GltfOptions {
|
|||
/** Whether to include lights through the KHR_punctual_lights extension. */
|
||||
bool useKHRLightsPunctual{true};
|
||||
|
||||
/** Whether to read multiple fbx animation files. */
|
||||
bool readAnimationFiles{false};
|
||||
|
||||
/** Whether to include blend shape normals, if present according to the SDK. */
|
||||
bool useBlendShapeNormals{false};
|
||||
/** Whether to include blend shape tangents, if present according to the SDK. */
|
||||
|
|
|
@ -720,7 +720,7 @@ static void ReadNodeHierarchy(
|
|||
}
|
||||
}
|
||||
|
||||
static void ReadAnimations(RawModel& raw, FbxScene* pScene, const GltfOptions& options) {
|
||||
static void ReadAnimations(RawModel& raw, FbxScene* pScene, const GltfOptions& options, bool nodeNameLookup) {
|
||||
FbxTime::EMode eMode = FbxTime::eFrames24;
|
||||
switch (options.animationFramerate) {
|
||||
case AnimationFramerateOptions::BAKE24:
|
||||
|
@ -816,7 +816,14 @@ static void ReadAnimations(RawModel& raw, FbxScene* pScene, const GltfOptions& o
|
|||
bool hasMorphs = false;
|
||||
|
||||
RawChannel channel;
|
||||
channel.nodeIndex = raw.GetNodeById(pNode->GetUniqueID());
|
||||
if (nodeNameLookup) {
|
||||
channel.nodeIndex = raw.GetNodeByName(pNode->GetName());
|
||||
} else {
|
||||
channel.nodeIndex = raw.GetNodeById(pNode->GetUniqueID());
|
||||
}
|
||||
if (channel.nodeIndex == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (FbxLongLong frameIndex = firstFrameIndex; frameIndex <= lastFrameIndex; frameIndex++) {
|
||||
FbxTime pTime;
|
||||
|
@ -1068,15 +1075,7 @@ static void FindFbxTextures(
|
|||
}
|
||||
}
|
||||
|
||||
bool LoadFBXFile(
|
||||
RawModel& raw,
|
||||
const std::string fbxFileName,
|
||||
const std::set<std::string>& textureExtensions,
|
||||
const GltfOptions& options) {
|
||||
FbxManager* pManager = FbxManager::Create();
|
||||
FbxIOSettings* pIoSettings = FbxIOSettings::Create(pManager, IOSROOT);
|
||||
pManager->SetIOSettings(pIoSettings);
|
||||
|
||||
static FbxScene* LoadScene(FbxManager* pManager, const std::string fbxFileName) {
|
||||
FbxImporter* pImporter = FbxImporter::Create(pManager, "");
|
||||
|
||||
if (!pImporter->Initialize(fbxFileName.c_str(), -1, pManager->GetIOSettings())) {
|
||||
|
@ -1084,8 +1083,7 @@ bool LoadFBXFile(
|
|||
fmt::printf("%s\n", pImporter->GetStatus().GetErrorString());
|
||||
}
|
||||
pImporter->Destroy();
|
||||
pManager->Destroy();
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FbxScene* pScene = FbxScene::Create(pManager, "fbxScene");
|
||||
|
@ -1093,14 +1091,9 @@ bool LoadFBXFile(
|
|||
pImporter->Destroy();
|
||||
|
||||
if (pScene == nullptr) {
|
||||
pImporter->Destroy();
|
||||
pManager->Destroy();
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::map<const FbxTexture*, FbxString> textureLocations;
|
||||
FindFbxTextures(pScene, fbxFileName, textureExtensions, textureLocations);
|
||||
|
||||
// Use Y up for glTF
|
||||
FbxAxisSystem::MayaYUp.ConvertScene(pScene);
|
||||
|
||||
|
@ -1113,14 +1106,54 @@ bool LoadFBXFile(
|
|||
if (sceneSystemUnit != FbxSystemUnit::cm) {
|
||||
FbxSystemUnit::cm.ConvertScene(pScene);
|
||||
}
|
||||
|
||||
return pScene;
|
||||
}
|
||||
|
||||
bool LoadFBXFile(
|
||||
RawModel& raw,
|
||||
const std::string fbxFileName,
|
||||
const std::set<std::string>& textureExtensions,
|
||||
const GltfOptions& options) {
|
||||
FbxManager* pManager = FbxManager::Create();
|
||||
FbxIOSettings* pIoSettings = FbxIOSettings::Create(pManager, IOSROOT);
|
||||
pManager->SetIOSettings(pIoSettings);
|
||||
|
||||
FbxScene* pScene = LoadScene(pManager, fbxFileName);
|
||||
if (pScene == nullptr) {
|
||||
pManager->Destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
// this is always 0.01, but let's opt for clarity.
|
||||
scaleFactor = FbxSystemUnit::m.GetConversionFactorFrom(FbxSystemUnit::cm);
|
||||
|
||||
std::map<const FbxTexture*, FbxString> textureLocations;
|
||||
FindFbxTextures(pScene, fbxFileName, textureExtensions, textureLocations);
|
||||
|
||||
ReadNodeHierarchy(raw, pScene, pScene->GetRootNode(), 0, "");
|
||||
ReadNodeAttributes(raw, pScene, pScene->GetRootNode(), textureLocations);
|
||||
ReadAnimations(raw, pScene, options);
|
||||
ReadAnimations(raw, pScene, options, false);
|
||||
|
||||
pScene->Destroy();
|
||||
|
||||
// read additional animation files
|
||||
bool readAnimationFiles = options.readAnimationFiles;
|
||||
int animationFileNumber = 1;
|
||||
while (readAnimationFiles) {
|
||||
std::string animationFileName = StringUtils::GetFolderString(fbxFileName) +
|
||||
StringUtils::GetFileBaseString(fbxFileName) +
|
||||
std::to_string(animationFileNumber) + ".fbx";
|
||||
FbxScene* pAnimationScene = LoadScene(pManager, animationFileName.c_str());
|
||||
if (pAnimationScene != nullptr) {
|
||||
ReadAnimations(raw, pAnimationScene, options, true);
|
||||
pAnimationScene->Destroy();
|
||||
animationFileNumber++;
|
||||
} else {
|
||||
readAnimationFiles = false;
|
||||
}
|
||||
}
|
||||
|
||||
pManager->Destroy();
|
||||
|
||||
return true;
|
||||
|
|
|
@ -640,6 +640,15 @@ int RawModel::GetNodeById(const long nodeId) const {
|
|||
return -1;
|
||||
}
|
||||
|
||||
int RawModel::GetNodeByName(const char* name) const {
|
||||
for (size_t i = 0; i < nodes.size(); i++) {
|
||||
if (nodes[i].name == name) {
|
||||
return (int)i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int RawModel::GetSurfaceById(const long surfaceId) const {
|
||||
for (size_t i = 0; i < surfaces.size(); i++) {
|
||||
if (surfaces[i].id == surfaceId) {
|
||||
|
|
|
@ -508,6 +508,7 @@ class RawModel {
|
|||
return nodes[index];
|
||||
}
|
||||
int GetNodeById(const long nodeId) const;
|
||||
int GetNodeByName(const char* name) const;
|
||||
|
||||
// Create individual attribute arrays.
|
||||
// Returns true if the vertices store the particular attribute.
|
||||
|
|
Loading…
Reference in New Issue