Compare commits

...

5 Commits
v0.9.7 ... main

Author SHA1 Message Date
Pär Winzell 739ee5db94
Kill AppVeyor builds.
We'll move to CircleCI when we find an active maintainer who wants to push new releases.
2020-04-20 12:10:09 -07:00
Benjamin MICHEL 37f992321e Fixed the npm library output path 2019-10-09 09:48:14 -07:00
Pär Winzell be627fa228 Minor README updates.
- Better 'tar' invocation that doesn't require GNU tar.
- No need for GIT_LFS_SKIP_SMUDGE anymore.
- Apply VSCode's MarkDown formatting suggestions.
2019-10-09 09:35:37 -07:00
vfxgordon 1d735698ba Morph target names output to mesh.extras.targetNames (#231) 2019-10-07 16:46:38 -07:00
Pär Winzell 5c3229d6cf Patch release, screwed up 0.9.7. 2019-09-11 11:16:50 -07:00
8 changed files with 167 additions and 93 deletions

View File

@ -1,4 +1,5 @@
# FBX2glTF # FBX2glTF
[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
This is a command line tool for converting 3D model assets on Autodesk's This is a command line tool for converting 3D model assets on Autodesk's
@ -17,11 +18,13 @@ Bleeding-edge binaries for Windows may be found [here](https://ci.appveyor.com/p
## Running ## Running
The tool can be invoked like so: The tool can be invoked like so:
``` ```
> FBX2glTF ~/models/butterfly.fbx > FBX2glTF ~/models/butterfly.fbx
``` ```
Or perhaps, as part of a more complex pipeline: Or perhaps, as part of a more complex pipeline:
``` ```
> FBX2glTF --binary --draco --verbose \ > FBX2glTF --binary --draco --verbose \
--input ~/models/source/butterfly.fbx \ --input ~/models/source/butterfly.fbx \
@ -33,6 +36,7 @@ There are also some friendly & hands-on instructions available [over at Facebook
### CLI Switches ### CLI Switches
You can always run the binary with --help to see what options it takes: You can always run the binary with --help to see what options it takes:
``` ```
FBX2glTF 0.9.7: Generate a glTF 2.0 representation of an FBX model. FBX2glTF 0.9.7: Generate a glTF 2.0 representation of an FBX model.
Usage: FBX2glTF [OPTIONS] [FBX Model] Usage: FBX2glTF [OPTIONS] [FBX Model]
@ -116,7 +120,7 @@ Some of these switches are not obvious:
will be chosen by default if you supply none of the others. Material switches will be chosen by default if you supply none of the others. Material switches
are documented further below. are documented further below.
- If you supply any `-keep-attribute` option, you enable a mode wherein you must - If you supply any `-keep-attribute` option, you enable a mode wherein you must
supply it repeatedly to list *all* the vertex attributes you wish to keep in supply it repeatedly to list _all_ the vertex attributes you wish to keep in
the conversion process. This is a way to trim the size of the resulting glTF the conversion process. This is a way to trim the size of the resulting glTF
if you know the FBX contains superfluous attributes. The supported arguments if you know the FBX contains superfluous attributes. The supported arguments
are `position`, `normal`, `tangent`, `color`, `uv0`, and `uv1`. are `position`, `normal`, `tangent`, `color`, `uv0`, and `uv1`.
@ -144,10 +148,12 @@ all of which are automatically downloaded and/or built.
build system will not successfully locate any other version. build system will not successfully locate any other version.
### Linux and MacOS X ### Linux and MacOS X
Your development environment will need to have: Your development environment will need to have:
- build essentials (gcc for Linux, clang for Mac) - build essentials (gcc for Linux, clang for Mac)
- cmake - cmake
- python 3.* and associated pip3/pip command - python 3.\* and associated pip3/pip command
- zstd - zstd
Then, compilation on Unix machines will look something like: Then, compilation on Unix machines will look something like:
@ -165,11 +171,11 @@ else
fi fi
# Fetch Project # Fetch Project
> GIT_LFS_SKIP_SMUDGE=1 git clone https://github.com/facebookincubator/FBX2glTF.git > git clone https://github.com/facebookincubator/FBX2glTF.git
> cd FBX2glTF > cd FBX2glTF
# Fetch and unpack FBX SDK # Fetch and unpack FBX SDK
> curl -sL "${FBXSDK_TARBALL}" | tar xz --strip-components=1 --wildcards */sdk > curl -sL "${FBXSDK_TARBALL}" | tar xz --strip-components=1 --include */sdk/
# Then decompress the contents # Then decompress the contents
> zstd -d -r --rm sdk > zstd -d -r --rm sdk
@ -198,10 +204,11 @@ versions of the IDE are unlikely to successfully build the tool.
Note that the `CMAKE_BUILD_TYPE` variable from the Unix Makefile system is Note that the `CMAKE_BUILD_TYPE` variable from the Unix Makefile system is
entirely ignored here; it is when you open the generated solution that entirely ignored here; it is when you open the generated solution that
you will be choose one of the canonical build types — *Debug*, you will be choose one of the canonical build types — _Debug_,
*Release*, *MinSizeRel*, and so on. _Release_, _MinSizeRel_, and so on.
## Conversion Process ## Conversion Process
The actual translation begins with the FBX SDK parsing the input file, and ends The actual translation begins with the FBX SDK parsing the input file, and ends
with the generation of the descriptive `JSON` that forms the core of glTF, along with the generation of the descriptive `JSON` that forms the core of glTF, along
with binary buffers that hold geometry and animations (and optionally also with binary buffers that hold geometry and animations (and optionally also
@ -213,13 +220,14 @@ process happens in reverse when we construct meshes and materials that conform
to the expectations of the glTF format. to the expectations of the glTF format.
### Animations ### Animations
Every animation in the FBX file becomes an animation in the glTF file. The Every animation in the FBX file becomes an animation in the glTF file. The
method used is one of "baking": we step through the interval of time spanned by method used is one of "baking": we step through the interval of time spanned by
the animation, keyframe by keyframe, calculate the local transform of each the animation, keyframe by keyframe, calculate the local transform of each
node, and whenever we find any node that's rotated, translated or scaled, we node, and whenever we find any node that's rotated, translated or scaled, we
record that fact in the output. record that fact in the output.
Beyond skeleton-based animation, *Blend Shapes* are also supported; they are Beyond skeleton-based animation, _Blend Shapes_ are also supported; they are
read from the FBX file on a per-mesh basis, and clips can use them by varying read from the FBX file on a per-mesh basis, and clips can use them by varying
the weights associated with each one. the weights associated with each one.
@ -228,6 +236,7 @@ drawback of creating potentially very large files. The more complex the
animation rig, the less avoidable this data explosion is. animation rig, the less avoidable this data explosion is.
There are three future enhancements we hope to see for animations: There are three future enhancements we hope to see for animations:
- Version 2.0 of glTF brought us support for expressing quadratic animation - Version 2.0 of glTF brought us support for expressing quadratic animation
curves, where previously we had only had linear. Not coincidentally, quadratic curves, where previously we had only had linear. Not coincidentally, quadratic
splines are one of the key ways animations are expressed inside the FBX. When splines are one of the key ways animations are expressed inside the FBX. When
@ -257,33 +266,37 @@ old workflow often contain baked lighting of the type that would arise naturally
in a PBR environment. in a PBR environment.
Some material settings remain well supported and transfer automatically: Some material settings remain well supported and transfer automatically:
- Emissive constants and textures
- Occlusion maps - Emissive constants and textures
- Normal maps - Occlusion maps
- Normal maps
This leaves the other traditional settings, first of Lambert: This leaves the other traditional settings, first of Lambert:
- Ambient — this is anathema in the PBR world, where such effects should
emerge naturally from the fundamental colour of the material and any ambient - Ambient — this is anathema in the PBR world, where such effects should
lighting present. emerge naturally from the fundamental colour of the material and any ambient
- Diffuse — the material's direction-agnostic, non-specular reflection, lighting present.
and additionally, with Blinn/Phong: - Diffuse — the material's direction-agnostic, non-specular reflection,
- Specular — a more polished material's direction-sensitive reflection, and additionally, with Blinn/Phong:
- Shininess — just how polished the material is; a higher value here yields a - Specular — a more polished material's direction-sensitive reflection,
more mirror-like surface. - Shininess — just how polished the material is; a higher value here yields a
more mirror-like surface.
(All these can be either constants or textures.) (All these can be either constants or textures.)
#### Exporting as Unlit #### Exporting as Unlit
If you have a model was constructed using an unlit workflow, e.g. a photogrammetry If you have a model was constructed using an unlit workflow, e.g. a photogrammetry
capture or a landscape with careful baked-in lighting, you may choose to export capture or a landscape with careful baked-in lighting, you may choose to export
it using the --khr-materials-common switch. This incurs a dependency on the glTF it using the --khr-materials-common switch. This incurs a dependency on the glTF
extension 'KHR_materials_unlit; a client that accepts that extension is making extension 'KHR_materials_unlit; a client that accepts that extension is making
a promise it'll do its best to render pixel values without lighting calculations. a promise it'll do its best to render pixel values without lighting calculations.
**Note that at the time of writing, this glTF extension is still undergoing the **Note that at the time of writing, this glTF extension is still undergoing the
ratification process** ratification process**
#### Exporting as Metallic-Roughness PBR #### Exporting as Metallic-Roughness PBR
Given the command line flag --pbr-metallic-roughness, we throw ourselves into Given the command line flag --pbr-metallic-roughness, we throw ourselves into
the warm embrace of glTF 2.0's PBR preference. the warm embrace of glTF 2.0's PBR preference.
@ -296,6 +309,7 @@ that route should be digested propertly by FBX2glTF.
when hooked up to Maya.) when hooked up to Maya.)
## Draco Compression ## Draco Compression
The tool will optionally apply [Draco](https://github.com/google/draco) The tool will optionally apply [Draco](https://github.com/google/draco)
compression to the geometric data of each mesh (vertex indices, positions, compression to the geometric data of each mesh (vertex indices, positions,
normals, per-vertex color, and so on). This can be dramatically effective normals, per-vertex color, and so on). This can be dramatically effective
@ -309,16 +323,18 @@ viewer that is willing and able to decompress the data.
ratification process.** ratification process.**
## Future Improvements ## Future Improvements
This tool is under continuous development. We do not have a development roadmap This tool is under continuous development. We do not have a development roadmap
per se, but some aspirations have been noted above. The canonical list of active per se, but some aspirations have been noted above. The canonical list of active
TODO items can be found TODO items can be found
[on GitHub](https://github.com/facebookincubator/FBX2glTF/labels/enhancement). [on GitHub](https://github.com/facebookincubator/FBX2glTF/labels/enhancement).
## Authors ## Authors
- Pär Winzell
- J.M.P. van Waveren - Pär Winzell
- Amanda Watson - J.M.P. van Waveren
- Amanda Watson
## License ## License
FBX2glTF is licensed under the [3-clause BSD license](LICENSE). FBX2glTF is licensed under the [3-clause BSD license](LICENSE).

View File

@ -1,58 +0,0 @@
# version format
version: 1.0.{build}
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
PYTHON: "C:\\Python36-x64"
FBXSDK_SDKS: sdk
stack: python %PYTHON%
#temporarily disabled
#cache:
# - C:\Users\appveyor\.conan\data -> appveyor.yml, conanfile.py
init:
- git config --global filter.lfs.required false
- git config --global filter.lfs.smudge "git-lfs smudge --skip %f"
- git config --global filter.lfs.process "git-lfs filter-process --skip"
install:
- cinst zstandard
- ps: Start-FileDownload 'https://github.com/zellski/FBXSDK-Windows/archive/2019.2.tar.gz'
- 7z e 2019.2.tar.gz
- 7z x 2019.2.tar
- ps: move -v .\FBXSDK-Windows-2019.2\sdk\ .
- ps: zstd -d -r --rm sdk
- cmd: echo "Downloading conan..."
- cmd: set PATH=%PYTHON%;%PYTHON%\Scripts;%PATH%
- cmd: python --version
- cmd: python -m pip install --upgrade pip
- cmd: pip install conan
- cmd: conan user # Create the conan data directory
- cmd: conan remote add bincrafters https://api.bintray.com/conan/bincrafters/public-conan
- cmd: conan --version
build_script:
- cmd: conan install . -i build -s build_type=Release -s compiler="Visual Studio" -s compiler.version=15
- cmd: conan build -bf build .
- cmd: move build\Release\FBX2glTF.exe build\Release\FBX2glTF-windows-x64.exe
test: off
artifacts:
- path: build/Release/FBX2glTF-windows-x64.exe
deploy:
tag: $(APPVEYOR_REPO_TAG_NAME)
description: ''
provider: GitHub
auth_token:
secure: OSvhQP0O9uaH+OFOJpbGiiBMRTOJ+H/VJHqVBhq39RNDnOfUEr/yjJNKh3JSdNqj
artifact: build/Release/FBX2glTF-windows-x64.exe
draft: true
prerelease: true
on:
branch: master
APPVEYOR_REPO_TAG: true

View File

@ -18,7 +18,7 @@ const binaries = {
/** /**
* Converts an FBX to a GTLF or GLB file. * Converts an FBX to a GTLF or GLB file.
* @param string srcFile path to the source file. * @param string srcFile path to the source file.
* @param string destFile path to the destination file. * @param string destFile path to the destination file or destination path.
* This must end in `.glb` or `.gltf` (case matters). * This must end in `.glb` or `.gltf` (case matters).
* @param string[] [opts] options to pass to the converter tool. * @param string[] [opts] options to pass to the converter tool.
* @return Promise<string> a promise that yields the full path to the converted * @return Promise<string> a promise that yields the full path to the converted
@ -33,19 +33,31 @@ function convert(srcFile, destFile, opts = []) {
throw new Error(`Unsupported OS: ${os.type()}`); throw new Error(`Unsupported OS: ${os.type()}`);
} }
let destExt; let destExt = path.extname(destFile).toLowerCase();
if (destFile.endsWith('.glb')) {
destExt = '.glb'; if (!destExt) {
opts.includes('--binary') || opts.push('--binary'); destExt = '.gltf'
} else if (destFile.endsWith('.gltf')) {
destExt = '.gltf'; const srcFilename = path.basename(srcFile, path.extname(srcFile))
} else { destFile = path.join(destFile, srcFilename + destExt)
}
if (destExt !== '.glb' && destExt !== '.gltf') {
throw new Error(`Unsupported file extension: ${destFile}`); throw new Error(`Unsupported file extension: ${destFile}`);
} }
const binary = opts.includes('--binary') || opts.includes('-b');
if (binary && destExt !== '.glb') {
destExt = '.glb';
} else if (!binary && destExt === 'glb') {
opts.push('--binary');
}
let srcPath = fs.realpathSync(srcFile); let srcPath = fs.realpathSync(srcFile);
let destDir = fs.realpathSync(path.dirname(destFile)); let destDir = fs.realpathSync(path.dirname(destFile));
let destPath = path.join(destDir, path.basename(destFile, destExt)); let destFilename = path.basename(destFile, path.extname(destFile)) + destExt;
let destPath = path.join(destDir, destFilename);
let args = opts.slice(0); let args = opts.slice(0);
args.push('--input', srcPath, '--output', destPath); args.push('--input', srcPath, '--output', destPath);
@ -72,7 +84,7 @@ function convert(srcFile, destFile, opts = []) {
reject(new Error(`Converter output:\n` + reject(new Error(`Converter output:\n` +
(output.length ? output : "<none>"))); (output.length ? output : "<none>")));
} else { } else {
resolve(destPath + destExt); resolve(destPath);
} }
}); });

93
npm/fbx2gltf/package-lock.json generated Normal file
View File

@ -0,0 +1,93 @@
{
"name": "fbx2gltf",
"version": "0.9.7-p1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"glob": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"requires": {
"glob": "^7.1.3"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
}
}
}

View File

@ -1,6 +1,6 @@
{ {
"name": "fbx2gltf", "name": "fbx2gltf",
"version": "0.9.7", "version": "0.9.7-p1",
"description": "Node wrapper around FBX2glTF tools.", "description": "Node wrapper around FBX2glTF tools.",
"main": "index.js", "main": "index.js",
"repository": { "repository": {

View File

@ -14,12 +14,21 @@ MeshData::MeshData(const std::string& name, const std::vector<float>& weights)
json MeshData::serialize() const { json MeshData::serialize() const {
json jsonPrimitivesArray = json::array(); json jsonPrimitivesArray = json::array();
json jsonTargetNamesArray = json::array();
for (const auto& primitive : primitives) { for (const auto& primitive : primitives) {
jsonPrimitivesArray.push_back(*primitive); jsonPrimitivesArray.push_back(*primitive);
if (!primitive->targetNames.empty()) {
for (auto targetName : primitive->targetNames) {
jsonTargetNamesArray.push_back(targetName);
}
}
} }
json result = {{"name", name}, {"primitives", jsonPrimitivesArray}}; json result = {{"name", name}, {"primitives", jsonPrimitivesArray}};
if (!weights.empty()) { if (!weights.empty()) {
result["weights"] = weights; result["weights"] = weights;
} }
if (!jsonTargetNamesArray.empty()) {
result["extras"]["targetNames"] = jsonTargetNamesArray;
}
return result; return result;
} }

View File

@ -45,6 +45,7 @@ void PrimitiveData::AddTarget(
positions->ix, positions->ix,
normals != nullptr ? normals->ix : -1, normals != nullptr ? normals->ix : -1,
tangents != nullptr ? tangents->ix : -1)); tangents != nullptr ? tangents->ix : -1));
targetNames.push_back(positions->name);
} }
void to_json(json& j, const PrimitiveData& d) { void to_json(json& j, const PrimitiveData& d) {

View File

@ -68,6 +68,7 @@ struct PrimitiveData {
const MeshMode mode; const MeshMode mode;
std::vector<std::tuple<int, int, int>> targetAccessors{}; std::vector<std::tuple<int, int, int>> targetAccessors{};
std::vector<std::string> targetNames{};
std::map<std::string, int> attributes; std::map<std::string, int> attributes;
std::map<std::string, int> dracoAttributes; std::map<std::string, int> dracoAttributes;