Merge pull request #1 from facebookincubator/master
update host master version
This commit is contained in:
commit
9b21de2ca1
|
@ -8,6 +8,8 @@ a modern runtime asset delivery format.
|
||||||
Precompiled binaries releases for Windows, Mac OS X and Linux may be
|
Precompiled binaries releases for Windows, Mac OS X and Linux may be
|
||||||
found [here](https://github.com/facebookincubator/FBX2glTF/releases).
|
found [here](https://github.com/facebookincubator/FBX2glTF/releases).
|
||||||
|
|
||||||
|
Bleeding-edge binaries are periodically built and publicly available [here](https://dev.azure.com/parwinzell/FBX2glTF/): click a build (usually the most recent), then the 'Artefacts' dropdown in the upper right.
|
||||||
|
|
||||||
## Running
|
## Running
|
||||||
|
|
||||||
The tool can be invoked like so:
|
The tool can be invoked like so:
|
||||||
|
|
|
@ -1,76 +1,80 @@
|
||||||
import { readFileSync } from 'fs';
|
import {assert, expect} from 'chai';
|
||||||
import * as tmp from 'tmp';
|
|
||||||
import * as path from 'path';
|
|
||||||
import * as fbx2gltf from 'fbx2gltf';
|
import * as fbx2gltf from 'fbx2gltf';
|
||||||
import { assert, expect } from 'chai';
|
import {readFileSync} from 'fs';
|
||||||
import { validateBytes } from 'gltf-validator';
|
import {validateBytes} from 'gltf-validator';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as tmp from 'tmp';
|
||||||
|
|
||||||
interface Model {
|
interface Model {
|
||||||
path: string;
|
path: string;
|
||||||
ignoredIssues?: Array<string>;
|
ignoredIssues?: Array<string>;
|
||||||
args?: Array<string>;
|
args?: Array<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MODELS :Array<Model> = [
|
const MODELS: Array<Model> = [
|
||||||
{ path: 'fromFacebook/Jon/jon_morph' },
|
{path : 'fromFacebook/Jon/jon_morph'},
|
||||||
{
|
{
|
||||||
path: 'fromFacebook/Jon/troll-final',
|
path : 'fromFacebook/Jon/troll-final',
|
||||||
ignoredIssues: [ 'ACCESSOR_NON_UNIT' ],
|
ignoredIssues : [ 'ACCESSOR_NON_UNIT' ],
|
||||||
},
|
},
|
||||||
{ path: 'fromFacebook/Natalie/GlitchRobot' },
|
{path : 'fromFacebook/Natalie/GlitchRobot'},
|
||||||
{ path: 'fromFacebook/Ocean/blackvan/blackvan_with_windows' },
|
{path : 'fromFacebook/Ocean/blackvan/blackvan_with_windows'},
|
||||||
{ path: 'fromFacebook/Ocean/zell_van_vertex_color' },
|
{
|
||||||
{ path: 'fromFacebook/RAZ/RAZ_ape' },
|
path : 'fromFacebook/Ocean/zell_van_vertex_color',
|
||||||
{ path: 'fromFbxSDK/Box' },
|
args : [ '--draco' ],
|
||||||
{
|
ignoredIssues : [ 'UNSUPPORTED_EXTENSION' ],
|
||||||
path: 'fromFbxSDK/Humanoid',
|
},
|
||||||
ignoredIssues: [ 'UNSUPPORTED_EXTENSION' ],
|
{path : 'fromFacebook/RAZ/RAZ_ape', args : [ '--long-indices=always' ]},
|
||||||
},
|
{path : 'fromFbxSDK/Box'},
|
||||||
{
|
{
|
||||||
path: 'fromFbxSDK/Camera',
|
path : 'fromFbxSDK/Humanoid',
|
||||||
ignoredIssues: [ 'UNSUPPORTED_EXTENSION' ],
|
ignoredIssues : [ 'UNSUPPORTED_EXTENSION' ],
|
||||||
},
|
},
|
||||||
{ path: 'fromFbxSDK/Normals' },
|
{
|
||||||
{ path: 'fromGltfSamples/BoxVertexColors/BoxVertexColors' },
|
path : 'fromFbxSDK/Camera',
|
||||||
{ path: 'fromGltfSamples/WaterBottle/NewWaterBottle' },
|
ignoredIssues : [ 'UNSUPPORTED_EXTENSION' ],
|
||||||
|
},
|
||||||
|
{path : 'fromFbxSDK/Normals'},
|
||||||
|
{path : 'fromGltfSamples/BoxVertexColors/BoxVertexColors', args : [ '--khr-materials-unlit' ]},
|
||||||
|
{path : 'fromGltfSamples/WaterBottle/NewWaterBottle'},
|
||||||
];
|
];
|
||||||
|
|
||||||
const CONVERSION_TIMEOUT_MS = 50000;
|
const CONVERSION_TIMEOUT_MS = 50000;
|
||||||
|
|
||||||
describe('FBX2glTF', () => {
|
describe('FBX2glTF', () => {
|
||||||
const tmpobj = tmp.dirSync();
|
const tmpobj = tmp.dirSync();
|
||||||
for(let model of MODELS) {
|
for (let model of MODELS) {
|
||||||
const modelName = path.basename(model.path);
|
const modelName = path.basename(model.path);
|
||||||
describe('Model: ' + modelName, () => {
|
describe('Model: ' + modelName, () => {
|
||||||
const fbxPath = path.join('models', model.path + '.fbx');
|
const fbxPath = path.join('models', model.path + '.fbx');
|
||||||
let glbBytes;
|
let glbBytes;
|
||||||
it('should convert fbx to glb', async () => {
|
it('should convert fbx to glb', async () => {
|
||||||
const glbPath = path.join(tmpobj.name, modelName + '.glb');
|
const glbPath = path.join(tmpobj.name, modelName + '.glb');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const destPath = await fbx2gltf(fbxPath, glbPath, model.args || []);
|
const destPath = await fbx2gltf(fbxPath, glbPath, model.args || []);
|
||||||
assert.isNotNull(destPath);
|
assert.isNotNull(destPath);
|
||||||
glbBytes = readFileSync(destPath);
|
glbBytes = readFileSync(destPath);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new Error('Conversion failed: ' + err);
|
throw new Error('Conversion failed: ' + err);
|
||||||
}
|
}
|
||||||
}).timeout(CONVERSION_TIMEOUT_MS);
|
}).timeout(CONVERSION_TIMEOUT_MS);
|
||||||
|
|
||||||
it('resulting glb should be valid', async() => {
|
it('resulting glb should be valid', async () => {
|
||||||
try {
|
try {
|
||||||
let options = <any>{};
|
let options = <any>{};
|
||||||
if (model.ignoredIssues) {
|
if (model.ignoredIssues) {
|
||||||
options.ignoredIssues = model.ignoredIssues;
|
options.ignoredIssues = model.ignoredIssues;
|
||||||
}
|
}
|
||||||
const report = await validateBytes(glbBytes, options);
|
const report = await validateBytes(glbBytes, options);
|
||||||
expect(report.issues.numErrors).to.equal(0);
|
expect(report.issues.numErrors).to.equal(0);
|
||||||
expect(report.issues.numWarnings).to.equal(0);
|
expect(report.issues.numWarnings).to.equal(0);
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new Error('Validation failed: ' + err);
|
throw new Error('Validation failed: ' + err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
console.log('GLB files may be inspected in: ' + tmpobj.name);
|
console.log('GLB files may be inspected in: ' + tmpobj.name);
|
||||||
});
|
});
|
||||||
|
|
|
@ -209,9 +209,11 @@ static void ReadMesh(
|
||||||
|
|
||||||
std::shared_ptr<RawMatProps> rawMatProps;
|
std::shared_ptr<RawMatProps> rawMatProps;
|
||||||
FbxString materialName;
|
FbxString materialName;
|
||||||
|
long materialId;
|
||||||
|
|
||||||
if (fbxMaterial == nullptr) {
|
if (fbxMaterial == nullptr) {
|
||||||
materialName = "DefaultMaterial";
|
materialName = "DefaultMaterial";
|
||||||
|
materialId = -1;
|
||||||
rawMatProps.reset(new RawTraditionalMatProps(
|
rawMatProps.reset(new RawTraditionalMatProps(
|
||||||
RAW_SHADING_MODEL_LAMBERT,
|
RAW_SHADING_MODEL_LAMBERT,
|
||||||
Vec3f(0, 0, 0),
|
Vec3f(0, 0, 0),
|
||||||
|
@ -222,6 +224,7 @@ static void ReadMesh(
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
materialName = fbxMaterial->name;
|
materialName = fbxMaterial->name;
|
||||||
|
materialId = fbxMaterial->id;
|
||||||
|
|
||||||
const auto maybeAddTexture = [&](const FbxFileTexture* tex, RawTextureUsage usage) {
|
const auto maybeAddTexture = [&](const FbxFileTexture* tex, RawTextureUsage usage) {
|
||||||
if (tex != nullptr) {
|
if (tex != nullptr) {
|
||||||
|
@ -436,8 +439,8 @@ static void ReadMesh(
|
||||||
|
|
||||||
const RawMaterialType materialType =
|
const RawMaterialType materialType =
|
||||||
GetMaterialType(raw, textures, vertexTransparency, skinning.IsSkinned());
|
GetMaterialType(raw, textures, vertexTransparency, skinning.IsSkinned());
|
||||||
const int rawMaterialIndex =
|
const int rawMaterialIndex = raw.AddMaterial(
|
||||||
raw.AddMaterial(materialName, materialType, textures, rawMatProps, userProperties);
|
materialId, materialName, materialType, textures, rawMatProps, userProperties);
|
||||||
|
|
||||||
raw.AddTriangle(
|
raw.AddTriangle(
|
||||||
rawVertexIndices[0],
|
rawVertexIndices[0],
|
||||||
|
|
|
@ -149,6 +149,7 @@ std::unique_ptr<FbxRoughMetMaterialInfo> Fbx3dsMaxPhysicalMaterialResolver::reso
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<FbxRoughMetMaterialInfo> res(new FbxRoughMetMaterialInfo(
|
std::unique_ptr<FbxRoughMetMaterialInfo> res(new FbxRoughMetMaterialInfo(
|
||||||
|
fbxMaterial->GetUniqueID(),
|
||||||
fbxMaterial->GetName(),
|
fbxMaterial->GetName(),
|
||||||
FbxRoughMetMaterialInfo::FBX_SHADER_METROUGH,
|
FbxRoughMetMaterialInfo::FBX_SHADER_METROUGH,
|
||||||
baseCol,
|
baseCol,
|
||||||
|
|
|
@ -16,9 +16,10 @@
|
||||||
|
|
||||||
class FbxMaterialInfo {
|
class FbxMaterialInfo {
|
||||||
public:
|
public:
|
||||||
FbxMaterialInfo(const FbxString& name, const FbxString& shadingModel)
|
FbxMaterialInfo(const FbxUInt64 id, const FbxString& name, const FbxString& shadingModel)
|
||||||
: name(name), shadingModel(shadingModel) {}
|
: id(id), name(name), shadingModel(shadingModel) {}
|
||||||
|
|
||||||
|
const FbxUInt64 id;
|
||||||
const FbxString name;
|
const FbxString name;
|
||||||
const FbxString shadingModel;
|
const FbxString shadingModel;
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,12 +21,13 @@ struct FbxRoughMetMaterialInfo : FbxMaterialInfo {
|
||||||
const std::map<const FbxTexture*, FbxString>& textureLocations);
|
const std::map<const FbxTexture*, FbxString>& textureLocations);
|
||||||
|
|
||||||
FbxRoughMetMaterialInfo(
|
FbxRoughMetMaterialInfo(
|
||||||
|
const FbxUInt64 id,
|
||||||
const FbxString& name,
|
const FbxString& name,
|
||||||
const FbxString& shadingModel,
|
const FbxString& shadingModel,
|
||||||
FbxDouble4 baseColor,
|
FbxDouble4 baseColor,
|
||||||
FbxDouble metallic,
|
FbxDouble metallic,
|
||||||
FbxDouble roughness)
|
FbxDouble roughness)
|
||||||
: FbxMaterialInfo(name, shadingModel),
|
: FbxMaterialInfo(id, name, shadingModel),
|
||||||
baseColor(baseColor),
|
baseColor(baseColor),
|
||||||
metallic(metallic),
|
metallic(metallic),
|
||||||
roughness(roughness) {}
|
roughness(roughness) {}
|
||||||
|
|
|
@ -54,6 +54,7 @@ std::unique_ptr<FbxRoughMetMaterialInfo> FbxStingrayPBSMaterialResolver::resolve
|
||||||
|
|
||||||
FbxDouble3 baseColor = getVec("base_color");
|
FbxDouble3 baseColor = getVec("base_color");
|
||||||
std::unique_ptr<FbxRoughMetMaterialInfo> res(new FbxRoughMetMaterialInfo(
|
std::unique_ptr<FbxRoughMetMaterialInfo> res(new FbxRoughMetMaterialInfo(
|
||||||
|
fbxMaterial->GetUniqueID(),
|
||||||
fbxMaterial->GetName(),
|
fbxMaterial->GetName(),
|
||||||
FbxRoughMetMaterialInfo::FBX_SHADER_METROUGH,
|
FbxRoughMetMaterialInfo::FBX_SHADER_METROUGH,
|
||||||
FbxDouble4(baseColor[0], baseColor[1], baseColor[2], 1),
|
FbxDouble4(baseColor[0], baseColor[1], baseColor[2], 1),
|
||||||
|
|
|
@ -68,8 +68,8 @@ std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialResolver::reso
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string name = fbxMaterial->GetName();
|
std::string name = fbxMaterial->GetName();
|
||||||
std::unique_ptr<FbxTraditionalMaterialInfo> res(
|
std::unique_ptr<FbxTraditionalMaterialInfo> res(new FbxTraditionalMaterialInfo(
|
||||||
new FbxTraditionalMaterialInfo(name.c_str(), fbxMaterial->ShadingModel.Get()));
|
fbxMaterial->GetUniqueID(), name.c_str(), fbxMaterial->ShadingModel.Get()));
|
||||||
|
|
||||||
// four properties are on the same structure and follow the same rules
|
// four properties are on the same structure and follow the same rules
|
||||||
auto handleBasicProperty = [&](const char* colName,
|
auto handleBasicProperty = [&](const char* colName,
|
||||||
|
|
|
@ -14,8 +14,11 @@ struct FbxTraditionalMaterialInfo : FbxMaterialInfo {
|
||||||
static constexpr const char* FBX_SHADER_BLINN = "Blinn";
|
static constexpr const char* FBX_SHADER_BLINN = "Blinn";
|
||||||
static constexpr const char* FBX_SHADER_PHONG = "Phong";
|
static constexpr const char* FBX_SHADER_PHONG = "Phong";
|
||||||
|
|
||||||
FbxTraditionalMaterialInfo(const FbxString& name, const FbxString& shadingModel)
|
FbxTraditionalMaterialInfo(
|
||||||
: FbxMaterialInfo(name, shadingModel) {}
|
const FbxUInt64 id,
|
||||||
|
const FbxString& name,
|
||||||
|
const FbxString& shadingModel)
|
||||||
|
: FbxMaterialInfo(id, name, shadingModel) {}
|
||||||
|
|
||||||
FbxFileTexture* texAmbient{};
|
FbxFileTexture* texAmbient{};
|
||||||
FbxVector4 colAmbient{};
|
FbxVector4 colAmbient{};
|
||||||
|
|
|
@ -77,11 +77,6 @@ static const std::vector<TriangleIndex> getIndexArray(const RawModel& raw) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: replace with a proper MaterialHasher class
|
|
||||||
static const std::string materialHash(const RawMaterial& m) {
|
|
||||||
return m.name + "_" + std::to_string(m.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
ModelData* Raw2Gltf(
|
ModelData* Raw2Gltf(
|
||||||
std::ofstream& gltfOutStream,
|
std::ofstream& gltfOutStream,
|
||||||
const std::string& outputFolder,
|
const std::string& outputFolder,
|
||||||
|
@ -123,7 +118,7 @@ ModelData* Raw2Gltf(
|
||||||
std::unique_ptr<GltfModel> gltf(new GltfModel(options));
|
std::unique_ptr<GltfModel> gltf(new GltfModel(options));
|
||||||
|
|
||||||
std::map<long, std::shared_ptr<NodeData>> nodesById;
|
std::map<long, std::shared_ptr<NodeData>> nodesById;
|
||||||
std::map<std::string, std::shared_ptr<MaterialData>> materialsByName;
|
std::map<long, std::shared_ptr<MaterialData>> materialsById;
|
||||||
std::map<std::string, std::shared_ptr<TextureData>> textureByIndicesKey;
|
std::map<std::string, std::shared_ptr<TextureData>> textureByIndicesKey;
|
||||||
std::map<long, std::shared_ptr<MeshData>> meshBySurfaceId;
|
std::map<long, std::shared_ptr<MeshData>> meshBySurfaceId;
|
||||||
|
|
||||||
|
@ -394,7 +389,8 @@ ModelData* Raw2Gltf(
|
||||||
emissiveFactor * emissiveIntensity,
|
emissiveFactor * emissiveIntensity,
|
||||||
khrCmnUnlitMat,
|
khrCmnUnlitMat,
|
||||||
pbrMetRough));
|
pbrMetRough));
|
||||||
materialsByName[materialHash(material)] = mData;
|
fmt::printf("Stashing material of id %ls, name %s...\n", material.id, material.name.c_str());
|
||||||
|
materialsById[material.id] = mData;
|
||||||
|
|
||||||
if (options.enableUserProperties) {
|
if (options.enableUserProperties) {
|
||||||
mData->userProperties = material.userProperties;
|
mData->userProperties = material.userProperties;
|
||||||
|
@ -408,7 +404,9 @@ ModelData* Raw2Gltf(
|
||||||
|
|
||||||
const RawMaterial& rawMaterial =
|
const RawMaterial& rawMaterial =
|
||||||
surfaceModel.GetMaterial(surfaceModel.GetTriangle(0).materialIndex);
|
surfaceModel.GetMaterial(surfaceModel.GetTriangle(0).materialIndex);
|
||||||
const MaterialData& mData = require(materialsByName, materialHash(rawMaterial));
|
fmt::printf(
|
||||||
|
"Seeking material of id %ls, name %s...\n", rawMaterial.id, rawMaterial.name.c_str());
|
||||||
|
const MaterialData& mData = require(materialsById, rawMaterial.id);
|
||||||
|
|
||||||
MeshData* mesh = nullptr;
|
MeshData* mesh = nullptr;
|
||||||
auto meshIter = meshBySurfaceId.find(surfaceId);
|
auto meshIter = meshBySurfaceId.find(surfaceId);
|
||||||
|
|
|
@ -129,6 +129,7 @@ int RawModel::AddTexture(
|
||||||
|
|
||||||
int RawModel::AddMaterial(const RawMaterial& material) {
|
int RawModel::AddMaterial(const RawMaterial& material) {
|
||||||
return AddMaterial(
|
return AddMaterial(
|
||||||
|
material.id,
|
||||||
material.name.c_str(),
|
material.name.c_str(),
|
||||||
material.type,
|
material.type,
|
||||||
material.textures,
|
material.textures,
|
||||||
|
@ -137,6 +138,7 @@ int RawModel::AddMaterial(const RawMaterial& material) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawModel::AddMaterial(
|
int RawModel::AddMaterial(
|
||||||
|
const long id,
|
||||||
const char* name,
|
const char* name,
|
||||||
const RawMaterialType materialType,
|
const RawMaterialType materialType,
|
||||||
const int textures[RAW_TEXTURE_USAGE_MAX],
|
const int textures[RAW_TEXTURE_USAGE_MAX],
|
||||||
|
@ -169,6 +171,7 @@ int RawModel::AddMaterial(
|
||||||
}
|
}
|
||||||
|
|
||||||
RawMaterial material;
|
RawMaterial material;
|
||||||
|
material.id = id;
|
||||||
material.name = name;
|
material.name = name;
|
||||||
material.type = materialType;
|
material.type = materialType;
|
||||||
material.info = materialInfo;
|
material.info = materialInfo;
|
||||||
|
|
|
@ -262,6 +262,7 @@ struct RawMetRoughMatProps : RawMatProps {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RawMaterial {
|
struct RawMaterial {
|
||||||
|
long id;
|
||||||
std::string name;
|
std::string name;
|
||||||
RawMaterialType type;
|
RawMaterialType type;
|
||||||
std::shared_ptr<RawMatProps> info;
|
std::shared_ptr<RawMatProps> info;
|
||||||
|
@ -374,6 +375,7 @@ class RawModel {
|
||||||
RawTextureUsage usage);
|
RawTextureUsage usage);
|
||||||
int AddMaterial(const RawMaterial& material);
|
int AddMaterial(const RawMaterial& material);
|
||||||
int AddMaterial(
|
int AddMaterial(
|
||||||
|
const long id,
|
||||||
const char* name,
|
const char* name,
|
||||||
const RawMaterialType materialType,
|
const RawMaterialType materialType,
|
||||||
const int textures[RAW_TEXTURE_USAGE_MAX],
|
const int textures[RAW_TEXTURE_USAGE_MAX],
|
||||||
|
|
Loading…
Reference in New Issue