import multiple animation files
This commit is contained in:
parent
13f463d336
commit
47001c9ce3
|
@ -47,6 +47,7 @@ Usage:
|
||||||
from the FBX.
|
from the FBX.
|
||||||
--khr-materials-unlit Use KHR_materials_unlit extension to specify
|
--khr-materials-unlit Use KHR_materials_unlit extension to specify
|
||||||
Unlit shader.
|
Unlit shader.
|
||||||
|
--animation-files Read multiple fbx animation files.
|
||||||
--blend-shape-normals Include blend shape normals, if reported
|
--blend-shape-normals Include blend shape normals, if reported
|
||||||
present by the FBX SDK.
|
present by the FBX SDK.
|
||||||
--blend-shape-tangents Include blend shape tangents, if reported
|
--blend-shape-tangents Include blend shape tangents, if reported
|
||||||
|
@ -75,6 +76,10 @@ Some of these switches are not obvious:
|
||||||
Your FBX is likely constructed with the assumption that `(0, 0)` is bottom
|
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,
|
left, whereas glTF has `(0, 0)` as top left. To produce spec-compliant glTF,
|
||||||
we must flip the texcoords. To request unflipped coordinates:
|
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.
|
- `--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.
|
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
|
- `--compute-normals` controls when automatic vertex normals should be computed
|
||||||
|
|
|
@ -125,6 +125,11 @@ int main(int argc, char* argv[]) {
|
||||||
[&](size_t count) { gltfOptions.useKHRLightsPunctual = (count == 0); },
|
[&](size_t count) { gltfOptions.useKHRLightsPunctual = (count == 0); },
|
||||||
"Don't use KHR_lights_punctual extension to export FBX lights.");
|
"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(
|
app.add_flag(
|
||||||
"--user-properties",
|
"--user-properties",
|
||||||
gltfOptions.enableUserProperties,
|
gltfOptions.enableUserProperties,
|
||||||
|
@ -302,7 +307,7 @@ int main(int argc, char* argv[]) {
|
||||||
if (verboseOutput) {
|
if (verboseOutput) {
|
||||||
fmt::printf("Loading FBX File: %s\n", inputPath);
|
fmt::printf("Loading FBX File: %s\n", inputPath);
|
||||||
}
|
}
|
||||||
if (!LoadFBXFile(raw, inputPath.c_str(), "png;jpg;jpeg")) {
|
if (!LoadFBXFile(raw, inputPath.c_str(), "png;jpg;jpeg", gltfOptions)) {
|
||||||
fmt::fprintf(stderr, "ERROR:: Failed to parse FBX: %s\n", inputPath);
|
fmt::fprintf(stderr, "ERROR:: Failed to parse FBX: %s\n", inputPath);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,9 @@ struct GltfOptions
|
||||||
/** Whether to include lights through the KHR_punctual_lights extension. */
|
/** Whether to include lights through the KHR_punctual_lights extension. */
|
||||||
bool useKHRLightsPunctual { true };
|
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. */
|
/** Whether to include blend shape normals, if present according to the SDK. */
|
||||||
bool useBlendShapeNormals { false };
|
bool useBlendShapeNormals { false };
|
||||||
/** Whether to include blend shape tangents, if present according to the SDK. */
|
/** Whether to include blend shape tangents, if present according to the SDK. */
|
||||||
|
|
|
@ -721,7 +721,7 @@ static void ReadNodeHierarchy(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReadAnimations(RawModel& raw, FbxScene* pScene) {
|
static void ReadAnimations(RawModel& raw, FbxScene* pScene, bool nodeNameLookup) {
|
||||||
FbxTime::EMode eMode = FbxTime::eFrames24;
|
FbxTime::EMode eMode = FbxTime::eFrames24;
|
||||||
const double epsilon = 1e-5f;
|
const double epsilon = 1e-5f;
|
||||||
|
|
||||||
|
@ -772,7 +772,14 @@ static void ReadAnimations(RawModel& raw, FbxScene* pScene) {
|
||||||
bool hasMorphs = false;
|
bool hasMorphs = false;
|
||||||
|
|
||||||
RawChannel channel;
|
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++) {
|
for (FbxLongLong frameIndex = firstFrameIndex; frameIndex <= lastFrameIndex; frameIndex++) {
|
||||||
FbxTime pTime;
|
FbxTime pTime;
|
||||||
|
@ -996,11 +1003,7 @@ static void FindFbxTextures(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadFBXFile(RawModel& raw, const char* fbxFileName, const char* textureExtensions) {
|
static FbxScene* LoadScene(FbxManager* pManager, const char* fbxFileName) {
|
||||||
FbxManager* pManager = FbxManager::Create();
|
|
||||||
FbxIOSettings* pIoSettings = FbxIOSettings::Create(pManager, IOSROOT);
|
|
||||||
pManager->SetIOSettings(pIoSettings);
|
|
||||||
|
|
||||||
FbxImporter* pImporter = FbxImporter::Create(pManager, "");
|
FbxImporter* pImporter = FbxImporter::Create(pManager, "");
|
||||||
|
|
||||||
if (!pImporter->Initialize(fbxFileName, -1, pManager->GetIOSettings())) {
|
if (!pImporter->Initialize(fbxFileName, -1, pManager->GetIOSettings())) {
|
||||||
|
@ -1008,8 +1011,7 @@ bool LoadFBXFile(RawModel& raw, const char* fbxFileName, const char* textureExte
|
||||||
fmt::printf("%s\n", pImporter->GetStatus().GetErrorString());
|
fmt::printf("%s\n", pImporter->GetStatus().GetErrorString());
|
||||||
}
|
}
|
||||||
pImporter->Destroy();
|
pImporter->Destroy();
|
||||||
pManager->Destroy();
|
return nullptr;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FbxScene* pScene = FbxScene::Create(pManager, "fbxScene");
|
FbxScene* pScene = FbxScene::Create(pManager, "fbxScene");
|
||||||
|
@ -1017,14 +1019,9 @@ bool LoadFBXFile(RawModel& raw, const char* fbxFileName, const char* textureExte
|
||||||
pImporter->Destroy();
|
pImporter->Destroy();
|
||||||
|
|
||||||
if (pScene == nullptr) {
|
if (pScene == nullptr) {
|
||||||
pImporter->Destroy();
|
return nullptr;
|
||||||
pManager->Destroy();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<const FbxTexture*, FbxString> textureLocations;
|
|
||||||
FindFbxTextures(pScene, fbxFileName, textureExtensions, textureLocations);
|
|
||||||
|
|
||||||
// Use Y up for glTF
|
// Use Y up for glTF
|
||||||
FbxAxisSystem::MayaYUp.ConvertScene(pScene);
|
FbxAxisSystem::MayaYUp.ConvertScene(pScene);
|
||||||
|
|
||||||
|
@ -1037,14 +1034,54 @@ bool LoadFBXFile(RawModel& raw, const char* fbxFileName, const char* textureExte
|
||||||
if (sceneSystemUnit != FbxSystemUnit::cm) {
|
if (sceneSystemUnit != FbxSystemUnit::cm) {
|
||||||
FbxSystemUnit::cm.ConvertScene(pScene);
|
FbxSystemUnit::cm.ConvertScene(pScene);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return pScene;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoadFBXFile(
|
||||||
|
RawModel& raw,
|
||||||
|
const char* fbxFileName,
|
||||||
|
const char* 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.
|
// this is always 0.01, but let's opt for clarity.
|
||||||
scaleFactor = FbxSystemUnit::m.GetConversionFactorFrom(FbxSystemUnit::cm);
|
scaleFactor = FbxSystemUnit::m.GetConversionFactorFrom(FbxSystemUnit::cm);
|
||||||
|
|
||||||
|
std::map<const FbxTexture*, FbxString> textureLocations;
|
||||||
|
FindFbxTextures(pScene, fbxFileName, textureExtensions, textureLocations);
|
||||||
|
|
||||||
ReadNodeHierarchy(raw, pScene, pScene->GetRootNode(), 0, "");
|
ReadNodeHierarchy(raw, pScene, pScene->GetRootNode(), 0, "");
|
||||||
ReadNodeAttributes(raw, pScene, pScene->GetRootNode(), textureLocations);
|
ReadNodeAttributes(raw, pScene, pScene->GetRootNode(), textureLocations);
|
||||||
ReadAnimations(raw, pScene);
|
ReadAnimations(raw, pScene, false);
|
||||||
|
|
||||||
pScene->Destroy();
|
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, true);
|
||||||
|
pAnimationScene->Destroy();
|
||||||
|
animationFileNumber++;
|
||||||
|
} else {
|
||||||
|
readAnimationFiles = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pManager->Destroy();
|
pManager->Destroy();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -11,6 +11,10 @@
|
||||||
|
|
||||||
#include "raw/RawModel.hpp"
|
#include "raw/RawModel.hpp"
|
||||||
|
|
||||||
bool LoadFBXFile(RawModel& raw, const char* fbxFileName, const char* textureExtensions);
|
bool LoadFBXFile(
|
||||||
|
RawModel& raw,
|
||||||
|
const char* fbxFileName,
|
||||||
|
const char* textureExtensions,
|
||||||
|
const GltfOptions& options);
|
||||||
|
|
||||||
json TranscribeProperty(FbxProperty& prop);
|
json TranscribeProperty(FbxProperty& prop);
|
|
@ -641,6 +641,15 @@ int RawModel::GetNodeById(const long nodeId) const {
|
||||||
return -1;
|
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 {
|
int RawModel::GetSurfaceById(const long surfaceId) const {
|
||||||
for (size_t i = 0; i < surfaces.size(); i++) {
|
for (size_t i = 0; i < surfaces.size(); i++) {
|
||||||
if (surfaces[i].id == surfaceId) {
|
if (surfaces[i].id == surfaceId) {
|
||||||
|
|
|
@ -509,6 +509,7 @@ class RawModel {
|
||||||
return nodes[index];
|
return nodes[index];
|
||||||
}
|
}
|
||||||
int GetNodeById(const long nodeId) const;
|
int GetNodeById(const long nodeId) const;
|
||||||
|
int GetNodeByName(const char* name) const;
|
||||||
|
|
||||||
// Create individual attribute arrays.
|
// Create individual attribute arrays.
|
||||||
// Returns true if the vertices store the particular attribute.
|
// Returns true if the vertices store the particular attribute.
|
||||||
|
|
Loading…
Reference in New Issue