Merge remote-tracking branch 'upstream/master' into feat/mocha-tests
This commit is contained in:
commit
f94b3650f2
|
@ -35,7 +35,7 @@ BreakBeforeTernaryOperators: true
|
||||||
BreakConstructorInitializersBeforeComma: false
|
BreakConstructorInitializersBeforeComma: false
|
||||||
BreakAfterJavaFieldAnnotations: false
|
BreakAfterJavaFieldAnnotations: false
|
||||||
BreakStringLiterals: false
|
BreakStringLiterals: false
|
||||||
ColumnLimit: 80
|
ColumnLimit: 100
|
||||||
CommentPragmas: '^ IWYU pragma:'
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
ConstructorInitializerIndentWidth: 4
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
|
|
@ -35,8 +35,7 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
CLI::App app{
|
CLI::App app{
|
||||||
fmt::sprintf(
|
fmt::sprintf(
|
||||||
"FBX2glTF %s: Generate a glTF 2.0 representation of an FBX model.",
|
"FBX2glTF %s: Generate a glTF 2.0 representation of an FBX model.", FBX2GLTF_VERSION),
|
||||||
FBX2GLTF_VERSION),
|
|
||||||
"FBX2glTF"};
|
"FBX2glTF"};
|
||||||
|
|
||||||
app.add_flag(
|
app.add_flag(
|
||||||
|
@ -45,32 +44,22 @@ int main(int argc, char* argv[]) {
|
||||||
"Include blend shape tangents, if reported present by the FBX SDK.");
|
"Include blend shape tangents, if reported present by the FBX SDK.");
|
||||||
|
|
||||||
app.add_flag_function("-V,--version", [&](size_t count) {
|
app.add_flag_function("-V,--version", [&](size_t count) {
|
||||||
fmt::printf(
|
fmt::printf("FBX2glTF version %s\nCopyright (c) 2016-2018 Oculus VR, LLC.\n", FBX2GLTF_VERSION);
|
||||||
"FBX2glTF version %s\nCopyright (c) 2016-2018 Oculus VR, LLC.\n",
|
|
||||||
FBX2GLTF_VERSION);
|
|
||||||
exit(0);
|
exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
std::string inputPath;
|
std::string inputPath;
|
||||||
app.add_option("FBX Model", inputPath, "The FBX model to convert.")
|
app.add_option("FBX Model", inputPath, "The FBX model to convert.")->check(CLI::ExistingFile);
|
||||||
->check(CLI::ExistingFile);
|
app.add_option("-i,--input", inputPath, "The FBX model to convert.")->check(CLI::ExistingFile);
|
||||||
app.add_option("-i,--input", inputPath, "The FBX model to convert.")
|
|
||||||
->check(CLI::ExistingFile);
|
|
||||||
|
|
||||||
std::string outputPath;
|
std::string outputPath;
|
||||||
app.add_option(
|
app.add_option("-o,--output", outputPath, "Where to generate the output, without suffix.");
|
||||||
"-o,--output",
|
|
||||||
outputPath,
|
|
||||||
"Where to generate the output, without suffix.");
|
|
||||||
|
|
||||||
app.add_flag(
|
app.add_flag(
|
||||||
"-e,--embed",
|
"-e,--embed",
|
||||||
gltfOptions.embedResources,
|
gltfOptions.embedResources,
|
||||||
"Inline buffers as data:// URIs within generated non-binary glTF.");
|
"Inline buffers as data:// URIs within generated non-binary glTF.");
|
||||||
app.add_flag(
|
app.add_flag("-b,--binary", gltfOptions.outputBinary, "Output a single binary format .glb file.");
|
||||||
"-b,--binary",
|
|
||||||
gltfOptions.outputBinary,
|
|
||||||
"Output a single binary format .glb file.");
|
|
||||||
|
|
||||||
app.add_option(
|
app.add_option(
|
||||||
"--long-indices",
|
"--long-indices",
|
||||||
|
@ -119,8 +108,7 @@ int main(int argc, char* argv[]) {
|
||||||
"--flip-u",
|
"--flip-u",
|
||||||
[&](size_t count) {
|
[&](size_t count) {
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
texturesTransforms.emplace_back(
|
texturesTransforms.emplace_back([](Vec2f uv) { return Vec2f(1.0f - uv[0], uv[1]); });
|
||||||
[](Vec2f uv) { return Vec2f(1.0f - uv[0], uv[1]); });
|
|
||||||
if (verboseOutput) {
|
if (verboseOutput) {
|
||||||
fmt::printf("Flipping texture coordinates in the 'U' dimension.\n");
|
fmt::printf("Flipping texture coordinates in the 'U' dimension.\n");
|
||||||
}
|
}
|
||||||
|
@ -128,23 +116,20 @@ int main(int argc, char* argv[]) {
|
||||||
},
|
},
|
||||||
"Flip all U texture coordinates.");
|
"Flip all U texture coordinates.");
|
||||||
|
|
||||||
app.add_flag("--no-flip-u", "Don't flip U texture coordinates.")
|
app.add_flag("--no-flip-u", "Don't flip U texture coordinates.")->excludes("--flip-u");
|
||||||
->excludes("--flip-u");
|
|
||||||
|
|
||||||
app.add_flag_function(
|
app.add_flag_function(
|
||||||
"--no-flip-v",
|
"--no-flip-v",
|
||||||
[&](size_t count) {
|
[&](size_t count) {
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
texturesTransforms.emplace_back(
|
texturesTransforms.emplace_back([](Vec2f uv) { return Vec2f(uv[0], 1.0f - uv[1]); });
|
||||||
[](Vec2f uv) { return Vec2f(uv[0], 1.0f - uv[1]); });
|
|
||||||
if (verboseOutput) {
|
if (verboseOutput) {
|
||||||
fmt::printf("NOT flipping texture coordinates in the 'V' dimension.\n");
|
fmt::printf("NOT flipping texture coordinates in the 'V' dimension.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Flip all V texture coordinates.");
|
"Flip all V texture coordinates.");
|
||||||
app.add_flag("--flip-v", "Don't flip U texture coordinates.")
|
app.add_flag("--flip-v", "Don't flip U texture coordinates.")->excludes("--no-flip-v");
|
||||||
->excludes("--no-flip-v");
|
|
||||||
|
|
||||||
app.add_flag(
|
app.add_flag(
|
||||||
"--pbr-metallic-rougnness",
|
"--pbr-metallic-rougnness",
|
||||||
|
@ -181,8 +166,8 @@ int main(int argc, char* argv[]) {
|
||||||
app.add_option(
|
app.add_option(
|
||||||
"-k,--keep-attribute",
|
"-k,--keep-attribute",
|
||||||
[&](std::vector<std::string> attributes) -> bool {
|
[&](std::vector<std::string> attributes) -> bool {
|
||||||
gltfOptions.keepAttribs = RAW_VERTEX_ATTRIBUTE_JOINT_INDICES |
|
gltfOptions.keepAttribs =
|
||||||
RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS;
|
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS;
|
||||||
for (std::string attribute : attributes) {
|
for (std::string attribute : attributes) {
|
||||||
if (attribute == "position") {
|
if (attribute == "position") {
|
||||||
gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_POSITION;
|
gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_POSITION;
|
||||||
|
@ -212,9 +197,7 @@ int main(int argc, char* argv[]) {
|
||||||
->type_name("(position|normal|tangent|binormial|color|uv0|uv1|auto)");
|
->type_name("(position|normal|tangent|binormial|color|uv0|uv1|auto)");
|
||||||
|
|
||||||
app.add_flag(
|
app.add_flag(
|
||||||
"-d,--draco",
|
"-d,--draco", gltfOptions.draco.enabled, "Apply Draco mesh compression to geometries.")
|
||||||
gltfOptions.draco.enabled,
|
|
||||||
"Apply Draco mesh compression to geometries.")
|
|
||||||
->group("Draco");
|
->group("Draco");
|
||||||
|
|
||||||
app.add_option(
|
app.add_option(
|
||||||
|
@ -301,16 +284,12 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// in gltf mode, we create a folder and write into that
|
// in gltf mode, we create a folder and write into that
|
||||||
outputFolder = fmt::format(
|
outputFolder =
|
||||||
"{}_out{}",
|
fmt::format("{}_out{}", outputPath.c_str(), (const char)StringUtils::GetPathSeparator());
|
||||||
outputPath.c_str(),
|
modelPath = outputFolder + StringUtils::GetFileNameString(outputPath) + ".gltf";
|
||||||
(const char)StringUtils::GetPathSeparator());
|
|
||||||
modelPath =
|
|
||||||
outputFolder + StringUtils::GetFileNameString(outputPath) + ".gltf";
|
|
||||||
}
|
}
|
||||||
if (!FileUtils::CreatePath(modelPath.c_str())) {
|
if (!FileUtils::CreatePath(modelPath.c_str())) {
|
||||||
fmt::fprintf(
|
fmt::fprintf(stderr, "ERROR: Failed to create folder: %s'\n", outputFolder.c_str());
|
||||||
stderr, "ERROR: Failed to create folder: %s'\n", outputFolder.c_str());
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,14 +313,9 @@ int main(int argc, char* argv[]) {
|
||||||
std::ofstream outStream; // note: auto-flushes in destructor
|
std::ofstream outStream; // note: auto-flushes in destructor
|
||||||
const auto streamStart = outStream.tellp();
|
const auto streamStart = outStream.tellp();
|
||||||
|
|
||||||
outStream.open(
|
outStream.open(modelPath, std::ios::trunc | std::ios::ate | std::ios::out | std::ios::binary);
|
||||||
modelPath,
|
|
||||||
std::ios::trunc | std::ios::ate | std::ios::out | std::ios::binary);
|
|
||||||
if (outStream.fail()) {
|
if (outStream.fail()) {
|
||||||
fmt::fprintf(
|
fmt::fprintf(stderr, "ERROR:: Couldn't open file for writing: %s\n", modelPath.c_str());
|
||||||
stderr,
|
|
||||||
"ERROR:: Couldn't open file for writing: %s\n",
|
|
||||||
modelPath.c_str());
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
data_render_model = Raw2Gltf(outStream, outputFolder, raw, gltfOptions);
|
data_render_model = Raw2Gltf(outStream, outputFolder, raw, gltfOptions);
|
||||||
|
@ -371,8 +345,7 @@ int main(int argc, char* argv[]) {
|
||||||
const std::string binaryPath = outputFolder + extBufferFilename;
|
const std::string binaryPath = outputFolder + extBufferFilename;
|
||||||
FILE* fp = fopen(binaryPath.c_str(), "wb");
|
FILE* fp = fopen(binaryPath.c_str(), "wb");
|
||||||
if (fp == nullptr) {
|
if (fp == nullptr) {
|
||||||
fmt::fprintf(
|
fmt::fprintf(stderr, "ERROR:: Couldn't open file '%s' for writing.\n", binaryPath);
|
||||||
stderr, "ERROR:: Couldn't open file '%s' for writing.\n", binaryPath);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,16 +354,12 @@ int main(int argc, char* argv[]) {
|
||||||
unsigned long binarySize = data_render_model->binary->size();
|
unsigned long binarySize = data_render_model->binary->size();
|
||||||
if (fwrite(binaryData, binarySize, 1, fp) != 1) {
|
if (fwrite(binaryData, binarySize, 1, fp) != 1) {
|
||||||
fmt::fprintf(
|
fmt::fprintf(
|
||||||
stderr,
|
stderr, "ERROR: Failed to write %lu bytes to file '%s'.\n", binarySize, binaryPath);
|
||||||
"ERROR: Failed to write %lu bytes to file '%s'.\n",
|
|
||||||
binarySize,
|
|
||||||
binaryPath);
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
fmt::printf(
|
fmt::printf("Wrote %lu bytes of binary data to %s.\n", binarySize, binaryPath);
|
||||||
"Wrote %lu bytes of binary data to %s.\n", binarySize, binaryPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete data_render_model;
|
delete data_render_model;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,6 +11,6 @@
|
||||||
|
|
||||||
#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);
|
||||||
|
|
||||||
json TranscribeProperty(FbxProperty &prop);
|
json TranscribeProperty(FbxProperty& prop);
|
|
@ -9,55 +9,63 @@
|
||||||
|
|
||||||
#include "FbxBlendShapesAccess.hpp"
|
#include "FbxBlendShapesAccess.hpp"
|
||||||
|
|
||||||
FbxBlendShapesAccess::TargetShape::TargetShape(const FbxShape *shape, FbxDouble fullWeight) :
|
FbxBlendShapesAccess::TargetShape::TargetShape(const FbxShape* shape, FbxDouble fullWeight)
|
||||||
shape(shape),
|
: shape(shape),
|
||||||
fullWeight(fullWeight),
|
fullWeight(fullWeight),
|
||||||
count(shape->GetControlPointsCount()),
|
count(shape->GetControlPointsCount()),
|
||||||
positions(shape->GetControlPoints()),
|
positions(shape->GetControlPoints()),
|
||||||
normals(FbxLayerElementAccess<FbxVector4>(shape->GetElementNormal(), shape->GetElementNormalCount())),
|
normals(FbxLayerElementAccess<FbxVector4>(
|
||||||
tangents(FbxLayerElementAccess<FbxVector4>(shape->GetElementTangent(), shape->GetElementTangentCount()))
|
shape->GetElementNormal(),
|
||||||
{}
|
shape->GetElementNormalCount())),
|
||||||
|
tangents(FbxLayerElementAccess<FbxVector4>(
|
||||||
|
shape->GetElementTangent(),
|
||||||
|
shape->GetElementTangentCount())) {}
|
||||||
|
|
||||||
FbxAnimCurve *FbxBlendShapesAccess::BlendChannel::ExtractAnimation(unsigned int animIx) const
|
FbxAnimCurve* FbxBlendShapesAccess::BlendChannel::ExtractAnimation(unsigned int animIx) const {
|
||||||
{
|
FbxAnimStack* stack = mesh->GetScene()->GetSrcObject<FbxAnimStack>(animIx);
|
||||||
FbxAnimStack *stack = mesh->GetScene()->GetSrcObject<FbxAnimStack>(animIx);
|
FbxAnimLayer* layer = stack->GetMember<FbxAnimLayer>(0);
|
||||||
FbxAnimLayer *layer = stack->GetMember<FbxAnimLayer>(0);
|
|
||||||
return mesh->GetShapeChannel(blendShapeIx, channelIx, layer, true);
|
return mesh->GetShapeChannel(blendShapeIx, channelIx, layer, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
FbxBlendShapesAccess::BlendChannel::BlendChannel(
|
FbxBlendShapesAccess::BlendChannel::BlendChannel(
|
||||||
FbxMesh *mesh, const unsigned int blendShapeIx, const unsigned int channelIx, const FbxDouble deformPercent,
|
FbxMesh* mesh,
|
||||||
const std::vector<FbxBlendShapesAccess::TargetShape> &targetShapes, std::string name) : mesh(mesh),
|
const unsigned int blendShapeIx,
|
||||||
|
const unsigned int channelIx,
|
||||||
|
const FbxDouble deformPercent,
|
||||||
|
const std::vector<FbxBlendShapesAccess::TargetShape>& targetShapes,
|
||||||
|
std::string name)
|
||||||
|
: mesh(mesh),
|
||||||
blendShapeIx(blendShapeIx),
|
blendShapeIx(blendShapeIx),
|
||||||
channelIx(channelIx),
|
channelIx(channelIx),
|
||||||
deformPercent(deformPercent),
|
deformPercent(deformPercent),
|
||||||
targetShapes(targetShapes),
|
targetShapes(targetShapes),
|
||||||
name(name)
|
name(name) {}
|
||||||
{}
|
|
||||||
|
|
||||||
std::vector<FbxBlendShapesAccess::BlendChannel> FbxBlendShapesAccess::extractChannels(FbxMesh *mesh) const
|
std::vector<FbxBlendShapesAccess::BlendChannel> FbxBlendShapesAccess::extractChannels(
|
||||||
{
|
FbxMesh* mesh) const {
|
||||||
std::vector<BlendChannel> channels;
|
std::vector<BlendChannel> channels;
|
||||||
for (int shapeIx = 0; shapeIx < mesh->GetDeformerCount(FbxDeformer::eBlendShape); shapeIx++) {
|
for (int shapeIx = 0; shapeIx < mesh->GetDeformerCount(FbxDeformer::eBlendShape); shapeIx++) {
|
||||||
auto *fbxBlendShape = static_cast<FbxBlendShape *>(mesh->GetDeformer(shapeIx, FbxDeformer::eBlendShape));
|
auto* fbxBlendShape =
|
||||||
|
static_cast<FbxBlendShape*>(mesh->GetDeformer(shapeIx, FbxDeformer::eBlendShape));
|
||||||
|
|
||||||
for (int channelIx = 0; channelIx < fbxBlendShape->GetBlendShapeChannelCount(); ++channelIx) {
|
for (int channelIx = 0; channelIx < fbxBlendShape->GetBlendShapeChannelCount(); ++channelIx) {
|
||||||
FbxBlendShapeChannel *fbxChannel = fbxBlendShape->GetBlendShapeChannel(channelIx);
|
FbxBlendShapeChannel* fbxChannel = fbxBlendShape->GetBlendShapeChannel(channelIx);
|
||||||
|
|
||||||
if (fbxChannel->GetTargetShapeCount() > 0) {
|
if (fbxChannel->GetTargetShapeCount() > 0) {
|
||||||
std::vector<TargetShape> targetShapes;
|
std::vector<TargetShape> targetShapes;
|
||||||
const double *fullWeights = fbxChannel->GetTargetShapeFullWeights();
|
const double* fullWeights = fbxChannel->GetTargetShapeFullWeights();
|
||||||
std::string name = std::string(fbxChannel->GetName());
|
std::string name = std::string(fbxChannel->GetName());
|
||||||
|
|
||||||
if (verboseOutput) {
|
if (verboseOutput) {
|
||||||
fmt::printf("\rblendshape channel: %s\n", name);
|
fmt::printf("\rblendshape channel: %s\n", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int targetIx = 0; targetIx < fbxChannel->GetTargetShapeCount(); targetIx ++) {
|
for (int targetIx = 0; targetIx < fbxChannel->GetTargetShapeCount(); targetIx++) {
|
||||||
FbxShape *fbxShape = fbxChannel->GetTargetShape(targetIx);
|
FbxShape* fbxShape = fbxChannel->GetTargetShape(targetIx);
|
||||||
targetShapes.emplace_back(fbxShape, fullWeights[targetIx]);
|
targetShapes.emplace_back(fbxShape, fullWeights[targetIx]);
|
||||||
}
|
}
|
||||||
channels.emplace_back(mesh, shapeIx, channelIx, fbxChannel->DeformPercent * 0.01, targetShapes, name);
|
channels.emplace_back(
|
||||||
|
mesh, shapeIx, channelIx, fbxChannel->DeformPercent * 0.01, targetShapes, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,47 +9,47 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include "FBX2glTF.h"
|
#include "FBX2glTF.h"
|
||||||
#include "FbxLayerElementAccess.hpp"
|
#include "FbxLayerElementAccess.hpp"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* At the FBX level, each Mesh can have a set of FbxBlendShape deformers; organisational units that contain no data
|
* At the FBX level, each Mesh can have a set of FbxBlendShape deformers; organisational units that
|
||||||
* of their own. The actual deformation is determined by one or more FbxBlendShapeChannels, whose influences are all
|
* contain no data of their own. The actual deformation is determined by one or more
|
||||||
* additively applied to the mesh. In a simpler world, each such channel would extend each base vertex with alternate
|
* FbxBlendShapeChannels, whose influences are all additively applied to the mesh. In a simpler
|
||||||
* position, and optionally normal and tangent.
|
* world, each such channel would extend each base vertex with alternate position, and optionally
|
||||||
|
* normal and tangent.
|
||||||
*
|
*
|
||||||
* It's not quite so simple, though. We also have progressive morphing, where one logical morph actually consists of
|
* It's not quite so simple, though. We also have progressive morphing, where one logical morph
|
||||||
* several concrete ones, each applied in sequence. For us, this means each channel contains a sequence of FbxShapes
|
* actually consists of several concrete ones, each applied in sequence. For us, this means each
|
||||||
* (aka target shape); these are the actual data-holding entities that provide the alternate vertex attributes. As such
|
* channel contains a sequence of FbxShapes (aka target shape); these are the actual data-holding
|
||||||
* a channel is given more weight, it moves from one target shape to another.
|
* entities that provide the alternate vertex attributes. As such a channel is given more weight, it
|
||||||
|
* moves from one target shape to another.
|
||||||
*
|
*
|
||||||
* The total number of alternate sets of attributes, then, is the total number of target shapes across all the channels
|
* The total number of alternate sets of attributes, then, is the total number of target shapes
|
||||||
* of all the blend shapes of the mesh.
|
* across all the channels of all the blend shapes of the mesh.
|
||||||
*
|
*
|
||||||
* Each animation in the scene stack can yield one or zero FbxAnimCurves per channel (not target shape). We evaluate
|
* Each animation in the scene stack can yield one or zero FbxAnimCurves per channel (not target
|
||||||
* these curves to get the weight of the channel: this weight is further introspected on to figure out which target
|
* shape). We evaluate these curves to get the weight of the channel: this weight is further
|
||||||
* shapes we're currently interpolation between.
|
* introspected on to figure out which target shapes we're currently interpolation between.
|
||||||
*/
|
*/
|
||||||
class FbxBlendShapesAccess
|
class FbxBlendShapesAccess {
|
||||||
{
|
public:
|
||||||
public:
|
|
||||||
/**
|
/**
|
||||||
* A target shape is on a 1:1 basis with the eventual glTF morph target, and is the object which contains the
|
* A target shape is on a 1:1 basis with the eventual glTF morph target, and is the object which
|
||||||
* actual morphed vertex data.
|
* contains the actual morphed vertex data.
|
||||||
*/
|
*/
|
||||||
struct TargetShape
|
struct TargetShape {
|
||||||
{
|
explicit TargetShape(const FbxShape* shape, FbxDouble fullWeight);
|
||||||
explicit TargetShape(const FbxShape *shape, FbxDouble fullWeight);
|
|
||||||
|
|
||||||
const FbxShape *shape;
|
const FbxShape* shape;
|
||||||
const FbxDouble fullWeight;
|
const FbxDouble fullWeight;
|
||||||
const unsigned int count;
|
const unsigned int count;
|
||||||
const FbxVector4 *positions;
|
const FbxVector4* positions;
|
||||||
const FbxLayerElementAccess<FbxVector4> normals;
|
const FbxLayerElementAccess<FbxVector4> normals;
|
||||||
const FbxLayerElementAccess<FbxVector4> tangents;
|
const FbxLayerElementAccess<FbxVector4> tangents;
|
||||||
};
|
};
|
||||||
|
@ -57,20 +57,18 @@ public:
|
||||||
/**
|
/**
|
||||||
* A channel collects a sequence (often of length 1) of target shapes.
|
* A channel collects a sequence (often of length 1) of target shapes.
|
||||||
*/
|
*/
|
||||||
struct BlendChannel
|
struct BlendChannel {
|
||||||
{
|
|
||||||
BlendChannel(
|
BlendChannel(
|
||||||
FbxMesh *mesh,
|
FbxMesh* mesh,
|
||||||
const unsigned int blendShapeIx,
|
const unsigned int blendShapeIx,
|
||||||
const unsigned int channelIx,
|
const unsigned int channelIx,
|
||||||
const FbxDouble deformPercent,
|
const FbxDouble deformPercent,
|
||||||
const std::vector<TargetShape> &targetShapes,
|
const std::vector<TargetShape>& targetShapes,
|
||||||
const std::string name
|
const std::string name);
|
||||||
);
|
|
||||||
|
|
||||||
FbxAnimCurve *ExtractAnimation(unsigned int animIx) const;
|
FbxAnimCurve* ExtractAnimation(unsigned int animIx) const;
|
||||||
|
|
||||||
FbxMesh *const mesh;
|
FbxMesh* const mesh;
|
||||||
|
|
||||||
const unsigned int blendShapeIx;
|
const unsigned int blendShapeIx;
|
||||||
const unsigned int channelIx;
|
const unsigned int channelIx;
|
||||||
|
@ -80,26 +78,28 @@ public:
|
||||||
const FbxDouble deformPercent;
|
const FbxDouble deformPercent;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit FbxBlendShapesAccess(FbxMesh *mesh) :
|
explicit FbxBlendShapesAccess(FbxMesh* mesh) : channels(extractChannels(mesh)) {}
|
||||||
channels(extractChannels(mesh))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
size_t GetChannelCount() const { return channels.size(); }
|
size_t GetChannelCount() const {
|
||||||
const BlendChannel &GetBlendChannel(size_t channelIx) const {
|
return channels.size();
|
||||||
|
}
|
||||||
|
const BlendChannel& GetBlendChannel(size_t channelIx) const {
|
||||||
return channels.at(channelIx);
|
return channels.at(channelIx);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GetTargetShapeCount(size_t channelIx) const { return channels[channelIx].targetShapes.size(); }
|
size_t GetTargetShapeCount(size_t channelIx) const {
|
||||||
const TargetShape &GetTargetShape(size_t channelIx, size_t targetShapeIx) const {
|
return channels[channelIx].targetShapes.size();
|
||||||
|
}
|
||||||
|
const TargetShape& GetTargetShape(size_t channelIx, size_t targetShapeIx) const {
|
||||||
return channels.at(channelIx).targetShapes[targetShapeIx];
|
return channels.at(channelIx).targetShapes[targetShapeIx];
|
||||||
}
|
}
|
||||||
|
|
||||||
FbxAnimCurve * GetAnimation(size_t channelIx, size_t animIx) const {
|
FbxAnimCurve* GetAnimation(size_t channelIx, size_t animIx) const {
|
||||||
return channels.at(channelIx).ExtractAnimation(animIx);
|
return channels.at(channelIx).ExtractAnimation(animIx);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<BlendChannel> extractChannels(FbxMesh *mesh) const;
|
std::vector<BlendChannel> extractChannels(FbxMesh* mesh) const;
|
||||||
|
|
||||||
const std::vector<BlendChannel> channels;
|
const std::vector<BlendChannel> channels;
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,35 +9,39 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "FBX2glTF.h"
|
#include "FBX2glTF.h"
|
||||||
|
|
||||||
template<typename _type_>
|
template <typename _type_>
|
||||||
class FbxLayerElementAccess
|
class FbxLayerElementAccess {
|
||||||
{
|
public:
|
||||||
public:
|
FbxLayerElementAccess(const FbxLayerElementTemplate<_type_>* layer, int count);
|
||||||
|
|
||||||
FbxLayerElementAccess(const FbxLayerElementTemplate<_type_> *layer, int count);
|
bool LayerPresent() const {
|
||||||
|
|
||||||
bool LayerPresent() const
|
|
||||||
{
|
|
||||||
return (mappingMode != FbxLayerElement::eNone);
|
return (mappingMode != FbxLayerElement::eNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
_type_ GetElement(const int polygonIndex, const int polygonVertexIndex, const int controlPointIndex, const _type_ defaultValue) const;
|
|
||||||
_type_ GetElement(
|
_type_ GetElement(
|
||||||
const int polygonIndex, const int polygonVertexIndex, const int controlPointIndex, const _type_ defaultValue,
|
const int polygonIndex,
|
||||||
const FbxMatrix &transform, const bool normalize) const;
|
const int polygonVertexIndex,
|
||||||
|
const int controlPointIndex,
|
||||||
|
const _type_ defaultValue) const;
|
||||||
|
_type_ GetElement(
|
||||||
|
const int polygonIndex,
|
||||||
|
const int polygonVertexIndex,
|
||||||
|
const int controlPointIndex,
|
||||||
|
const _type_ defaultValue,
|
||||||
|
const FbxMatrix& transform,
|
||||||
|
const bool normalize) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FbxLayerElement::EMappingMode mappingMode;
|
FbxLayerElement::EMappingMode mappingMode;
|
||||||
const FbxLayerElementArrayTemplate<_type_> *elements;
|
const FbxLayerElementArrayTemplate<_type_>* elements;
|
||||||
const FbxLayerElementArrayTemplate<int> *indices;
|
const FbxLayerElementArrayTemplate<int>* indices;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename _type_>
|
template <typename _type_>
|
||||||
FbxLayerElementAccess<_type_>::FbxLayerElementAccess(const FbxLayerElementTemplate<_type_> *layer, int count) :
|
FbxLayerElementAccess<_type_>::FbxLayerElementAccess(
|
||||||
mappingMode(FbxLayerElement::eNone),
|
const FbxLayerElementTemplate<_type_>* layer,
|
||||||
elements(nullptr),
|
int count)
|
||||||
indices(nullptr)
|
: mappingMode(FbxLayerElement::eNone), elements(nullptr), indices(nullptr) {
|
||||||
{
|
|
||||||
if (count <= 0 || layer == nullptr) {
|
if (count <= 0 || layer == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -47,19 +51,23 @@ FbxLayerElementAccess<_type_>::FbxLayerElementAccess(const FbxLayerElementTempla
|
||||||
newMappingMode == FbxLayerElement::eByPolygon) {
|
newMappingMode == FbxLayerElement::eByPolygon) {
|
||||||
mappingMode = newMappingMode;
|
mappingMode = newMappingMode;
|
||||||
elements = &layer->GetDirectArray();
|
elements = &layer->GetDirectArray();
|
||||||
indices = (
|
indices = (layer->GetReferenceMode() == FbxLayerElement::eIndexToDirect ||
|
||||||
layer->GetReferenceMode() == FbxLayerElement::eIndexToDirect ||
|
layer->GetReferenceMode() == FbxLayerElement::eIndex)
|
||||||
layer->GetReferenceMode() == FbxLayerElement::eIndex) ? &layer->GetIndexArray() : nullptr;
|
? &layer->GetIndexArray()
|
||||||
|
: nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename _type_>
|
template <typename _type_>
|
||||||
_type_ FbxLayerElementAccess<_type_>::GetElement(
|
_type_ FbxLayerElementAccess<_type_>::GetElement(
|
||||||
const int polygonIndex, const int polygonVertexIndex, const int controlPointIndex, const _type_ defaultValue) const
|
const int polygonIndex,
|
||||||
{
|
const int polygonVertexIndex,
|
||||||
|
const int controlPointIndex,
|
||||||
|
const _type_ defaultValue) const {
|
||||||
if (mappingMode != FbxLayerElement::eNone) {
|
if (mappingMode != FbxLayerElement::eNone) {
|
||||||
int index = (mappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex :
|
int index = (mappingMode == FbxLayerElement::eByControlPoint)
|
||||||
((mappingMode == FbxLayerElement::eByPolygonVertex) ? polygonVertexIndex : polygonIndex);
|
? controlPointIndex
|
||||||
|
: ((mappingMode == FbxLayerElement::eByPolygonVertex) ? polygonVertexIndex : polygonIndex);
|
||||||
index = (indices != nullptr) ? (*indices)[index] : index;
|
index = (indices != nullptr) ? (*indices)[index] : index;
|
||||||
_type_ element = elements->GetAt(index);
|
_type_ element = elements->GetAt(index);
|
||||||
return element;
|
return element;
|
||||||
|
@ -67,13 +75,17 @@ _type_ FbxLayerElementAccess<_type_>::GetElement(
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename _type_>
|
template <typename _type_>
|
||||||
_type_ FbxLayerElementAccess<_type_>::GetElement(
|
_type_ FbxLayerElementAccess<_type_>::GetElement(
|
||||||
const int polygonIndex, const int polygonVertexIndex, const int controlPointIndex, const _type_ defaultValue,
|
const int polygonIndex,
|
||||||
const FbxMatrix &transform, const bool normalize) const
|
const int polygonVertexIndex,
|
||||||
{
|
const int controlPointIndex,
|
||||||
|
const _type_ defaultValue,
|
||||||
|
const FbxMatrix& transform,
|
||||||
|
const bool normalize) const {
|
||||||
if (mappingMode != FbxLayerElement::eNone) {
|
if (mappingMode != FbxLayerElement::eNone) {
|
||||||
_type_ element = transform.MultNormalize(GetElement(polygonIndex, polygonVertexIndex, controlPointIndex, defaultValue));
|
_type_ element = transform.MultNormalize(
|
||||||
|
GetElement(polygonIndex, polygonVertexIndex, controlPointIndex, defaultValue));
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
element.Normalize();
|
element.Normalize();
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,9 @@
|
||||||
#include "FBX2glTF.h"
|
#include "FBX2glTF.h"
|
||||||
|
|
||||||
class FbxMaterialInfo {
|
class FbxMaterialInfo {
|
||||||
public:
|
public:
|
||||||
FbxMaterialInfo(const FbxString &name, const FbxString &shadingModel)
|
FbxMaterialInfo(const FbxString& name, const FbxString& shadingModel)
|
||||||
: name(name),
|
: name(name), shadingModel(shadingModel) {}
|
||||||
shadingModel(shadingModel) {}
|
|
||||||
|
|
||||||
const FbxString name;
|
const FbxString name;
|
||||||
const FbxString shadingModel;
|
const FbxString shadingModel;
|
||||||
|
|
|
@ -10,21 +10,23 @@
|
||||||
#include "FbxMaterialsAccess.hpp"
|
#include "FbxMaterialsAccess.hpp"
|
||||||
#include "Fbx2Raw.hpp"
|
#include "Fbx2Raw.hpp"
|
||||||
|
|
||||||
FbxMaterialsAccess::FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<const FbxTexture *, FbxString> &textureLocations) :
|
FbxMaterialsAccess::FbxMaterialsAccess(
|
||||||
mappingMode(FbxGeometryElement::eNone),
|
const FbxMesh* pMesh,
|
||||||
mesh(nullptr),
|
const std::map<const FbxTexture*, FbxString>& textureLocations)
|
||||||
indices(nullptr)
|
: mappingMode(FbxGeometryElement::eNone), mesh(nullptr), indices(nullptr) {
|
||||||
{
|
|
||||||
if (pMesh->GetElementMaterialCount() <= 0) {
|
if (pMesh->GetElementMaterialCount() <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FbxGeometryElement::EMappingMode materialMappingMode = pMesh->GetElementMaterial()->GetMappingMode();
|
const FbxGeometryElement::EMappingMode materialMappingMode =
|
||||||
if (materialMappingMode != FbxGeometryElement::eByPolygon && materialMappingMode != FbxGeometryElement::eAllSame) {
|
pMesh->GetElementMaterial()->GetMappingMode();
|
||||||
|
if (materialMappingMode != FbxGeometryElement::eByPolygon &&
|
||||||
|
materialMappingMode != FbxGeometryElement::eAllSame) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FbxGeometryElement::EReferenceMode materialReferenceMode = pMesh->GetElementMaterial()->GetReferenceMode();
|
const FbxGeometryElement::EReferenceMode materialReferenceMode =
|
||||||
|
pMesh->GetElementMaterial()->GetReferenceMode();
|
||||||
if (materialReferenceMode != FbxGeometryElement::eIndexToDirect) {
|
if (materialReferenceMode != FbxGeometryElement::eIndexToDirect) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -39,16 +41,15 @@ FbxMaterialsAccess::FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<cons
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
FbxSurfaceMaterial* surfaceMaterial = mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(materialNum);
|
FbxSurfaceMaterial* surfaceMaterial =
|
||||||
|
mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(materialNum);
|
||||||
|
|
||||||
if (materialNum >= summaries.size()) {
|
if (materialNum >= summaries.size()) {
|
||||||
summaries.resize(materialNum + 1);
|
summaries.resize(materialNum + 1);
|
||||||
}
|
}
|
||||||
auto summary = summaries[materialNum];
|
auto summary = summaries[materialNum];
|
||||||
if (summary == nullptr) {
|
if (summary == nullptr) {
|
||||||
summary = summaries[materialNum] = GetMaterialInfo(
|
summary = summaries[materialNum] = GetMaterialInfo(surfaceMaterial, textureLocations);
|
||||||
surfaceMaterial,
|
|
||||||
textureLocations);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (materialNum >= userProperties.size()) {
|
if (materialNum >= userProperties.size()) {
|
||||||
|
@ -56,8 +57,7 @@ FbxMaterialsAccess::FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<cons
|
||||||
}
|
}
|
||||||
if (userProperties[materialNum].empty()) {
|
if (userProperties[materialNum].empty()) {
|
||||||
FbxProperty objectProperty = surfaceMaterial->GetFirstProperty();
|
FbxProperty objectProperty = surfaceMaterial->GetFirstProperty();
|
||||||
while (objectProperty.IsValid())
|
while (objectProperty.IsValid()) {
|
||||||
{
|
|
||||||
if (objectProperty.GetFlag(FbxPropertyFlags::eUserDefined)) {
|
if (objectProperty.GetFlag(FbxPropertyFlags::eUserDefined)) {
|
||||||
userProperties[materialNum].push_back(TranscribeProperty(objectProperty).dump());
|
userProperties[materialNum].push_back(TranscribeProperty(objectProperty).dump());
|
||||||
}
|
}
|
||||||
|
@ -67,22 +67,23 @@ FbxMaterialsAccess::FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<cons
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::shared_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterial(const int polygonIndex) const
|
const std::shared_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterial(
|
||||||
{
|
const int polygonIndex) const {
|
||||||
if (mappingMode != FbxGeometryElement::eNone) {
|
if (mappingMode != FbxGeometryElement::eNone) {
|
||||||
const int materialNum = indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
|
const int materialNum =
|
||||||
|
indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
|
||||||
if (materialNum < 0) {
|
if (materialNum < 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return summaries.at((unsigned long) materialNum);
|
return summaries.at((unsigned long)materialNum);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string> FbxMaterialsAccess::GetUserProperties(const int polygonIndex) const
|
const std::vector<std::string> FbxMaterialsAccess::GetUserProperties(const int polygonIndex) const {
|
||||||
{
|
|
||||||
if (mappingMode != FbxGeometryElement::eNone) {
|
if (mappingMode != FbxGeometryElement::eNone) {
|
||||||
const int materialNum = indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
|
const int materialNum =
|
||||||
|
indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
|
||||||
if (materialNum < 0) {
|
if (materialNum < 0) {
|
||||||
return std::vector<std::string>();
|
return std::vector<std::string>();
|
||||||
}
|
}
|
||||||
|
@ -91,9 +92,9 @@ const std::vector<std::string> FbxMaterialsAccess::GetUserProperties(const int p
|
||||||
return std::vector<std::string>();
|
return std::vector<std::string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<FbxMaterialInfo>
|
std::unique_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterialInfo(
|
||||||
FbxMaterialsAccess::GetMaterialInfo(FbxSurfaceMaterial *material, const std::map<const FbxTexture *, FbxString> &textureLocations)
|
FbxSurfaceMaterial* material,
|
||||||
{
|
const std::map<const FbxTexture*, FbxString>& textureLocations) {
|
||||||
std::unique_ptr<FbxMaterialInfo> res;
|
std::unique_ptr<FbxMaterialInfo> res;
|
||||||
res = FbxRoughMetMaterialInfo::From(material, textureLocations);
|
res = FbxRoughMetMaterialInfo::From(material, textureLocations);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
|
@ -101,4 +102,3 @@ FbxMaterialsAccess::GetMaterialInfo(FbxSurfaceMaterial *material, const std::map
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,26 +11,27 @@
|
||||||
|
|
||||||
#include "Fbx2Raw.hpp"
|
#include "Fbx2Raw.hpp"
|
||||||
#include "FbxMaterialInfo.hpp"
|
#include "FbxMaterialInfo.hpp"
|
||||||
#include "FbxTraditionalMaterialInfo.hpp"
|
|
||||||
#include "FbxRoughMetMaterialInfo.hpp"
|
#include "FbxRoughMetMaterialInfo.hpp"
|
||||||
|
#include "FbxTraditionalMaterialInfo.hpp"
|
||||||
|
|
||||||
class FbxMaterialsAccess
|
class FbxMaterialsAccess {
|
||||||
{
|
public:
|
||||||
public:
|
FbxMaterialsAccess(
|
||||||
|
const FbxMesh* pMesh,
|
||||||
FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<const FbxTexture *, FbxString> &textureLocations);
|
const std::map<const FbxTexture*, FbxString>& textureLocations);
|
||||||
|
|
||||||
const std::shared_ptr<FbxMaterialInfo> GetMaterial(const int polygonIndex) const;
|
const std::shared_ptr<FbxMaterialInfo> GetMaterial(const int polygonIndex) const;
|
||||||
|
|
||||||
const std::vector<std::string> GetUserProperties(const int polygonIndex) const;
|
const std::vector<std::string> GetUserProperties(const int polygonIndex) const;
|
||||||
|
|
||||||
std::unique_ptr<FbxMaterialInfo>
|
std::unique_ptr<FbxMaterialInfo> GetMaterialInfo(
|
||||||
GetMaterialInfo(FbxSurfaceMaterial *material, const std::map<const FbxTexture *, FbxString> &textureLocations);
|
FbxSurfaceMaterial* material,
|
||||||
|
const std::map<const FbxTexture*, FbxString>& textureLocations);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FbxGeometryElement::EMappingMode mappingMode;
|
FbxGeometryElement::EMappingMode mappingMode;
|
||||||
std::vector<std::shared_ptr<FbxMaterialInfo>> summaries {};
|
std::vector<std::shared_ptr<FbxMaterialInfo>> summaries{};
|
||||||
std::vector<std::vector<std::string>> userProperties;
|
std::vector<std::vector<std::string>> userProperties;
|
||||||
const FbxMesh *mesh;
|
const FbxMesh* mesh;
|
||||||
const FbxLayerElementArrayTemplate<int> *indices;
|
const FbxLayerElementArrayTemplate<int>* indices;
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,24 +7,27 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "FbxRoughMetMaterialInfo.hpp"
|
#include "FbxRoughMetMaterialInfo.hpp"
|
||||||
|
|
||||||
std::unique_ptr<FbxRoughMetMaterialInfo>
|
std::unique_ptr<FbxRoughMetMaterialInfo> FbxRoughMetMaterialInfo::From(
|
||||||
FbxRoughMetMaterialInfo::From(FbxSurfaceMaterial *fbxMaterial, const std::map<const FbxTexture *, FbxString> &textureLocations)
|
FbxSurfaceMaterial* fbxMaterial,
|
||||||
{
|
const std::map<const FbxTexture*, FbxString>& textureLocations) {
|
||||||
std::unique_ptr<FbxRoughMetMaterialInfo> res(new FbxRoughMetMaterialInfo(fbxMaterial->GetName(), FBX_SHADER_METROUGH));
|
std::unique_ptr<FbxRoughMetMaterialInfo> res(
|
||||||
|
new FbxRoughMetMaterialInfo(fbxMaterial->GetName(), FBX_SHADER_METROUGH));
|
||||||
|
|
||||||
const FbxProperty mayaProp = fbxMaterial->FindProperty("Maya");
|
const FbxProperty mayaProp = fbxMaterial->FindProperty("Maya");
|
||||||
if (mayaProp.GetPropertyDataType() != FbxCompoundDT) {
|
if (mayaProp.GetPropertyDataType() != FbxCompoundDT) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (!fbxMaterial->ShadingModel.Get().IsEmpty()) {
|
if (!fbxMaterial->ShadingModel.Get().IsEmpty()) {
|
||||||
::fmt::printf("Warning: Material %s has surprising shading model: %s\n",
|
::fmt::printf(
|
||||||
fbxMaterial->GetName(), fbxMaterial->ShadingModel.Get());
|
"Warning: Material %s has surprising shading model: %s\n",
|
||||||
|
fbxMaterial->GetName(),
|
||||||
|
fbxMaterial->ShadingModel.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto getTex = [&](std::string propName) {
|
auto getTex = [&](std::string propName) {
|
||||||
const FbxFileTexture *ptr = nullptr;
|
const FbxFileTexture* ptr = nullptr;
|
||||||
|
|
||||||
const FbxProperty useProp = mayaProp.FindHierarchical(("use_" + propName + "_map").c_str());
|
const FbxProperty useProp = mayaProp.FindHierarchical(("use_" + propName + "_map").c_str());
|
||||||
if (useProp.IsValid() && useProp.Get<bool>()) {
|
if (useProp.IsValid() && useProp.Get<bool>()) {
|
||||||
|
@ -36,8 +39,10 @@ FbxRoughMetMaterialInfo::From(FbxSurfaceMaterial *fbxMaterial, const std::map<co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (verboseOutput && useProp.IsValid()) {
|
} else if (verboseOutput && useProp.IsValid()) {
|
||||||
fmt::printf("Note: Property '%s' of material '%s' exists, but is flagged as 'do not use'.\n",
|
fmt::printf(
|
||||||
propName, fbxMaterial->GetName());
|
"Note: Property '%s' of material '%s' exists, but is flagged as 'do not use'.\n",
|
||||||
|
propName,
|
||||||
|
fbxMaterial->GetName());
|
||||||
}
|
}
|
||||||
return ptr;
|
return ptr;
|
||||||
};
|
};
|
||||||
|
@ -48,7 +53,7 @@ FbxRoughMetMaterialInfo::From(FbxSurfaceMaterial *fbxMaterial, const std::map<co
|
||||||
};
|
};
|
||||||
|
|
||||||
auto getVal = [&](std::string propName) -> FbxDouble {
|
auto getVal = [&](std::string propName) -> FbxDouble {
|
||||||
const FbxProperty vecProp = mayaProp.FindHierarchical(propName .c_str());
|
const FbxProperty vecProp = mayaProp.FindHierarchical(propName.c_str());
|
||||||
return vecProp.IsValid() ? vecProp.Get<FbxDouble>() : 0;
|
return vecProp.IsValid() ? vecProp.Get<FbxDouble>() : 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,36 +7,35 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
|
||||||
#include <set>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include "FbxMaterialInfo.hpp"
|
#include "FbxMaterialInfo.hpp"
|
||||||
|
|
||||||
struct FbxRoughMetMaterialInfo : FbxMaterialInfo {
|
struct FbxRoughMetMaterialInfo : FbxMaterialInfo {
|
||||||
static constexpr const char *FBX_SHADER_METROUGH = "MetallicRoughness";
|
static constexpr const char* FBX_SHADER_METROUGH = "MetallicRoughness";
|
||||||
|
|
||||||
static std::unique_ptr<FbxRoughMetMaterialInfo> From(
|
static std::unique_ptr<FbxRoughMetMaterialInfo> From(
|
||||||
FbxSurfaceMaterial *fbxMaterial,
|
FbxSurfaceMaterial* fbxMaterial,
|
||||||
const std::map<const FbxTexture *, FbxString> &textureLocations);
|
const std::map<const FbxTexture*, FbxString>& textureLocations);
|
||||||
|
|
||||||
FbxRoughMetMaterialInfo(const FbxString &name, const FbxString &shadingModel)
|
FbxRoughMetMaterialInfo(const FbxString& name, const FbxString& shadingModel)
|
||||||
: FbxMaterialInfo(name, shadingModel)
|
: FbxMaterialInfo(name, shadingModel) {}
|
||||||
{}
|
|
||||||
|
|
||||||
const FbxFileTexture *texColor {};
|
const FbxFileTexture* texColor{};
|
||||||
FbxVector4 colBase {};
|
FbxVector4 colBase{};
|
||||||
const FbxFileTexture *texNormal {};
|
const FbxFileTexture* texNormal{};
|
||||||
const FbxFileTexture *texMetallic {};
|
const FbxFileTexture* texMetallic{};
|
||||||
FbxDouble metallic {};
|
FbxDouble metallic{};
|
||||||
const FbxFileTexture *texRoughness {};
|
const FbxFileTexture* texRoughness{};
|
||||||
FbxDouble roughness {};
|
FbxDouble roughness{};
|
||||||
const FbxFileTexture *texEmissive {};
|
const FbxFileTexture* texEmissive{};
|
||||||
FbxVector4 colEmissive {};
|
FbxVector4 colEmissive{};
|
||||||
FbxDouble emissiveIntensity {};
|
FbxDouble emissiveIntensity{};
|
||||||
const FbxFileTexture *texAmbientOcclusion {};
|
const FbxFileTexture* texAmbientOcclusion{};
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
|
|
||||||
#include "FbxSkinningAccess.hpp"
|
#include "FbxSkinningAccess.hpp"
|
||||||
|
|
||||||
FbxSkinningAccess::FbxSkinningAccess(const FbxMesh *pMesh, FbxScene *pScene, FbxNode *pNode)
|
FbxSkinningAccess::FbxSkinningAccess(const FbxMesh* pMesh, FbxScene* pScene, FbxNode* pNode)
|
||||||
: rootIndex(-1)
|
: rootIndex(-1) {
|
||||||
{
|
|
||||||
for (int deformerIndex = 0; deformerIndex < pMesh->GetDeformerCount(); deformerIndex++) {
|
for (int deformerIndex = 0; deformerIndex < pMesh->GetDeformerCount(); deformerIndex++) {
|
||||||
FbxSkin *skin = reinterpret_cast< FbxSkin * >( pMesh->GetDeformer(deformerIndex, FbxDeformer::eSkin));
|
FbxSkin* skin =
|
||||||
|
reinterpret_cast<FbxSkin*>(pMesh->GetDeformer(deformerIndex, FbxDeformer::eSkin));
|
||||||
if (skin != nullptr) {
|
if (skin != nullptr) {
|
||||||
const int clusterCount = skin->GetClusterCount();
|
const int clusterCount = skin->GetClusterCount();
|
||||||
if (clusterCount == 0) {
|
if (clusterCount == 0) {
|
||||||
|
@ -24,10 +24,10 @@ FbxSkinningAccess::FbxSkinningAccess(const FbxMesh *pMesh, FbxScene *pScene, Fbx
|
||||||
vertexJointWeights.resize(controlPointCount, Vec4f(0.0f, 0.0f, 0.0f, 0.0f));
|
vertexJointWeights.resize(controlPointCount, Vec4f(0.0f, 0.0f, 0.0f, 0.0f));
|
||||||
|
|
||||||
for (int clusterIndex = 0; clusterIndex < clusterCount; clusterIndex++) {
|
for (int clusterIndex = 0; clusterIndex < clusterCount; clusterIndex++) {
|
||||||
FbxCluster *cluster = skin->GetCluster(clusterIndex);
|
FbxCluster* cluster = skin->GetCluster(clusterIndex);
|
||||||
const int indexCount = cluster->GetControlPointIndicesCount();
|
const int indexCount = cluster->GetControlPointIndicesCount();
|
||||||
const int *clusterIndices = cluster->GetControlPointIndices();
|
const int* clusterIndices = cluster->GetControlPointIndices();
|
||||||
const double *clusterWeights = cluster->GetControlPointWeights();
|
const double* clusterWeights = cluster->GetControlPointWeights();
|
||||||
|
|
||||||
assert(cluster->GetLinkMode() == FbxCluster::eNormalize);
|
assert(cluster->GetLinkMode() == FbxCluster::eNormalize);
|
||||||
|
|
||||||
|
@ -47,7 +47,8 @@ FbxSkinningAccess::FbxSkinningAccess(const FbxMesh *pMesh, FbxScene *pScene, Fbx
|
||||||
jointIds.push_back(cluster->GetLink()->GetUniqueID());
|
jointIds.push_back(cluster->GetLink()->GetUniqueID());
|
||||||
|
|
||||||
const FbxAMatrix globalNodeTransform = cluster->GetLink()->EvaluateGlobalTransform();
|
const FbxAMatrix globalNodeTransform = cluster->GetLink()->EvaluateGlobalTransform();
|
||||||
jointSkinningTransforms.push_back(FbxMatrix(globalNodeTransform * globalBindposeInverseMatrix));
|
jointSkinningTransforms.push_back(
|
||||||
|
FbxMatrix(globalNodeTransform * globalBindposeInverseMatrix));
|
||||||
jointInverseGlobalTransforms.push_back(FbxMatrix(globalNodeTransform.Inverse()));
|
jointInverseGlobalTransforms.push_back(FbxMatrix(globalNodeTransform.Inverse()));
|
||||||
|
|
||||||
for (int i = 0; i < indexCount; i++) {
|
for (int i = 0; i < indexCount; i++) {
|
||||||
|
@ -58,16 +59,20 @@ FbxSkinningAccess::FbxSkinningAccess(const FbxMesh *pMesh, FbxScene *pScene, Fbx
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
vertexJointIndices[clusterIndices[i]][MAX_WEIGHTS - 1] = clusterIndex;
|
vertexJointIndices[clusterIndices[i]][MAX_WEIGHTS - 1] = clusterIndex;
|
||||||
vertexJointWeights[clusterIndices[i]][MAX_WEIGHTS - 1] = (float) clusterWeights[i];
|
vertexJointWeights[clusterIndices[i]][MAX_WEIGHTS - 1] = (float)clusterWeights[i];
|
||||||
for (int j = MAX_WEIGHTS - 1; j > 0; j--) {
|
for (int j = MAX_WEIGHTS - 1; j > 0; j--) {
|
||||||
if (vertexJointWeights[clusterIndices[i]][j - 1] >= vertexJointWeights[clusterIndices[i]][j]) {
|
if (vertexJointWeights[clusterIndices[i]][j - 1] >=
|
||||||
|
vertexJointWeights[clusterIndices[i]][j]) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
std::swap(vertexJointIndices[clusterIndices[i]][j - 1], vertexJointIndices[clusterIndices[i]][j]);
|
std::swap(
|
||||||
std::swap(vertexJointWeights[clusterIndices[i]][j - 1], vertexJointWeights[clusterIndices[i]][j]);
|
vertexJointIndices[clusterIndices[i]][j - 1],
|
||||||
|
vertexJointIndices[clusterIndices[i]][j]);
|
||||||
|
std::swap(
|
||||||
|
vertexJointWeights[clusterIndices[i]][j - 1],
|
||||||
|
vertexJointWeights[clusterIndices[i]][j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
for (int i = 0; i < controlPointCount; i++) {
|
for (int i = 0; i < controlPointCount; i++) {
|
||||||
vertexJointWeights[i] = vertexJointWeights[i].Normalized();
|
vertexJointWeights[i] = vertexJointWeights[i].Normalized();
|
||||||
|
@ -77,8 +82,8 @@ FbxSkinningAccess::FbxSkinningAccess(const FbxMesh *pMesh, FbxScene *pScene, Fbx
|
||||||
|
|
||||||
rootIndex = -1;
|
rootIndex = -1;
|
||||||
for (size_t i = 0; i < jointNodes.size() && rootIndex == -1; i++) {
|
for (size_t i = 0; i < jointNodes.size() && rootIndex == -1; i++) {
|
||||||
rootIndex = (int) i;
|
rootIndex = (int)i;
|
||||||
FbxNode *parent = jointNodes[i]->GetParent();
|
FbxNode* parent = jointNodes[i]->GetParent();
|
||||||
if (parent == nullptr) {
|
if (parent == nullptr) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,81 +9,69 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
|
||||||
#include <set>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include "FBX2glTF.h"
|
#include "FBX2glTF.h"
|
||||||
|
|
||||||
class FbxSkinningAccess
|
class FbxSkinningAccess {
|
||||||
{
|
public:
|
||||||
public:
|
|
||||||
|
|
||||||
static const int MAX_WEIGHTS = 4;
|
static const int MAX_WEIGHTS = 4;
|
||||||
|
|
||||||
FbxSkinningAccess(const FbxMesh *pMesh, FbxScene *pScene, FbxNode *pNode);
|
FbxSkinningAccess(const FbxMesh* pMesh, FbxScene* pScene, FbxNode* pNode);
|
||||||
|
|
||||||
bool IsSkinned() const
|
bool IsSkinned() const {
|
||||||
{
|
|
||||||
return (vertexJointWeights.size() > 0);
|
return (vertexJointWeights.size() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetNodeCount() const
|
int GetNodeCount() const {
|
||||||
{
|
return (int)jointNodes.size();
|
||||||
return (int) jointNodes.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FbxNode *GetJointNode(const int jointIndex) const
|
FbxNode* GetJointNode(const int jointIndex) const {
|
||||||
{
|
|
||||||
return jointNodes[jointIndex];
|
return jointNodes[jointIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
const long GetJointId(const int jointIndex) const
|
const long GetJointId(const int jointIndex) const {
|
||||||
{
|
|
||||||
return jointIds[jointIndex];
|
return jointIds[jointIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
const FbxMatrix &GetJointSkinningTransform(const int jointIndex) const
|
const FbxMatrix& GetJointSkinningTransform(const int jointIndex) const {
|
||||||
{
|
|
||||||
return jointSkinningTransforms[jointIndex];
|
return jointSkinningTransforms[jointIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
const FbxMatrix &GetJointInverseGlobalTransforms(const int jointIndex) const
|
const FbxMatrix& GetJointInverseGlobalTransforms(const int jointIndex) const {
|
||||||
{
|
|
||||||
return jointInverseGlobalTransforms[jointIndex];
|
return jointInverseGlobalTransforms[jointIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
const long GetRootNode() const
|
const long GetRootNode() const {
|
||||||
{
|
|
||||||
assert(rootIndex != -1);
|
assert(rootIndex != -1);
|
||||||
return jointIds[rootIndex];
|
return jointIds[rootIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
const FbxAMatrix &GetInverseBindMatrix(const int jointIndex) const
|
const FbxAMatrix& GetInverseBindMatrix(const int jointIndex) const {
|
||||||
{
|
|
||||||
return inverseBindMatrices[jointIndex];
|
return inverseBindMatrices[jointIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Vec4i GetVertexIndices(const int controlPointIndex) const
|
const Vec4i GetVertexIndices(const int controlPointIndex) const {
|
||||||
{
|
return (!vertexJointIndices.empty()) ? vertexJointIndices[controlPointIndex]
|
||||||
return (!vertexJointIndices.empty()) ?
|
: Vec4i(0, 0, 0, 0);
|
||||||
vertexJointIndices[controlPointIndex] : Vec4i(0, 0, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Vec4f GetVertexWeights(const int controlPointIndex) const
|
const Vec4f GetVertexWeights(const int controlPointIndex) const {
|
||||||
{
|
return (!vertexJointWeights.empty()) ? vertexJointWeights[controlPointIndex]
|
||||||
return (!vertexJointWeights.empty()) ?
|
: Vec4f(0, 0, 0, 0);
|
||||||
vertexJointWeights[controlPointIndex] : Vec4f(0, 0, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int rootIndex;
|
int rootIndex;
|
||||||
std::vector<long> jointIds;
|
std::vector<long> jointIds;
|
||||||
std::vector<FbxNode *> jointNodes;
|
std::vector<FbxNode*> jointNodes;
|
||||||
std::vector<FbxMatrix> jointSkinningTransforms;
|
std::vector<FbxMatrix> jointSkinningTransforms;
|
||||||
std::vector<FbxMatrix> jointInverseGlobalTransforms;
|
std::vector<FbxMatrix> jointInverseGlobalTransforms;
|
||||||
std::vector<FbxAMatrix> inverseBindMatrices;
|
std::vector<FbxAMatrix> inverseBindMatrices;
|
||||||
|
|
|
@ -9,14 +9,14 @@
|
||||||
|
|
||||||
#include "FbxTraditionalMaterialInfo.hpp"
|
#include "FbxTraditionalMaterialInfo.hpp"
|
||||||
|
|
||||||
std::unique_ptr<FbxTraditionalMaterialInfo>
|
std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialInfo::From(
|
||||||
FbxTraditionalMaterialInfo::From(FbxSurfaceMaterial *fbxMaterial, const std::map<const FbxTexture *, FbxString> &textureLocations)
|
FbxSurfaceMaterial* fbxMaterial,
|
||||||
{
|
const std::map<const FbxTexture*, FbxString>& textureLocations) {
|
||||||
auto getSurfaceScalar = [&](const char *propName) -> std::tuple<FbxDouble, FbxFileTexture *> {
|
auto getSurfaceScalar = [&](const char* propName) -> std::tuple<FbxDouble, FbxFileTexture*> {
|
||||||
const FbxProperty prop = fbxMaterial->FindProperty(propName);
|
const FbxProperty prop = fbxMaterial->FindProperty(propName);
|
||||||
|
|
||||||
FbxDouble val(0);
|
FbxDouble val(0);
|
||||||
FbxFileTexture *tex = prop.GetSrcObject<FbxFileTexture>();
|
FbxFileTexture* tex = prop.GetSrcObject<FbxFileTexture>();
|
||||||
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
|
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
|
||||||
tex = nullptr;
|
tex = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -26,11 +26,11 @@ FbxTraditionalMaterialInfo::From(FbxSurfaceMaterial *fbxMaterial, const std::map
|
||||||
return std::make_tuple(val, tex);
|
return std::make_tuple(val, tex);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto getSurfaceVector = [&](const char *propName) -> std::tuple<FbxDouble3, FbxFileTexture *> {
|
auto getSurfaceVector = [&](const char* propName) -> std::tuple<FbxDouble3, FbxFileTexture*> {
|
||||||
const FbxProperty prop = fbxMaterial->FindProperty(propName);
|
const FbxProperty prop = fbxMaterial->FindProperty(propName);
|
||||||
|
|
||||||
FbxDouble3 val(1, 1, 1);
|
FbxDouble3 val(1, 1, 1);
|
||||||
FbxFileTexture *tex = prop.GetSrcObject<FbxFileTexture>();
|
FbxFileTexture* tex = prop.GetSrcObject<FbxFileTexture>();
|
||||||
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
|
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
|
||||||
tex = nullptr;
|
tex = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -40,21 +40,23 @@ FbxTraditionalMaterialInfo::From(FbxSurfaceMaterial *fbxMaterial, const std::map
|
||||||
return std::make_tuple(val, tex);
|
return std::make_tuple(val, tex);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto getSurfaceValues = [&](const char *colName, const char *facName) -> std::tuple<FbxVector4, FbxFileTexture *, FbxFileTexture *> {
|
auto getSurfaceValues =
|
||||||
|
[&](const char* colName,
|
||||||
|
const char* facName) -> std::tuple<FbxVector4, FbxFileTexture*, FbxFileTexture*> {
|
||||||
const FbxProperty colProp = fbxMaterial->FindProperty(colName);
|
const FbxProperty colProp = fbxMaterial->FindProperty(colName);
|
||||||
const FbxProperty facProp = fbxMaterial->FindProperty(facName);
|
const FbxProperty facProp = fbxMaterial->FindProperty(facName);
|
||||||
|
|
||||||
FbxDouble3 colorVal(1, 1, 1);
|
FbxDouble3 colorVal(1, 1, 1);
|
||||||
FbxDouble factorVal(1);
|
FbxDouble factorVal(1);
|
||||||
|
|
||||||
FbxFileTexture *colTex = colProp.GetSrcObject<FbxFileTexture>();
|
FbxFileTexture* colTex = colProp.GetSrcObject<FbxFileTexture>();
|
||||||
if (colTex != nullptr && textureLocations.find(colTex) == textureLocations.end()) {
|
if (colTex != nullptr && textureLocations.find(colTex) == textureLocations.end()) {
|
||||||
colTex = nullptr;
|
colTex = nullptr;
|
||||||
}
|
}
|
||||||
if (colTex == nullptr && colProp.IsValid()) {
|
if (colTex == nullptr && colProp.IsValid()) {
|
||||||
colorVal = colProp.Get<FbxDouble3>();
|
colorVal = colProp.Get<FbxDouble3>();
|
||||||
}
|
}
|
||||||
FbxFileTexture *facTex = facProp.GetSrcObject<FbxFileTexture>();
|
FbxFileTexture* facTex = facProp.GetSrcObject<FbxFileTexture>();
|
||||||
if (facTex != nullptr && textureLocations.find(facTex) == textureLocations.end()) {
|
if (facTex != nullptr && textureLocations.find(facTex) == textureLocations.end()) {
|
||||||
facTex = nullptr;
|
facTex = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -63,25 +65,29 @@ FbxTraditionalMaterialInfo::From(FbxSurfaceMaterial *fbxMaterial, const std::map
|
||||||
}
|
}
|
||||||
|
|
||||||
auto val = FbxVector4(
|
auto val = FbxVector4(
|
||||||
colorVal[0] * factorVal,
|
colorVal[0] * factorVal, colorVal[1] * factorVal, colorVal[2] * factorVal, factorVal);
|
||||||
colorVal[1] * factorVal,
|
|
||||||
colorVal[2] * factorVal,
|
|
||||||
factorVal);
|
|
||||||
return std::make_tuple(val, colTex, facTex);
|
return std::make_tuple(val, colTex, facTex);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string name = fbxMaterial->GetName();
|
std::string name = fbxMaterial->GetName();
|
||||||
std::unique_ptr<FbxTraditionalMaterialInfo> res(new FbxTraditionalMaterialInfo(name.c_str(), fbxMaterial->ShadingModel.Get()));
|
std::unique_ptr<FbxTraditionalMaterialInfo> res(
|
||||||
|
new FbxTraditionalMaterialInfo(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, const char *facName) -> std::tuple<FbxVector4, FbxFileTexture *>{
|
auto handleBasicProperty = [&](const char* colName,
|
||||||
|
const char* facName) -> std::tuple<FbxVector4, FbxFileTexture*> {
|
||||||
FbxFileTexture *colTex, *facTex;
|
FbxFileTexture *colTex, *facTex;
|
||||||
FbxVector4 vec;
|
FbxVector4 vec;
|
||||||
|
|
||||||
std::tie(vec, colTex, facTex) = getSurfaceValues(colName, facName);
|
std::tie(vec, colTex, facTex) = getSurfaceValues(colName, facName);
|
||||||
if (colTex) {
|
if (colTex) {
|
||||||
if (facTex) {
|
if (facTex) {
|
||||||
fmt::printf("Warning: Mat [%s]: Can't handle both %s and %s textures; discarding %s.\n", name, colName, facName, facName);
|
fmt::printf(
|
||||||
|
"Warning: Mat [%s]: Can't handle both %s and %s textures; discarding %s.\n",
|
||||||
|
name,
|
||||||
|
colName,
|
||||||
|
facName,
|
||||||
|
facName);
|
||||||
}
|
}
|
||||||
return std::make_tuple(vec, colTex);
|
return std::make_tuple(vec, colTex);
|
||||||
}
|
}
|
||||||
|
@ -109,16 +115,23 @@ FbxTraditionalMaterialInfo::From(FbxSurfaceMaterial *fbxMaterial, const std::map
|
||||||
FbxVector4 transparency;
|
FbxVector4 transparency;
|
||||||
// extract any existing textures only so we can warn that we're throwing them away
|
// extract any existing textures only so we can warn that we're throwing them away
|
||||||
FbxFileTexture *colTex, *facTex;
|
FbxFileTexture *colTex, *facTex;
|
||||||
std::tie(transparency, colTex, facTex) =
|
std::tie(transparency, colTex, facTex) = getSurfaceValues(
|
||||||
getSurfaceValues(FbxSurfaceMaterial::sTransparentColor, FbxSurfaceMaterial::sTransparencyFactor);
|
FbxSurfaceMaterial::sTransparentColor, FbxSurfaceMaterial::sTransparencyFactor);
|
||||||
if (colTex) {
|
if (colTex) {
|
||||||
fmt::printf("Warning: Mat [%s]: Can't handle texture for %s; discarding.\n", name, FbxSurfaceMaterial::sTransparentColor);
|
fmt::printf(
|
||||||
|
"Warning: Mat [%s]: Can't handle texture for %s; discarding.\n",
|
||||||
|
name,
|
||||||
|
FbxSurfaceMaterial::sTransparentColor);
|
||||||
}
|
}
|
||||||
if (facTex) {
|
if (facTex) {
|
||||||
fmt::printf("Warning: Mat [%s]: Can't handle texture for %s; discarding.\n", name, FbxSurfaceMaterial::sTransparencyFactor);
|
fmt::printf(
|
||||||
|
"Warning: Mat [%s]: Can't handle texture for %s; discarding.\n",
|
||||||
|
name,
|
||||||
|
FbxSurfaceMaterial::sTransparencyFactor);
|
||||||
}
|
}
|
||||||
// FBX color is RGB, so we calculate the A channel as the average of the FBX transparency color vector
|
// FBX color is RGB, so we calculate the A channel as the average of the FBX transparency color
|
||||||
res->colDiffuse[3] = 1.0 - (transparency[0] + transparency[1] + transparency[2])/3.0;
|
// vector
|
||||||
|
res->colDiffuse[3] = 1.0 - (transparency[0] + transparency[1] + transparency[2]) / 3.0;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,38 +7,37 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
|
||||||
#include <set>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include "FbxMaterialInfo.hpp"
|
#include "FbxMaterialInfo.hpp"
|
||||||
|
|
||||||
struct FbxTraditionalMaterialInfo : FbxMaterialInfo {
|
struct FbxTraditionalMaterialInfo : FbxMaterialInfo {
|
||||||
static constexpr const char *FBX_SHADER_LAMBERT = "Lambert";
|
static constexpr const char* FBX_SHADER_LAMBERT = "Lambert";
|
||||||
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(const FbxString& name, const FbxString& shadingModel)
|
||||||
: FbxMaterialInfo(name, shadingModel)
|
: FbxMaterialInfo(name, shadingModel) {}
|
||||||
{}
|
|
||||||
|
|
||||||
FbxFileTexture *texAmbient {};
|
FbxFileTexture* texAmbient{};
|
||||||
FbxVector4 colAmbient {};
|
FbxVector4 colAmbient{};
|
||||||
FbxFileTexture *texSpecular {};
|
FbxFileTexture* texSpecular{};
|
||||||
FbxVector4 colSpecular {};
|
FbxVector4 colSpecular{};
|
||||||
FbxFileTexture *texDiffuse {};
|
FbxFileTexture* texDiffuse{};
|
||||||
FbxVector4 colDiffuse {};
|
FbxVector4 colDiffuse{};
|
||||||
FbxFileTexture *texEmissive {};
|
FbxFileTexture* texEmissive{};
|
||||||
FbxVector4 colEmissive {};
|
FbxVector4 colEmissive{};
|
||||||
FbxFileTexture *texNormal {};
|
FbxFileTexture* texNormal{};
|
||||||
FbxFileTexture *texShininess {};
|
FbxFileTexture* texShininess{};
|
||||||
FbxDouble shininess {};
|
FbxDouble shininess{};
|
||||||
|
|
||||||
static std::unique_ptr<FbxTraditionalMaterialInfo> From(
|
static std::unique_ptr<FbxTraditionalMaterialInfo> From(
|
||||||
FbxSurfaceMaterial *fbxMaterial,
|
FbxSurfaceMaterial* fbxMaterial,
|
||||||
const std::map<const FbxTexture *, FbxString> &textureLocations);
|
const std::map<const FbxTexture*, FbxString>& textureLocations);
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,12 +18,14 @@ std::unique_ptr<FbxRoughMetMaterialInfo> Fbx3dsMaxPhysicalMaterialResolver::reso
|
||||||
|
|
||||||
FbxString shadingModel = fbxMaterial->ShadingModel.Get();
|
FbxString shadingModel = fbxMaterial->ShadingModel.Get();
|
||||||
if (!shadingModel.IsEmpty() && shadingModel != "unknown") {
|
if (!shadingModel.IsEmpty() && shadingModel != "unknown") {
|
||||||
::fmt::printf("Warning: Material %s has surprising shading model: %s\n",
|
::fmt::printf(
|
||||||
fbxMaterial->GetName(), shadingModel);
|
"Warning: Material %s has surprising shading model: %s\n",
|
||||||
|
fbxMaterial->GetName(),
|
||||||
|
shadingModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto getTex = [&](std::string propName) -> const FbxFileTexture * {
|
auto getTex = [&](std::string propName) -> const FbxFileTexture* {
|
||||||
const FbxFileTexture *ptr = nullptr;
|
const FbxFileTexture* ptr = nullptr;
|
||||||
|
|
||||||
const FbxProperty useProp = props.FindHierarchical((propName + "_map_on").c_str());
|
const FbxProperty useProp = props.FindHierarchical((propName + "_map_on").c_str());
|
||||||
if (useProp.IsValid() && useProp.Get<bool>()) {
|
if (useProp.IsValid() && useProp.Get<bool>()) {
|
||||||
|
@ -35,8 +37,10 @@ std::unique_ptr<FbxRoughMetMaterialInfo> Fbx3dsMaxPhysicalMaterialResolver::reso
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (verboseOutput && useProp.IsValid()) {
|
} else if (verboseOutput && useProp.IsValid()) {
|
||||||
fmt::printf("Note: property '%s' of 3dsMax Physical material '%s' exists, but is flagged as 'off'.\n",
|
fmt::printf(
|
||||||
propName, fbxMaterial->GetName());
|
"Note: property '%s' of 3dsMax Physical material '%s' exists, but is flagged as 'off'.\n",
|
||||||
|
propName,
|
||||||
|
fbxMaterial->GetName());
|
||||||
}
|
}
|
||||||
return ptr;
|
return ptr;
|
||||||
};
|
};
|
||||||
|
@ -46,21 +50,21 @@ std::unique_ptr<FbxRoughMetMaterialInfo> Fbx3dsMaxPhysicalMaterialResolver::reso
|
||||||
|
|
||||||
// baseWeight && baseColor
|
// baseWeight && baseColor
|
||||||
FbxDouble baseWeight = getValue(props, "base_weight", 1.0);
|
FbxDouble baseWeight = getValue(props, "base_weight", 1.0);
|
||||||
const auto *baseWeightMap = getTex("base_weight");
|
const auto* baseWeightMap = getTex("base_weight");
|
||||||
FbxDouble4 baseCol = getValue(props, "base_color", FbxDouble4(0.5, 0.5, 0.5, 1.0));
|
FbxDouble4 baseCol = getValue(props, "base_color", FbxDouble4(0.5, 0.5, 0.5, 1.0));
|
||||||
const auto *baseTex = getTex("base_color");
|
const auto* baseTex = getTex("base_color");
|
||||||
|
|
||||||
double emissiveWeight = getValue(props, "emission", 0.0);
|
double emissiveWeight = getValue(props, "emission", 0.0);
|
||||||
const auto *emissiveWeightMap = getTex("emission");
|
const auto* emissiveWeightMap = getTex("emission");
|
||||||
FbxDouble4 emissiveColor = getValue(props, "emit_color", FbxDouble4(1, 1, 1, 1));
|
FbxDouble4 emissiveColor = getValue(props, "emit_color", FbxDouble4(1, 1, 1, 1));
|
||||||
const auto *emissiveColorMap = getTex("emit_color");
|
const auto* emissiveColorMap = getTex("emit_color");
|
||||||
// TODO: emit_luminance, emit_kelvin?
|
// TODO: emit_luminance, emit_kelvin?
|
||||||
|
|
||||||
// roughness & metalness: supported
|
// roughness & metalness: supported
|
||||||
double roughness = getValue(props, "roughness", 0.0);
|
double roughness = getValue(props, "roughness", 0.0);
|
||||||
const auto *roughnessMap = getTex("roughness");
|
const auto* roughnessMap = getTex("roughness");
|
||||||
double metalness = getValue(props, "metalness", 0.0);
|
double metalness = getValue(props, "metalness", 0.0);
|
||||||
const auto *metalnessMap = getTex("metalness");
|
const auto* metalnessMap = getTex("metalness");
|
||||||
|
|
||||||
// TODO: does invertRoughness affect roughness_map too?
|
// TODO: does invertRoughness affect roughness_map too?
|
||||||
bool invertRoughness = getValue(props, "inv_roughness", false);
|
bool invertRoughness = getValue(props, "inv_roughness", false);
|
||||||
|
@ -70,17 +74,17 @@ std::unique_ptr<FbxRoughMetMaterialInfo> Fbx3dsMaxPhysicalMaterialResolver::reso
|
||||||
|
|
||||||
// TODO: attempt to bake transparency > 0.0f into the alpha of baseColour?
|
// TODO: attempt to bake transparency > 0.0f into the alpha of baseColour?
|
||||||
double transparency = getValue(props, "transparency", 0.0);
|
double transparency = getValue(props, "transparency", 0.0);
|
||||||
const auto *transparencyMap = getTex("transparency");
|
const auto* transparencyMap = getTex("transparency");
|
||||||
|
|
||||||
// SSS: not supported
|
// SSS: not supported
|
||||||
double scattering = getValue(props, "scattering", 0.0);
|
double scattering = getValue(props, "scattering", 0.0);
|
||||||
const auto *scatteringMap = getTex("scattering");
|
const auto* scatteringMap = getTex("scattering");
|
||||||
|
|
||||||
// reflectivity: not supported
|
// reflectivity: not supported
|
||||||
double reflectivityWeight = getValue(props, "reflectivity", 1.);
|
double reflectivityWeight = getValue(props, "reflectivity", 1.);
|
||||||
const auto *reflectivityWeightMap = getTex("reflectivity");
|
const auto* reflectivityWeightMap = getTex("reflectivity");
|
||||||
FbxDouble4 reflectivityColor = getValue(props, "refl_color", FbxDouble4(1, 1, 1, 1));
|
FbxDouble4 reflectivityColor = getValue(props, "refl_color", FbxDouble4(1, 1, 1, 1));
|
||||||
const auto *reflectivityColorMap = getTex("refl_color");
|
const auto* reflectivityColorMap = getTex("refl_color");
|
||||||
|
|
||||||
// coatings: not supported
|
// coatings: not supported
|
||||||
double coating = getValue(props, "coating", 0.0);
|
double coating = getValue(props, "coating", 0.0);
|
||||||
|
@ -95,18 +99,15 @@ std::unique_ptr<FbxRoughMetMaterialInfo> Fbx3dsMaxPhysicalMaterialResolver::reso
|
||||||
double anisotropy = getValue(props, "anisotropy", 1.0);
|
double anisotropy = getValue(props, "anisotropy", 1.0);
|
||||||
|
|
||||||
// TODO: how the heck do we combine these to generate a normal map?
|
// TODO: how the heck do we combine these to generate a normal map?
|
||||||
const auto *bumpMap = getTex("bump");
|
const auto* bumpMap = getTex("bump");
|
||||||
const auto *displacementMap = getTex("displacement");
|
const auto* displacementMap = getTex("displacement");
|
||||||
|
|
||||||
std::unique_ptr<FbxRoughMetMaterialInfo> res(
|
std::unique_ptr<FbxRoughMetMaterialInfo> res(new FbxRoughMetMaterialInfo(
|
||||||
new FbxRoughMetMaterialInfo(
|
|
||||||
fbxMaterial->GetName(),
|
fbxMaterial->GetName(),
|
||||||
FbxRoughMetMaterialInfo::FBX_SHADER_METROUGH,
|
FbxRoughMetMaterialInfo::FBX_SHADER_METROUGH,
|
||||||
baseCol,
|
baseCol,
|
||||||
metalness,
|
metalness,
|
||||||
roughness
|
roughness));
|
||||||
)
|
|
||||||
);
|
|
||||||
res->texBaseColor = baseTex;
|
res->texBaseColor = baseTex;
|
||||||
res->baseWeight = baseWeight;
|
res->baseWeight = baseWeight;
|
||||||
res->texBaseWeight = baseWeightMap;
|
res->texBaseWeight = baseWeightMap;
|
||||||
|
|
|
@ -11,21 +11,23 @@
|
||||||
#include "RoughnessMetallicMaterials.hpp"
|
#include "RoughnessMetallicMaterials.hpp"
|
||||||
#include "TraditionalMaterials.hpp"
|
#include "TraditionalMaterials.hpp"
|
||||||
|
|
||||||
FbxMaterialsAccess::FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<const FbxTexture *, FbxString> &textureLocations) :
|
FbxMaterialsAccess::FbxMaterialsAccess(
|
||||||
mappingMode(FbxGeometryElement::eNone),
|
const FbxMesh* pMesh,
|
||||||
mesh(nullptr),
|
const std::map<const FbxTexture*, FbxString>& textureLocations)
|
||||||
indices(nullptr)
|
: mappingMode(FbxGeometryElement::eNone), mesh(nullptr), indices(nullptr) {
|
||||||
{
|
|
||||||
if (pMesh->GetElementMaterialCount() <= 0) {
|
if (pMesh->GetElementMaterialCount() <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FbxGeometryElement::EMappingMode materialMappingMode = pMesh->GetElementMaterial()->GetMappingMode();
|
const FbxGeometryElement::EMappingMode materialMappingMode =
|
||||||
if (materialMappingMode != FbxGeometryElement::eByPolygon && materialMappingMode != FbxGeometryElement::eAllSame) {
|
pMesh->GetElementMaterial()->GetMappingMode();
|
||||||
|
if (materialMappingMode != FbxGeometryElement::eByPolygon &&
|
||||||
|
materialMappingMode != FbxGeometryElement::eAllSame) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FbxGeometryElement::EReferenceMode materialReferenceMode = pMesh->GetElementMaterial()->GetReferenceMode();
|
const FbxGeometryElement::EReferenceMode materialReferenceMode =
|
||||||
|
pMesh->GetElementMaterial()->GetReferenceMode();
|
||||||
if (materialReferenceMode != FbxGeometryElement::eIndexToDirect) {
|
if (materialReferenceMode != FbxGeometryElement::eIndexToDirect) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -45,28 +47,29 @@ FbxMaterialsAccess::FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<cons
|
||||||
auto summary = summaries[materialNum];
|
auto summary = summaries[materialNum];
|
||||||
if (summary == nullptr) {
|
if (summary == nullptr) {
|
||||||
summary = summaries[materialNum] = GetMaterialInfo(
|
summary = summaries[materialNum] = GetMaterialInfo(
|
||||||
mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(materialNum),
|
mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(materialNum), textureLocations);
|
||||||
textureLocations);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::shared_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterial(const int polygonIndex) const
|
const std::shared_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterial(
|
||||||
{
|
const int polygonIndex) const {
|
||||||
if (mappingMode != FbxGeometryElement::eNone) {
|
if (mappingMode != FbxGeometryElement::eNone) {
|
||||||
const int materialNum = indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
|
const int materialNum =
|
||||||
|
indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
|
||||||
if (materialNum < 0) {
|
if (materialNum < 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return summaries.at((unsigned long) materialNum);
|
return summaries.at((unsigned long)materialNum);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<FbxMaterialInfo>
|
std::unique_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterialInfo(
|
||||||
FbxMaterialsAccess::GetMaterialInfo(FbxSurfaceMaterial *material, const std::map<const FbxTexture *, FbxString> &textureLocations)
|
FbxSurfaceMaterial* material,
|
||||||
{
|
const std::map<const FbxTexture*, FbxString>& textureLocations) {
|
||||||
std::unique_ptr<FbxMaterialInfo> res = FbxStingrayPBSMaterialResolver(material, textureLocations).resolve();
|
std::unique_ptr<FbxMaterialInfo> res =
|
||||||
|
FbxStingrayPBSMaterialResolver(material, textureLocations).resolve();
|
||||||
if (res == nullptr) {
|
if (res == nullptr) {
|
||||||
res = Fbx3dsMaxPhysicalMaterialResolver(material, textureLocations).resolve();
|
res = Fbx3dsMaxPhysicalMaterialResolver(material, textureLocations).resolve();
|
||||||
if (res == nullptr) {
|
if (res == nullptr) {
|
||||||
|
@ -75,4 +78,3 @@ FbxMaterialsAccess::GetMaterialInfo(FbxSurfaceMaterial *material, const std::map
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,46 +15,43 @@
|
||||||
#include "FBX2glTF.h"
|
#include "FBX2glTF.h"
|
||||||
|
|
||||||
class FbxMaterialInfo {
|
class FbxMaterialInfo {
|
||||||
public:
|
public:
|
||||||
FbxMaterialInfo(const FbxString &name, const FbxString &shadingModel)
|
FbxMaterialInfo(const FbxString& name, const FbxString& shadingModel)
|
||||||
: name(name)
|
: name(name), shadingModel(shadingModel) {}
|
||||||
, shadingModel(shadingModel)
|
|
||||||
{}
|
|
||||||
|
|
||||||
const FbxString name;
|
const FbxString name;
|
||||||
const FbxString shadingModel;
|
const FbxString shadingModel;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class FbxMaterialResolver
|
class FbxMaterialResolver {
|
||||||
{
|
public:
|
||||||
public:
|
|
||||||
FbxMaterialResolver(
|
FbxMaterialResolver(
|
||||||
FbxSurfaceMaterial *fbxMaterial,
|
FbxSurfaceMaterial* fbxMaterial,
|
||||||
const std::map<const FbxTexture *, FbxString> &textureLocations)
|
const std::map<const FbxTexture*, FbxString>& textureLocations)
|
||||||
: fbxMaterial(fbxMaterial)
|
: fbxMaterial(fbxMaterial), textureLocations(textureLocations) {}
|
||||||
, textureLocations(textureLocations)
|
|
||||||
{}
|
|
||||||
virtual std::unique_ptr<T> resolve() const = 0;
|
virtual std::unique_ptr<T> resolve() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const FbxSurfaceMaterial *fbxMaterial;
|
const FbxSurfaceMaterial* fbxMaterial;
|
||||||
const std::map<const FbxTexture *, FbxString> textureLocations;
|
const std::map<const FbxTexture*, FbxString> textureLocations;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FbxMaterialsAccess
|
class FbxMaterialsAccess {
|
||||||
{
|
public:
|
||||||
public:
|
FbxMaterialsAccess(
|
||||||
FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<const FbxTexture *, FbxString> &textureLocations);
|
const FbxMesh* pMesh,
|
||||||
|
const std::map<const FbxTexture*, FbxString>& textureLocations);
|
||||||
|
|
||||||
const std::shared_ptr<FbxMaterialInfo> GetMaterial(const int polygonIndex) const;
|
const std::shared_ptr<FbxMaterialInfo> GetMaterial(const int polygonIndex) const;
|
||||||
|
|
||||||
std::unique_ptr<FbxMaterialInfo>
|
std::unique_ptr<FbxMaterialInfo> GetMaterialInfo(
|
||||||
GetMaterialInfo(FbxSurfaceMaterial *material, const std::map<const FbxTexture *, FbxString> &textureLocations);
|
FbxSurfaceMaterial* material,
|
||||||
|
const std::map<const FbxTexture*, FbxString>& textureLocations);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FbxGeometryElement::EMappingMode mappingMode;
|
FbxGeometryElement::EMappingMode mappingMode;
|
||||||
std::vector<std::shared_ptr<FbxMaterialInfo>> summaries {};
|
std::vector<std::shared_ptr<FbxMaterialInfo>> summaries{};
|
||||||
const FbxMesh *mesh;
|
const FbxMesh* mesh;
|
||||||
const FbxLayerElementArrayTemplate<int> *indices;
|
const FbxLayerElementArrayTemplate<int>* indices;
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,24 +14,22 @@
|
||||||
#include "FbxMaterials.hpp"
|
#include "FbxMaterials.hpp"
|
||||||
|
|
||||||
struct FbxRoughMetMaterialInfo : FbxMaterialInfo {
|
struct FbxRoughMetMaterialInfo : FbxMaterialInfo {
|
||||||
static constexpr const char *FBX_SHADER_METROUGH = "MetallicRoughness";
|
static constexpr const char* FBX_SHADER_METROUGH = "MetallicRoughness";
|
||||||
|
|
||||||
static std::unique_ptr<FbxRoughMetMaterialInfo> From(
|
static std::unique_ptr<FbxRoughMetMaterialInfo> From(
|
||||||
FbxSurfaceMaterial *fbxMaterial,
|
FbxSurfaceMaterial* fbxMaterial,
|
||||||
const std::map<const FbxTexture *, FbxString> &textureLocations);
|
const std::map<const FbxTexture*, FbxString>& textureLocations);
|
||||||
|
|
||||||
FbxRoughMetMaterialInfo(
|
FbxRoughMetMaterialInfo(
|
||||||
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(name, shadingModel)
|
baseColor(baseColor),
|
||||||
, baseColor(baseColor)
|
metallic(metallic),
|
||||||
, metallic(metallic)
|
roughness(roughness) {}
|
||||||
, roughness(roughness)
|
|
||||||
{}
|
|
||||||
|
|
||||||
const FbxVector4 baseColor;
|
const FbxVector4 baseColor;
|
||||||
const FbxDouble metallic;
|
const FbxDouble metallic;
|
||||||
|
@ -41,40 +39,38 @@ struct FbxRoughMetMaterialInfo : FbxMaterialInfo {
|
||||||
FbxVector4 emissive = FbxVector4(0, 0, 0, 1);
|
FbxVector4 emissive = FbxVector4(0, 0, 0, 1);
|
||||||
FbxDouble emissiveIntensity = 1;
|
FbxDouble emissiveIntensity = 1;
|
||||||
|
|
||||||
const FbxFileTexture *texNormal = nullptr;
|
const FbxFileTexture* texNormal = nullptr;
|
||||||
const FbxFileTexture *texBaseColor = nullptr;
|
const FbxFileTexture* texBaseColor = nullptr;
|
||||||
const FbxFileTexture *texBaseWeight = nullptr;
|
const FbxFileTexture* texBaseWeight = nullptr;
|
||||||
const FbxFileTexture *texMetallic = nullptr;
|
const FbxFileTexture* texMetallic = nullptr;
|
||||||
const FbxFileTexture *texRoughness = nullptr;
|
const FbxFileTexture* texRoughness = nullptr;
|
||||||
const FbxFileTexture *texEmissive = nullptr;
|
const FbxFileTexture* texEmissive = nullptr;
|
||||||
const FbxFileTexture *texEmissiveWeight = nullptr;
|
const FbxFileTexture* texEmissiveWeight = nullptr;
|
||||||
const FbxFileTexture *texAmbientOcclusion = nullptr;
|
const FbxFileTexture* texAmbientOcclusion = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FbxStingrayPBSMaterialResolver : FbxMaterialResolver<FbxRoughMetMaterialInfo> {
|
class FbxStingrayPBSMaterialResolver : FbxMaterialResolver<FbxRoughMetMaterialInfo> {
|
||||||
public:
|
public:
|
||||||
FbxStingrayPBSMaterialResolver(
|
FbxStingrayPBSMaterialResolver(
|
||||||
FbxSurfaceMaterial *fbxMaterial,
|
FbxSurfaceMaterial* fbxMaterial,
|
||||||
const std::map<const FbxTexture *, FbxString> &textureLocations)
|
const std::map<const FbxTexture*, FbxString>& textureLocations)
|
||||||
: FbxMaterialResolver(fbxMaterial, textureLocations)
|
: FbxMaterialResolver(fbxMaterial, textureLocations) {}
|
||||||
{}
|
|
||||||
|
|
||||||
virtual std::unique_ptr<FbxRoughMetMaterialInfo> resolve() const;
|
virtual std::unique_ptr<FbxRoughMetMaterialInfo> resolve() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Fbx3dsMaxPhysicalMaterialResolver : FbxMaterialResolver<FbxRoughMetMaterialInfo> {
|
class Fbx3dsMaxPhysicalMaterialResolver : FbxMaterialResolver<FbxRoughMetMaterialInfo> {
|
||||||
public:
|
public:
|
||||||
Fbx3dsMaxPhysicalMaterialResolver(
|
Fbx3dsMaxPhysicalMaterialResolver(
|
||||||
FbxSurfaceMaterial *fbxMaterial,
|
FbxSurfaceMaterial* fbxMaterial,
|
||||||
const std::map<const FbxTexture *, FbxString> &textureLocations)
|
const std::map<const FbxTexture*, FbxString>& textureLocations)
|
||||||
: FbxMaterialResolver(fbxMaterial, textureLocations)
|
: FbxMaterialResolver(fbxMaterial, textureLocations) {}
|
||||||
{}
|
|
||||||
|
|
||||||
virtual std::unique_ptr<FbxRoughMetMaterialInfo> resolve() const;
|
virtual std::unique_ptr<FbxRoughMetMaterialInfo> resolve() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename T>
|
template <typename T>
|
||||||
T getValue(const FbxProperty &props, std::string propName, const T& default) const {
|
T getValue(const FbxProperty& props, std::string propName, const T& default) const {
|
||||||
const FbxProperty prop = props.FindHierarchical(propName.c_str());
|
const FbxProperty prop = props.FindHierarchical(propName.c_str());
|
||||||
return prop.IsValid() ? prop.Get<T>() : default;
|
return prop.IsValid() ? prop.Get<T>() : default;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,14 @@ std::unique_ptr<FbxRoughMetMaterialInfo> FbxStingrayPBSMaterialResolver::resolve
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (!fbxMaterial->ShadingModel.Get().IsEmpty()) {
|
if (!fbxMaterial->ShadingModel.Get().IsEmpty()) {
|
||||||
::fmt::printf("Warning: Material %s has surprising shading model: %s\n",
|
::fmt::printf(
|
||||||
fbxMaterial->GetName(), fbxMaterial->ShadingModel.Get());
|
"Warning: Material %s has surprising shading model: %s\n",
|
||||||
|
fbxMaterial->GetName(),
|
||||||
|
fbxMaterial->ShadingModel.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto getTex = [&](std::string propName) {
|
auto getTex = [&](std::string propName) {
|
||||||
const FbxFileTexture *ptr = nullptr;
|
const FbxFileTexture* ptr = nullptr;
|
||||||
|
|
||||||
const FbxProperty useProp = mayaProp.FindHierarchical(("use_" + propName + "_map").c_str());
|
const FbxProperty useProp = mayaProp.FindHierarchical(("use_" + propName + "_map").c_str());
|
||||||
if (useProp.IsValid() && useProp.Get<bool>()) {
|
if (useProp.IsValid() && useProp.Get<bool>()) {
|
||||||
|
@ -32,8 +34,10 @@ std::unique_ptr<FbxRoughMetMaterialInfo> FbxStingrayPBSMaterialResolver::resolve
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (verboseOutput && useProp.IsValid()) {
|
} else if (verboseOutput && useProp.IsValid()) {
|
||||||
fmt::printf("Note: Property '%s' of Stingray PBS material '%s' exists, but is flagged as 'do not use'.\n",
|
fmt::printf(
|
||||||
propName, fbxMaterial->GetName());
|
"Note: Property '%s' of Stingray PBS material '%s' exists, but is flagged as 'do not use'.\n",
|
||||||
|
propName,
|
||||||
|
fbxMaterial->GetName());
|
||||||
}
|
}
|
||||||
return ptr;
|
return ptr;
|
||||||
};
|
};
|
||||||
|
@ -44,20 +48,17 @@ std::unique_ptr<FbxRoughMetMaterialInfo> FbxStingrayPBSMaterialResolver::resolve
|
||||||
};
|
};
|
||||||
|
|
||||||
auto getVal = [&](std::string propName) -> FbxDouble {
|
auto getVal = [&](std::string propName) -> FbxDouble {
|
||||||
const FbxProperty vecProp = mayaProp.FindHierarchical(propName .c_str());
|
const FbxProperty vecProp = mayaProp.FindHierarchical(propName.c_str());
|
||||||
return vecProp.IsValid() ? vecProp.Get<FbxDouble>() : 0;
|
return vecProp.IsValid() ? vecProp.Get<FbxDouble>() : 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
FbxDouble3 baseColor = getVec("base_color");
|
FbxDouble3 baseColor = getVec("base_color");
|
||||||
std::unique_ptr<FbxRoughMetMaterialInfo> res(
|
std::unique_ptr<FbxRoughMetMaterialInfo> res(new FbxRoughMetMaterialInfo(
|
||||||
new FbxRoughMetMaterialInfo(
|
|
||||||
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),
|
||||||
getVal("metallic"),
|
getVal("metallic"),
|
||||||
getVal("roughness")
|
getVal("roughness")));
|
||||||
)
|
|
||||||
);
|
|
||||||
res->texNormal = getTex("normal");
|
res->texNormal = getTex("normal");
|
||||||
res->texBaseColor = getTex("color");
|
res->texBaseColor = getTex("color");
|
||||||
res->texAmbientOcclusion = getTex("ao");
|
res->texAmbientOcclusion = getTex("ao");
|
||||||
|
|
|
@ -9,13 +9,12 @@
|
||||||
|
|
||||||
#include "TraditionalMaterials.hpp"
|
#include "TraditionalMaterials.hpp"
|
||||||
|
|
||||||
std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialResolver::resolve() const
|
std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialResolver::resolve() const {
|
||||||
{
|
auto getSurfaceScalar = [&](const char* propName) -> std::tuple<FbxDouble, FbxFileTexture*> {
|
||||||
auto getSurfaceScalar = [&](const char *propName) -> std::tuple<FbxDouble, FbxFileTexture *> {
|
|
||||||
const FbxProperty prop = fbxMaterial->FindProperty(propName);
|
const FbxProperty prop = fbxMaterial->FindProperty(propName);
|
||||||
|
|
||||||
FbxDouble val(0);
|
FbxDouble val(0);
|
||||||
FbxFileTexture *tex = prop.GetSrcObject<FbxFileTexture>();
|
FbxFileTexture* tex = prop.GetSrcObject<FbxFileTexture>();
|
||||||
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
|
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
|
||||||
tex = nullptr;
|
tex = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -25,11 +24,11 @@ std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialResolver::reso
|
||||||
return std::make_tuple(val, tex);
|
return std::make_tuple(val, tex);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto getSurfaceVector = [&](const char *propName) -> std::tuple<FbxDouble3, FbxFileTexture *> {
|
auto getSurfaceVector = [&](const char* propName) -> std::tuple<FbxDouble3, FbxFileTexture*> {
|
||||||
const FbxProperty prop = fbxMaterial->FindProperty(propName);
|
const FbxProperty prop = fbxMaterial->FindProperty(propName);
|
||||||
|
|
||||||
FbxDouble3 val(1, 1, 1);
|
FbxDouble3 val(1, 1, 1);
|
||||||
FbxFileTexture *tex = prop.GetSrcObject<FbxFileTexture>();
|
FbxFileTexture* tex = prop.GetSrcObject<FbxFileTexture>();
|
||||||
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
|
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
|
||||||
tex = nullptr;
|
tex = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -39,21 +38,23 @@ std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialResolver::reso
|
||||||
return std::make_tuple(val, tex);
|
return std::make_tuple(val, tex);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto getSurfaceValues = [&](const char *colName, const char *facName) -> std::tuple<FbxVector4, FbxFileTexture *, FbxFileTexture *> {
|
auto getSurfaceValues =
|
||||||
|
[&](const char* colName,
|
||||||
|
const char* facName) -> std::tuple<FbxVector4, FbxFileTexture*, FbxFileTexture*> {
|
||||||
const FbxProperty colProp = fbxMaterial->FindProperty(colName);
|
const FbxProperty colProp = fbxMaterial->FindProperty(colName);
|
||||||
const FbxProperty facProp = fbxMaterial->FindProperty(facName);
|
const FbxProperty facProp = fbxMaterial->FindProperty(facName);
|
||||||
|
|
||||||
FbxDouble3 colorVal(1, 1, 1);
|
FbxDouble3 colorVal(1, 1, 1);
|
||||||
FbxDouble factorVal(1);
|
FbxDouble factorVal(1);
|
||||||
|
|
||||||
FbxFileTexture *colTex = colProp.GetSrcObject<FbxFileTexture>();
|
FbxFileTexture* colTex = colProp.GetSrcObject<FbxFileTexture>();
|
||||||
if (colTex != nullptr && textureLocations.find(colTex) == textureLocations.end()) {
|
if (colTex != nullptr && textureLocations.find(colTex) == textureLocations.end()) {
|
||||||
colTex = nullptr;
|
colTex = nullptr;
|
||||||
}
|
}
|
||||||
if (colTex == nullptr && colProp.IsValid()) {
|
if (colTex == nullptr && colProp.IsValid()) {
|
||||||
colorVal = colProp.Get<FbxDouble3>();
|
colorVal = colProp.Get<FbxDouble3>();
|
||||||
}
|
}
|
||||||
FbxFileTexture *facTex = facProp.GetSrcObject<FbxFileTexture>();
|
FbxFileTexture* facTex = facProp.GetSrcObject<FbxFileTexture>();
|
||||||
if (facTex != nullptr && textureLocations.find(facTex) == textureLocations.end()) {
|
if (facTex != nullptr && textureLocations.find(facTex) == textureLocations.end()) {
|
||||||
facTex = nullptr;
|
facTex = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -62,25 +63,29 @@ std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialResolver::reso
|
||||||
}
|
}
|
||||||
|
|
||||||
auto val = FbxVector4(
|
auto val = FbxVector4(
|
||||||
colorVal[0] * factorVal,
|
colorVal[0] * factorVal, colorVal[1] * factorVal, colorVal[2] * factorVal, factorVal);
|
||||||
colorVal[1] * factorVal,
|
|
||||||
colorVal[2] * factorVal,
|
|
||||||
factorVal);
|
|
||||||
return std::make_tuple(val, colTex, facTex);
|
return std::make_tuple(val, colTex, facTex);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string name = fbxMaterial->GetName();
|
std::string name = fbxMaterial->GetName();
|
||||||
std::unique_ptr<FbxTraditionalMaterialInfo> res(new FbxTraditionalMaterialInfo(name.c_str(), fbxMaterial->ShadingModel.Get()));
|
std::unique_ptr<FbxTraditionalMaterialInfo> res(
|
||||||
|
new FbxTraditionalMaterialInfo(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, const char *facName) -> std::tuple<FbxVector4, FbxFileTexture *>{
|
auto handleBasicProperty = [&](const char* colName,
|
||||||
|
const char* facName) -> std::tuple<FbxVector4, FbxFileTexture*> {
|
||||||
FbxFileTexture *colTex, *facTex;
|
FbxFileTexture *colTex, *facTex;
|
||||||
FbxVector4 vec;
|
FbxVector4 vec;
|
||||||
|
|
||||||
std::tie(vec, colTex, facTex) = getSurfaceValues(colName, facName);
|
std::tie(vec, colTex, facTex) = getSurfaceValues(colName, facName);
|
||||||
if (colTex) {
|
if (colTex) {
|
||||||
if (facTex) {
|
if (facTex) {
|
||||||
fmt::printf("Warning: Mat [%s]: Can't handle both %s and %s textures; discarding %s.\n", name, colName, facName, facName);
|
fmt::printf(
|
||||||
|
"Warning: Mat [%s]: Can't handle both %s and %s textures; discarding %s.\n",
|
||||||
|
name,
|
||||||
|
colName,
|
||||||
|
facName,
|
||||||
|
facName);
|
||||||
}
|
}
|
||||||
return std::make_tuple(vec, colTex);
|
return std::make_tuple(vec, colTex);
|
||||||
}
|
}
|
||||||
|
@ -108,16 +113,23 @@ std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialResolver::reso
|
||||||
FbxVector4 transparency;
|
FbxVector4 transparency;
|
||||||
// extract any existing textures only so we can warn that we're throwing them away
|
// extract any existing textures only so we can warn that we're throwing them away
|
||||||
FbxFileTexture *colTex, *facTex;
|
FbxFileTexture *colTex, *facTex;
|
||||||
std::tie(transparency, colTex, facTex) =
|
std::tie(transparency, colTex, facTex) = getSurfaceValues(
|
||||||
getSurfaceValues(FbxSurfaceMaterial::sTransparentColor, FbxSurfaceMaterial::sTransparencyFactor);
|
FbxSurfaceMaterial::sTransparentColor, FbxSurfaceMaterial::sTransparencyFactor);
|
||||||
if (colTex) {
|
if (colTex) {
|
||||||
fmt::printf("Warning: Mat [%s]: Can't handle texture for %s; discarding.\n", name, FbxSurfaceMaterial::sTransparentColor);
|
fmt::printf(
|
||||||
|
"Warning: Mat [%s]: Can't handle texture for %s; discarding.\n",
|
||||||
|
name,
|
||||||
|
FbxSurfaceMaterial::sTransparentColor);
|
||||||
}
|
}
|
||||||
if (facTex) {
|
if (facTex) {
|
||||||
fmt::printf("Warning: Mat [%s]: Can't handle texture for %s; discarding.\n", name, FbxSurfaceMaterial::sTransparencyFactor);
|
fmt::printf(
|
||||||
|
"Warning: Mat [%s]: Can't handle texture for %s; discarding.\n",
|
||||||
|
name,
|
||||||
|
FbxSurfaceMaterial::sTransparencyFactor);
|
||||||
}
|
}
|
||||||
// FBX color is RGB, so we calculate the A channel as the average of the FBX transparency color vector
|
// FBX color is RGB, so we calculate the A channel as the average of the FBX transparency color
|
||||||
res->colDiffuse[3] = 1.0 - (transparency[0] + transparency[1] + transparency[2])/3.0;
|
// vector
|
||||||
|
res->colDiffuse[3] = 1.0 - (transparency[0] + transparency[1] + transparency[2]) / 3.0;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,34 +10,32 @@
|
||||||
#include "FbxMaterials.hpp"
|
#include "FbxMaterials.hpp"
|
||||||
|
|
||||||
struct FbxTraditionalMaterialInfo : FbxMaterialInfo {
|
struct FbxTraditionalMaterialInfo : FbxMaterialInfo {
|
||||||
static constexpr const char *FBX_SHADER_LAMBERT = "Lambert";
|
static constexpr const char* FBX_SHADER_LAMBERT = "Lambert";
|
||||||
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(const FbxString& name, const FbxString& shadingModel)
|
||||||
: FbxMaterialInfo(name, shadingModel)
|
: FbxMaterialInfo(name, shadingModel) {}
|
||||||
{}
|
|
||||||
|
|
||||||
FbxFileTexture *texAmbient {};
|
FbxFileTexture* texAmbient{};
|
||||||
FbxVector4 colAmbient {};
|
FbxVector4 colAmbient{};
|
||||||
FbxFileTexture *texSpecular {};
|
FbxFileTexture* texSpecular{};
|
||||||
FbxVector4 colSpecular {};
|
FbxVector4 colSpecular{};
|
||||||
FbxFileTexture *texDiffuse {};
|
FbxFileTexture* texDiffuse{};
|
||||||
FbxVector4 colDiffuse {};
|
FbxVector4 colDiffuse{};
|
||||||
FbxFileTexture *texEmissive {};
|
FbxFileTexture* texEmissive{};
|
||||||
FbxVector4 colEmissive {};
|
FbxVector4 colEmissive{};
|
||||||
FbxFileTexture *texNormal {};
|
FbxFileTexture* texNormal{};
|
||||||
FbxFileTexture *texShininess {};
|
FbxFileTexture* texShininess{};
|
||||||
FbxDouble shininess {};
|
FbxDouble shininess{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class FbxTraditionalMaterialResolver : FbxMaterialResolver<FbxTraditionalMaterialInfo> {
|
class FbxTraditionalMaterialResolver : FbxMaterialResolver<FbxTraditionalMaterialInfo> {
|
||||||
public:
|
public:
|
||||||
FbxTraditionalMaterialResolver(
|
FbxTraditionalMaterialResolver(
|
||||||
FbxSurfaceMaterial *fbxMaterial,
|
FbxSurfaceMaterial* fbxMaterial,
|
||||||
const std::map<const FbxTexture *, FbxString> &textureLocations)
|
const std::map<const FbxTexture*, FbxString>& textureLocations)
|
||||||
: FbxMaterialResolver(fbxMaterial, textureLocations)
|
: FbxMaterialResolver(fbxMaterial, textureLocations) {}
|
||||||
{}
|
|
||||||
|
|
||||||
virtual std::unique_ptr<FbxTraditionalMaterialInfo> resolve() const;
|
virtual std::unique_ptr<FbxTraditionalMaterialInfo> resolve() const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
/**
|
/**
|
||||||
* Copyright (c) 2014-present, Facebook, Inc.
|
* Copyright (c) 2014-present, Facebook, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under the BSD-style license found in the
|
* This source code is licensed under the BSD-style license found in the
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "GltfModel.hpp"
|
#include "GltfModel.hpp"
|
||||||
|
|
||||||
std::shared_ptr<BufferViewData> GltfModel::GetAlignedBufferView(BufferData &buffer, const BufferViewData::GL_ArrayType target)
|
std::shared_ptr<BufferViewData> GltfModel::GetAlignedBufferView(
|
||||||
{
|
BufferData& buffer,
|
||||||
|
const BufferViewData::GL_ArrayType target) {
|
||||||
unsigned long bufferSize = this->binary->size();
|
unsigned long bufferSize = this->binary->size();
|
||||||
if ((bufferSize % 4) > 0) {
|
if ((bufferSize % 4) > 0) {
|
||||||
bufferSize += (4 - (bufferSize % 4));
|
bufferSize += (4 - (bufferSize % 4));
|
||||||
|
@ -20,8 +21,8 @@ std::shared_ptr<BufferViewData> GltfModel::GetAlignedBufferView(BufferData &buff
|
||||||
}
|
}
|
||||||
|
|
||||||
// add a bufferview on the fly and copy data into it
|
// add a bufferview on the fly and copy data into it
|
||||||
std::shared_ptr<BufferViewData> GltfModel::AddRawBufferView(BufferData &buffer, const char *source, uint32_t bytes)
|
std::shared_ptr<BufferViewData>
|
||||||
{
|
GltfModel::AddRawBufferView(BufferData& buffer, const char* source, uint32_t bytes) {
|
||||||
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
|
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
|
||||||
bufferView->byteLength = bytes;
|
bufferView->byteLength = bytes;
|
||||||
|
|
||||||
|
@ -34,8 +35,9 @@ std::shared_ptr<BufferViewData> GltfModel::AddRawBufferView(BufferData &buffer,
|
||||||
return bufferView;
|
return bufferView;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<BufferViewData> GltfModel::AddBufferViewForFile(BufferData &buffer, const std::string &filename)
|
std::shared_ptr<BufferViewData> GltfModel::AddBufferViewForFile(
|
||||||
{
|
BufferData& buffer,
|
||||||
|
const std::string& filename) {
|
||||||
// see if we've already created a BufferViewData for this precise file
|
// see if we've already created a BufferViewData for this precise file
|
||||||
auto iter = filenameToBufferView.find(filename);
|
auto iter = filenameToBufferView.find(filename);
|
||||||
if (iter != filenameToBufferView.end()) {
|
if (iter != filenameToBufferView.end()) {
|
||||||
|
@ -62,8 +64,7 @@ std::shared_ptr<BufferViewData> GltfModel::AddBufferViewForFile(BufferData &buff
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GltfModel::serializeHolders(json &glTFJson)
|
void GltfModel::serializeHolders(json& glTFJson) {
|
||||||
{
|
|
||||||
serializeHolder(glTFJson, "buffers", buffers);
|
serializeHolder(glTFJson, "buffers", buffers);
|
||||||
serializeHolder(glTFJson, "bufferViews", bufferViews);
|
serializeHolder(glTFJson, "bufferViews", bufferViews);
|
||||||
serializeHolder(glTFJson, "scenes", scenes);
|
serializeHolder(glTFJson, "scenes", scenes);
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/**
|
/**
|
||||||
* Copyright (c) 2014-present, Facebook, Inc.
|
* Copyright (c) 2014-present, Facebook, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under the BSD-style license found in the
|
* This source code is licensed under the BSD-style license found in the
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
@ -30,21 +30,20 @@
|
||||||
#include "gltf/properties/TextureData.hpp"
|
#include "gltf/properties/TextureData.hpp"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* glTF 2.0 is based on the idea that data structs within a file are referenced by index; an accessor will
|
* glTF 2.0 is based on the idea that data structs within a file are referenced by index; an
|
||||||
* point to the n:th buffer view, and so on. The Holder class takes a freshly instantiated class, and then
|
* accessor will point to the n:th buffer view, and so on. The Holder class takes a freshly
|
||||||
* creates, stored, and returns a shared_ptr<T> for it.
|
* instantiated class, and then creates, stored, and returns a shared_ptr<T> for it.
|
||||||
*
|
*
|
||||||
* The idea is that every glTF resource in the file will live as long as the Holder does, and the Holders
|
* The idea is that every glTF resource in the file will live as long as the Holder does, and the
|
||||||
* are all kept in the GLTFData struct. Clients may certainly cnhoose to perpetuate the full shared_ptr<T>
|
* Holders are all kept in the GLTFData struct. Clients may certainly cnhoose to perpetuate the full
|
||||||
* reference counting type, but generally speaking we pass around simple T& and T* types because the GLTFData
|
* shared_ptr<T> reference counting type, but generally speaking we pass around simple T& and T*
|
||||||
* struct will, by design, outlive all other activity that takes place during in a single conversion run.
|
* types because the GLTFData struct will, by design, outlive all other activity that takes place
|
||||||
*/
|
* during in a single conversion run.
|
||||||
template<typename T>
|
*/
|
||||||
class Holder
|
template <typename T>
|
||||||
{
|
class Holder {
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<T> hold(T *ptr)
|
std::shared_ptr<T> hold(T* ptr) {
|
||||||
{
|
|
||||||
ptr->ix = ptrs.size();
|
ptr->ix = ptrs.size();
|
||||||
ptrs.emplace_back(ptr);
|
ptrs.emplace_back(ptr);
|
||||||
return ptrs.back();
|
return ptrs.back();
|
||||||
|
@ -52,53 +51,60 @@ public:
|
||||||
std::vector<std::shared_ptr<T>> ptrs;
|
std::vector<std::shared_ptr<T>> ptrs;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GltfModel
|
class GltfModel {
|
||||||
{
|
public:
|
||||||
public:
|
explicit GltfModel(const GltfOptions& options)
|
||||||
explicit GltfModel(const GltfOptions &options)
|
: binary(new std::vector<uint8_t>),
|
||||||
: binary(new std::vector<uint8_t>)
|
isGlb(options.outputBinary),
|
||||||
, isGlb(options.outputBinary)
|
defaultSampler(nullptr),
|
||||||
, defaultSampler(nullptr)
|
defaultBuffer(buffers.hold(buildDefaultBuffer(options))) {
|
||||||
, defaultBuffer(buffers.hold(buildDefaultBuffer(options)))
|
|
||||||
{
|
|
||||||
defaultSampler = samplers.hold(buildDefaultSampler());
|
defaultSampler = samplers.hold(buildDefaultSampler());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<BufferViewData> GetAlignedBufferView(BufferData &buffer, const BufferViewData::GL_ArrayType target);
|
std::shared_ptr<BufferViewData> GetAlignedBufferView(
|
||||||
std::shared_ptr<BufferViewData> AddRawBufferView(BufferData &buffer, const char *source, uint32_t bytes);
|
BufferData& buffer,
|
||||||
std::shared_ptr<BufferViewData> AddBufferViewForFile(BufferData &buffer, const std::string &filename);
|
const BufferViewData::GL_ArrayType target);
|
||||||
|
std::shared_ptr<BufferViewData>
|
||||||
|
AddRawBufferView(BufferData& buffer, const char* source, uint32_t bytes);
|
||||||
|
std::shared_ptr<BufferViewData> AddBufferViewForFile(
|
||||||
|
BufferData& buffer,
|
||||||
|
const std::string& filename);
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
std::shared_ptr<AccessorData> AddAccessorWithView(
|
std::shared_ptr<AccessorData> AddAccessorWithView(
|
||||||
BufferViewData &bufferView, const GLType &type, const std::vector<T> &source, std::string name)
|
BufferViewData& bufferView,
|
||||||
{
|
const GLType& type,
|
||||||
|
const std::vector<T>& source,
|
||||||
|
std::string name) {
|
||||||
auto accessor = accessors.hold(new AccessorData(bufferView, type, name));
|
auto accessor = accessors.hold(new AccessorData(bufferView, type, name));
|
||||||
accessor->appendAsBinaryArray(source, *binary);
|
accessor->appendAsBinaryArray(source, *binary);
|
||||||
bufferView.byteLength = accessor->byteLength();
|
bufferView.byteLength = accessor->byteLength();
|
||||||
return accessor;
|
return accessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
std::shared_ptr<AccessorData> AddAccessorAndView(
|
std::shared_ptr<AccessorData>
|
||||||
BufferData &buffer, const GLType &type, const std::vector<T> &source)
|
AddAccessorAndView(BufferData& buffer, const GLType& type, const std::vector<T>& source) {
|
||||||
{
|
|
||||||
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
|
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
|
||||||
return AddAccessorWithView(*bufferView, type, source, std::string(""));
|
return AddAccessorWithView(*bufferView, type, source, std::string(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
std::shared_ptr<AccessorData> AddAccessorAndView(
|
std::shared_ptr<AccessorData> AddAccessorAndView(
|
||||||
BufferData &buffer, const GLType &type, const std::vector<T> &source, std::string name)
|
BufferData& buffer,
|
||||||
{
|
const GLType& type,
|
||||||
|
const std::vector<T>& source,
|
||||||
|
std::string name) {
|
||||||
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
|
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
|
||||||
return AddAccessorWithView(*bufferView, type, source, name);
|
return AddAccessorWithView(*bufferView, type, source, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
std::shared_ptr<AccessorData> AddAttributeToPrimitive(
|
std::shared_ptr<AccessorData> AddAttributeToPrimitive(
|
||||||
BufferData &buffer, const RawModel &surfaceModel, PrimitiveData &primitive,
|
BufferData& buffer,
|
||||||
const AttributeDefinition<T> &attrDef)
|
const RawModel& surfaceModel,
|
||||||
{
|
PrimitiveData& primitive,
|
||||||
|
const AttributeDefinition<T>& attrDef) {
|
||||||
// copy attribute data into vector
|
// copy attribute data into vector
|
||||||
std::vector<T> attribArr;
|
std::vector<T> attribArr;
|
||||||
surfaceModel.GetAttributeArray<T>(attribArr, attrDef.rawAttributeIx);
|
surfaceModel.GetAttributeArray<T>(attribArr, attrDef.rawAttributeIx);
|
||||||
|
@ -117,19 +123,18 @@ public:
|
||||||
return accessor;
|
return accessor;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
void serializeHolder(json &glTFJson, std::string key, const Holder<T> holder)
|
void serializeHolder(json& glTFJson, std::string key, const Holder<T> holder) {
|
||||||
{
|
|
||||||
if (!holder.ptrs.empty()) {
|
if (!holder.ptrs.empty()) {
|
||||||
std::vector<json> bits;
|
std::vector<json> bits;
|
||||||
for (const auto &ptr : holder.ptrs) {
|
for (const auto& ptr : holder.ptrs) {
|
||||||
bits.push_back(ptr->serialize());
|
bits.push_back(ptr->serialize());
|
||||||
}
|
}
|
||||||
glTFJson[key] = bits;
|
glTFJson[key] = bits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void serializeHolders(json &glTFJson);
|
void serializeHolders(json& glTFJson);
|
||||||
|
|
||||||
const bool isGlb;
|
const bool isGlb;
|
||||||
|
|
||||||
|
@ -156,13 +161,12 @@ public:
|
||||||
std::shared_ptr<SamplerData> defaultSampler;
|
std::shared_ptr<SamplerData> defaultSampler;
|
||||||
std::shared_ptr<BufferData> defaultBuffer;
|
std::shared_ptr<BufferData> defaultBuffer;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SamplerData *buildDefaultSampler() {
|
SamplerData* buildDefaultSampler() {
|
||||||
return new SamplerData();
|
return new SamplerData();
|
||||||
}
|
}
|
||||||
BufferData *buildDefaultBuffer(const GltfOptions &options) {
|
BufferData* buildDefaultBuffer(const GltfOptions& options) {
|
||||||
return options.outputBinary ?
|
return options.outputBinary ? new BufferData(binary)
|
||||||
new BufferData(binary) :
|
: new BufferData(extBufferFilename, binary, options.embedResources);
|
||||||
new BufferData(extBufferFilename, binary, options.embedResources);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,17 +9,17 @@
|
||||||
|
|
||||||
#include "Raw2Gltf.hpp"
|
#include "Raw2Gltf.hpp"
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <cstdint>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include <stb_image.h>
|
#include <stb_image.h>
|
||||||
#include <stb_image_write.h>
|
#include <stb_image_write.h>
|
||||||
|
|
||||||
#include "utils/String_Utils.hpp"
|
|
||||||
#include "utils/Image_Utils.hpp"
|
|
||||||
#include <utils/File_Utils.hpp>
|
#include <utils/File_Utils.hpp>
|
||||||
|
#include "utils/Image_Utils.hpp"
|
||||||
|
#include "utils/String_Utils.hpp"
|
||||||
|
|
||||||
#include "raw/RawModel.hpp"
|
#include "raw/RawModel.hpp"
|
||||||
|
|
||||||
|
@ -38,8 +38,8 @@
|
||||||
#include "gltf/properties/SkinData.hpp"
|
#include "gltf/properties/SkinData.hpp"
|
||||||
#include "gltf/properties/TextureData.hpp"
|
#include "gltf/properties/TextureData.hpp"
|
||||||
|
|
||||||
#include "TextureBuilder.hpp"
|
|
||||||
#include "GltfModel.hpp"
|
#include "GltfModel.hpp"
|
||||||
|
#include "TextureBuilder.hpp"
|
||||||
|
|
||||||
typedef uint32_t TriangleIndex;
|
typedef uint32_t TriangleIndex;
|
||||||
|
|
||||||
|
@ -50,53 +50,50 @@ typedef uint32_t TriangleIndex;
|
||||||
* registered under that name. This is safe in the context of this tool, where all such data
|
* registered under that name. This is safe in the context of this tool, where all such data
|
||||||
* classes are guaranteed to stick around for the duration of the process.
|
* classes are guaranteed to stick around for the duration of the process.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template <typename T>
|
||||||
T &require(std::map<std::string, std::shared_ptr<T>> map, const std::string &key)
|
T& require(std::map<std::string, std::shared_ptr<T>> map, const std::string& key) {
|
||||||
{
|
|
||||||
auto iter = map.find(key);
|
auto iter = map.find(key);
|
||||||
assert(iter != map.end());
|
assert(iter != map.end());
|
||||||
T &result = *iter->second;
|
T& result = *iter->second;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
T &require(std::map<long, std::shared_ptr<T>> map, long key)
|
T& require(std::map<long, std::shared_ptr<T>> map, long key) {
|
||||||
{
|
|
||||||
auto iter = map.find(key);
|
auto iter = map.find(key);
|
||||||
assert(iter != map.end());
|
assert(iter != map.end());
|
||||||
T &result = *iter->second;
|
T& result = *iter->second;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const std::vector<TriangleIndex> getIndexArray(const RawModel &raw)
|
static const std::vector<TriangleIndex> getIndexArray(const RawModel& raw) {
|
||||||
{
|
|
||||||
std::vector<TriangleIndex> result;
|
std::vector<TriangleIndex> result;
|
||||||
|
|
||||||
for (int i = 0; i < raw.GetTriangleCount(); i++) {
|
for (int i = 0; i < raw.GetTriangleCount(); i++) {
|
||||||
result.push_back((TriangleIndex) raw.GetTriangle(i).verts[0]);
|
result.push_back((TriangleIndex)raw.GetTriangle(i).verts[0]);
|
||||||
result.push_back((TriangleIndex) raw.GetTriangle(i).verts[1]);
|
result.push_back((TriangleIndex)raw.GetTriangle(i).verts[1]);
|
||||||
result.push_back((TriangleIndex) raw.GetTriangle(i).verts[2]);
|
result.push_back((TriangleIndex)raw.GetTriangle(i).verts[2]);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: replace with a proper MaterialHasher class
|
// TODO: replace with a proper MaterialHasher class
|
||||||
static const std::string materialHash(const RawMaterial &m) {
|
static const std::string materialHash(const RawMaterial& m) {
|
||||||
return m.name + "_" + std::to_string(m.type);
|
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,
|
||||||
const RawModel &raw,
|
const RawModel& raw,
|
||||||
const GltfOptions &options
|
const GltfOptions& options) {
|
||||||
)
|
|
||||||
{
|
|
||||||
if (verboseOutput) {
|
if (verboseOutput) {
|
||||||
fmt::printf("Building render model...\n");
|
fmt::printf("Building render model...\n");
|
||||||
for (int i = 0; i < raw.GetMaterialCount(); i++) {
|
for (int i = 0; i < raw.GetMaterialCount(); i++) {
|
||||||
fmt::printf(
|
fmt::printf(
|
||||||
"Material %d: %s [shading: %s]\n", i, raw.GetMaterial(i).name.c_str(),
|
"Material %d: %s [shading: %s]\n",
|
||||||
|
i,
|
||||||
|
raw.GetMaterial(i).name.c_str(),
|
||||||
Describe(raw.GetMaterial(i).info->shadingModel));
|
Describe(raw.GetMaterial(i).info->shadingModel));
|
||||||
}
|
}
|
||||||
if (raw.GetVertexCount() > 2 * raw.GetTriangleCount()) {
|
if (raw.GetVertexCount() > 2 * raw.GetTriangleCount()) {
|
||||||
|
@ -117,7 +114,7 @@ ModelData *Raw2Gltf(
|
||||||
fmt::printf("%7d triangles\n", raw.GetTriangleCount());
|
fmt::printf("%7d triangles\n", raw.GetTriangleCount());
|
||||||
fmt::printf("%7d textures\n", raw.GetTextureCount());
|
fmt::printf("%7d textures\n", raw.GetTextureCount());
|
||||||
fmt::printf("%7d nodes\n", raw.GetNodeCount());
|
fmt::printf("%7d nodes\n", raw.GetNodeCount());
|
||||||
fmt::printf("%7d surfaces\n", (int) materialModels.size());
|
fmt::printf("%7d surfaces\n", (int)materialModels.size());
|
||||||
fmt::printf("%7d animations\n", raw.GetAnimationCount());
|
fmt::printf("%7d animations\n", raw.GetAnimationCount());
|
||||||
fmt::printf("%7d cameras\n", raw.GetCameraCount());
|
fmt::printf("%7d cameras\n", raw.GetCameraCount());
|
||||||
fmt::printf("%7d lights\n", raw.GetLightCount());
|
fmt::printf("%7d lights\n", raw.GetLightCount());
|
||||||
|
@ -130,8 +127,9 @@ ModelData *Raw2Gltf(
|
||||||
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;
|
||||||
|
|
||||||
// for now, we only have one buffer; data->binary points to the same vector as that BufferData does.
|
// for now, we only have one buffer; data->binary points to the same vector as that BufferData
|
||||||
BufferData &buffer = *gltf->defaultBuffer;
|
// does.
|
||||||
|
BufferData& buffer = *gltf->defaultBuffer;
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// nodes
|
// nodes
|
||||||
|
@ -139,7 +137,7 @@ ModelData *Raw2Gltf(
|
||||||
|
|
||||||
for (int i = 0; i < raw.GetNodeCount(); i++) {
|
for (int i = 0; i < raw.GetNodeCount(); i++) {
|
||||||
// assumption: RawNode index == NodeData index
|
// assumption: RawNode index == NodeData index
|
||||||
const RawNode &node = raw.GetNode(i);
|
const RawNode& node = raw.GetNode(i);
|
||||||
|
|
||||||
auto nodeData = gltf->nodes.hold(
|
auto nodeData = gltf->nodes.hold(
|
||||||
new NodeData(node.name, node.translation, node.rotation, node.scale, node.isJoint));
|
new NodeData(node.name, node.translation, node.rotation, node.scale, node.isJoint));
|
||||||
|
@ -148,7 +146,7 @@ ModelData *Raw2Gltf(
|
||||||
nodeData->userProperties = node.userProperties;
|
nodeData->userProperties = node.userProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &childId : node.childIds) {
|
for (const auto& childId : node.childIds) {
|
||||||
int childIx = raw.GetNodeById(childId);
|
int childIx = raw.GetNodeById(childId);
|
||||||
assert(childIx >= 0);
|
assert(childIx >= 0);
|
||||||
nodeData->AddChildNode(childIx);
|
nodeData->AddChildNode(childIx);
|
||||||
|
@ -162,45 +160,61 @@ ModelData *Raw2Gltf(
|
||||||
//
|
//
|
||||||
|
|
||||||
for (int i = 0; i < raw.GetAnimationCount(); i++) {
|
for (int i = 0; i < raw.GetAnimationCount(); i++) {
|
||||||
const RawAnimation &animation = raw.GetAnimation(i);
|
const RawAnimation& animation = raw.GetAnimation(i);
|
||||||
|
|
||||||
if (animation.channels.size() == 0) {
|
if (animation.channels.size() == 0) {
|
||||||
fmt::printf("Warning: animation '%s' has zero channels. Skipping.\n", animation.name.c_str());
|
fmt::printf(
|
||||||
|
"Warning: animation '%s' has zero channels. Skipping.\n", animation.name.c_str());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto accessor = gltf->AddAccessorAndView(buffer, GLT_FLOAT, animation.times);
|
auto accessor = gltf->AddAccessorAndView(buffer, GLT_FLOAT, animation.times);
|
||||||
accessor->min = { *std::min_element(std::begin(animation.times), std::end(animation.times)) };
|
accessor->min = {*std::min_element(std::begin(animation.times), std::end(animation.times))};
|
||||||
accessor->max = { *std::max_element(std::begin(animation.times), std::end(animation.times)) };
|
accessor->max = {*std::max_element(std::begin(animation.times), std::end(animation.times))};
|
||||||
|
|
||||||
AnimationData &aDat = *gltf->animations.hold(new AnimationData(animation.name, *accessor));
|
AnimationData& aDat = *gltf->animations.hold(new AnimationData(animation.name, *accessor));
|
||||||
if (verboseOutput) {
|
if (verboseOutput) {
|
||||||
fmt::printf("Animation '%s' has %lu channels:\n", animation.name.c_str(), animation.channels.size());
|
fmt::printf(
|
||||||
|
"Animation '%s' has %lu channels:\n",
|
||||||
|
animation.name.c_str(),
|
||||||
|
animation.channels.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t channelIx = 0; channelIx < animation.channels.size(); channelIx++) {
|
for (size_t channelIx = 0; channelIx < animation.channels.size(); channelIx++) {
|
||||||
const RawChannel &channel = animation.channels[channelIx];
|
const RawChannel& channel = animation.channels[channelIx];
|
||||||
const RawNode &node = raw.GetNode(channel.nodeIndex);
|
const RawNode& node = raw.GetNode(channel.nodeIndex);
|
||||||
|
|
||||||
if (verboseOutput) {
|
if (verboseOutput) {
|
||||||
fmt::printf(
|
fmt::printf(
|
||||||
" Channel %lu (%s) has translations/rotations/scales/weights: [%lu, %lu, %lu, %lu]\n",
|
" Channel %lu (%s) has translations/rotations/scales/weights: [%lu, %lu, %lu, %lu]\n",
|
||||||
channelIx, node.name.c_str(), channel.translations.size(), channel.rotations.size(),
|
channelIx,
|
||||||
channel.scales.size(), channel.weights.size());
|
node.name.c_str(),
|
||||||
|
channel.translations.size(),
|
||||||
|
channel.rotations.size(),
|
||||||
|
channel.scales.size(),
|
||||||
|
channel.weights.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeData &nDat = require(nodesById, node.id);
|
NodeData& nDat = require(nodesById, node.id);
|
||||||
if (!channel.translations.empty()) {
|
if (!channel.translations.empty()) {
|
||||||
aDat.AddNodeChannel(nDat, *gltf->AddAccessorAndView(buffer, GLT_VEC3F, channel.translations), "translation");
|
aDat.AddNodeChannel(
|
||||||
|
nDat,
|
||||||
|
*gltf->AddAccessorAndView(buffer, GLT_VEC3F, channel.translations),
|
||||||
|
"translation");
|
||||||
}
|
}
|
||||||
if (!channel.rotations.empty()) {
|
if (!channel.rotations.empty()) {
|
||||||
aDat.AddNodeChannel(nDat, *gltf->AddAccessorAndView(buffer, GLT_QUATF, channel.rotations), "rotation");
|
aDat.AddNodeChannel(
|
||||||
|
nDat, *gltf->AddAccessorAndView(buffer, GLT_QUATF, channel.rotations), "rotation");
|
||||||
}
|
}
|
||||||
if (!channel.scales.empty()) {
|
if (!channel.scales.empty()) {
|
||||||
aDat.AddNodeChannel(nDat, *gltf->AddAccessorAndView(buffer, GLT_VEC3F, channel.scales), "scale");
|
aDat.AddNodeChannel(
|
||||||
|
nDat, *gltf->AddAccessorAndView(buffer, GLT_VEC3F, channel.scales), "scale");
|
||||||
}
|
}
|
||||||
if (!channel.weights.empty()) {
|
if (!channel.weights.empty()) {
|
||||||
aDat.AddNodeChannel(nDat, *gltf->AddAccessorAndView(buffer, {CT_FLOAT, 1, "SCALAR"}, channel.weights), "weights");
|
aDat.AddNodeChannel(
|
||||||
|
nDat,
|
||||||
|
*gltf->AddAccessorAndView(buffer, {CT_FLOAT, 1, "SCALAR"}, channel.weights),
|
||||||
|
"weights");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,9 +233,8 @@ ModelData *Raw2Gltf(
|
||||||
//
|
//
|
||||||
|
|
||||||
for (int materialIndex = 0; materialIndex < raw.GetMaterialCount(); materialIndex++) {
|
for (int materialIndex = 0; materialIndex < raw.GetMaterialCount(); materialIndex++) {
|
||||||
const RawMaterial &material = raw.GetMaterial(materialIndex);
|
const RawMaterial& material = raw.GetMaterial(materialIndex);
|
||||||
const bool isTransparent =
|
const bool isTransparent = material.type == RAW_MATERIAL_TYPE_TRANSPARENT ||
|
||||||
material.type == RAW_MATERIAL_TYPE_TRANSPARENT ||
|
|
||||||
material.type == RAW_MATERIAL_TYPE_SKINNED_TRANSPARENT;
|
material.type == RAW_MATERIAL_TYPE_SKINNED_TRANSPARENT;
|
||||||
|
|
||||||
Vec3f emissiveFactor;
|
Vec3f emissiveFactor;
|
||||||
|
@ -229,12 +242,14 @@ ModelData *Raw2Gltf(
|
||||||
|
|
||||||
// acquire the texture of a specific RawTextureUsage as *TextData, or nullptr if none exists
|
// acquire the texture of a specific RawTextureUsage as *TextData, or nullptr if none exists
|
||||||
auto simpleTex = [&](RawTextureUsage usage) -> std::shared_ptr<TextureData> {
|
auto simpleTex = [&](RawTextureUsage usage) -> std::shared_ptr<TextureData> {
|
||||||
return (material.textures[usage] >= 0) ? textureBuilder.simple(material.textures[usage], "simple") : nullptr;
|
return (material.textures[usage] >= 0)
|
||||||
|
? textureBuilder.simple(material.textures[usage], "simple")
|
||||||
|
: nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
TextureData *normalTexture = simpleTex(RAW_TEXTURE_USAGE_NORMAL).get();
|
TextureData* normalTexture = simpleTex(RAW_TEXTURE_USAGE_NORMAL).get();
|
||||||
TextureData *emissiveTexture = simpleTex(RAW_TEXTURE_USAGE_EMISSIVE).get();
|
TextureData* emissiveTexture = simpleTex(RAW_TEXTURE_USAGE_EMISSIVE).get();
|
||||||
TextureData *occlusionTexture = nullptr;
|
TextureData* occlusionTexture = nullptr;
|
||||||
|
|
||||||
std::shared_ptr<PBRMetallicRoughness> pbrMetRough;
|
std::shared_ptr<PBRMetallicRoughness> pbrMetRough;
|
||||||
if (options.usePBRMetRough) {
|
if (options.usePBRMetRough) {
|
||||||
|
@ -250,8 +265,9 @@ ModelData *Raw2Gltf(
|
||||||
* METALLIC and ROUGHNESS textures are packed in G and B channels of a rough/met texture.
|
* METALLIC and ROUGHNESS textures are packed in G and B channels of a rough/met texture.
|
||||||
* Other values translate directly.
|
* Other values translate directly.
|
||||||
*/
|
*/
|
||||||
RawMetRoughMatProps *props = (RawMetRoughMatProps *) material.info.get();
|
RawMetRoughMatProps* props = (RawMetRoughMatProps*)material.info.get();
|
||||||
// merge metallic into the blue channel and roughness into the green, of a new combinatory texture
|
// merge metallic into the blue channel and roughness into the green, of a new combinatory
|
||||||
|
// texture
|
||||||
aoMetRoughTex = textureBuilder.combine(
|
aoMetRoughTex = textureBuilder.combine(
|
||||||
{
|
{
|
||||||
material.textures[RAW_TEXTURE_USAGE_OCCLUSION],
|
material.textures[RAW_TEXTURE_USAGE_OCCLUSION],
|
||||||
|
@ -259,8 +275,8 @@ ModelData *Raw2Gltf(
|
||||||
material.textures[RAW_TEXTURE_USAGE_ROUGHNESS],
|
material.textures[RAW_TEXTURE_USAGE_ROUGHNESS],
|
||||||
},
|
},
|
||||||
"ao_met_rough",
|
"ao_met_rough",
|
||||||
[&](const std::vector<const TextureBuilder::pixel *> pixels) -> TextureBuilder::pixel {
|
[&](const std::vector<const TextureBuilder::pixel*> pixels) -> TextureBuilder::pixel {
|
||||||
return { {(*pixels[0])[0], (*pixels[2])[0], (*pixels[1])[0], 1} };
|
return {{(*pixels[0])[0], (*pixels[2])[0], (*pixels[1])[0], 1}};
|
||||||
},
|
},
|
||||||
false);
|
false);
|
||||||
|
|
||||||
|
@ -270,7 +286,8 @@ ModelData *Raw2Gltf(
|
||||||
roughness = props->roughness;
|
roughness = props->roughness;
|
||||||
emissiveFactor = props->emissiveFactor;
|
emissiveFactor = props->emissiveFactor;
|
||||||
emissiveIntensity = props->emissiveIntensity;
|
emissiveIntensity = props->emissiveIntensity;
|
||||||
// add the occlusion texture only if actual occlusion pixels exist in the aoNetRough texture.
|
// add the occlusion texture only if actual occlusion pixels exist in the aoNetRough
|
||||||
|
// texture.
|
||||||
if (material.textures[RAW_TEXTURE_USAGE_OCCLUSION] >= 0) {
|
if (material.textures[RAW_TEXTURE_USAGE_OCCLUSION] >= 0) {
|
||||||
occlusionTexture = aoMetRoughTex.get();
|
occlusionTexture = aoMetRoughTex.get();
|
||||||
}
|
}
|
||||||
|
@ -280,12 +297,11 @@ ModelData *Raw2Gltf(
|
||||||
*
|
*
|
||||||
* Diffuse channel is used as base colour. Simple constants for metallic and roughness.
|
* Diffuse channel is used as base colour. Simple constants for metallic and roughness.
|
||||||
*/
|
*/
|
||||||
const RawTraditionalMatProps *props = ((RawTraditionalMatProps *) material.info.get());
|
const RawTraditionalMatProps* props = ((RawTraditionalMatProps*)material.info.get());
|
||||||
diffuseFactor = props->diffuseFactor;
|
diffuseFactor = props->diffuseFactor;
|
||||||
|
|
||||||
if (material.info->shadingModel == RAW_SHADING_MODEL_BLINN ||
|
if (material.info->shadingModel == RAW_SHADING_MODEL_BLINN ||
|
||||||
material.info->shadingModel == RAW_SHADING_MODEL_PHONG)
|
material.info->shadingModel == RAW_SHADING_MODEL_PHONG) {
|
||||||
{
|
|
||||||
// blinn/phong hardcoded to 0.4 metallic
|
// blinn/phong hardcoded to 0.4 metallic
|
||||||
metallic = 0.4f;
|
metallic = 0.4f;
|
||||||
|
|
||||||
|
@ -295,17 +311,19 @@ ModelData *Raw2Gltf(
|
||||||
// shininess 6 -> roughness 0.5
|
// shininess 6 -> roughness 0.5
|
||||||
// shininess 16 -> roughness ~0.33
|
// shininess 16 -> roughness ~0.33
|
||||||
// as shininess ==> oo, roughness ==> 0
|
// as shininess ==> oo, roughness ==> 0
|
||||||
auto getRoughness = [&](float shininess) {
|
auto getRoughness = [&](float shininess) { return sqrtf(2.0f / (2.0f + shininess)); };
|
||||||
return sqrtf(2.0f / (2.0f + shininess));
|
|
||||||
};
|
|
||||||
|
|
||||||
aoMetRoughTex = textureBuilder.combine(
|
aoMetRoughTex = textureBuilder.combine(
|
||||||
{ material.textures[RAW_TEXTURE_USAGE_SHININESS], },
|
{
|
||||||
|
material.textures[RAW_TEXTURE_USAGE_SHININESS],
|
||||||
|
},
|
||||||
"ao_met_rough",
|
"ao_met_rough",
|
||||||
[&](const std::vector<const TextureBuilder::pixel *> pixels) -> TextureBuilder::pixel {
|
[&](const std::vector<const TextureBuilder::pixel*> pixels)
|
||||||
// do not multiply with props->shininess; that doesn't work like the other factors.
|
-> TextureBuilder::pixel {
|
||||||
|
// do not multiply with props->shininess; that doesn't work like the other
|
||||||
|
// factors.
|
||||||
float shininess = props->shininess * (*pixels[0])[0];
|
float shininess = props->shininess * (*pixels[0])[0];
|
||||||
return { {0, getRoughness(shininess), metallic, 1} };
|
return {{0, getRoughness(shininess), metallic, 1}};
|
||||||
},
|
},
|
||||||
false);
|
false);
|
||||||
|
|
||||||
|
@ -327,7 +345,8 @@ ModelData *Raw2Gltf(
|
||||||
emissiveFactor = props->emissiveFactor;
|
emissiveFactor = props->emissiveFactor;
|
||||||
emissiveIntensity = 1.0f;
|
emissiveIntensity = 1.0f;
|
||||||
}
|
}
|
||||||
pbrMetRough.reset(new PBRMetallicRoughness(baseColorTex.get(), aoMetRoughTex.get(), diffuseFactor, metallic, roughness));
|
pbrMetRough.reset(new PBRMetallicRoughness(
|
||||||
|
baseColorTex.get(), aoMetRoughTex.get(), diffuseFactor, metallic, roughness));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<KHRCmnUnlitMaterial> khrCmnUnlitMat;
|
std::shared_ptr<KHRCmnUnlitMaterial> khrCmnUnlitMat;
|
||||||
|
@ -341,16 +360,17 @@ ModelData *Raw2Gltf(
|
||||||
std::shared_ptr<TextureData> baseColorTex;
|
std::shared_ptr<TextureData> baseColorTex;
|
||||||
|
|
||||||
if (material.info->shadingModel == RAW_SHADING_MODEL_PBR_MET_ROUGH) {
|
if (material.info->shadingModel == RAW_SHADING_MODEL_PBR_MET_ROUGH) {
|
||||||
RawMetRoughMatProps *props = (RawMetRoughMatProps *) material.info.get();
|
RawMetRoughMatProps* props = (RawMetRoughMatProps*)material.info.get();
|
||||||
diffuseFactor = props->diffuseFactor;
|
diffuseFactor = props->diffuseFactor;
|
||||||
baseColorTex = simpleTex(RAW_TEXTURE_USAGE_ALBEDO);
|
baseColorTex = simpleTex(RAW_TEXTURE_USAGE_ALBEDO);
|
||||||
} else {
|
} else {
|
||||||
RawTraditionalMatProps *props = ((RawTraditionalMatProps *) material.info.get());
|
RawTraditionalMatProps* props = ((RawTraditionalMatProps*)material.info.get());
|
||||||
diffuseFactor = props->diffuseFactor;
|
diffuseFactor = props->diffuseFactor;
|
||||||
baseColorTex = simpleTex(RAW_TEXTURE_USAGE_DIFFUSE);
|
baseColorTex = simpleTex(RAW_TEXTURE_USAGE_DIFFUSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
pbrMetRough.reset(new PBRMetallicRoughness(baseColorTex.get(), nullptr, diffuseFactor, 0.0f, 1.0f));
|
pbrMetRough.reset(
|
||||||
|
new PBRMetallicRoughness(baseColorTex.get(), nullptr, diffuseFactor, 0.0f, 1.0f));
|
||||||
|
|
||||||
khrCmnUnlitMat.reset(new KHRCmnUnlitMaterial());
|
khrCmnUnlitMat.reset(new KHRCmnUnlitMaterial());
|
||||||
}
|
}
|
||||||
|
@ -358,11 +378,16 @@ ModelData *Raw2Gltf(
|
||||||
occlusionTexture = simpleTex(RAW_TEXTURE_USAGE_OCCLUSION).get();
|
occlusionTexture = simpleTex(RAW_TEXTURE_USAGE_OCCLUSION).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MaterialData> mData = gltf->materials.hold(
|
std::shared_ptr<MaterialData> mData = gltf->materials.hold(new MaterialData(
|
||||||
new MaterialData(
|
material.name,
|
||||||
material.name, isTransparent, material.info->shadingModel,
|
isTransparent,
|
||||||
normalTexture, occlusionTexture, emissiveTexture,
|
material.info->shadingModel,
|
||||||
emissiveFactor * emissiveIntensity, khrCmnUnlitMat, pbrMetRough));
|
normalTexture,
|
||||||
|
occlusionTexture,
|
||||||
|
emissiveTexture,
|
||||||
|
emissiveFactor * emissiveIntensity,
|
||||||
|
khrCmnUnlitMat,
|
||||||
|
pbrMetRough));
|
||||||
materialsByName[materialHash(material)] = mData;
|
materialsByName[materialHash(material)] = mData;
|
||||||
|
|
||||||
if (options.enableUserProperties) {
|
if (options.enableUserProperties) {
|
||||||
|
@ -370,22 +395,23 @@ ModelData *Raw2Gltf(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &surfaceModel : materialModels) {
|
for (const auto& surfaceModel : materialModels) {
|
||||||
assert(surfaceModel.GetSurfaceCount() == 1);
|
assert(surfaceModel.GetSurfaceCount() == 1);
|
||||||
const RawSurface &rawSurface = surfaceModel.GetSurface(0);
|
const RawSurface& rawSurface = surfaceModel.GetSurface(0);
|
||||||
const long surfaceId = rawSurface.id;
|
const long surfaceId = rawSurface.id;
|
||||||
|
|
||||||
const RawMaterial &rawMaterial = surfaceModel.GetMaterial(surfaceModel.GetTriangle(0).materialIndex);
|
const RawMaterial& rawMaterial =
|
||||||
const MaterialData &mData = require(materialsByName, materialHash(rawMaterial));
|
surfaceModel.GetMaterial(surfaceModel.GetTriangle(0).materialIndex);
|
||||||
|
const MaterialData& mData = require(materialsByName, materialHash(rawMaterial));
|
||||||
|
|
||||||
MeshData *mesh = nullptr;
|
MeshData* mesh = nullptr;
|
||||||
auto meshIter = meshBySurfaceId.find(surfaceId);
|
auto meshIter = meshBySurfaceId.find(surfaceId);
|
||||||
if (meshIter != meshBySurfaceId.end()) {
|
if (meshIter != meshBySurfaceId.end()) {
|
||||||
mesh = meshIter->second.get();
|
mesh = meshIter->second.get();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
std::vector<float> defaultDeforms;
|
std::vector<float> defaultDeforms;
|
||||||
for (const auto &channel : rawSurface.blendChannels) {
|
for (const auto& channel : rawSurface.blendChannels) {
|
||||||
defaultDeforms.push_back(channel.defaultDeform);
|
defaultDeforms.push_back(channel.defaultDeform);
|
||||||
}
|
}
|
||||||
auto meshPtr = gltf->meshes.hold(new MeshData(rawSurface.name, defaultDeforms));
|
auto meshPtr = gltf->meshes.hold(new MeshData(rawSurface.name, defaultDeforms));
|
||||||
|
@ -393,10 +419,9 @@ ModelData *Raw2Gltf(
|
||||||
mesh = meshPtr.get();
|
mesh = meshPtr.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool useLongIndices =
|
bool useLongIndices = (options.useLongIndices == UseLongIndicesOptions::ALWAYS) ||
|
||||||
(options.useLongIndices == UseLongIndicesOptions::ALWAYS)
|
(options.useLongIndices == UseLongIndicesOptions::AUTO &&
|
||||||
|| (options.useLongIndices == UseLongIndicesOptions::AUTO
|
surfaceModel.GetVertexCount() > 65535);
|
||||||
&& surfaceModel.GetVertexCount() > 65535);
|
|
||||||
|
|
||||||
std::shared_ptr<PrimitiveData> primitive;
|
std::shared_ptr<PrimitiveData> primitive;
|
||||||
if (options.draco.enabled) {
|
if (options.draco.enabled) {
|
||||||
|
@ -414,13 +439,16 @@ ModelData *Raw2Gltf(
|
||||||
dracoMesh->SetFace(draco::FaceIndex(ii), face);
|
dracoMesh->SetFace(draco::FaceIndex(ii), face);
|
||||||
}
|
}
|
||||||
|
|
||||||
AccessorData &indexes = *gltf->accessors.hold(new AccessorData(useLongIndices ? GLT_UINT : GLT_USHORT));
|
AccessorData& indexes =
|
||||||
|
*gltf->accessors.hold(new AccessorData(useLongIndices ? GLT_UINT : GLT_USHORT));
|
||||||
indexes.count = 3 * triangleCount;
|
indexes.count = 3 * triangleCount;
|
||||||
primitive.reset(new PrimitiveData(indexes, mData, dracoMesh));
|
primitive.reset(new PrimitiveData(indexes, mData, dracoMesh));
|
||||||
} else {
|
} else {
|
||||||
const AccessorData &indexes = *gltf->AddAccessorWithView(
|
const AccessorData& indexes = *gltf->AddAccessorWithView(
|
||||||
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ELEMENT_ARRAY_BUFFER),
|
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ELEMENT_ARRAY_BUFFER),
|
||||||
useLongIndices ? GLT_UINT : GLT_USHORT, getIndexArray(surfaceModel), std::string(""));
|
useLongIndices ? GLT_UINT : GLT_USHORT,
|
||||||
|
getIndexArray(surfaceModel),
|
||||||
|
std::string(""));
|
||||||
primitive.reset(new PrimitiveData(indexes, mData));
|
primitive.reset(new PrimitiveData(indexes, mData));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -429,17 +457,25 @@ ModelData *Raw2Gltf(
|
||||||
//
|
//
|
||||||
{
|
{
|
||||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_POSITION) != 0) {
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_POSITION) != 0) {
|
||||||
const AttributeDefinition<Vec3f> ATTR_POSITION("POSITION", &RawVertex::position,
|
const AttributeDefinition<Vec3f> ATTR_POSITION(
|
||||||
GLT_VEC3F, draco::GeometryAttribute::POSITION, draco::DT_FLOAT32);
|
"POSITION",
|
||||||
auto accessor = gltf->AddAttributeToPrimitive<Vec3f>(
|
&RawVertex::position,
|
||||||
buffer, surfaceModel, *primitive, ATTR_POSITION);
|
GLT_VEC3F,
|
||||||
|
draco::GeometryAttribute::POSITION,
|
||||||
|
draco::DT_FLOAT32);
|
||||||
|
auto accessor =
|
||||||
|
gltf->AddAttributeToPrimitive<Vec3f>(buffer, surfaceModel, *primitive, ATTR_POSITION);
|
||||||
|
|
||||||
accessor->min = toStdVec(rawSurface.bounds.min);
|
accessor->min = toStdVec(rawSurface.bounds.min);
|
||||||
accessor->max = toStdVec(rawSurface.bounds.max);
|
accessor->max = toStdVec(rawSurface.bounds.max);
|
||||||
}
|
}
|
||||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_NORMAL) != 0) {
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_NORMAL) != 0) {
|
||||||
const AttributeDefinition<Vec3f> ATTR_NORMAL("NORMAL", &RawVertex::normal,
|
const AttributeDefinition<Vec3f> ATTR_NORMAL(
|
||||||
GLT_VEC3F, draco::GeometryAttribute::NORMAL, draco::DT_FLOAT32);
|
"NORMAL",
|
||||||
|
&RawVertex::normal,
|
||||||
|
GLT_VEC3F,
|
||||||
|
draco::GeometryAttribute::NORMAL,
|
||||||
|
draco::DT_FLOAT32);
|
||||||
gltf->AddAttributeToPrimitive<Vec3f>(buffer, surfaceModel, *primitive, ATTR_NORMAL);
|
gltf->AddAttributeToPrimitive<Vec3f>(buffer, surfaceModel, *primitive, ATTR_NORMAL);
|
||||||
}
|
}
|
||||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_TANGENT) != 0) {
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_TANGENT) != 0) {
|
||||||
|
@ -447,41 +483,61 @@ ModelData *Raw2Gltf(
|
||||||
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_TANGENT);
|
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_TANGENT);
|
||||||
}
|
}
|
||||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_COLOR) != 0) {
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_COLOR) != 0) {
|
||||||
const AttributeDefinition<Vec4f> ATTR_COLOR("COLOR_0", &RawVertex::color, GLT_VEC4F,
|
const AttributeDefinition<Vec4f> ATTR_COLOR(
|
||||||
draco::GeometryAttribute::COLOR, draco::DT_FLOAT32);
|
"COLOR_0",
|
||||||
|
&RawVertex::color,
|
||||||
|
GLT_VEC4F,
|
||||||
|
draco::GeometryAttribute::COLOR,
|
||||||
|
draco::DT_FLOAT32);
|
||||||
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_COLOR);
|
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_COLOR);
|
||||||
}
|
}
|
||||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_UV0) != 0) {
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_UV0) != 0) {
|
||||||
const AttributeDefinition<Vec2f> ATTR_TEXCOORD_0("TEXCOORD_0", &RawVertex::uv0,
|
const AttributeDefinition<Vec2f> ATTR_TEXCOORD_0(
|
||||||
GLT_VEC2F, draco::GeometryAttribute::TEX_COORD, draco::DT_FLOAT32);
|
"TEXCOORD_0",
|
||||||
|
&RawVertex::uv0,
|
||||||
|
GLT_VEC2F,
|
||||||
|
draco::GeometryAttribute::TEX_COORD,
|
||||||
|
draco::DT_FLOAT32);
|
||||||
gltf->AddAttributeToPrimitive<Vec2f>(buffer, surfaceModel, *primitive, ATTR_TEXCOORD_0);
|
gltf->AddAttributeToPrimitive<Vec2f>(buffer, surfaceModel, *primitive, ATTR_TEXCOORD_0);
|
||||||
}
|
}
|
||||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_UV1) != 0) {
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_UV1) != 0) {
|
||||||
const AttributeDefinition<Vec2f> ATTR_TEXCOORD_1("TEXCOORD_1", &RawVertex::uv1,
|
const AttributeDefinition<Vec2f> ATTR_TEXCOORD_1(
|
||||||
GLT_VEC2F, draco::GeometryAttribute::TEX_COORD, draco::DT_FLOAT32);
|
"TEXCOORD_1",
|
||||||
|
&RawVertex::uv1,
|
||||||
|
GLT_VEC2F,
|
||||||
|
draco::GeometryAttribute::TEX_COORD,
|
||||||
|
draco::DT_FLOAT32);
|
||||||
gltf->AddAttributeToPrimitive<Vec2f>(buffer, surfaceModel, *primitive, ATTR_TEXCOORD_1);
|
gltf->AddAttributeToPrimitive<Vec2f>(buffer, surfaceModel, *primitive, ATTR_TEXCOORD_1);
|
||||||
}
|
}
|
||||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES) != 0) {
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES) != 0) {
|
||||||
const AttributeDefinition<Vec4i> ATTR_JOINTS("JOINTS_0", &RawVertex::jointIndices,
|
const AttributeDefinition<Vec4i> ATTR_JOINTS(
|
||||||
GLT_VEC4I, draco::GeometryAttribute::GENERIC, draco::DT_UINT16);
|
"JOINTS_0",
|
||||||
|
&RawVertex::jointIndices,
|
||||||
|
GLT_VEC4I,
|
||||||
|
draco::GeometryAttribute::GENERIC,
|
||||||
|
draco::DT_UINT16);
|
||||||
gltf->AddAttributeToPrimitive<Vec4i>(buffer, surfaceModel, *primitive, ATTR_JOINTS);
|
gltf->AddAttributeToPrimitive<Vec4i>(buffer, surfaceModel, *primitive, ATTR_JOINTS);
|
||||||
}
|
}
|
||||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS) != 0) {
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS) != 0) {
|
||||||
const AttributeDefinition<Vec4f> ATTR_WEIGHTS("WEIGHTS_0", &RawVertex::jointWeights,
|
const AttributeDefinition<Vec4f> ATTR_WEIGHTS(
|
||||||
GLT_VEC4F, draco::GeometryAttribute::GENERIC, draco::DT_FLOAT32);
|
"WEIGHTS_0",
|
||||||
|
&RawVertex::jointWeights,
|
||||||
|
GLT_VEC4F,
|
||||||
|
draco::GeometryAttribute::GENERIC,
|
||||||
|
draco::DT_FLOAT32);
|
||||||
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_WEIGHTS);
|
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_WEIGHTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// each channel present in the mesh always ends up a target in the primitive
|
// each channel present in the mesh always ends up a target in the primitive
|
||||||
for (int channelIx = 0; channelIx < rawSurface.blendChannels.size(); channelIx ++) {
|
for (int channelIx = 0; channelIx < rawSurface.blendChannels.size(); channelIx++) {
|
||||||
const auto &channel = rawSurface.blendChannels[channelIx];
|
const auto& channel = rawSurface.blendChannels[channelIx];
|
||||||
|
|
||||||
// track the bounds of each shape channel
|
// track the bounds of each shape channel
|
||||||
Bounds<float, 3> shapeBounds;
|
Bounds<float, 3> shapeBounds;
|
||||||
|
|
||||||
std::vector<Vec3f> positions, normals;
|
std::vector<Vec3f> positions, normals;
|
||||||
std::vector<Vec4f> tangents;
|
std::vector<Vec4f> tangents;
|
||||||
for (int jj = 0; jj < surfaceModel.GetVertexCount(); jj ++) {
|
for (int jj = 0; jj < surfaceModel.GetVertexCount(); jj++) {
|
||||||
auto blendVertex = surfaceModel.GetVertex(jj).blends[channelIx];
|
auto blendVertex = surfaceModel.GetVertex(jj).blends[channelIx];
|
||||||
shapeBounds.AddPoint(blendVertex.position);
|
shapeBounds.AddPoint(blendVertex.position);
|
||||||
positions.push_back(blendVertex.position);
|
positions.push_back(blendVertex.position);
|
||||||
|
@ -494,7 +550,9 @@ ModelData *Raw2Gltf(
|
||||||
}
|
}
|
||||||
std::shared_ptr<AccessorData> pAcc = gltf->AddAccessorWithView(
|
std::shared_ptr<AccessorData> pAcc = gltf->AddAccessorWithView(
|
||||||
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER),
|
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER),
|
||||||
GLT_VEC3F, positions, channel.name);
|
GLT_VEC3F,
|
||||||
|
positions,
|
||||||
|
channel.name);
|
||||||
pAcc->min = toStdVec(shapeBounds.min);
|
pAcc->min = toStdVec(shapeBounds.min);
|
||||||
pAcc->max = toStdVec(shapeBounds.max);
|
pAcc->max = toStdVec(shapeBounds.max);
|
||||||
|
|
||||||
|
@ -502,14 +560,18 @@ ModelData *Raw2Gltf(
|
||||||
if (!normals.empty()) {
|
if (!normals.empty()) {
|
||||||
nAcc = gltf->AddAccessorWithView(
|
nAcc = gltf->AddAccessorWithView(
|
||||||
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER),
|
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER),
|
||||||
GLT_VEC3F, normals, channel.name);
|
GLT_VEC3F,
|
||||||
|
normals,
|
||||||
|
channel.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<AccessorData> tAcc;
|
std::shared_ptr<AccessorData> tAcc;
|
||||||
if (!tangents.empty()) {
|
if (!tangents.empty()) {
|
||||||
nAcc = gltf->AddAccessorWithView(
|
nAcc = gltf->AddAccessorWithView(
|
||||||
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER),
|
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER),
|
||||||
GLT_VEC4F, tangents, channel.name);
|
GLT_VEC4F,
|
||||||
|
tangents,
|
||||||
|
channel.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
primitive->AddTarget(pAcc.get(), nAcc.get(), tAcc.get());
|
primitive->AddTarget(pAcc.get(), nAcc.get(), tAcc.get());
|
||||||
|
@ -524,19 +586,24 @@ ModelData *Raw2Gltf(
|
||||||
encoder.SetSpeedOptions(dracoSpeed, dracoSpeed);
|
encoder.SetSpeedOptions(dracoSpeed, dracoSpeed);
|
||||||
}
|
}
|
||||||
if (options.draco.quantBitsPosition != -1) {
|
if (options.draco.quantBitsPosition != -1) {
|
||||||
encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, options.draco.quantBitsPosition);
|
encoder.SetAttributeQuantization(
|
||||||
|
draco::GeometryAttribute::POSITION, options.draco.quantBitsPosition);
|
||||||
}
|
}
|
||||||
if (options.draco.quantBitsTexCoord != -1) {
|
if (options.draco.quantBitsTexCoord != -1) {
|
||||||
encoder.SetAttributeQuantization(draco::GeometryAttribute::TEX_COORD, options.draco.quantBitsTexCoord);
|
encoder.SetAttributeQuantization(
|
||||||
|
draco::GeometryAttribute::TEX_COORD, options.draco.quantBitsTexCoord);
|
||||||
}
|
}
|
||||||
if (options.draco.quantBitsNormal != -1) {
|
if (options.draco.quantBitsNormal != -1) {
|
||||||
encoder.SetAttributeQuantization(draco::GeometryAttribute::NORMAL, options.draco.quantBitsNormal);
|
encoder.SetAttributeQuantization(
|
||||||
|
draco::GeometryAttribute::NORMAL, options.draco.quantBitsNormal);
|
||||||
}
|
}
|
||||||
if (options.draco.quantBitsColor != -1) {
|
if (options.draco.quantBitsColor != -1) {
|
||||||
encoder.SetAttributeQuantization(draco::GeometryAttribute::COLOR, options.draco.quantBitsColor);
|
encoder.SetAttributeQuantization(
|
||||||
|
draco::GeometryAttribute::COLOR, options.draco.quantBitsColor);
|
||||||
}
|
}
|
||||||
if (options.draco.quantBitsGeneric != -1) {
|
if (options.draco.quantBitsGeneric != -1) {
|
||||||
encoder.SetAttributeQuantization(draco::GeometryAttribute::GENERIC, options.draco.quantBitsGeneric);
|
encoder.SetAttributeQuantization(
|
||||||
|
draco::GeometryAttribute::GENERIC, options.draco.quantBitsGeneric);
|
||||||
}
|
}
|
||||||
|
|
||||||
draco::EncoderBuffer dracoBuffer;
|
draco::EncoderBuffer dracoBuffer;
|
||||||
|
@ -554,18 +621,17 @@ ModelData *Raw2Gltf(
|
||||||
//
|
//
|
||||||
|
|
||||||
for (int i = 0; i < raw.GetNodeCount(); i++) {
|
for (int i = 0; i < raw.GetNodeCount(); i++) {
|
||||||
const RawNode &node = raw.GetNode(i);
|
const RawNode& node = raw.GetNode(i);
|
||||||
auto nodeData = gltf->nodes.ptrs[i];
|
auto nodeData = gltf->nodes.ptrs[i];
|
||||||
|
|
||||||
//
|
//
|
||||||
// Assign mesh to node
|
// Assign mesh to node
|
||||||
//
|
//
|
||||||
if (node.surfaceId > 0)
|
if (node.surfaceId > 0) {
|
||||||
{
|
|
||||||
int surfaceIndex = raw.GetSurfaceById(node.surfaceId);
|
int surfaceIndex = raw.GetSurfaceById(node.surfaceId);
|
||||||
const RawSurface &rawSurface = raw.GetSurface(surfaceIndex);
|
const RawSurface& rawSurface = raw.GetSurface(surfaceIndex);
|
||||||
|
|
||||||
MeshData &meshData = require(meshBySurfaceId, rawSurface.id);
|
MeshData& meshData = require(meshBySurfaceId, rawSurface.id);
|
||||||
nodeData->SetMesh(meshData.ix);
|
nodeData->SetMesh(meshData.ix);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -575,12 +641,12 @@ ModelData *Raw2Gltf(
|
||||||
if (nodeData->skin == -1) {
|
if (nodeData->skin == -1) {
|
||||||
// glTF uses column-major matrices
|
// glTF uses column-major matrices
|
||||||
std::vector<Mat4f> inverseBindMatrices;
|
std::vector<Mat4f> inverseBindMatrices;
|
||||||
for (const auto &inverseBindMatrice : rawSurface.inverseBindMatrices) {
|
for (const auto& inverseBindMatrice : rawSurface.inverseBindMatrices) {
|
||||||
inverseBindMatrices.push_back(inverseBindMatrice.Transpose());
|
inverseBindMatrices.push_back(inverseBindMatrice.Transpose());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint32_t> jointIndexes;
|
std::vector<uint32_t> jointIndexes;
|
||||||
for (const auto &jointId : rawSurface.jointIds) {
|
for (const auto& jointId : rawSurface.jointIds) {
|
||||||
jointIndexes.push_back(require(nodesById, jointId).ix);
|
jointIndexes.push_back(require(nodesById, jointId).ix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,14 +666,14 @@ ModelData *Raw2Gltf(
|
||||||
//
|
//
|
||||||
|
|
||||||
for (int i = 0; i < raw.GetCameraCount(); i++) {
|
for (int i = 0; i < raw.GetCameraCount(); i++) {
|
||||||
const RawCamera &cam = raw.GetCamera(i);
|
const RawCamera& cam = raw.GetCamera(i);
|
||||||
CameraData &camera = *gltf->cameras.hold(new CameraData());
|
CameraData& camera = *gltf->cameras.hold(new CameraData());
|
||||||
camera.name = cam.name;
|
camera.name = cam.name;
|
||||||
|
|
||||||
if (cam.mode == RawCamera::CAMERA_MODE_PERSPECTIVE) {
|
if (cam.mode == RawCamera::CAMERA_MODE_PERSPECTIVE) {
|
||||||
camera.type = "perspective";
|
camera.type = "perspective";
|
||||||
camera.aspectRatio = cam.perspective.aspectRatio;
|
camera.aspectRatio = cam.perspective.aspectRatio;
|
||||||
camera.yfov = cam.perspective.fovDegreesY * ((float) M_PI / 180.0f);
|
camera.yfov = cam.perspective.fovDegreesY * ((float)M_PI / 180.0f);
|
||||||
camera.znear = cam.perspective.nearZ;
|
camera.znear = cam.perspective.nearZ;
|
||||||
camera.zfar = cam.perspective.farZ;
|
camera.zfar = cam.perspective.farZ;
|
||||||
} else {
|
} else {
|
||||||
|
@ -632,10 +698,10 @@ ModelData *Raw2Gltf(
|
||||||
//
|
//
|
||||||
std::vector<json> khrPunctualLights;
|
std::vector<json> khrPunctualLights;
|
||||||
if (options.useKHRLightsPunctual) {
|
if (options.useKHRLightsPunctual) {
|
||||||
for (int i = 0; i < raw.GetLightCount(); i ++) {
|
for (int i = 0; i < raw.GetLightCount(); i++) {
|
||||||
const RawLight &light = raw.GetLight(i);
|
const RawLight& light = raw.GetLight(i);
|
||||||
LightData::Type type;
|
LightData::Type type;
|
||||||
switch(light.type) {
|
switch (light.type) {
|
||||||
case RAW_LIGHT_TYPE_DIRECTIONAL:
|
case RAW_LIGHT_TYPE_DIRECTIONAL:
|
||||||
type = LightData::Type::Directional;
|
type = LightData::Type::Directional;
|
||||||
break;
|
break;
|
||||||
|
@ -659,7 +725,7 @@ ModelData *Raw2Gltf(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < raw.GetNodeCount(); i++) {
|
for (int i = 0; i < raw.GetNodeCount(); i++) {
|
||||||
const RawNode &node = raw.GetNode(i);
|
const RawNode& node = raw.GetNode(i);
|
||||||
const auto nodeData = gltf->nodes.ptrs[i];
|
const auto nodeData = gltf->nodes.ptrs[i];
|
||||||
|
|
||||||
if (node.lightIx >= 0) {
|
if (node.lightIx >= 0) {
|
||||||
|
@ -669,22 +735,37 @@ ModelData *Raw2Gltf(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeData &rootNode = require(nodesById, raw.GetRootNode());
|
NodeData& rootNode = require(nodesById, raw.GetRootNode());
|
||||||
const SceneData &rootScene = *gltf->scenes.hold(new SceneData(DEFAULT_SCENE_NAME, rootNode));
|
const SceneData& rootScene = *gltf->scenes.hold(new SceneData(DEFAULT_SCENE_NAME, rootNode));
|
||||||
|
|
||||||
if (options.outputBinary) {
|
if (options.outputBinary) {
|
||||||
// note: glTF binary is little-endian
|
// note: glTF binary is little-endian
|
||||||
const char glbHeader[] = {
|
const char glbHeader[] = {
|
||||||
'g', 'l', 'T', 'F', // magic
|
'g',
|
||||||
0x02, 0x00, 0x00, 0x00, // version
|
'l',
|
||||||
0x00, 0x00, 0x00, 0x00, // total length: written in later
|
'T',
|
||||||
|
'F', // magic
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00, // version
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00, // total length: written in later
|
||||||
};
|
};
|
||||||
gltfOutStream.write(glbHeader, 12);
|
gltfOutStream.write(glbHeader, 12);
|
||||||
|
|
||||||
// binary glTF 2.0 has a sub-header for each of the JSON and BIN chunks
|
// binary glTF 2.0 has a sub-header for each of the JSON and BIN chunks
|
||||||
const char glb2JsonHeader[] = {
|
const char glb2JsonHeader[] = {
|
||||||
0x00, 0x00, 0x00, 0x00, // chunk length: written in later
|
0x00,
|
||||||
'J', 'S', 'O', 'N', // chunk type: 0x4E4F534A aka JSON
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00, // chunk length: written in later
|
||||||
|
'J',
|
||||||
|
'S',
|
||||||
|
'O',
|
||||||
|
'N', // chunk type: 0x4E4F534A aka JSON
|
||||||
};
|
};
|
||||||
gltfOutStream.write(glb2JsonHeader, 8);
|
gltfOutStream.write(glb2JsonHeader, 8);
|
||||||
}
|
}
|
||||||
|
@ -702,12 +783,8 @@ ModelData *Raw2Gltf(
|
||||||
extensionsRequired.push_back(KHR_DRACO_MESH_COMPRESSION);
|
extensionsRequired.push_back(KHR_DRACO_MESH_COMPRESSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
json glTFJson {
|
json glTFJson{{"asset", {{"generator", "FBX2glTF v" + FBX2GLTF_VERSION}, {"version", "2.0"}}},
|
||||||
{ "asset", {
|
{"scene", rootScene.ix}};
|
||||||
{ "generator", "FBX2glTF v" + FBX2GLTF_VERSION },
|
|
||||||
{ "version", "2.0" }}},
|
|
||||||
{ "scene", rootScene.ix }
|
|
||||||
};
|
|
||||||
if (!extensionsUsed.empty()) {
|
if (!extensionsUsed.empty()) {
|
||||||
glTFJson["extensionsUsed"] = extensionsUsed;
|
glTFJson["extensionsUsed"] = extensionsUsed;
|
||||||
}
|
}
|
||||||
|
@ -720,29 +797,35 @@ ModelData *Raw2Gltf(
|
||||||
gltfOutStream << glTFJson.dump(options.outputBinary ? 0 : 4);
|
gltfOutStream << glTFJson.dump(options.outputBinary ? 0 : 4);
|
||||||
}
|
}
|
||||||
if (options.outputBinary) {
|
if (options.outputBinary) {
|
||||||
uint32_t jsonLength = (uint32_t) gltfOutStream.tellp() - 20;
|
uint32_t jsonLength = (uint32_t)gltfOutStream.tellp() - 20;
|
||||||
// the binary body must begin on a 4-aligned address, so pad json with spaces if necessary
|
// the binary body must begin on a 4-aligned address, so pad json with spaces if necessary
|
||||||
while ((jsonLength % 4) != 0) {
|
while ((jsonLength % 4) != 0) {
|
||||||
gltfOutStream.put(' ');
|
gltfOutStream.put(' ');
|
||||||
jsonLength++;
|
jsonLength++;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t binHeader = (uint32_t) gltfOutStream.tellp();
|
uint32_t binHeader = (uint32_t)gltfOutStream.tellp();
|
||||||
// binary glTF 2.0 has a sub-header for each of the JSON and BIN chunks
|
// binary glTF 2.0 has a sub-header for each of the JSON and BIN chunks
|
||||||
const char glb2BinaryHeader[] = {
|
const char glb2BinaryHeader[] = {
|
||||||
0x00, 0x00, 0x00, 0x00, // chunk length: written in later
|
0x00,
|
||||||
'B', 'I', 'N', 0x00, // chunk type: 0x004E4942 aka BIN
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00, // chunk length: written in later
|
||||||
|
'B',
|
||||||
|
'I',
|
||||||
|
'N',
|
||||||
|
0x00, // chunk type: 0x004E4942 aka BIN
|
||||||
};
|
};
|
||||||
gltfOutStream.write(glb2BinaryHeader, 8);
|
gltfOutStream.write(glb2BinaryHeader, 8);
|
||||||
|
|
||||||
// append binary buffer directly to .glb file
|
// append binary buffer directly to .glb file
|
||||||
uint32_t binaryLength = gltf->binary->size();
|
uint32_t binaryLength = gltf->binary->size();
|
||||||
gltfOutStream.write((const char *) &(*gltf->binary)[0], binaryLength);
|
gltfOutStream.write((const char*)&(*gltf->binary)[0], binaryLength);
|
||||||
while ((binaryLength % 4) != 0) {
|
while ((binaryLength % 4) != 0) {
|
||||||
gltfOutStream.put('\0');
|
gltfOutStream.put('\0');
|
||||||
binaryLength++;
|
binaryLength++;
|
||||||
}
|
}
|
||||||
uint32_t totalLength = (uint32_t) gltfOutStream.tellp();
|
uint32_t totalLength = (uint32_t)gltfOutStream.tellp();
|
||||||
|
|
||||||
// seek back to sub-header for json chunk
|
// seek back to sub-header for json chunk
|
||||||
gltfOutStream.seekp(8);
|
gltfOutStream.seekp(8);
|
||||||
|
|
|
@ -27,8 +27,7 @@ const std::string extBufferFilename = "buffer.bin";
|
||||||
|
|
||||||
struct ComponentType {
|
struct ComponentType {
|
||||||
// OpenGL Datatype enums
|
// OpenGL Datatype enums
|
||||||
enum GL_DataType
|
enum GL_DataType {
|
||||||
{
|
|
||||||
GL_BYTE = 5120,
|
GL_BYTE = 5120,
|
||||||
GL_UNSIGNED_BYTE,
|
GL_UNSIGNED_BYTE,
|
||||||
GL_SHORT,
|
GL_SHORT,
|
||||||
|
@ -48,55 +47,56 @@ const ComponentType CT_FLOAT = {ComponentType::GL_FLOAT, 4};
|
||||||
|
|
||||||
// Map our low-level data types for glTF output
|
// Map our low-level data types for glTF output
|
||||||
struct GLType {
|
struct GLType {
|
||||||
GLType(const ComponentType &componentType, unsigned int count, const std::string dataType)
|
GLType(const ComponentType& componentType, unsigned int count, const std::string dataType)
|
||||||
: componentType(componentType),
|
: componentType(componentType), count(count), dataType(dataType) {}
|
||||||
count(count),
|
|
||||||
dataType(dataType)
|
|
||||||
{}
|
|
||||||
|
|
||||||
unsigned int byteStride() const { return componentType.size * count; }
|
unsigned int byteStride() const {
|
||||||
|
return componentType.size * count;
|
||||||
|
}
|
||||||
|
|
||||||
void write(uint8_t *buf, const float scalar) const { *((float *) buf) = scalar; }
|
void write(uint8_t* buf, const float scalar) const {
|
||||||
void write(uint8_t *buf, const uint32_t scalar) const {
|
*((float*)buf) = scalar;
|
||||||
switch(componentType.size) {
|
}
|
||||||
|
void write(uint8_t* buf, const uint32_t scalar) const {
|
||||||
|
switch (componentType.size) {
|
||||||
case 1:
|
case 1:
|
||||||
*buf = (uint8_t)scalar;
|
*buf = (uint8_t)scalar;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
*((uint16_t *) buf) = (uint16_t)scalar;
|
*((uint16_t*)buf) = (uint16_t)scalar;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
*((uint32_t *) buf) = scalar;
|
*((uint32_t*)buf) = scalar;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, int d>
|
template <class T, int d>
|
||||||
void write(uint8_t *buf, const mathfu::Vector<T, d> &vector) const {
|
void write(uint8_t* buf, const mathfu::Vector<T, d>& vector) const {
|
||||||
for (int ii = 0; ii < d; ii ++) {
|
for (int ii = 0; ii < d; ii++) {
|
||||||
((T *)buf)[ii] = vector(ii);
|
((T*)buf)[ii] = vector(ii);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template<class T, int d>
|
template <class T, int d>
|
||||||
void write(uint8_t *buf, const mathfu::Matrix<T, d> &matrix) const {
|
void write(uint8_t* buf, const mathfu::Matrix<T, d>& matrix) const {
|
||||||
// three matrix types require special alignment considerations that we don't handle
|
// three matrix types require special alignment considerations that we don't handle
|
||||||
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment
|
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment
|
||||||
assert(!(sizeof(T) == 1 && d == 2));
|
assert(!(sizeof(T) == 1 && d == 2));
|
||||||
assert(!(sizeof(T) == 1 && d == 3));
|
assert(!(sizeof(T) == 1 && d == 3));
|
||||||
assert(!(sizeof(T) == 2 && d == 2));
|
assert(!(sizeof(T) == 2 && d == 2));
|
||||||
for (int col = 0; col < d; col ++) {
|
for (int col = 0; col < d; col++) {
|
||||||
for (int row = 0; row < d; row ++) {
|
for (int row = 0; row < d; row++) {
|
||||||
// glTF matrices are column-major
|
// glTF matrices are column-major
|
||||||
((T *)buf)[col * d + row] = matrix(row, col);
|
((T*)buf)[col * d + row] = matrix(row, col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template<class T>
|
template <class T>
|
||||||
void write(uint8_t *buf, const mathfu::Quaternion<T> &quaternion) const {
|
void write(uint8_t* buf, const mathfu::Quaternion<T>& quaternion) const {
|
||||||
for (int ii = 0; ii < 3; ii++) {
|
for (int ii = 0; ii < 3; ii++) {
|
||||||
((T *)buf)[ii] = quaternion.vector()(ii);
|
((T*)buf)[ii] = quaternion.vector()(ii);
|
||||||
}
|
}
|
||||||
((T *)buf)[3] = quaternion.scalar();
|
((T*)buf)[3] = quaternion.scalar();
|
||||||
}
|
}
|
||||||
|
|
||||||
const ComponentType componentType;
|
const ComponentType componentType;
|
||||||
|
@ -119,25 +119,26 @@ const GLType GLT_QUATF = {CT_FLOAT, 4, "VEC4"};
|
||||||
/**
|
/**
|
||||||
* The base of any indexed glTF entity.
|
* The base of any indexed glTF entity.
|
||||||
*/
|
*/
|
||||||
struct Holdable
|
struct Holdable {
|
||||||
{
|
|
||||||
uint32_t ix;
|
uint32_t ix;
|
||||||
|
|
||||||
virtual json serialize() const = 0;
|
virtual json serialize() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
struct AttributeDefinition
|
struct AttributeDefinition {
|
||||||
{
|
|
||||||
const std::string gltfName;
|
const std::string gltfName;
|
||||||
const T RawVertex::* rawAttributeIx;
|
const T RawVertex::*rawAttributeIx;
|
||||||
const GLType glType;
|
const GLType glType;
|
||||||
const draco::GeometryAttribute::Type dracoAttribute;
|
const draco::GeometryAttribute::Type dracoAttribute;
|
||||||
const draco::DataType dracoComponentType;
|
const draco::DataType dracoComponentType;
|
||||||
|
|
||||||
AttributeDefinition(
|
AttributeDefinition(
|
||||||
const std::string gltfName, const T RawVertex::*rawAttributeIx, const GLType &_glType,
|
const std::string gltfName,
|
||||||
const draco::GeometryAttribute::Type dracoAttribute, const draco::DataType dracoComponentType)
|
const T RawVertex::*rawAttributeIx,
|
||||||
|
const GLType& _glType,
|
||||||
|
const draco::GeometryAttribute::Type dracoAttribute,
|
||||||
|
const draco::DataType dracoComponentType)
|
||||||
: gltfName(gltfName),
|
: gltfName(gltfName),
|
||||||
rawAttributeIx(rawAttributeIx),
|
rawAttributeIx(rawAttributeIx),
|
||||||
glType(_glType),
|
glType(_glType),
|
||||||
|
@ -145,7 +146,9 @@ struct AttributeDefinition
|
||||||
dracoComponentType(dracoComponentType) {}
|
dracoComponentType(dracoComponentType) {}
|
||||||
|
|
||||||
AttributeDefinition(
|
AttributeDefinition(
|
||||||
const std::string gltfName, const T RawVertex::*rawAttributeIx, const GLType &_glType)
|
const std::string gltfName,
|
||||||
|
const T RawVertex::*rawAttributeIx,
|
||||||
|
const GLType& _glType)
|
||||||
: gltfName(gltfName),
|
: gltfName(gltfName),
|
||||||
rawAttributeIx(rawAttributeIx),
|
rawAttributeIx(rawAttributeIx),
|
||||||
glType(_glType),
|
glType(_glType),
|
||||||
|
@ -169,19 +172,15 @@ struct SceneData;
|
||||||
struct SkinData;
|
struct SkinData;
|
||||||
struct TextureData;
|
struct TextureData;
|
||||||
|
|
||||||
struct ModelData
|
struct ModelData {
|
||||||
{
|
explicit ModelData(std::shared_ptr<const std::vector<uint8_t>> const& _binary)
|
||||||
explicit ModelData(std::shared_ptr<const std::vector<uint8_t> > const &_binary)
|
: binary(_binary) {}
|
||||||
: binary(_binary)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<const std::vector<uint8_t> > const binary;
|
std::shared_ptr<const std::vector<uint8_t>> const binary;
|
||||||
};
|
};
|
||||||
|
|
||||||
ModelData *Raw2Gltf(
|
ModelData* Raw2Gltf(
|
||||||
std::ofstream &gltfOutStream,
|
std::ofstream& gltfOutStream,
|
||||||
const std::string &outputFolder,
|
const std::string& outputFolder,
|
||||||
const RawModel &raw,
|
const RawModel& raw,
|
||||||
const GltfOptions &options
|
const GltfOptions& options);
|
||||||
);
|
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
/**
|
/**
|
||||||
* Copyright (c) 2014-present, Facebook, Inc.
|
* Copyright (c) 2014-present, Facebook, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under the BSD-style license found in the
|
* This source code is licensed under the BSD-style license found in the
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "TextureBuilder.hpp"
|
#include "TextureBuilder.hpp"
|
||||||
|
|
||||||
#include <stb_image.h>
|
#include <stb_image.h>
|
||||||
#include <stb_image_write.h>
|
#include <stb_image_write.h>
|
||||||
|
|
||||||
|
#include <utils/File_Utils.hpp>
|
||||||
#include <utils/Image_Utils.hpp>
|
#include <utils/Image_Utils.hpp>
|
||||||
#include <utils/String_Utils.hpp>
|
#include <utils/String_Utils.hpp>
|
||||||
#include <utils/File_Utils.hpp>
|
|
||||||
|
|
||||||
#include <gltf/properties/ImageData.hpp>
|
#include <gltf/properties/ImageData.hpp>
|
||||||
#include <gltf/properties/TextureData.hpp>
|
#include <gltf/properties/TextureData.hpp>
|
||||||
|
@ -24,18 +24,17 @@ struct TexInfo {
|
||||||
explicit TexInfo(int rawTexIx) : rawTexIx(rawTexIx) {}
|
explicit TexInfo(int rawTexIx) : rawTexIx(rawTexIx) {}
|
||||||
|
|
||||||
const int rawTexIx;
|
const int rawTexIx;
|
||||||
int width {};
|
int width{};
|
||||||
int height {};
|
int height{};
|
||||||
int channels {};
|
int channels{};
|
||||||
uint8_t *pixels {};
|
uint8_t* pixels{};
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<TextureData> TextureBuilder::combine(
|
std::shared_ptr<TextureData> TextureBuilder::combine(
|
||||||
const std::vector<int> &ixVec,
|
const std::vector<int>& ixVec,
|
||||||
const std::string &tag,
|
const std::string& tag,
|
||||||
const pixel_merger &computePixel,
|
const pixel_merger& computePixel,
|
||||||
bool includeAlphaChannel)
|
bool includeAlphaChannel) {
|
||||||
{
|
|
||||||
const std::string key = texIndicesKey(ixVec, tag);
|
const std::string key = texIndicesKey(ixVec, tag);
|
||||||
auto iter = textureByIndicesKey.find(key);
|
auto iter = textureByIndicesKey.find(key);
|
||||||
if (iter != textureByIndicesKey.end()) {
|
if (iter != textureByIndicesKey.end()) {
|
||||||
|
@ -44,27 +43,30 @@ std::shared_ptr<TextureData> TextureBuilder::combine(
|
||||||
|
|
||||||
int width = -1, height = -1;
|
int width = -1, height = -1;
|
||||||
std::string mergedFilename = tag;
|
std::string mergedFilename = tag;
|
||||||
std::vector<TexInfo> texes { };
|
std::vector<TexInfo> texes{};
|
||||||
for (const int rawTexIx : ixVec) {
|
for (const int rawTexIx : ixVec) {
|
||||||
TexInfo info(rawTexIx);
|
TexInfo info(rawTexIx);
|
||||||
if (rawTexIx >= 0) {
|
if (rawTexIx >= 0) {
|
||||||
const RawTexture &rawTex = raw.GetTexture(rawTexIx);
|
const RawTexture& rawTex = raw.GetTexture(rawTexIx);
|
||||||
const std::string &fileLoc = rawTex.fileLocation;
|
const std::string& fileLoc = rawTex.fileLocation;
|
||||||
const std::string &name = StringUtils::GetFileBaseString(StringUtils::GetFileNameString(fileLoc));
|
const std::string& name =
|
||||||
|
StringUtils::GetFileBaseString(StringUtils::GetFileNameString(fileLoc));
|
||||||
if (!fileLoc.empty()) {
|
if (!fileLoc.empty()) {
|
||||||
info.pixels = stbi_load(fileLoc.c_str(), &info.width, &info.height, &info.channels, 0);
|
info.pixels = stbi_load(fileLoc.c_str(), &info.width, &info.height, &info.channels, 0);
|
||||||
if (!info.pixels) {
|
if (!info.pixels) {
|
||||||
fmt::printf("Warning: merge texture [%d](%s) could not be loaded.\n",
|
fmt::printf("Warning: merge texture [%d](%s) could not be loaded.\n", rawTexIx, name);
|
||||||
rawTexIx,
|
|
||||||
name);
|
|
||||||
} else {
|
} else {
|
||||||
if (width < 0) {
|
if (width < 0) {
|
||||||
width = info.width;
|
width = info.width;
|
||||||
height = info.height;
|
height = info.height;
|
||||||
} else if (width != info.width || height != info.height) {
|
} else if (width != info.width || height != info.height) {
|
||||||
fmt::printf("Warning: texture %s (%d, %d) can't be merged with previous texture(s) of dimension (%d, %d)\n",
|
fmt::printf(
|
||||||
|
"Warning: texture %s (%d, %d) can't be merged with previous texture(s) of dimension (%d, %d)\n",
|
||||||
name,
|
name,
|
||||||
info.width, info.height, width, height);
|
info.width,
|
||||||
|
info.height,
|
||||||
|
width,
|
||||||
|
height);
|
||||||
// this is bad enough that we abort the whole merge
|
// this is bad enough that we abort the whole merge
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -88,28 +90,28 @@ std::shared_ptr<TextureData> TextureBuilder::combine(
|
||||||
|
|
||||||
std::vector<uint8_t> mergedPixels(static_cast<size_t>(channels * width * height));
|
std::vector<uint8_t> mergedPixels(static_cast<size_t>(channels * width * height));
|
||||||
std::vector<pixel> pixels(texes.size());
|
std::vector<pixel> pixels(texes.size());
|
||||||
std::vector<const pixel *> pixelPointers(texes.size());
|
std::vector<const pixel*> pixelPointers(texes.size());
|
||||||
for (int xx = 0; xx < width; xx ++) {
|
for (int xx = 0; xx < width; xx++) {
|
||||||
for (int yy = 0; yy < height; yy ++) {
|
for (int yy = 0; yy < height; yy++) {
|
||||||
pixels.clear();
|
pixels.clear();
|
||||||
for (int jj = 0; jj < texes.size(); jj ++) {
|
for (int jj = 0; jj < texes.size(); jj++) {
|
||||||
const TexInfo &tex = texes[jj];
|
const TexInfo& tex = texes[jj];
|
||||||
// each texture's structure will depend on its channel count
|
// each texture's structure will depend on its channel count
|
||||||
int ii = tex.channels * (xx + yy*width);
|
int ii = tex.channels * (xx + yy * width);
|
||||||
int kk = 0;
|
int kk = 0;
|
||||||
if (tex.pixels != nullptr) {
|
if (tex.pixels != nullptr) {
|
||||||
for (; kk < tex.channels; kk ++) {
|
for (; kk < tex.channels; kk++) {
|
||||||
pixels[jj][kk] = tex.pixels[ii++] / 255.0f;
|
pixels[jj][kk] = tex.pixels[ii++] / 255.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (; kk < pixels[jj].size(); kk ++) {
|
for (; kk < pixels[jj].size(); kk++) {
|
||||||
pixels[jj][kk] = 1.0f;
|
pixels[jj][kk] = 1.0f;
|
||||||
}
|
}
|
||||||
pixelPointers[jj] = &pixels[jj];
|
pixelPointers[jj] = &pixels[jj];
|
||||||
}
|
}
|
||||||
const pixel merged = computePixel(pixelPointers);
|
const pixel merged = computePixel(pixelPointers);
|
||||||
int ii = channels * (xx + yy*width);
|
int ii = channels * (xx + yy * width);
|
||||||
for (int jj = 0; jj < channels; jj ++) {
|
for (int jj = 0; jj < channels; jj++) {
|
||||||
mergedPixels[ii + jj] = static_cast<uint8_t>(fmax(0, fmin(255.0f, merged[jj] * 255.0f)));
|
mergedPixels[ii + jj] = static_cast<uint8_t>(fmax(0, fmin(255.0f, merged[jj] * 255.0f)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,32 +123,40 @@ std::shared_ptr<TextureData> TextureBuilder::combine(
|
||||||
std::vector<char> imgBuffer;
|
std::vector<char> imgBuffer;
|
||||||
int res;
|
int res;
|
||||||
if (png) {
|
if (png) {
|
||||||
res = stbi_write_png_to_func(WriteToVectorContext, &imgBuffer,
|
res = stbi_write_png_to_func(
|
||||||
width, height, channels, mergedPixels.data(), width * channels);
|
WriteToVectorContext,
|
||||||
|
&imgBuffer,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
channels,
|
||||||
|
mergedPixels.data(),
|
||||||
|
width * channels);
|
||||||
} else {
|
} else {
|
||||||
res = stbi_write_jpg_to_func(WriteToVectorContext, &imgBuffer,
|
res = stbi_write_jpg_to_func(
|
||||||
width, height, channels, mergedPixels.data(), 80);
|
WriteToVectorContext, &imgBuffer, width, height, channels, mergedPixels.data(), 80);
|
||||||
}
|
}
|
||||||
if (!res) {
|
if (!res) {
|
||||||
fmt::printf("Warning: failed to generate merge texture '%s'.\n", mergedFilename);
|
fmt::printf("Warning: failed to generate merge texture '%s'.\n", mergedFilename);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageData *image;
|
ImageData* image;
|
||||||
if (options.outputBinary) {
|
if (options.outputBinary) {
|
||||||
const auto bufferView = gltf.AddRawBufferView(*gltf.defaultBuffer, imgBuffer.data(), imgBuffer.size());
|
const auto bufferView =
|
||||||
|
gltf.AddRawBufferView(*gltf.defaultBuffer, imgBuffer.data(), imgBuffer.size());
|
||||||
image = new ImageData(mergedName, *bufferView, png ? "image/png" : "image/jpeg");
|
image = new ImageData(mergedName, *bufferView, png ? "image/png" : "image/jpeg");
|
||||||
} else {
|
} else {
|
||||||
const std::string imageFilename = mergedFilename + (png ? ".png" : ".jpg");
|
const std::string imageFilename = mergedFilename + (png ? ".png" : ".jpg");
|
||||||
const std::string imagePath = outputFolder + imageFilename;
|
const std::string imagePath = outputFolder + imageFilename;
|
||||||
FILE *fp = fopen(imagePath.c_str(), "wb");
|
FILE* fp = fopen(imagePath.c_str(), "wb");
|
||||||
if (fp == nullptr) {
|
if (fp == nullptr) {
|
||||||
fmt::printf("Warning:: Couldn't write file '%s' for writing.\n", imagePath);
|
fmt::printf("Warning:: Couldn't write file '%s' for writing.\n", imagePath);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fwrite(imgBuffer.data(), imgBuffer.size(), 1, fp) != 1) {
|
if (fwrite(imgBuffer.data(), imgBuffer.size(), 1, fp) != 1) {
|
||||||
fmt::printf("Warning: Failed to write %lu bytes to file '%s'.\n", imgBuffer.size(), imagePath);
|
fmt::printf(
|
||||||
|
"Warning: Failed to write %lu bytes to file '%s'.\n", imgBuffer.size(), imagePath);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -163,18 +173,18 @@ std::shared_ptr<TextureData> TextureBuilder::combine(
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Create a new TextureData for the given RawTexture index, or return a previously created one. */
|
/** Create a new TextureData for the given RawTexture index, or return a previously created one. */
|
||||||
std::shared_ptr<TextureData> TextureBuilder::simple(int rawTexIndex, const std::string &tag) {
|
std::shared_ptr<TextureData> TextureBuilder::simple(int rawTexIndex, const std::string& tag) {
|
||||||
const std::string key = texIndicesKey({ rawTexIndex }, tag);
|
const std::string key = texIndicesKey({rawTexIndex}, tag);
|
||||||
auto iter = textureByIndicesKey.find(key);
|
auto iter = textureByIndicesKey.find(key);
|
||||||
if (iter != textureByIndicesKey.end()) {
|
if (iter != textureByIndicesKey.end()) {
|
||||||
return iter->second;
|
return iter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const RawTexture &rawTexture = raw.GetTexture(rawTexIndex);
|
const RawTexture& rawTexture = raw.GetTexture(rawTexIndex);
|
||||||
const std::string textureName = StringUtils::GetFileBaseString(rawTexture.name);
|
const std::string textureName = StringUtils::GetFileBaseString(rawTexture.name);
|
||||||
const std::string relativeFilename = StringUtils::GetFileNameString(rawTexture.fileLocation);
|
const std::string relativeFilename = StringUtils::GetFileNameString(rawTexture.fileLocation);
|
||||||
|
|
||||||
ImageData *image = nullptr;
|
ImageData* image = nullptr;
|
||||||
if (options.outputBinary) {
|
if (options.outputBinary) {
|
||||||
auto bufferView = gltf.AddBufferViewForFile(*gltf.defaultBuffer, rawTexture.fileLocation);
|
auto bufferView = gltf.AddBufferViewForFile(*gltf.defaultBuffer, rawTexture.fileLocation);
|
||||||
if (bufferView) {
|
if (bufferView) {
|
||||||
|
@ -185,8 +195,7 @@ std::shared_ptr<TextureData> TextureBuilder::simple(int rawTexIndex, const std::
|
||||||
} else if (!relativeFilename.empty()) {
|
} else if (!relativeFilename.empty()) {
|
||||||
image = new ImageData(relativeFilename, relativeFilename);
|
image = new ImageData(relativeFilename, relativeFilename);
|
||||||
std::string outputPath = outputFolder + StringUtils::NormalizePath(relativeFilename);
|
std::string outputPath = outputFolder + StringUtils::NormalizePath(relativeFilename);
|
||||||
if (FileUtils::CopyFile(rawTexture.fileLocation, outputPath, true))
|
if (FileUtils::CopyFile(rawTexture.fileLocation, outputPath, true)) {
|
||||||
{
|
|
||||||
if (verboseOutput) {
|
if (verboseOutput) {
|
||||||
fmt::printf("Copied texture '%s' to output folder: %s\n", textureName, outputPath);
|
fmt::printf("Copied texture '%s' to output folder: %s\n", textureName, outputPath);
|
||||||
}
|
}
|
||||||
|
@ -200,13 +209,11 @@ std::shared_ptr<TextureData> TextureBuilder::simple(int rawTexIndex, const std::
|
||||||
// fallback is tiny transparent PNG
|
// fallback is tiny transparent PNG
|
||||||
image = new ImageData(
|
image = new ImageData(
|
||||||
textureName,
|
textureName,
|
||||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg=="
|
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<TextureData> texDat = gltf.textures.hold(
|
std::shared_ptr<TextureData> texDat = gltf.textures.hold(
|
||||||
new TextureData(textureName, *gltf.defaultSampler, *gltf.images.hold(image)));
|
new TextureData(textureName, *gltf.defaultSampler, *gltf.images.hold(image)));
|
||||||
textureByIndicesKey.insert(std::make_pair(key, texDat));
|
textureByIndicesKey.insert(std::make_pair(key, texDat));
|
||||||
return texDat;
|
return texDat;
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
/**
|
/**
|
||||||
* Copyright (c) 2014-present, Facebook, Inc.
|
* Copyright (c) 2014-present, Facebook, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under the BSD-style license found in the
|
* This source code is licensed under the BSD-style license found in the
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
@ -17,30 +17,28 @@
|
||||||
|
|
||||||
#include "GltfModel.hpp"
|
#include "GltfModel.hpp"
|
||||||
|
|
||||||
class TextureBuilder
|
class TextureBuilder {
|
||||||
{
|
public:
|
||||||
public:
|
|
||||||
using pixel = std::array<float, 4>; // pixel components are floats in [0, 1]
|
using pixel = std::array<float, 4>; // pixel components are floats in [0, 1]
|
||||||
using pixel_merger = std::function<pixel(const std::vector<const pixel *>)>;
|
using pixel_merger = std::function<pixel(const std::vector<const pixel*>)>;
|
||||||
|
|
||||||
TextureBuilder(const RawModel &raw, const GltfOptions &options, const std::string &outputFolder, GltfModel &gltf)
|
TextureBuilder(
|
||||||
: raw(raw)
|
const RawModel& raw,
|
||||||
, options(options)
|
const GltfOptions& options,
|
||||||
, outputFolder(outputFolder)
|
const std::string& outputFolder,
|
||||||
, gltf(gltf)
|
GltfModel& gltf)
|
||||||
{}
|
: raw(raw), options(options), outputFolder(outputFolder), gltf(gltf) {}
|
||||||
~TextureBuilder() {}
|
~TextureBuilder() {}
|
||||||
|
|
||||||
std::shared_ptr<TextureData> combine(
|
std::shared_ptr<TextureData> combine(
|
||||||
const std::vector<int> &ixVec,
|
const std::vector<int>& ixVec,
|
||||||
const std::string &tag,
|
const std::string& tag,
|
||||||
const pixel_merger &mergeFunction,
|
const pixel_merger& mergeFunction,
|
||||||
bool transparency
|
bool transparency);
|
||||||
);
|
|
||||||
|
|
||||||
std::shared_ptr<TextureData> simple(int rawTexIndex, const std::string &tag);
|
std::shared_ptr<TextureData> simple(int rawTexIndex, const std::string& tag);
|
||||||
|
|
||||||
static std::string texIndicesKey(const std::vector<int> &ixVec, const std::string &tag) {
|
static std::string texIndicesKey(const std::vector<int>& ixVec, const std::string& tag) {
|
||||||
std::string result = tag;
|
std::string result = tag;
|
||||||
for (int ix : ixVec) {
|
for (int ix : ixVec) {
|
||||||
result += "_" + std::to_string(ix);
|
result += "_" + std::to_string(ix);
|
||||||
|
@ -49,28 +47,32 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string describeChannel(int channels) {
|
static std::string describeChannel(int channels) {
|
||||||
switch(channels) {
|
switch (channels) {
|
||||||
case 1: return "G";
|
case 1:
|
||||||
case 2: return "GA";
|
return "G";
|
||||||
case 3: return "RGB";
|
case 2:
|
||||||
case 4: return "RGBA";
|
return "GA";
|
||||||
|
case 3:
|
||||||
|
return "RGB";
|
||||||
|
case 4:
|
||||||
|
return "RGBA";
|
||||||
default:
|
default:
|
||||||
return fmt::format("?%d?", channels);
|
return fmt::format("?%d?", channels);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void WriteToVectorContext(void *context, void *data, int size) {
|
static void WriteToVectorContext(void* context, void* data, int size) {
|
||||||
auto *vec = static_cast<std::vector<char> *>(context);
|
auto* vec = static_cast<std::vector<char>*>(context);
|
||||||
for (int ii = 0; ii < size; ii ++) {
|
for (int ii = 0; ii < size; ii++) {
|
||||||
vec->push_back(((char *) data)[ii]);
|
vec->push_back(((char*)data)[ii]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const RawModel &raw;
|
const RawModel& raw;
|
||||||
const GltfOptions &options;
|
const GltfOptions& options;
|
||||||
const std::string outputFolder;
|
const std::string outputFolder;
|
||||||
GltfModel &gltf;
|
GltfModel& gltf;
|
||||||
|
|
||||||
std::map<std::string, std::shared_ptr<TextureData>> textureByIndicesKey;
|
std::map<std::string, std::shared_ptr<TextureData>> textureByIndicesKey;
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,32 +10,20 @@
|
||||||
#include "AccessorData.hpp"
|
#include "AccessorData.hpp"
|
||||||
#include "BufferViewData.hpp"
|
#include "BufferViewData.hpp"
|
||||||
|
|
||||||
AccessorData::AccessorData(const BufferViewData &bufferView, GLType type, std::string name)
|
AccessorData::AccessorData(const BufferViewData& bufferView, GLType type, std::string name)
|
||||||
: Holdable(),
|
: Holdable(),
|
||||||
bufferView(bufferView.ix),
|
bufferView(bufferView.ix),
|
||||||
type(std::move(type)),
|
type(std::move(type)),
|
||||||
byteOffset(0),
|
byteOffset(0),
|
||||||
count(0),
|
count(0),
|
||||||
name(name)
|
name(name) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
AccessorData::AccessorData(GLType type)
|
AccessorData::AccessorData(GLType type)
|
||||||
: Holdable(),
|
: Holdable(), bufferView(-1), type(std::move(type)), byteOffset(0), count(0) {}
|
||||||
bufferView(-1),
|
|
||||||
type(std::move(type)),
|
|
||||||
byteOffset(0),
|
|
||||||
count(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
json AccessorData::serialize() const
|
json AccessorData::serialize() const {
|
||||||
{
|
json result{
|
||||||
json result {
|
{"componentType", type.componentType.glType}, {"type", type.dataType}, {"count", count}};
|
||||||
{ "componentType", type.componentType.glType },
|
|
||||||
{ "type", type.dataType },
|
|
||||||
{ "count", count }
|
|
||||||
};
|
|
||||||
if (bufferView >= 0) {
|
if (bufferView >= 0) {
|
||||||
result["bufferView"] = bufferView;
|
result["bufferView"] = bufferView;
|
||||||
result["byteOffset"] = byteOffset;
|
result["byteOffset"] = byteOffset;
|
||||||
|
|
|
@ -11,29 +11,29 @@
|
||||||
|
|
||||||
#include "gltf/Raw2Gltf.hpp"
|
#include "gltf/Raw2Gltf.hpp"
|
||||||
|
|
||||||
struct AccessorData : Holdable
|
struct AccessorData : Holdable {
|
||||||
{
|
AccessorData(const BufferViewData& bufferView, GLType type, std::string name);
|
||||||
AccessorData(const BufferViewData &bufferView, GLType type, std::string name);
|
|
||||||
explicit AccessorData(GLType type);
|
explicit AccessorData(GLType type);
|
||||||
|
|
||||||
json serialize() const override;
|
json serialize() const override;
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
void appendAsBinaryArray(const std::vector<T> &in, std::vector<uint8_t> &out)
|
void appendAsBinaryArray(const std::vector<T>& in, std::vector<uint8_t>& out) {
|
||||||
{
|
|
||||||
const unsigned int stride = type.byteStride();
|
const unsigned int stride = type.byteStride();
|
||||||
const size_t offset = out.size();
|
const size_t offset = out.size();
|
||||||
const size_t count = in.size();
|
const size_t count = in.size();
|
||||||
|
|
||||||
this->count = (unsigned int) count;
|
this->count = (unsigned int)count;
|
||||||
|
|
||||||
out.resize(offset + count * stride);
|
out.resize(offset + count * stride);
|
||||||
for (int ii = 0; ii < count; ii ++) {
|
for (int ii = 0; ii < count; ii++) {
|
||||||
type.write(&out[offset + ii * stride], in[ii]);
|
type.write(&out[offset + ii * stride], in[ii]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int byteLength() const { return type.byteStride() * count; }
|
unsigned int byteLength() const {
|
||||||
|
return type.byteStride() * count;
|
||||||
|
}
|
||||||
|
|
||||||
const int bufferView;
|
const int bufferView;
|
||||||
const GLType type;
|
const GLType type;
|
||||||
|
|
|
@ -14,57 +14,42 @@
|
||||||
#include "AccessorData.hpp"
|
#include "AccessorData.hpp"
|
||||||
#include "NodeData.hpp"
|
#include "NodeData.hpp"
|
||||||
|
|
||||||
AnimationData::AnimationData(std::string name, const AccessorData &timeAccessor)
|
AnimationData::AnimationData(std::string name, const AccessorData& timeAccessor)
|
||||||
: Holdable(),
|
: Holdable(), name(std::move(name)), timeAccessor(timeAccessor.ix) {}
|
||||||
name(std::move(name)),
|
|
||||||
timeAccessor(timeAccessor.ix) {}
|
|
||||||
|
|
||||||
// assumption: 1-to-1 relationship between channels and samplers; this is a simplification on what
|
// assumption: 1-to-1 relationship between channels and samplers; this is a simplification on what
|
||||||
// glTF can express, but it means we can rely on samplerIx == channelIx throughout an animation
|
// glTF can express, but it means we can rely on samplerIx == channelIx throughout an animation
|
||||||
void AnimationData::AddNodeChannel(const NodeData &node, const AccessorData &accessor, std::string path)
|
void AnimationData::AddNodeChannel(
|
||||||
{
|
const NodeData& node,
|
||||||
|
const AccessorData& accessor,
|
||||||
|
std::string path) {
|
||||||
assert(channels.size() == samplers.size());
|
assert(channels.size() == samplers.size());
|
||||||
uint32_t ix = channels.size();
|
uint32_t ix = channels.size();
|
||||||
channels.emplace_back(channel_t(ix, node, std::move(path)));
|
channels.emplace_back(channel_t(ix, node, std::move(path)));
|
||||||
samplers.emplace_back(sampler_t(timeAccessor, accessor.ix));
|
samplers.emplace_back(sampler_t(timeAccessor, accessor.ix));
|
||||||
}
|
}
|
||||||
|
|
||||||
json AnimationData::serialize() const
|
json AnimationData::serialize() const {
|
||||||
{
|
return {{"name", name}, {"channels", channels}, {"samplers", samplers}};
|
||||||
return {
|
}
|
||||||
{ "name", name },
|
|
||||||
{ "channels", channels },
|
AnimationData::channel_t::channel_t(uint32_t ix, const NodeData& node, std::string path)
|
||||||
{ "samplers", samplers }
|
: ix(ix), node(node.ix), path(std::move(path)) {}
|
||||||
};
|
|
||||||
}
|
AnimationData::sampler_t::sampler_t(uint32_t time, uint32_t output) : time(time), output(output) {}
|
||||||
|
|
||||||
AnimationData::channel_t::channel_t(uint32_t ix, const NodeData &node, std::string path)
|
void to_json(json& j, const AnimationData::channel_t& data) {
|
||||||
: ix(ix),
|
j = json{{"sampler", data.ix},
|
||||||
node(node.ix),
|
{
|
||||||
path(std::move(path))
|
"target",
|
||||||
{
|
{{"node", data.node}, {"path", data.path}},
|
||||||
}
|
}};
|
||||||
|
}
|
||||||
AnimationData::sampler_t::sampler_t(uint32_t time, uint32_t output)
|
|
||||||
: time(time),
|
void to_json(json& j, const AnimationData::sampler_t& data) {
|
||||||
output(output)
|
j = json{
|
||||||
{
|
{"input", data.time},
|
||||||
}
|
{"interpolation", "LINEAR"},
|
||||||
|
{"output", data.output},
|
||||||
void to_json(json &j, const AnimationData::channel_t &data) {
|
|
||||||
j = json {
|
|
||||||
{ "sampler", data.ix },
|
|
||||||
{ "target", {
|
|
||||||
{ "node", data.node },
|
|
||||||
{ "path", data.path }},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void to_json(json &j, const AnimationData::sampler_t &data) {
|
|
||||||
j = json {
|
|
||||||
{ "input", data.time },
|
|
||||||
{ "interpolation", "LINEAR" },
|
|
||||||
{ "output", data.output },
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,27 +11,24 @@
|
||||||
|
|
||||||
#include "gltf/Raw2Gltf.hpp"
|
#include "gltf/Raw2Gltf.hpp"
|
||||||
|
|
||||||
struct AnimationData : Holdable
|
struct AnimationData : Holdable {
|
||||||
{
|
AnimationData(std::string name, const AccessorData& timeAccessor);
|
||||||
AnimationData(std::string name, const AccessorData &timeAccessor);
|
|
||||||
|
|
||||||
// assumption: 1-to-1 relationship between channels and samplers; this is a simplification on what
|
// assumption: 1-to-1 relationship between channels and samplers; this is a simplification on what
|
||||||
// glTF can express, but it means we can rely on samplerIx == channelIx throughout an animation
|
// glTF can express, but it means we can rely on samplerIx == channelIx throughout an animation
|
||||||
void AddNodeChannel(const NodeData &node, const AccessorData &accessor, std::string path);
|
void AddNodeChannel(const NodeData& node, const AccessorData& accessor, std::string path);
|
||||||
|
|
||||||
json serialize() const override;
|
json serialize() const override;
|
||||||
|
|
||||||
struct channel_t
|
struct channel_t {
|
||||||
{
|
channel_t(uint32_t _ix, const NodeData& node, std::string path);
|
||||||
channel_t(uint32_t _ix, const NodeData &node, std::string path);
|
|
||||||
|
|
||||||
const uint32_t ix;
|
const uint32_t ix;
|
||||||
const uint32_t node;
|
const uint32_t node;
|
||||||
const std::string path;
|
const std::string path;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sampler_t
|
struct sampler_t {
|
||||||
{
|
|
||||||
sampler_t(uint32_t time, uint32_t output);
|
sampler_t(uint32_t time, uint32_t output);
|
||||||
|
|
||||||
const uint32_t time;
|
const uint32_t time;
|
||||||
|
@ -44,5 +41,5 @@ struct AnimationData : Holdable
|
||||||
std::vector<sampler_t> samplers;
|
std::vector<sampler_t> samplers;
|
||||||
};
|
};
|
||||||
|
|
||||||
void to_json(json &j, const AnimationData::channel_t &data);
|
void to_json(json& j, const AnimationData::channel_t& data);
|
||||||
void to_json(json &j, const AnimationData::sampler_t &data);
|
void to_json(json& j, const AnimationData::sampler_t& data);
|
||||||
|
|
|
@ -11,26 +11,17 @@
|
||||||
|
|
||||||
#include "BufferData.hpp"
|
#include "BufferData.hpp"
|
||||||
|
|
||||||
BufferData::BufferData(const std::shared_ptr<const std::vector<uint8_t> > &binData)
|
BufferData::BufferData(const std::shared_ptr<const std::vector<uint8_t>>& binData)
|
||||||
: Holdable(),
|
: Holdable(), isGlb(true), binData(binData) {}
|
||||||
isGlb(true),
|
|
||||||
binData(binData)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
BufferData::BufferData(std::string uri, const std::shared_ptr<const std::vector<uint8_t> > &binData, bool isEmbedded)
|
BufferData::BufferData(
|
||||||
: Holdable(),
|
std::string uri,
|
||||||
isGlb(false),
|
const std::shared_ptr<const std::vector<uint8_t>>& binData,
|
||||||
uri(isEmbedded ? "" : std::move(uri)),
|
bool isEmbedded)
|
||||||
binData(binData)
|
: Holdable(), isGlb(false), uri(isEmbedded ? "" : std::move(uri)), binData(binData) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
json BufferData::serialize() const
|
json BufferData::serialize() const {
|
||||||
{
|
json result{{"byteLength", binData->size()}};
|
||||||
json result{
|
|
||||||
{"byteLength", binData->size()}
|
|
||||||
};
|
|
||||||
if (!isGlb) {
|
if (!isGlb) {
|
||||||
if (!uri.empty()) {
|
if (!uri.empty()) {
|
||||||
result["uri"] = uri;
|
result["uri"] = uri;
|
||||||
|
|
|
@ -11,15 +11,17 @@
|
||||||
|
|
||||||
#include "gltf/Raw2Gltf.hpp"
|
#include "gltf/Raw2Gltf.hpp"
|
||||||
|
|
||||||
struct BufferData : Holdable
|
struct BufferData : Holdable {
|
||||||
{
|
explicit BufferData(const std::shared_ptr<const std::vector<uint8_t>>& binData);
|
||||||
explicit BufferData(const std::shared_ptr<const std::vector<uint8_t> > &binData);
|
|
||||||
|
|
||||||
BufferData(std::string uri, const std::shared_ptr<const std::vector<uint8_t> > &binData, bool isEmbedded = false);
|
BufferData(
|
||||||
|
std::string uri,
|
||||||
|
const std::shared_ptr<const std::vector<uint8_t>>& binData,
|
||||||
|
bool isEmbedded = false);
|
||||||
|
|
||||||
json serialize() const override;
|
json serialize() const override;
|
||||||
|
|
||||||
const bool isGlb;
|
const bool isGlb;
|
||||||
const std::string uri;
|
const std::string uri;
|
||||||
const std::shared_ptr<const std::vector<uint8_t> > binData; // TODO this is just weird
|
const std::shared_ptr<const std::vector<uint8_t>> binData; // TODO this is just weird
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,21 +10,14 @@
|
||||||
#include "BufferViewData.hpp"
|
#include "BufferViewData.hpp"
|
||||||
#include "BufferData.hpp"
|
#include "BufferData.hpp"
|
||||||
|
|
||||||
BufferViewData::BufferViewData(const BufferData &_buffer, const size_t _byteOffset, const GL_ArrayType _target)
|
BufferViewData::BufferViewData(
|
||||||
: Holdable(),
|
const BufferData& _buffer,
|
||||||
buffer(_buffer.ix),
|
const size_t _byteOffset,
|
||||||
byteOffset((unsigned int) _byteOffset),
|
const GL_ArrayType _target)
|
||||||
target(_target)
|
: Holdable(), buffer(_buffer.ix), byteOffset((unsigned int)_byteOffset), target(_target) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
json BufferViewData::serialize() const
|
json BufferViewData::serialize() const {
|
||||||
{
|
json result{{"buffer", buffer}, {"byteLength", byteLength}, {"byteOffset", byteOffset}};
|
||||||
json result {
|
|
||||||
{ "buffer", buffer },
|
|
||||||
{ "byteLength", byteLength },
|
|
||||||
{ "byteOffset", byteOffset }
|
|
||||||
};
|
|
||||||
if (target != GL_ARRAY_NONE) {
|
if (target != GL_ARRAY_NONE) {
|
||||||
result["target"] = target;
|
result["target"] = target;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,16 +11,14 @@
|
||||||
|
|
||||||
#include "gltf/Raw2Gltf.hpp"
|
#include "gltf/Raw2Gltf.hpp"
|
||||||
|
|
||||||
struct BufferViewData : Holdable
|
struct BufferViewData : Holdable {
|
||||||
{
|
enum GL_ArrayType {
|
||||||
enum GL_ArrayType
|
|
||||||
{
|
|
||||||
GL_ARRAY_NONE = 0, // no GL buffer is being set
|
GL_ARRAY_NONE = 0, // no GL buffer is being set
|
||||||
GL_ARRAY_BUFFER = 34962,
|
GL_ARRAY_BUFFER = 34962,
|
||||||
GL_ELEMENT_ARRAY_BUFFER = 34963
|
GL_ELEMENT_ARRAY_BUFFER = 34963
|
||||||
};
|
};
|
||||||
|
|
||||||
BufferViewData(const BufferData &_buffer, const size_t _byteOffset, const GL_ArrayType _target);
|
BufferViewData(const BufferData& _buffer, const size_t _byteOffset, const GL_ArrayType _target);
|
||||||
|
|
||||||
json serialize() const override;
|
json serialize() const override;
|
||||||
|
|
||||||
|
|
|
@ -10,26 +10,14 @@
|
||||||
#include "CameraData.hpp"
|
#include "CameraData.hpp"
|
||||||
|
|
||||||
CameraData::CameraData()
|
CameraData::CameraData()
|
||||||
: Holdable(),
|
: Holdable(), aspectRatio(0.0f), yfov(0.0f), xmag(0.0f), ymag(0.0f), znear(0.0f), zfar(0.0f) {}
|
||||||
aspectRatio(0.0f),
|
|
||||||
yfov(0.0f),
|
|
||||||
xmag(0.0f),
|
|
||||||
ymag(0.0f),
|
|
||||||
znear(0.0f),
|
|
||||||
zfar(0.0f)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
json CameraData::serialize() const
|
json CameraData::serialize() const {
|
||||||
{
|
json result{
|
||||||
json result {
|
{"name", name},
|
||||||
{ "name", name },
|
{"type", type},
|
||||||
{ "type", type },
|
|
||||||
};
|
|
||||||
json subResult {
|
|
||||||
{ "znear", znear },
|
|
||||||
{ "zfar", zfar }
|
|
||||||
};
|
};
|
||||||
|
json subResult{{"znear", znear}, {"zfar", zfar}};
|
||||||
if (type == "perspective") {
|
if (type == "perspective") {
|
||||||
subResult["aspectRatio"] = aspectRatio;
|
subResult["aspectRatio"] = aspectRatio;
|
||||||
subResult["yfov"] = yfov;
|
subResult["yfov"] = yfov;
|
||||||
|
|
|
@ -12,8 +12,7 @@
|
||||||
#include "gltf/Raw2Gltf.hpp"
|
#include "gltf/Raw2Gltf.hpp"
|
||||||
|
|
||||||
// TODO: this class needs some work
|
// TODO: this class needs some work
|
||||||
struct CameraData : Holdable
|
struct CameraData : Holdable {
|
||||||
{
|
|
||||||
CameraData();
|
CameraData();
|
||||||
json serialize() const override;
|
json serialize() const override;
|
||||||
|
|
||||||
|
|
|
@ -14,32 +14,14 @@
|
||||||
#include "BufferViewData.hpp"
|
#include "BufferViewData.hpp"
|
||||||
|
|
||||||
ImageData::ImageData(std::string name, std::string uri)
|
ImageData::ImageData(std::string name, std::string uri)
|
||||||
: Holdable(),
|
: Holdable(), name(std::move(name)), uri(std::move(uri)), bufferView(-1) {}
|
||||||
name(std::move(name)),
|
|
||||||
uri(std::move(uri)),
|
|
||||||
bufferView(-1)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageData::ImageData(std::string name, const BufferViewData &bufferView, std::string mimeType)
|
ImageData::ImageData(std::string name, const BufferViewData& bufferView, std::string mimeType)
|
||||||
: Holdable(),
|
: Holdable(), name(std::move(name)), bufferView(bufferView.ix), mimeType(std::move(mimeType)) {}
|
||||||
name(std::move(name)),
|
|
||||||
bufferView(bufferView.ix),
|
|
||||||
mimeType(std::move(mimeType))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
json ImageData::serialize() const
|
json ImageData::serialize() const {
|
||||||
{
|
|
||||||
if (bufferView < 0) {
|
if (bufferView < 0) {
|
||||||
return {
|
return {{"name", name}, {"uri", uri}};
|
||||||
{ "name", name },
|
|
||||||
{ "uri", uri }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
return {
|
return {{"name", name}, {"bufferView", bufferView}, {"mimeType", mimeType}};
|
||||||
{ "name", name },
|
|
||||||
{ "bufferView", bufferView },
|
|
||||||
{ "mimeType", mimeType }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,9 @@
|
||||||
|
|
||||||
#include "gltf/Raw2Gltf.hpp"
|
#include "gltf/Raw2Gltf.hpp"
|
||||||
|
|
||||||
struct ImageData : Holdable
|
struct ImageData : Holdable {
|
||||||
{
|
|
||||||
ImageData(std::string name, std::string uri);
|
ImageData(std::string name, std::string uri);
|
||||||
ImageData(std::string name, const BufferViewData &bufferView, std::string mimeType);
|
ImageData(std::string name, const BufferViewData& bufferView, std::string mimeType);
|
||||||
|
|
||||||
json serialize() const override;
|
json serialize() const override;
|
||||||
|
|
||||||
|
|
|
@ -10,25 +10,22 @@
|
||||||
#include "LightData.hpp"
|
#include "LightData.hpp"
|
||||||
|
|
||||||
LightData::LightData(
|
LightData::LightData(
|
||||||
std::string name, Type type, Vec3f color, float intensity,
|
std::string name,
|
||||||
float innerConeAngle, float outerConeAngle)
|
Type type,
|
||||||
|
Vec3f color,
|
||||||
|
float intensity,
|
||||||
|
float innerConeAngle,
|
||||||
|
float outerConeAngle)
|
||||||
: Holdable(),
|
: Holdable(),
|
||||||
type(type),
|
type(type),
|
||||||
color(color),
|
color(color),
|
||||||
intensity(intensity),
|
intensity(intensity),
|
||||||
innerConeAngle(innerConeAngle),
|
innerConeAngle(innerConeAngle),
|
||||||
outerConeAngle(outerConeAngle)
|
outerConeAngle(outerConeAngle) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
json LightData::serialize() const
|
json LightData::serialize() const {
|
||||||
{
|
json result{{"name", name}, {"color", toStdVec(color)}, {"intensity", intensity}};
|
||||||
json result {
|
switch (type) {
|
||||||
{ "name", name },
|
|
||||||
{ "color", toStdVec(color) },
|
|
||||||
{ "intensity", intensity }
|
|
||||||
};
|
|
||||||
switch(type) {
|
|
||||||
case Directional:
|
case Directional:
|
||||||
result["type"] = "directional";
|
result["type"] = "directional";
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -11,16 +11,20 @@
|
||||||
|
|
||||||
#include "gltf/Raw2Gltf.hpp"
|
#include "gltf/Raw2Gltf.hpp"
|
||||||
|
|
||||||
struct LightData : Holdable
|
struct LightData : Holdable {
|
||||||
{
|
|
||||||
enum Type {
|
enum Type {
|
||||||
Directional,
|
Directional,
|
||||||
Point,
|
Point,
|
||||||
Spot,
|
Spot,
|
||||||
};
|
};
|
||||||
|
|
||||||
LightData(std::string name, Type type, Vec3f color, float intensity,
|
LightData(
|
||||||
float innerConeAngle, float outerConeAngle);
|
std::string name,
|
||||||
|
Type type,
|
||||||
|
Vec3f color,
|
||||||
|
float intensity,
|
||||||
|
float innerConeAngle,
|
||||||
|
float outerConeAngle);
|
||||||
|
|
||||||
json serialize() const override;
|
json serialize() const override;
|
||||||
|
|
||||||
|
|
|
@ -11,55 +11,48 @@
|
||||||
#include "TextureData.hpp"
|
#include "TextureData.hpp"
|
||||||
|
|
||||||
// TODO: retrieve & pass in correct UV set from FBX
|
// TODO: retrieve & pass in correct UV set from FBX
|
||||||
std::unique_ptr<Tex> Tex::ref(const TextureData *tex, uint32_t texCoord)
|
std::unique_ptr<Tex> Tex::ref(const TextureData* tex, uint32_t texCoord) {
|
||||||
{
|
return std::unique_ptr<Tex>{(tex != nullptr) ? new Tex(tex->ix, texCoord) : nullptr};
|
||||||
return std::unique_ptr<Tex> { (tex != nullptr) ? new Tex(tex->ix, texCoord) : nullptr };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Tex::Tex(uint32_t texRef, uint32_t texCoord)
|
Tex::Tex(uint32_t texRef, uint32_t texCoord) : texRef(texRef), texCoord(texCoord) {}
|
||||||
: texRef(texRef),
|
|
||||||
texCoord(texCoord) {}
|
|
||||||
|
|
||||||
void to_json(json &j, const Tex &data) {
|
void to_json(json& j, const Tex& data) {
|
||||||
j = json {
|
j = json{{"index", data.texRef}, {"texCoord", data.texCoord}};
|
||||||
{ "index", data.texRef },
|
|
||||||
{ "texCoord", data.texCoord }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KHRCmnUnlitMaterial::KHRCmnUnlitMaterial()
|
KHRCmnUnlitMaterial::KHRCmnUnlitMaterial() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void to_json(json &j, const KHRCmnUnlitMaterial &d)
|
void to_json(json& j, const KHRCmnUnlitMaterial& d) {
|
||||||
{
|
|
||||||
j = json({});
|
j = json({});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float clamp(float d, float bottom = 0, float top = 1) {
|
inline float clamp(float d, float bottom = 0, float top = 1) {
|
||||||
return std::max(bottom, std::min(top, d));
|
return std::max(bottom, std::min(top, d));
|
||||||
}
|
}
|
||||||
inline Vec3f clamp(const Vec3f &vec, const Vec3f &bottom = VEC3F_ZERO, const Vec3f &top = VEC3F_ONE) {
|
inline Vec3f
|
||||||
|
clamp(const Vec3f& vec, const Vec3f& bottom = VEC3F_ZERO, const Vec3f& top = VEC3F_ONE) {
|
||||||
return Vec3f::Max(bottom, Vec3f::Min(top, vec));
|
return Vec3f::Max(bottom, Vec3f::Min(top, vec));
|
||||||
}
|
}
|
||||||
inline Vec4f clamp(const Vec4f &vec, const Vec4f &bottom = VEC4F_ZERO, const Vec4f &top = VEC4F_ONE) {
|
inline Vec4f
|
||||||
|
clamp(const Vec4f& vec, const Vec4f& bottom = VEC4F_ZERO, const Vec4f& top = VEC4F_ONE) {
|
||||||
return Vec4f::Max(bottom, Vec4f::Min(top, vec));
|
return Vec4f::Max(bottom, Vec4f::Min(top, vec));
|
||||||
}
|
}
|
||||||
|
|
||||||
PBRMetallicRoughness::PBRMetallicRoughness(
|
PBRMetallicRoughness::PBRMetallicRoughness(
|
||||||
const TextureData *baseColorTexture, const TextureData *metRoughTexture,
|
const TextureData* baseColorTexture,
|
||||||
const Vec4f &baseColorFactor, float metallic, float roughness)
|
const TextureData* metRoughTexture,
|
||||||
|
const Vec4f& baseColorFactor,
|
||||||
|
float metallic,
|
||||||
|
float roughness)
|
||||||
: baseColorTexture(Tex::ref(baseColorTexture)),
|
: baseColorTexture(Tex::ref(baseColorTexture)),
|
||||||
metRoughTexture(Tex::ref(metRoughTexture)),
|
metRoughTexture(Tex::ref(metRoughTexture)),
|
||||||
baseColorFactor(clamp(baseColorFactor)),
|
baseColorFactor(clamp(baseColorFactor)),
|
||||||
metallic(clamp(metallic)),
|
metallic(clamp(metallic)),
|
||||||
roughness(clamp(roughness))
|
roughness(clamp(roughness)) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void to_json(json &j, const PBRMetallicRoughness &d)
|
void to_json(json& j, const PBRMetallicRoughness& d) {
|
||||||
{
|
j = {};
|
||||||
j = { };
|
|
||||||
if (d.baseColorTexture != nullptr) {
|
if (d.baseColorTexture != nullptr) {
|
||||||
j["baseColorTexture"] = *d.baseColorTexture;
|
j["baseColorTexture"] = *d.baseColorTexture;
|
||||||
}
|
}
|
||||||
|
@ -79,9 +72,13 @@ void to_json(json &j, const PBRMetallicRoughness &d)
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialData::MaterialData(
|
MaterialData::MaterialData(
|
||||||
std::string name, bool isTransparent, const RawShadingModel shadingModel,
|
std::string name,
|
||||||
const TextureData *normalTexture, const TextureData *occlusionTexture,
|
bool isTransparent,
|
||||||
const TextureData *emissiveTexture, const Vec3f & emissiveFactor,
|
const RawShadingModel shadingModel,
|
||||||
|
const TextureData* normalTexture,
|
||||||
|
const TextureData* occlusionTexture,
|
||||||
|
const TextureData* emissiveTexture,
|
||||||
|
const Vec3f& emissiveFactor,
|
||||||
std::shared_ptr<KHRCmnUnlitMaterial> const khrCmnConstantMaterial,
|
std::shared_ptr<KHRCmnUnlitMaterial> const khrCmnConstantMaterial,
|
||||||
std::shared_ptr<PBRMetallicRoughness> const pbrMetallicRoughness)
|
std::shared_ptr<PBRMetallicRoughness> const pbrMetallicRoughness)
|
||||||
: Holdable(),
|
: Holdable(),
|
||||||
|
@ -95,18 +92,13 @@ MaterialData::MaterialData(
|
||||||
khrCmnConstantMaterial(khrCmnConstantMaterial),
|
khrCmnConstantMaterial(khrCmnConstantMaterial),
|
||||||
pbrMetallicRoughness(pbrMetallicRoughness) {}
|
pbrMetallicRoughness(pbrMetallicRoughness) {}
|
||||||
|
|
||||||
json MaterialData::serialize() const
|
json MaterialData::serialize() const {
|
||||||
{
|
json result = {{"name", name},
|
||||||
json result = {
|
{"alphaMode", isTransparent ? "BLEND" : "OPAQUE"},
|
||||||
{ "name", name },
|
{"extras",
|
||||||
{ "alphaMode", isTransparent ? "BLEND" : "OPAQUE" },
|
{{"fromFBX",
|
||||||
{ "extras", {
|
{{"shadingModel", Describe(shadingModel)},
|
||||||
{ "fromFBX", {
|
{"isTruePBR", shadingModel == RAW_SHADING_MODEL_PBR_MET_ROUGH}}}}}};
|
||||||
{ "shadingModel", Describe(shadingModel) },
|
|
||||||
{ "isTruePBR", shadingModel == RAW_SHADING_MODEL_PBR_MET_ROUGH }
|
|
||||||
}}
|
|
||||||
}}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (normalTexture != nullptr) {
|
if (normalTexture != nullptr) {
|
||||||
result["normalTexture"] = *normalTexture;
|
result["normalTexture"] = *normalTexture;
|
||||||
|
@ -124,18 +116,16 @@ json MaterialData::serialize() const
|
||||||
result["pbrMetallicRoughness"] = *pbrMetallicRoughness;
|
result["pbrMetallicRoughness"] = *pbrMetallicRoughness;
|
||||||
}
|
}
|
||||||
if (khrCmnConstantMaterial != nullptr) {
|
if (khrCmnConstantMaterial != nullptr) {
|
||||||
json extensions = { };
|
json extensions = {};
|
||||||
extensions[KHR_MATERIALS_CMN_UNLIT] = *khrCmnConstantMaterial;
|
extensions[KHR_MATERIALS_CMN_UNLIT] = *khrCmnConstantMaterial;
|
||||||
result["extensions"] = extensions;
|
result["extensions"] = extensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& i : userProperties)
|
for (const auto& i : userProperties) {
|
||||||
{
|
|
||||||
auto& prop_map = result["extras"]["fromFBX"]["userProperties"];
|
auto& prop_map = result["extras"]["fromFBX"]["userProperties"];
|
||||||
|
|
||||||
json j = json::parse(i);
|
json j = json::parse(i);
|
||||||
for (const auto& k : json::iterator_wrapper(j))
|
for (const auto& k : json::iterator_wrapper(j)) {
|
||||||
{
|
|
||||||
prop_map[k.key()] = k.value();
|
prop_map[k.key()] = k.value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,25 +13,25 @@
|
||||||
|
|
||||||
#include "gltf/Raw2Gltf.hpp"
|
#include "gltf/Raw2Gltf.hpp"
|
||||||
|
|
||||||
struct Tex
|
struct Tex {
|
||||||
{
|
static std::unique_ptr<Tex> ref(const TextureData* tex, uint32_t texCoord = 0);
|
||||||
static std::unique_ptr<Tex> ref(const TextureData *tex, uint32_t texCoord = 0);
|
|
||||||
explicit Tex(uint32_t texRef, uint32_t texCoord);
|
explicit Tex(uint32_t texRef, uint32_t texCoord);
|
||||||
|
|
||||||
const uint32_t texRef;
|
const uint32_t texRef;
|
||||||
const uint32_t texCoord;
|
const uint32_t texCoord;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct KHRCmnUnlitMaterial
|
struct KHRCmnUnlitMaterial {
|
||||||
{
|
|
||||||
KHRCmnUnlitMaterial();
|
KHRCmnUnlitMaterial();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PBRMetallicRoughness
|
struct PBRMetallicRoughness {
|
||||||
{
|
|
||||||
PBRMetallicRoughness(
|
PBRMetallicRoughness(
|
||||||
const TextureData *baseColorTexture, const TextureData *metRoughTexture,
|
const TextureData* baseColorTexture,
|
||||||
const Vec4f &baseColorFactor, float metallic = 0.1f, float roughness = 0.6f);
|
const TextureData* metRoughTexture,
|
||||||
|
const Vec4f& baseColorFactor,
|
||||||
|
float metallic = 0.1f,
|
||||||
|
float roughness = 0.6f);
|
||||||
|
|
||||||
std::unique_ptr<Tex> baseColorTexture;
|
std::unique_ptr<Tex> baseColorTexture;
|
||||||
std::unique_ptr<Tex> metRoughTexture;
|
std::unique_ptr<Tex> metRoughTexture;
|
||||||
|
@ -40,12 +40,15 @@ struct PBRMetallicRoughness
|
||||||
const float roughness;
|
const float roughness;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MaterialData : Holdable
|
struct MaterialData : Holdable {
|
||||||
{
|
|
||||||
MaterialData(
|
MaterialData(
|
||||||
std::string name, bool isTransparent, RawShadingModel shadingModel,
|
std::string name,
|
||||||
const TextureData *normalTexture, const TextureData *occlusionTexture,
|
bool isTransparent,
|
||||||
const TextureData *emissiveTexture, const Vec3f &emissiveFactor,
|
RawShadingModel shadingModel,
|
||||||
|
const TextureData* normalTexture,
|
||||||
|
const TextureData* occlusionTexture,
|
||||||
|
const TextureData* emissiveTexture,
|
||||||
|
const Vec3f& emissiveFactor,
|
||||||
std::shared_ptr<KHRCmnUnlitMaterial> const khrCmnConstantMaterial,
|
std::shared_ptr<KHRCmnUnlitMaterial> const khrCmnConstantMaterial,
|
||||||
std::shared_ptr<PBRMetallicRoughness> const pbrMetallicRoughness);
|
std::shared_ptr<PBRMetallicRoughness> const pbrMetallicRoughness);
|
||||||
|
|
||||||
|
@ -65,6 +68,6 @@ struct MaterialData : Holdable
|
||||||
std::vector<std::string> userProperties;
|
std::vector<std::string> userProperties;
|
||||||
};
|
};
|
||||||
|
|
||||||
void to_json(json &j, const Tex &data);
|
void to_json(json& j, const Tex& data);
|
||||||
void to_json(json &j, const KHRCmnUnlitMaterial &d);
|
void to_json(json& j, const KHRCmnUnlitMaterial& d);
|
||||||
void to_json(json &j, const PBRMetallicRoughness &d);
|
void to_json(json& j, const PBRMetallicRoughness& d);
|
||||||
|
|
|
@ -10,23 +10,15 @@
|
||||||
#include "MeshData.hpp"
|
#include "MeshData.hpp"
|
||||||
#include "PrimitiveData.hpp"
|
#include "PrimitiveData.hpp"
|
||||||
|
|
||||||
MeshData::MeshData(const std::string &name, const std::vector<float> &weights)
|
MeshData::MeshData(const std::string& name, const std::vector<float>& weights)
|
||||||
: Holdable(),
|
: Holdable(), name(name), weights(weights) {}
|
||||||
name(name),
|
|
||||||
weights(weights)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
json MeshData::serialize() const
|
json MeshData::serialize() const {
|
||||||
{
|
|
||||||
json jsonPrimitivesArray = json::array();
|
json jsonPrimitivesArray = json::array();
|
||||||
for (const auto &primitive : primitives) {
|
for (const auto& primitive : primitives) {
|
||||||
jsonPrimitivesArray.push_back(*primitive);
|
jsonPrimitivesArray.push_back(*primitive);
|
||||||
}
|
}
|
||||||
json result = {
|
json result = {{"name", name}, {"primitives", jsonPrimitivesArray}};
|
||||||
{ "name", name },
|
|
||||||
{ "primitives", jsonPrimitivesArray }
|
|
||||||
};
|
|
||||||
if (!weights.empty()) {
|
if (!weights.empty()) {
|
||||||
result["weights"] = weights;
|
result["weights"] = weights;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,10 @@
|
||||||
|
|
||||||
#include "PrimitiveData.hpp"
|
#include "PrimitiveData.hpp"
|
||||||
|
|
||||||
struct MeshData : Holdable
|
struct MeshData : Holdable {
|
||||||
{
|
MeshData(const std::string& name, const std::vector<float>& weights);
|
||||||
MeshData(const std::string &name, const std::vector<float> &weights);
|
|
||||||
|
|
||||||
void AddPrimitive(std::shared_ptr<PrimitiveData> primitive)
|
void AddPrimitive(std::shared_ptr<PrimitiveData> primitive) {
|
||||||
{
|
|
||||||
primitives.push_back(std::move(primitive));
|
primitives.push_back(std::move(primitive));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,11 @@
|
||||||
#include "NodeData.hpp"
|
#include "NodeData.hpp"
|
||||||
|
|
||||||
NodeData::NodeData(
|
NodeData::NodeData(
|
||||||
std::string name, const Vec3f &translation,
|
std::string name,
|
||||||
const Quatf &rotation, const Vec3f &scale, bool isJoint)
|
const Vec3f& translation,
|
||||||
|
const Quatf& rotation,
|
||||||
|
const Vec3f& scale,
|
||||||
|
bool isJoint)
|
||||||
: Holdable(),
|
: Holdable(),
|
||||||
name(std::move(name)),
|
name(std::move(name)),
|
||||||
isJoint(isJoint),
|
isJoint(isJoint),
|
||||||
|
@ -22,44 +25,36 @@ NodeData::NodeData(
|
||||||
mesh(-1),
|
mesh(-1),
|
||||||
camera(-1),
|
camera(-1),
|
||||||
light(-1),
|
light(-1),
|
||||||
skin(-1)
|
skin(-1) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeData::AddChildNode(uint32_t childIx)
|
void NodeData::AddChildNode(uint32_t childIx) {
|
||||||
{
|
|
||||||
children.push_back(childIx);
|
children.push_back(childIx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeData::SetMesh(uint32_t meshIx)
|
void NodeData::SetMesh(uint32_t meshIx) {
|
||||||
{
|
|
||||||
assert(mesh < 0);
|
assert(mesh < 0);
|
||||||
assert(!isJoint);
|
assert(!isJoint);
|
||||||
mesh = meshIx;
|
mesh = meshIx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeData::SetSkin(uint32_t skinIx)
|
void NodeData::SetSkin(uint32_t skinIx) {
|
||||||
{
|
|
||||||
assert(skin < 0);
|
assert(skin < 0);
|
||||||
assert(!isJoint);
|
assert(!isJoint);
|
||||||
skin = skinIx;
|
skin = skinIx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeData::SetCamera(uint32_t cameraIndex)
|
void NodeData::SetCamera(uint32_t cameraIndex) {
|
||||||
{
|
|
||||||
assert(!isJoint);
|
assert(!isJoint);
|
||||||
camera = cameraIndex;
|
camera = cameraIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeData::SetLight(uint32_t lightIndex)
|
void NodeData::SetLight(uint32_t lightIndex) {
|
||||||
{
|
|
||||||
assert(!isJoint);
|
assert(!isJoint);
|
||||||
light = lightIndex;
|
light = lightIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
json NodeData::serialize() const
|
json NodeData::serialize() const {
|
||||||
{
|
json result = {{"name", name}};
|
||||||
json result = { { "name", name } };
|
|
||||||
|
|
||||||
// if any of the T/R/S have NaN components, just leave them out of the glTF
|
// if any of the T/R/S have NaN components, just leave them out of the glTF
|
||||||
auto maybeAdd = [&](std::string key, std::vector<float> vec) -> void {
|
auto maybeAdd = [&](std::string key, std::vector<float> vec) -> void {
|
||||||
|
@ -96,13 +91,11 @@ json NodeData::serialize() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& i : userProperties)
|
for (const auto& i : userProperties) {
|
||||||
{
|
|
||||||
auto& prop_map = result["extras"]["fromFBX"]["userProperties"];
|
auto& prop_map = result["extras"]["fromFBX"]["userProperties"];
|
||||||
|
|
||||||
json j = json::parse(i);
|
json j = json::parse(i);
|
||||||
for (const auto& k : json::iterator_wrapper(j))
|
for (const auto& k : json::iterator_wrapper(j)) {
|
||||||
{
|
|
||||||
prop_map[k.key()] = k.value();
|
prop_map[k.key()] = k.value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,13 @@
|
||||||
|
|
||||||
#include "gltf/Raw2Gltf.hpp"
|
#include "gltf/Raw2Gltf.hpp"
|
||||||
|
|
||||||
struct NodeData : Holdable
|
struct NodeData : Holdable {
|
||||||
{
|
NodeData(
|
||||||
NodeData(std::string name, const Vec3f &translation, const Quatf &rotation, const Vec3f &scale, bool isJoint);
|
std::string name,
|
||||||
|
const Vec3f& translation,
|
||||||
|
const Quatf& rotation,
|
||||||
|
const Vec3f& scale,
|
||||||
|
bool isJoint);
|
||||||
|
|
||||||
void AddChildNode(uint32_t childIx);
|
void AddChildNode(uint32_t childIx);
|
||||||
void SetMesh(uint32_t meshIx);
|
void SetMesh(uint32_t meshIx);
|
||||||
|
|
|
@ -9,73 +9,71 @@
|
||||||
|
|
||||||
#include "PrimitiveData.hpp"
|
#include "PrimitiveData.hpp"
|
||||||
|
|
||||||
#include "MaterialData.hpp"
|
|
||||||
#include "AccessorData.hpp"
|
#include "AccessorData.hpp"
|
||||||
#include "BufferViewData.hpp"
|
#include "BufferViewData.hpp"
|
||||||
|
#include "MaterialData.hpp"
|
||||||
|
|
||||||
PrimitiveData::PrimitiveData(const AccessorData &indices, const MaterialData &material, std::shared_ptr<draco::Mesh> dracoMesh)
|
PrimitiveData::PrimitiveData(
|
||||||
|
const AccessorData& indices,
|
||||||
|
const MaterialData& material,
|
||||||
|
std::shared_ptr<draco::Mesh> dracoMesh)
|
||||||
: indices(indices.ix),
|
: indices(indices.ix),
|
||||||
material(material.ix),
|
material(material.ix),
|
||||||
mode(TRIANGLES),
|
mode(TRIANGLES),
|
||||||
dracoMesh(dracoMesh),
|
dracoMesh(dracoMesh),
|
||||||
dracoBufferView(-1) {}
|
dracoBufferView(-1) {}
|
||||||
|
|
||||||
PrimitiveData::PrimitiveData(const AccessorData &indices, const MaterialData &material)
|
PrimitiveData::PrimitiveData(const AccessorData& indices, const MaterialData& material)
|
||||||
: indices(indices.ix),
|
: indices(indices.ix),
|
||||||
material(material.ix),
|
material(material.ix),
|
||||||
mode(TRIANGLES),
|
mode(TRIANGLES),
|
||||||
dracoMesh(nullptr),
|
dracoMesh(nullptr),
|
||||||
dracoBufferView(-1)
|
dracoBufferView(-1) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrimitiveData::AddAttrib(std::string name, const AccessorData &accessor)
|
void PrimitiveData::AddAttrib(std::string name, const AccessorData& accessor) {
|
||||||
{
|
|
||||||
attributes[name] = accessor.ix;
|
attributes[name] = accessor.ix;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrimitiveData::NoteDracoBuffer(const BufferViewData &data)
|
void PrimitiveData::NoteDracoBuffer(const BufferViewData& data) {
|
||||||
{
|
|
||||||
dracoBufferView = data.ix;
|
dracoBufferView = data.ix;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrimitiveData::AddTarget(const AccessorData *positions, const AccessorData *normals, const AccessorData *tangents)
|
void PrimitiveData::AddTarget(
|
||||||
{
|
const AccessorData* positions,
|
||||||
|
const AccessorData* normals,
|
||||||
|
const AccessorData* tangents) {
|
||||||
targetAccessors.push_back(std::make_tuple(
|
targetAccessors.push_back(std::make_tuple(
|
||||||
positions->ix,
|
positions->ix,
|
||||||
normals != nullptr ? normals->ix : -1,
|
normals != nullptr ? normals->ix : -1,
|
||||||
tangents != nullptr ? tangents ->ix : -1
|
tangents != nullptr ? tangents->ix : -1));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void to_json(json &j, const PrimitiveData &d) {
|
void to_json(json& j, const PrimitiveData& d) {
|
||||||
j = {
|
j = {{"material", d.material}, {"mode", d.mode}, {"attributes", d.attributes}};
|
||||||
{ "material", d.material },
|
|
||||||
{ "mode", d.mode },
|
|
||||||
{ "attributes", d.attributes }
|
|
||||||
};
|
|
||||||
if (d.indices >= 0) {
|
if (d.indices >= 0) {
|
||||||
j["indices"] = d.indices;
|
j["indices"] = d.indices;
|
||||||
}
|
}
|
||||||
if (!d.targetAccessors.empty()) {
|
if (!d.targetAccessors.empty()) {
|
||||||
json targets {};
|
json targets{};
|
||||||
int pIx, nIx, tIx;
|
int pIx, nIx, tIx;
|
||||||
for (auto accessor : d.targetAccessors) {
|
for (auto accessor : d.targetAccessors) {
|
||||||
std::tie(pIx, nIx, tIx) = accessor;
|
std::tie(pIx, nIx, tIx) = accessor;
|
||||||
json target {};
|
json target{};
|
||||||
if (pIx >= 0) { target["POSITION"] = pIx; }
|
if (pIx >= 0) {
|
||||||
if (nIx >= 0) { target["NORMAL"] = nIx; }
|
target["POSITION"] = pIx;
|
||||||
if (tIx >= 0) { target["TANGENT"] = tIx; }
|
}
|
||||||
|
if (nIx >= 0) {
|
||||||
|
target["NORMAL"] = nIx;
|
||||||
|
}
|
||||||
|
if (tIx >= 0) {
|
||||||
|
target["TANGENT"] = tIx;
|
||||||
|
}
|
||||||
targets.push_back(target);
|
targets.push_back(target);
|
||||||
}
|
}
|
||||||
j["targets"] = targets;
|
j["targets"] = targets;
|
||||||
}
|
}
|
||||||
if (!d.dracoAttributes.empty()) {
|
if (!d.dracoAttributes.empty()) {
|
||||||
j["extensions"] = {
|
j["extensions"] = {{KHR_DRACO_MESH_COMPRESSION,
|
||||||
{ KHR_DRACO_MESH_COMPRESSION, {
|
{{"bufferView", d.dracoBufferView}, {"attributes", d.dracoAttributes}}}};
|
||||||
{ "bufferView", d.dracoBufferView },
|
|
||||||
{ "attributes", d.dracoAttributes }
|
|
||||||
}}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,8 @@
|
||||||
|
|
||||||
#include "gltf/Raw2Gltf.hpp"
|
#include "gltf/Raw2Gltf.hpp"
|
||||||
|
|
||||||
struct PrimitiveData
|
struct PrimitiveData {
|
||||||
{
|
enum MeshMode {
|
||||||
enum MeshMode
|
|
||||||
{
|
|
||||||
POINTS = 0,
|
POINTS = 0,
|
||||||
LINES,
|
LINES,
|
||||||
LINE_LOOP,
|
LINE_LOOP,
|
||||||
|
@ -24,29 +22,39 @@ struct PrimitiveData
|
||||||
TRIANGLE_FAN
|
TRIANGLE_FAN
|
||||||
};
|
};
|
||||||
|
|
||||||
PrimitiveData(const AccessorData &indices, const MaterialData &material, std::shared_ptr<draco::Mesh> dracoMesh);
|
PrimitiveData(
|
||||||
|
const AccessorData& indices,
|
||||||
|
const MaterialData& material,
|
||||||
|
std::shared_ptr<draco::Mesh> dracoMesh);
|
||||||
|
|
||||||
PrimitiveData(const AccessorData &indices, const MaterialData &material);
|
PrimitiveData(const AccessorData& indices, const MaterialData& material);
|
||||||
|
|
||||||
void AddAttrib(std::string name, const AccessorData &accessor);
|
void AddAttrib(std::string name, const AccessorData& accessor);
|
||||||
|
|
||||||
void AddTarget(const AccessorData *positions, const AccessorData *normals, const AccessorData *tangents);
|
void AddTarget(
|
||||||
|
const AccessorData* positions,
|
||||||
|
const AccessorData* normals,
|
||||||
|
const AccessorData* tangents);
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
void AddDracoAttrib(const AttributeDefinition<T> attribute, const std::vector<T> &attribArr)
|
void AddDracoAttrib(const AttributeDefinition<T> attribute, const std::vector<T>& attribArr) {
|
||||||
{
|
|
||||||
draco::PointAttribute att;
|
draco::PointAttribute att;
|
||||||
int8_t componentCount = attribute.glType.count;
|
int8_t componentCount = attribute.glType.count;
|
||||||
att.Init(
|
att.Init(
|
||||||
attribute.dracoAttribute, nullptr, componentCount, attribute.dracoComponentType,
|
attribute.dracoAttribute,
|
||||||
false, componentCount * draco::DataTypeLength(attribute.dracoComponentType), 0);
|
nullptr,
|
||||||
|
componentCount,
|
||||||
|
attribute.dracoComponentType,
|
||||||
|
false,
|
||||||
|
componentCount * draco::DataTypeLength(attribute.dracoComponentType),
|
||||||
|
0);
|
||||||
|
|
||||||
const int dracoAttId = dracoMesh->AddAttribute(att, true, attribArr.size());
|
const int dracoAttId = dracoMesh->AddAttribute(att, true, attribArr.size());
|
||||||
draco::PointAttribute *attPtr = dracoMesh->attribute(dracoAttId);
|
draco::PointAttribute* attPtr = dracoMesh->attribute(dracoAttId);
|
||||||
|
|
||||||
std::vector<uint8_t> buf(sizeof(T));
|
std::vector<uint8_t> buf(sizeof(T));
|
||||||
for (uint32_t ii = 0; ii < attribArr.size(); ii++) {
|
for (uint32_t ii = 0; ii < attribArr.size(); ii++) {
|
||||||
uint8_t *ptr = &buf[0];
|
uint8_t* ptr = &buf[0];
|
||||||
attribute.glType.write(ptr, attribArr[ii]);
|
attribute.glType.write(ptr, attribArr[ii]);
|
||||||
attPtr->SetAttributeValue(attPtr->mapped_index(draco::PointIndex(ii)), ptr);
|
attPtr->SetAttributeValue(attPtr->mapped_index(draco::PointIndex(ii)), ptr);
|
||||||
}
|
}
|
||||||
|
@ -54,13 +62,13 @@ struct PrimitiveData
|
||||||
dracoAttributes[attribute.gltfName] = dracoAttId;
|
dracoAttributes[attribute.gltfName] = dracoAttId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NoteDracoBuffer(const BufferViewData &data);
|
void NoteDracoBuffer(const BufferViewData& data);
|
||||||
|
|
||||||
const int indices;
|
const int indices;
|
||||||
const unsigned int material;
|
const unsigned int material;
|
||||||
const MeshMode mode;
|
const MeshMode mode;
|
||||||
|
|
||||||
std::vector<std::tuple<int, int, int>> targetAccessors {};
|
std::vector<std::tuple<int, int, int>> targetAccessors{};
|
||||||
|
|
||||||
std::map<std::string, int> attributes;
|
std::map<std::string, int> attributes;
|
||||||
std::map<std::string, int> dracoAttributes;
|
std::map<std::string, int> dracoAttributes;
|
||||||
|
@ -69,4 +77,4 @@ struct PrimitiveData
|
||||||
int dracoBufferView;
|
int dracoBufferView;
|
||||||
};
|
};
|
||||||
|
|
||||||
void to_json(json &j, const PrimitiveData &d);
|
void to_json(json& j, const PrimitiveData& d);
|
||||||
|
|
|
@ -11,13 +11,9 @@
|
||||||
|
|
||||||
#include "gltf/Raw2Gltf.hpp"
|
#include "gltf/Raw2Gltf.hpp"
|
||||||
|
|
||||||
struct SamplerData : Holdable
|
struct SamplerData : Holdable {
|
||||||
{
|
|
||||||
// this is where magFilter, minFilter, wrapS and wrapT would go, should we want it
|
// this is where magFilter, minFilter, wrapS and wrapT would go, should we want it
|
||||||
SamplerData()
|
SamplerData() : Holdable() {}
|
||||||
: Holdable()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
json serialize() const override {
|
json serialize() const override {
|
||||||
return json::object();
|
return json::object();
|
||||||
|
|
|
@ -11,18 +11,10 @@
|
||||||
|
|
||||||
#include "NodeData.hpp"
|
#include "NodeData.hpp"
|
||||||
|
|
||||||
SceneData::SceneData(std::string name, const NodeData &rootNode)
|
SceneData::SceneData(std::string name, const NodeData& rootNode)
|
||||||
: Holdable(),
|
: Holdable(), name(std::move(name)), nodes({rootNode.ix}) {}
|
||||||
name(std::move(name)),
|
|
||||||
nodes({rootNode.ix})
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
json SceneData::serialize() const
|
json SceneData::serialize() const {
|
||||||
{
|
|
||||||
assert(nodes.size() <= 1);
|
assert(nodes.size() <= 1);
|
||||||
return {
|
return {{"name", name}, {"nodes", nodes}};
|
||||||
{ "name", name },
|
|
||||||
{ "nodes", nodes }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,8 @@
|
||||||
|
|
||||||
#include "gltf/Raw2Gltf.hpp"
|
#include "gltf/Raw2Gltf.hpp"
|
||||||
|
|
||||||
struct SceneData : Holdable
|
struct SceneData : Holdable {
|
||||||
{
|
SceneData(std::string name, const NodeData& rootNode);
|
||||||
SceneData(std::string name, const NodeData &rootNode);
|
|
||||||
|
|
||||||
json serialize() const override;
|
json serialize() const override;
|
||||||
|
|
||||||
|
|
|
@ -13,20 +13,16 @@
|
||||||
#include "NodeData.hpp"
|
#include "NodeData.hpp"
|
||||||
|
|
||||||
SkinData::SkinData(
|
SkinData::SkinData(
|
||||||
const std::vector<uint32_t> joints, const AccessorData &inverseBindMatricesAccessor,
|
const std::vector<uint32_t> joints,
|
||||||
const NodeData &skeletonRootNode)
|
const AccessorData& inverseBindMatricesAccessor,
|
||||||
|
const NodeData& skeletonRootNode)
|
||||||
: Holdable(),
|
: Holdable(),
|
||||||
joints(joints),
|
joints(joints),
|
||||||
inverseBindMatrices(inverseBindMatricesAccessor.ix),
|
inverseBindMatrices(inverseBindMatricesAccessor.ix),
|
||||||
skeletonRootNode(skeletonRootNode.ix)
|
skeletonRootNode(skeletonRootNode.ix) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
json SkinData::serialize() const
|
json SkinData::serialize() const {
|
||||||
{
|
return {{"joints", joints},
|
||||||
return {
|
{"inverseBindMatrices", inverseBindMatrices},
|
||||||
{ "joints", joints },
|
{"skeleton", skeletonRootNode}};
|
||||||
{ "inverseBindMatrices", inverseBindMatrices },
|
|
||||||
{ "skeleton", skeletonRootNode }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
|
|
||||||
#include "gltf/Raw2Gltf.hpp"
|
#include "gltf/Raw2Gltf.hpp"
|
||||||
|
|
||||||
struct SkinData : Holdable
|
struct SkinData : Holdable {
|
||||||
{
|
|
||||||
SkinData(
|
SkinData(
|
||||||
const std::vector<uint32_t> joints, const AccessorData &inverseBindMatricesAccessor,
|
const std::vector<uint32_t> joints,
|
||||||
const NodeData &skeletonRootNode);
|
const AccessorData& inverseBindMatricesAccessor,
|
||||||
|
const NodeData& skeletonRootNode);
|
||||||
|
|
||||||
json serialize() const override;
|
json serialize() const override;
|
||||||
|
|
||||||
|
|
|
@ -12,19 +12,9 @@
|
||||||
#include "ImageData.hpp"
|
#include "ImageData.hpp"
|
||||||
#include "SamplerData.hpp"
|
#include "SamplerData.hpp"
|
||||||
|
|
||||||
TextureData::TextureData(std::string name, const SamplerData &sampler, const ImageData &source)
|
TextureData::TextureData(std::string name, const SamplerData& sampler, const ImageData& source)
|
||||||
: Holdable(),
|
: Holdable(), name(std::move(name)), sampler(sampler.ix), source(source.ix) {}
|
||||||
name(std::move(name)),
|
|
||||||
sampler(sampler.ix),
|
|
||||||
source(source.ix)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
json TextureData::serialize() const
|
json TextureData::serialize() const {
|
||||||
{
|
return {{"name", name}, {"sampler", sampler}, {"source", source}};
|
||||||
return {
|
|
||||||
{ "name", name },
|
|
||||||
{ "sampler", sampler },
|
|
||||||
{ "source", source }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,8 @@
|
||||||
|
|
||||||
#include "gltf/Raw2Gltf.hpp"
|
#include "gltf/Raw2Gltf.hpp"
|
||||||
|
|
||||||
struct TextureData : Holdable
|
struct TextureData : Holdable {
|
||||||
{
|
TextureData(std::string name, const SamplerData& sampler, const ImageData& source);
|
||||||
TextureData(std::string name, const SamplerData &sampler, const ImageData &source);
|
|
||||||
|
|
||||||
json serialize() const override;
|
json serialize() const override;
|
||||||
|
|
||||||
|
|
|
@ -11,18 +11,17 @@
|
||||||
|
|
||||||
#include <fbxsdk.h>
|
#include <fbxsdk.h>
|
||||||
|
|
||||||
#include <mathfu/vector.h>
|
|
||||||
#include <mathfu/matrix.h>
|
#include <mathfu/matrix.h>
|
||||||
#include <mathfu/quaternion.h>
|
#include <mathfu/quaternion.h>
|
||||||
#include <mathfu/rect.h>
|
#include <mathfu/rect.h>
|
||||||
|
#include <mathfu/vector.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All the mathfu:: implementations of our core data types.
|
* All the mathfu:: implementations of our core data types.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<class T, int d>
|
template <class T, int d>
|
||||||
struct Bounds
|
struct Bounds {
|
||||||
{
|
|
||||||
mathfu::Vector<T, d> min;
|
mathfu::Vector<T, d> min;
|
||||||
mathfu::Vector<T, d> max;
|
mathfu::Vector<T, d> max;
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
|
@ -33,9 +32,9 @@ struct Bounds
|
||||||
initialized = false;
|
initialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddPoint(const mathfu::Vector<T, d> &p) {
|
void AddPoint(const mathfu::Vector<T, d>& p) {
|
||||||
if (initialized) {
|
if (initialized) {
|
||||||
for (int ii = 0; ii < d; ii ++) {
|
for (int ii = 0; ii < d; ii++) {
|
||||||
min(ii) = std::min(min(ii), p(ii));
|
min(ii) = std::min(min(ii), p(ii));
|
||||||
max(ii) = std::max(max(ii), p(ii));
|
max(ii) = std::max(max(ii), p(ii));
|
||||||
}
|
}
|
||||||
|
@ -58,46 +57,47 @@ typedef mathfu::Matrix<float, 4> Mat4f;
|
||||||
typedef mathfu::Quaternion<float> Quatf;
|
typedef mathfu::Quaternion<float> Quatf;
|
||||||
typedef Bounds<float, 3> Boundsf;
|
typedef Bounds<float, 3> Boundsf;
|
||||||
|
|
||||||
#define VEC3F_ONE (Vec3f {1.0f})
|
#define VEC3F_ONE (Vec3f{1.0f})
|
||||||
#define VEC3F_ZERO (Vec3f {0.0f})
|
#define VEC3F_ZERO (Vec3f{0.0f})
|
||||||
#define VEC4F_ONE (Vec4f {1.0f})
|
#define VEC4F_ONE (Vec4f{1.0f})
|
||||||
#define VEC4F_ZERO (Vec4f {0.0f})
|
#define VEC4F_ZERO (Vec4f{0.0f})
|
||||||
|
|
||||||
template<class T, int d> inline std::vector<T> toStdVec(const mathfu::Vector <T, d> &vec)
|
template <class T, int d>
|
||||||
{
|
inline std::vector<T> toStdVec(const mathfu::Vector<T, d>& vec) {
|
||||||
std::vector<T> result(d);
|
std::vector<T> result(d);
|
||||||
for (int ii = 0; ii < d; ii ++) {
|
for (int ii = 0; ii < d; ii++) {
|
||||||
result[ii] = vec[ii];
|
result[ii] = vec[ii];
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T> std::vector<T> toStdVec(const mathfu::Quaternion<T> &quat) {
|
template <class T>
|
||||||
return std::vector<T> { quat.vector()[0], quat.vector()[1], quat.vector()[2], quat.scalar() };
|
std::vector<T> toStdVec(const mathfu::Quaternion<T>& quat) {
|
||||||
|
return std::vector<T>{quat.vector()[0], quat.vector()[1], quat.vector()[2], quat.scalar()};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Vec3f toVec3f(const FbxDouble3 &v) {
|
inline Vec3f toVec3f(const FbxDouble3& v) {
|
||||||
return Vec3f((float) v[0], (float) v[1], (float) v[2]);
|
return Vec3f((float)v[0], (float)v[1], (float)v[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Vec3f toVec3f(const FbxVector4 &v) {
|
inline Vec3f toVec3f(const FbxVector4& v) {
|
||||||
return Vec3f((float) v[0], (float) v[1], (float) v[2]);
|
return Vec3f((float)v[0], (float)v[1], (float)v[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Vec4f toVec4f(const FbxVector4 &v) {
|
inline Vec4f toVec4f(const FbxVector4& v) {
|
||||||
return Vec4f((float) v[0], (float) v[1], (float) v[2], (float) v[3]);
|
return Vec4f((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Mat4f toMat4f(const FbxAMatrix &m) {
|
inline Mat4f toMat4f(const FbxAMatrix& m) {
|
||||||
auto result = Mat4f();
|
auto result = Mat4f();
|
||||||
for (int row = 0; row < 4; row ++) {
|
for (int row = 0; row < 4; row++) {
|
||||||
for (int col = 0; col < 4; col ++) {
|
for (int col = 0; col < 4; col++) {
|
||||||
result(row, col) = (float) m[row][col];
|
result(row, col) = (float)m[row][col];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Quatf toQuatf(const FbxQuaternion &q) {
|
inline Quatf toQuatf(const FbxQuaternion& q) {
|
||||||
return Quatf((float) q[3], (float) q[0], (float) q[1], (float) q[2]);
|
return Quatf((float)q[3], (float)q[0], (float)q[1], (float)q[2]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,120 +9,136 @@
|
||||||
|
|
||||||
#include "RawModel.hpp"
|
#include "RawModel.hpp"
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#if defined( __unix__ )
|
#if defined(__unix__)
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "utils/String_Utils.hpp"
|
|
||||||
#include "utils/Image_Utils.hpp"
|
#include "utils/Image_Utils.hpp"
|
||||||
|
#include "utils/String_Utils.hpp"
|
||||||
|
|
||||||
bool RawVertex::operator==(const RawVertex &other) const
|
bool RawVertex::operator==(const RawVertex& other) const {
|
||||||
{
|
return (position == other.position) && (normal == other.normal) && (tangent == other.tangent) &&
|
||||||
return (position == other.position) &&
|
(binormal == other.binormal) && (color == other.color) && (uv0 == other.uv0) &&
|
||||||
(normal == other.normal) &&
|
(uv1 == other.uv1) && (jointIndices == other.jointIndices) &&
|
||||||
(tangent == other.tangent) &&
|
(jointWeights == other.jointWeights) && (polarityUv0 == other.polarityUv0) &&
|
||||||
(binormal == other.binormal) &&
|
(blendSurfaceIx == other.blendSurfaceIx) && (blends == other.blends);
|
||||||
(color == other.color) &&
|
|
||||||
(uv0 == other.uv0) &&
|
|
||||||
(uv1 == other.uv1) &&
|
|
||||||
(jointIndices == other.jointIndices) &&
|
|
||||||
(jointWeights == other.jointWeights) &&
|
|
||||||
(polarityUv0 == other.polarityUv0) &&
|
|
||||||
(blendSurfaceIx == other.blendSurfaceIx) &&
|
|
||||||
(blends == other.blends);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RawVertex::Difference(const RawVertex &other) const
|
size_t RawVertex::Difference(const RawVertex& other) const {
|
||||||
{
|
|
||||||
size_t attributes = 0;
|
size_t attributes = 0;
|
||||||
if (position != other.position) { attributes |= RAW_VERTEX_ATTRIBUTE_POSITION; }
|
if (position != other.position) {
|
||||||
if (normal != other.normal) { attributes |= RAW_VERTEX_ATTRIBUTE_NORMAL; }
|
attributes |= RAW_VERTEX_ATTRIBUTE_POSITION;
|
||||||
if (tangent != other.tangent) { attributes |= RAW_VERTEX_ATTRIBUTE_TANGENT; }
|
}
|
||||||
if (binormal != other.binormal) { attributes |= RAW_VERTEX_ATTRIBUTE_BINORMAL; }
|
if (normal != other.normal) {
|
||||||
if (color != other.color) { attributes |= RAW_VERTEX_ATTRIBUTE_COLOR; }
|
attributes |= RAW_VERTEX_ATTRIBUTE_NORMAL;
|
||||||
if (uv0 != other.uv0) { attributes |= RAW_VERTEX_ATTRIBUTE_UV0; }
|
}
|
||||||
if (uv1 != other.uv1) { attributes |= RAW_VERTEX_ATTRIBUTE_UV1; }
|
if (tangent != other.tangent) {
|
||||||
|
attributes |= RAW_VERTEX_ATTRIBUTE_TANGENT;
|
||||||
|
}
|
||||||
|
if (binormal != other.binormal) {
|
||||||
|
attributes |= RAW_VERTEX_ATTRIBUTE_BINORMAL;
|
||||||
|
}
|
||||||
|
if (color != other.color) {
|
||||||
|
attributes |= RAW_VERTEX_ATTRIBUTE_COLOR;
|
||||||
|
}
|
||||||
|
if (uv0 != other.uv0) {
|
||||||
|
attributes |= RAW_VERTEX_ATTRIBUTE_UV0;
|
||||||
|
}
|
||||||
|
if (uv1 != other.uv1) {
|
||||||
|
attributes |= RAW_VERTEX_ATTRIBUTE_UV1;
|
||||||
|
}
|
||||||
// Always need both or neither.
|
// Always need both or neither.
|
||||||
if (jointIndices != other.jointIndices) { attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS; }
|
if (jointIndices != other.jointIndices) {
|
||||||
if (jointWeights != other.jointWeights) { attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS; }
|
attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS;
|
||||||
|
}
|
||||||
|
if (jointWeights != other.jointWeights) {
|
||||||
|
attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS;
|
||||||
|
}
|
||||||
return attributes;
|
return attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
RawModel::RawModel()
|
RawModel::RawModel() : vertexAttributes(0) {}
|
||||||
: vertexAttributes(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void RawModel::AddVertexAttribute(const RawVertexAttribute attrib)
|
void RawModel::AddVertexAttribute(const RawVertexAttribute attrib) {
|
||||||
{
|
|
||||||
vertexAttributes |= attrib;
|
vertexAttributes |= attrib;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawModel::AddVertex(const RawVertex &vertex)
|
int RawModel::AddVertex(const RawVertex& vertex) {
|
||||||
{
|
|
||||||
auto it = vertexHash.find(vertex);
|
auto it = vertexHash.find(vertex);
|
||||||
if (it != vertexHash.end()) {
|
if (it != vertexHash.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
vertexHash.emplace(vertex, (int) vertices.size());
|
vertexHash.emplace(vertex, (int)vertices.size());
|
||||||
vertices.push_back(vertex);
|
vertices.push_back(vertex);
|
||||||
return (int) vertices.size() - 1;
|
return (int)vertices.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawModel::AddTriangle(const int v0, const int v1, const int v2, const int materialIndex, const int surfaceIndex)
|
int RawModel::AddTriangle(
|
||||||
{
|
const int v0,
|
||||||
|
const int v1,
|
||||||
|
const int v2,
|
||||||
|
const int materialIndex,
|
||||||
|
const int surfaceIndex) {
|
||||||
const RawTriangle triangle = {{v0, v1, v2}, materialIndex, surfaceIndex};
|
const RawTriangle triangle = {{v0, v1, v2}, materialIndex, surfaceIndex};
|
||||||
triangles.push_back(triangle);
|
triangles.push_back(triangle);
|
||||||
return (int) triangles.size() - 1;
|
return (int)triangles.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawModel::AddTexture(const std::string &name, const std::string &fileName, const std::string &fileLocation, RawTextureUsage usage)
|
int RawModel::AddTexture(
|
||||||
{
|
const std::string& name,
|
||||||
|
const std::string& fileName,
|
||||||
|
const std::string& fileLocation,
|
||||||
|
RawTextureUsage usage) {
|
||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < textures.size(); i++) {
|
for (size_t i = 0; i < textures.size(); i++) {
|
||||||
if (StringUtils::CompareNoCase(textures[i].name, name) == 0 && textures[i].usage == usage) {
|
if (StringUtils::CompareNoCase(textures[i].name, name) == 0 && textures[i].usage == usage) {
|
||||||
return (int) i;
|
return (int)i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ImageUtils::ImageProperties
|
const ImageUtils::ImageProperties properties = ImageUtils::GetImageProperties(
|
||||||
properties = ImageUtils::GetImageProperties(!fileLocation.empty() ? fileLocation.c_str() : fileName.c_str());
|
!fileLocation.empty() ? fileLocation.c_str() : fileName.c_str());
|
||||||
|
|
||||||
RawTexture texture;
|
RawTexture texture;
|
||||||
texture.name = name;
|
texture.name = name;
|
||||||
texture.width = properties.width;
|
texture.width = properties.width;
|
||||||
texture.height = properties.height;
|
texture.height = properties.height;
|
||||||
texture.mipLevels = (int) ceilf(log2f(std::max((float) properties.width, (float) properties.height)));
|
texture.mipLevels =
|
||||||
|
(int)ceilf(log2f(std::max((float)properties.width, (float)properties.height)));
|
||||||
texture.usage = usage;
|
texture.usage = usage;
|
||||||
texture.occlusion = (properties.occlusion == ImageUtils::IMAGE_TRANSPARENT) ?
|
texture.occlusion = (properties.occlusion == ImageUtils::IMAGE_TRANSPARENT)
|
||||||
RAW_TEXTURE_OCCLUSION_TRANSPARENT : RAW_TEXTURE_OCCLUSION_OPAQUE;
|
? RAW_TEXTURE_OCCLUSION_TRANSPARENT
|
||||||
|
: RAW_TEXTURE_OCCLUSION_OPAQUE;
|
||||||
texture.fileName = fileName;
|
texture.fileName = fileName;
|
||||||
texture.fileLocation = fileLocation;
|
texture.fileLocation = fileLocation;
|
||||||
textures.emplace_back(texture);
|
textures.emplace_back(texture);
|
||||||
return (int) textures.size() - 1;
|
return (int)textures.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawModel::AddMaterial(const RawMaterial &material)
|
int RawModel::AddMaterial(const RawMaterial& material) {
|
||||||
{
|
return AddMaterial(
|
||||||
return AddMaterial(material.name.c_str(), material.type, material.textures, material.info, material.userProperties);
|
material.name.c_str(),
|
||||||
|
material.type,
|
||||||
|
material.textures,
|
||||||
|
material.info,
|
||||||
|
material.userProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawModel::AddMaterial(
|
int RawModel::AddMaterial(
|
||||||
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],
|
||||||
std::shared_ptr<RawMatProps> materialInfo,
|
std::shared_ptr<RawMatProps> materialInfo,
|
||||||
const std::vector<std::string>& userProperties)
|
const std::vector<std::string>& userProperties) {
|
||||||
{
|
|
||||||
for (size_t i = 0; i < materials.size(); i++) {
|
for (size_t i = 0; i < materials.size(); i++) {
|
||||||
if (materials[i].name != name) {
|
if (materials[i].name != name) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -139,14 +155,13 @@ int RawModel::AddMaterial(
|
||||||
}
|
}
|
||||||
if (materials[i].userProperties.size() != userProperties.size()) {
|
if (materials[i].userProperties.size() != userProperties.size()) {
|
||||||
match = false;
|
match = false;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
for (int j = 0; match && j < userProperties.size(); j++) {
|
for (int j = 0; match && j < userProperties.size(); j++) {
|
||||||
match = match && (materials[i].userProperties[j] == userProperties[j]);
|
match = match && (materials[i].userProperties[j] == userProperties[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (match) {
|
if (match) {
|
||||||
return (int) i;
|
return (int)i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,18 +177,17 @@ int RawModel::AddMaterial(
|
||||||
|
|
||||||
materials.emplace_back(material);
|
materials.emplace_back(material);
|
||||||
|
|
||||||
return (int) materials.size() - 1;
|
return (int)materials.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawModel::AddLight(
|
int RawModel::AddLight(
|
||||||
const char *name,
|
const char* name,
|
||||||
const RawLightType lightType,
|
const RawLightType lightType,
|
||||||
const Vec3f color,
|
const Vec3f color,
|
||||||
const float intensity,
|
const float intensity,
|
||||||
const float innerConeAngle,
|
const float innerConeAngle,
|
||||||
const float outerConeAngle)
|
const float outerConeAngle) {
|
||||||
{
|
for (size_t i = 0; i < lights.size(); i++) {
|
||||||
for (size_t i = 0; i < lights.size(); i ++) {
|
|
||||||
if (lights[i].name != name || lights[i].type != lightType) {
|
if (lights[i].name != name || lights[i].type != lightType) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -184,9 +198,9 @@ int RawModel::AddLight(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (int) i;
|
return (int)i;
|
||||||
}
|
}
|
||||||
RawLight light {
|
RawLight light{
|
||||||
name,
|
name,
|
||||||
lightType,
|
lightType,
|
||||||
color,
|
color,
|
||||||
|
@ -195,29 +209,26 @@ int RawModel::AddLight(
|
||||||
outerConeAngle,
|
outerConeAngle,
|
||||||
};
|
};
|
||||||
lights.push_back(light);
|
lights.push_back(light);
|
||||||
return (int) lights.size() - 1;
|
return (int)lights.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int RawModel::AddSurface(const RawSurface& surface) {
|
||||||
int RawModel::AddSurface(const RawSurface &surface)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < surfaces.size(); i++) {
|
for (size_t i = 0; i < surfaces.size(); i++) {
|
||||||
if (StringUtils::CompareNoCase(surfaces[i].name, surface.name) == 0) {
|
if (StringUtils::CompareNoCase(surfaces[i].name, surface.name) == 0) {
|
||||||
return (int) i;
|
return (int)i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
surfaces.emplace_back(surface);
|
surfaces.emplace_back(surface);
|
||||||
return (int) (surfaces.size() - 1);
|
return (int)(surfaces.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawModel::AddSurface(const char *name, const long surfaceId)
|
int RawModel::AddSurface(const char* name, const long surfaceId) {
|
||||||
{
|
|
||||||
assert(name[0] != '\0');
|
assert(name[0] != '\0');
|
||||||
|
|
||||||
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) {
|
||||||
return (int) i;
|
return (int)i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RawSurface surface;
|
RawSurface surface;
|
||||||
|
@ -227,17 +238,15 @@ int RawModel::AddSurface(const char *name, const long surfaceId)
|
||||||
surface.discrete = false;
|
surface.discrete = false;
|
||||||
|
|
||||||
surfaces.emplace_back(surface);
|
surfaces.emplace_back(surface);
|
||||||
return (int) (surfaces.size() - 1);
|
return (int)(surfaces.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawModel::AddAnimation(const RawAnimation &animation)
|
int RawModel::AddAnimation(const RawAnimation& animation) {
|
||||||
{
|
|
||||||
animations.emplace_back(animation);
|
animations.emplace_back(animation);
|
||||||
return (int) (animations.size() - 1);
|
return (int)(animations.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawModel::AddNode(const RawNode &node)
|
int RawModel::AddNode(const RawNode& node) {
|
||||||
{
|
|
||||||
for (size_t i = 0; i < nodes.size(); i++) {
|
for (size_t i = 0; i < nodes.size(); i++) {
|
||||||
if (nodes[i].id == node.id) {
|
if (nodes[i].id == node.id) {
|
||||||
return (int)i;
|
return (int)i;
|
||||||
|
@ -245,13 +254,17 @@ int RawModel::AddNode(const RawNode &node)
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes.emplace_back(node);
|
nodes.emplace_back(node);
|
||||||
return (int) nodes.size() - 1;
|
return (int)nodes.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawModel::AddCameraPerspective(
|
int RawModel::AddCameraPerspective(
|
||||||
const char *name, const long nodeId, const float aspectRatio, const float fovDegreesX, const float fovDegreesY, const float nearZ,
|
const char* name,
|
||||||
const float farZ)
|
const long nodeId,
|
||||||
{
|
const float aspectRatio,
|
||||||
|
const float fovDegreesX,
|
||||||
|
const float fovDegreesY,
|
||||||
|
const float nearZ,
|
||||||
|
const float farZ) {
|
||||||
RawCamera camera;
|
RawCamera camera;
|
||||||
camera.name = name;
|
camera.name = name;
|
||||||
camera.nodeId = nodeId;
|
camera.nodeId = nodeId;
|
||||||
|
@ -262,12 +275,16 @@ int RawModel::AddCameraPerspective(
|
||||||
camera.perspective.nearZ = nearZ;
|
camera.perspective.nearZ = nearZ;
|
||||||
camera.perspective.farZ = farZ;
|
camera.perspective.farZ = farZ;
|
||||||
cameras.emplace_back(camera);
|
cameras.emplace_back(camera);
|
||||||
return (int) cameras.size() - 1;
|
return (int)cameras.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawModel::AddCameraOrthographic(
|
int RawModel::AddCameraOrthographic(
|
||||||
const char *name, const long nodeId, const float magX, const float magY, const float nearZ, const float farZ)
|
const char* name,
|
||||||
{
|
const long nodeId,
|
||||||
|
const float magX,
|
||||||
|
const float magY,
|
||||||
|
const float nearZ,
|
||||||
|
const float farZ) {
|
||||||
RawCamera camera;
|
RawCamera camera;
|
||||||
camera.name = name;
|
camera.name = name;
|
||||||
camera.nodeId = nodeId;
|
camera.nodeId = nodeId;
|
||||||
|
@ -277,16 +294,15 @@ int RawModel::AddCameraOrthographic(
|
||||||
camera.orthographic.nearZ = nearZ;
|
camera.orthographic.nearZ = nearZ;
|
||||||
camera.orthographic.farZ = farZ;
|
camera.orthographic.farZ = farZ;
|
||||||
cameras.emplace_back(camera);
|
cameras.emplace_back(camera);
|
||||||
return (int) cameras.size() - 1;
|
return (int)cameras.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawModel::AddNode(const long id, const char *name, const long parentId)
|
int RawModel::AddNode(const long id, const char* name, const long parentId) {
|
||||||
{
|
|
||||||
assert(name[0] != '\0');
|
assert(name[0] != '\0');
|
||||||
|
|
||||||
for (size_t i = 0; i < nodes.size(); i++) {
|
for (size_t i = 0; i < nodes.size(); i++) {
|
||||||
if (nodes[i].id == id ) {
|
if (nodes[i].id == id) {
|
||||||
return (int) i;
|
return (int)i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,11 +318,10 @@ int RawModel::AddNode(const long id, const char *name, const long parentId)
|
||||||
joint.scale = Vec3f(1, 1, 1);
|
joint.scale = Vec3f(1, 1, 1);
|
||||||
|
|
||||||
nodes.emplace_back(joint);
|
nodes.emplace_back(joint);
|
||||||
return (int) nodes.size() - 1;
|
return (int)nodes.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RawModel::Condense()
|
void RawModel::Condense() {
|
||||||
{
|
|
||||||
// Only keep surfaces that are referenced by one or more triangles.
|
// Only keep surfaces that are referenced by one or more triangles.
|
||||||
{
|
{
|
||||||
std::vector<RawSurface> oldSurfaces = surfaces;
|
std::vector<RawSurface> oldSurfaces = surfaces;
|
||||||
|
@ -314,16 +329,17 @@ void RawModel::Condense()
|
||||||
surfaces.clear();
|
surfaces.clear();
|
||||||
|
|
||||||
std::set<int> survivingSurfaceIds;
|
std::set<int> survivingSurfaceIds;
|
||||||
for (auto &triangle : triangles) {
|
for (auto& triangle : triangles) {
|
||||||
const RawSurface &surface = oldSurfaces[triangle.surfaceIndex];
|
const RawSurface& surface = oldSurfaces[triangle.surfaceIndex];
|
||||||
const int surfaceIndex = AddSurface(surface.name.c_str(), surface.id);
|
const int surfaceIndex = AddSurface(surface.name.c_str(), surface.id);
|
||||||
surfaces[surfaceIndex] = surface;
|
surfaces[surfaceIndex] = surface;
|
||||||
triangle.surfaceIndex = surfaceIndex;
|
triangle.surfaceIndex = surfaceIndex;
|
||||||
survivingSurfaceIds.emplace(surface.id);
|
survivingSurfaceIds.emplace(surface.id);
|
||||||
}
|
}
|
||||||
// clear out references to meshes that no longer exist
|
// clear out references to meshes that no longer exist
|
||||||
for (auto &node : nodes) {
|
for (auto& node : nodes) {
|
||||||
if (node.surfaceId != 0 && survivingSurfaceIds.find(node.surfaceId) == survivingSurfaceIds.end()) {
|
if (node.surfaceId != 0 &&
|
||||||
|
survivingSurfaceIds.find(node.surfaceId) == survivingSurfaceIds.end()) {
|
||||||
node.surfaceId = 0;
|
node.surfaceId = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -335,8 +351,8 @@ void RawModel::Condense()
|
||||||
|
|
||||||
materials.clear();
|
materials.clear();
|
||||||
|
|
||||||
for (auto &triangle : triangles) {
|
for (auto& triangle : triangles) {
|
||||||
const RawMaterial &material = oldMaterials[triangle.materialIndex];
|
const RawMaterial& material = oldMaterials[triangle.materialIndex];
|
||||||
const int materialIndex = AddMaterial(material);
|
const int materialIndex = AddMaterial(material);
|
||||||
materials[materialIndex] = material;
|
materials[materialIndex] = material;
|
||||||
triangle.materialIndex = materialIndex;
|
triangle.materialIndex = materialIndex;
|
||||||
|
@ -349,11 +365,12 @@ void RawModel::Condense()
|
||||||
|
|
||||||
textures.clear();
|
textures.clear();
|
||||||
|
|
||||||
for (auto &material : materials) {
|
for (auto& material : materials) {
|
||||||
for (int j = 0; j < RAW_TEXTURE_USAGE_MAX; j++) {
|
for (int j = 0; j < RAW_TEXTURE_USAGE_MAX; j++) {
|
||||||
if (material.textures[j] >= 0) {
|
if (material.textures[j] >= 0) {
|
||||||
const RawTexture &texture = oldTextures[material.textures[j]];
|
const RawTexture& texture = oldTextures[material.textures[j]];
|
||||||
const int textureIndex = AddTexture(texture.name, texture.fileName, texture.fileLocation, texture.usage);
|
const int textureIndex =
|
||||||
|
AddTexture(texture.name, texture.fileName, texture.fileLocation, texture.usage);
|
||||||
textures[textureIndex] = texture;
|
textures[textureIndex] = texture;
|
||||||
material.textures[j] = textureIndex;
|
material.textures[j] = textureIndex;
|
||||||
}
|
}
|
||||||
|
@ -368,7 +385,7 @@ void RawModel::Condense()
|
||||||
vertexHash.clear();
|
vertexHash.clear();
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
|
|
||||||
for (auto &triangle : triangles) {
|
for (auto& triangle : triangles) {
|
||||||
for (int j = 0; j < 3; j++) {
|
for (int j = 0; j < 3; j++) {
|
||||||
triangle.verts[j] = AddVertex(oldVertices[triangle.verts[j]]);
|
triangle.verts[j] = AddVertex(oldVertices[triangle.verts[j]]);
|
||||||
}
|
}
|
||||||
|
@ -376,9 +393,8 @@ void RawModel::Condense()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RawModel::TransformGeometry(ComputeNormalsOption normals)
|
void RawModel::TransformGeometry(ComputeNormalsOption normals) {
|
||||||
{
|
switch (normals) {
|
||||||
switch(normals) {
|
|
||||||
case ComputeNormalsOption::NEVER:
|
case ComputeNormalsOption::NEVER:
|
||||||
break;
|
break;
|
||||||
case ComputeNormalsOption::MISSING:
|
case ComputeNormalsOption::MISSING:
|
||||||
|
@ -404,26 +420,23 @@ void RawModel::TransformGeometry(ComputeNormalsOption normals)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RawModel::TransformTextures(const std::vector<std::function<Vec2f(Vec2f)>> &transforms)
|
void RawModel::TransformTextures(const std::vector<std::function<Vec2f(Vec2f)>>& transforms) {
|
||||||
{
|
for (auto& vertice : vertices) {
|
||||||
for (auto &vertice : vertices) {
|
|
||||||
if ((vertexAttributes & RAW_VERTEX_ATTRIBUTE_UV0) != 0) {
|
if ((vertexAttributes & RAW_VERTEX_ATTRIBUTE_UV0) != 0) {
|
||||||
for (const auto &fun : transforms) {
|
for (const auto& fun : transforms) {
|
||||||
vertice.uv0 = fun(vertice.uv0);
|
vertice.uv0 = fun(vertice.uv0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((vertexAttributes & RAW_VERTEX_ATTRIBUTE_UV1) != 0) {
|
if ((vertexAttributes & RAW_VERTEX_ATTRIBUTE_UV1) != 0) {
|
||||||
for (const auto &fun : transforms) {
|
for (const auto& fun : transforms) {
|
||||||
vertice.uv1 = fun(vertice.uv1);
|
vertice.uv1 = fun(vertice.uv1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TriangleModelSortPos
|
struct TriangleModelSortPos {
|
||||||
{
|
static bool Compare(const RawTriangle& a, const RawTriangle& b) {
|
||||||
static bool Compare(const RawTriangle &a, const RawTriangle &b)
|
|
||||||
{
|
|
||||||
if (a.materialIndex != b.materialIndex) {
|
if (a.materialIndex != b.materialIndex) {
|
||||||
return a.materialIndex < b.materialIndex;
|
return a.materialIndex < b.materialIndex;
|
||||||
}
|
}
|
||||||
|
@ -434,10 +447,8 @@ struct TriangleModelSortPos
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TriangleModelSortNeg
|
struct TriangleModelSortNeg {
|
||||||
{
|
static bool Compare(const RawTriangle& a, const RawTriangle& b) {
|
||||||
static bool Compare(const RawTriangle &a, const RawTriangle &b)
|
|
||||||
{
|
|
||||||
if (a.materialIndex != b.materialIndex) {
|
if (a.materialIndex != b.materialIndex) {
|
||||||
return a.materialIndex < b.materialIndex;
|
return a.materialIndex < b.materialIndex;
|
||||||
}
|
}
|
||||||
|
@ -449,8 +460,10 @@ struct TriangleModelSortNeg
|
||||||
};
|
};
|
||||||
|
|
||||||
void RawModel::CreateMaterialModels(
|
void RawModel::CreateMaterialModels(
|
||||||
std::vector<RawModel> &materialModels, bool shortIndices, const int keepAttribs, const bool forceDiscrete) const
|
std::vector<RawModel>& materialModels,
|
||||||
{
|
bool shortIndices,
|
||||||
|
const int keepAttribs,
|
||||||
|
const bool forceDiscrete) const {
|
||||||
// Sort all triangles based on material first, then surface, then first vertex index.
|
// Sort all triangles based on material first, then surface, then first vertex index.
|
||||||
std::vector<RawTriangle> sortedTriangles;
|
std::vector<RawTriangle> sortedTriangles;
|
||||||
|
|
||||||
|
@ -459,7 +472,7 @@ void RawModel::CreateMaterialModels(
|
||||||
// Split the triangles into opaque and transparent triangles.
|
// Split the triangles into opaque and transparent triangles.
|
||||||
std::vector<RawTriangle> opaqueTriangles;
|
std::vector<RawTriangle> opaqueTriangles;
|
||||||
std::vector<RawTriangle> transparentTriangles;
|
std::vector<RawTriangle> transparentTriangles;
|
||||||
for (const auto &triangle : triangles) {
|
for (const auto& triangle : triangles) {
|
||||||
const int materialIndex = triangle.materialIndex;
|
const int materialIndex = triangle.materialIndex;
|
||||||
if (materialIndex < 0) {
|
if (materialIndex < 0) {
|
||||||
opaqueTriangles.push_back(triangle);
|
opaqueTriangles.push_back(triangle);
|
||||||
|
@ -487,13 +500,14 @@ void RawModel::CreateMaterialModels(
|
||||||
std::sort(opaqueTriangles.begin(), opaqueTriangles.end(), TriangleModelSortPos::Compare);
|
std::sort(opaqueTriangles.begin(), opaqueTriangles.end(), TriangleModelSortPos::Compare);
|
||||||
|
|
||||||
// Sort the transparent triangles in the reverse direction.
|
// Sort the transparent triangles in the reverse direction.
|
||||||
std::sort(transparentTriangles.begin(), transparentTriangles.end(), TriangleModelSortNeg::Compare);
|
std::sort(
|
||||||
|
transparentTriangles.begin(), transparentTriangles.end(), TriangleModelSortNeg::Compare);
|
||||||
|
|
||||||
// Add the triangles to the sorted list.
|
// Add the triangles to the sorted list.
|
||||||
for (const auto &opaqueTriangle : opaqueTriangles) {
|
for (const auto& opaqueTriangle : opaqueTriangles) {
|
||||||
sortedTriangles.push_back(opaqueTriangle);
|
sortedTriangles.push_back(opaqueTriangle);
|
||||||
}
|
}
|
||||||
for (const auto &transparentTriangle : transparentTriangles) {
|
for (const auto& transparentTriangle : transparentTriangles) {
|
||||||
sortedTriangles.push_back(transparentTriangle);
|
sortedTriangles.push_back(transparentTriangle);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -503,7 +517,7 @@ void RawModel::CreateMaterialModels(
|
||||||
|
|
||||||
// Overestimate the number of models that will be created to avoid massive reallocation.
|
// Overestimate the number of models that will be created to avoid massive reallocation.
|
||||||
int discreteCount = 0;
|
int discreteCount = 0;
|
||||||
for (const auto &surface : surfaces) {
|
for (const auto& surface : surfaces) {
|
||||||
discreteCount += surface.discrete ? 1 : 0;
|
discreteCount += surface.discrete ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,15 +527,13 @@ void RawModel::CreateMaterialModels(
|
||||||
const RawVertex defaultVertex;
|
const RawVertex defaultVertex;
|
||||||
|
|
||||||
// Create a separate model for each material.
|
// Create a separate model for each material.
|
||||||
RawModel *model;
|
RawModel* model;
|
||||||
for (size_t i = 0; i < sortedTriangles.size(); i++) {
|
for (size_t i = 0; i < sortedTriangles.size(); i++) {
|
||||||
|
|
||||||
if (sortedTriangles[i].materialIndex < 0 || sortedTriangles[i].surfaceIndex < 0) {
|
if (sortedTriangles[i].materialIndex < 0 || sortedTriangles[i].surfaceIndex < 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == 0 ||
|
if (i == 0 || (shortIndices && model->GetVertexCount() >= 0xFFFE) ||
|
||||||
(shortIndices && model->GetVertexCount() >= 0xFFFE) ||
|
|
||||||
sortedTriangles[i].materialIndex != sortedTriangles[i - 1].materialIndex ||
|
sortedTriangles[i].materialIndex != sortedTriangles[i - 1].materialIndex ||
|
||||||
(sortedTriangles[i].surfaceIndex != sortedTriangles[i - 1].surfaceIndex &&
|
(sortedTriangles[i].surfaceIndex != sortedTriangles[i - 1].surfaceIndex &&
|
||||||
(forceDiscrete || surfaces[sortedTriangles[i].surfaceIndex].discrete ||
|
(forceDiscrete || surfaces[sortedTriangles[i].surfaceIndex].discrete ||
|
||||||
|
@ -536,11 +548,11 @@ void RawModel::CreateMaterialModels(
|
||||||
const int prevSurfaceCount = model->GetSurfaceCount();
|
const int prevSurfaceCount = model->GetSurfaceCount();
|
||||||
const int materialIndex = model->AddMaterial(materials[sortedTriangles[i].materialIndex]);
|
const int materialIndex = model->AddMaterial(materials[sortedTriangles[i].materialIndex]);
|
||||||
const int surfaceIndex = model->AddSurface(surfaces[sortedTriangles[i].surfaceIndex]);
|
const int surfaceIndex = model->AddSurface(surfaces[sortedTriangles[i].surfaceIndex]);
|
||||||
RawSurface &rawSurface = model->GetSurface(surfaceIndex);
|
RawSurface& rawSurface = model->GetSurface(surfaceIndex);
|
||||||
|
|
||||||
if (model->GetSurfaceCount() > prevSurfaceCount) {
|
if (model->GetSurfaceCount() > prevSurfaceCount) {
|
||||||
const std::vector<long> &jointIds = surfaces[sortedTriangles[i].surfaceIndex].jointIds;
|
const std::vector<long>& jointIds = surfaces[sortedTriangles[i].surfaceIndex].jointIds;
|
||||||
for (const auto &jointId : jointIds) {
|
for (const auto& jointId : jointIds) {
|
||||||
const int nodeIndex = GetNodeById(jointId);
|
const int nodeIndex = GetNodeById(jointId);
|
||||||
assert(nodeIndex != -1);
|
assert(nodeIndex != -1);
|
||||||
model->AddNode(GetNode(nodeIndex));
|
model->AddNode(GetNode(nodeIndex));
|
||||||
|
@ -560,33 +572,48 @@ void RawModel::CreateMaterialModels(
|
||||||
if ((keepAttribs & RAW_VERTEX_ATTRIBUTE_AUTO) != 0) {
|
if ((keepAttribs & RAW_VERTEX_ATTRIBUTE_AUTO) != 0) {
|
||||||
keep |= RAW_VERTEX_ATTRIBUTE_POSITION;
|
keep |= RAW_VERTEX_ATTRIBUTE_POSITION;
|
||||||
|
|
||||||
const RawMaterial &mat = model->GetMaterial(materialIndex);
|
const RawMaterial& mat = model->GetMaterial(materialIndex);
|
||||||
if (mat.textures[RAW_TEXTURE_USAGE_DIFFUSE] != -1) {
|
if (mat.textures[RAW_TEXTURE_USAGE_DIFFUSE] != -1) {
|
||||||
keep |= RAW_VERTEX_ATTRIBUTE_UV0;
|
keep |= RAW_VERTEX_ATTRIBUTE_UV0;
|
||||||
}
|
}
|
||||||
if (mat.textures[RAW_TEXTURE_USAGE_NORMAL] != -1) {
|
if (mat.textures[RAW_TEXTURE_USAGE_NORMAL] != -1) {
|
||||||
keep |= RAW_VERTEX_ATTRIBUTE_NORMAL |
|
keep |= RAW_VERTEX_ATTRIBUTE_NORMAL | RAW_VERTEX_ATTRIBUTE_TANGENT |
|
||||||
RAW_VERTEX_ATTRIBUTE_TANGENT |
|
RAW_VERTEX_ATTRIBUTE_BINORMAL | RAW_VERTEX_ATTRIBUTE_UV0;
|
||||||
RAW_VERTEX_ATTRIBUTE_BINORMAL |
|
|
||||||
RAW_VERTEX_ATTRIBUTE_UV0;
|
|
||||||
}
|
}
|
||||||
if (mat.textures[RAW_TEXTURE_USAGE_SPECULAR] != -1) {
|
if (mat.textures[RAW_TEXTURE_USAGE_SPECULAR] != -1) {
|
||||||
keep |= RAW_VERTEX_ATTRIBUTE_NORMAL |
|
keep |= RAW_VERTEX_ATTRIBUTE_NORMAL | RAW_VERTEX_ATTRIBUTE_UV0;
|
||||||
RAW_VERTEX_ATTRIBUTE_UV0;
|
|
||||||
}
|
}
|
||||||
if (mat.textures[RAW_TEXTURE_USAGE_EMISSIVE] != -1) {
|
if (mat.textures[RAW_TEXTURE_USAGE_EMISSIVE] != -1) {
|
||||||
keep |= RAW_VERTEX_ATTRIBUTE_UV1;
|
keep |= RAW_VERTEX_ATTRIBUTE_UV1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((keep & RAW_VERTEX_ATTRIBUTE_POSITION) == 0) { vertex.position = defaultVertex.position; }
|
if ((keep & RAW_VERTEX_ATTRIBUTE_POSITION) == 0) {
|
||||||
if ((keep & RAW_VERTEX_ATTRIBUTE_NORMAL) == 0) { vertex.normal = defaultVertex.normal; }
|
vertex.position = defaultVertex.position;
|
||||||
if ((keep & RAW_VERTEX_ATTRIBUTE_TANGENT) == 0) { vertex.tangent = defaultVertex.tangent; }
|
}
|
||||||
if ((keep & RAW_VERTEX_ATTRIBUTE_BINORMAL) == 0) { vertex.binormal = defaultVertex.binormal; }
|
if ((keep & RAW_VERTEX_ATTRIBUTE_NORMAL) == 0) {
|
||||||
if ((keep & RAW_VERTEX_ATTRIBUTE_COLOR) == 0) { vertex.color = defaultVertex.color; }
|
vertex.normal = defaultVertex.normal;
|
||||||
if ((keep & RAW_VERTEX_ATTRIBUTE_UV0) == 0) { vertex.uv0 = defaultVertex.uv0; }
|
}
|
||||||
if ((keep & RAW_VERTEX_ATTRIBUTE_UV1) == 0) { vertex.uv1 = defaultVertex.uv1; }
|
if ((keep & RAW_VERTEX_ATTRIBUTE_TANGENT) == 0) {
|
||||||
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES) == 0) { vertex.jointIndices = defaultVertex.jointIndices; }
|
vertex.tangent = defaultVertex.tangent;
|
||||||
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS) == 0) { vertex.jointWeights = defaultVertex.jointWeights; }
|
}
|
||||||
|
if ((keep & RAW_VERTEX_ATTRIBUTE_BINORMAL) == 0) {
|
||||||
|
vertex.binormal = defaultVertex.binormal;
|
||||||
|
}
|
||||||
|
if ((keep & RAW_VERTEX_ATTRIBUTE_COLOR) == 0) {
|
||||||
|
vertex.color = defaultVertex.color;
|
||||||
|
}
|
||||||
|
if ((keep & RAW_VERTEX_ATTRIBUTE_UV0) == 0) {
|
||||||
|
vertex.uv0 = defaultVertex.uv0;
|
||||||
|
}
|
||||||
|
if ((keep & RAW_VERTEX_ATTRIBUTE_UV1) == 0) {
|
||||||
|
vertex.uv1 = defaultVertex.uv1;
|
||||||
|
}
|
||||||
|
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES) == 0) {
|
||||||
|
vertex.jointIndices = defaultVertex.jointIndices;
|
||||||
|
}
|
||||||
|
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS) == 0) {
|
||||||
|
vertex.jointWeights = defaultVertex.jointWeights;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
verts[j] = model->AddVertex(vertex);
|
verts[j] = model->AddVertex(vertex);
|
||||||
|
@ -599,18 +626,16 @@ void RawModel::CreateMaterialModels(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawModel::GetNodeById(const long nodeId) const
|
int RawModel::GetNodeById(const long nodeId) const {
|
||||||
{
|
|
||||||
for (size_t i = 0; i < nodes.size(); i++) {
|
for (size_t i = 0; i < nodes.size(); i++) {
|
||||||
if (nodes[i].id == nodeId) {
|
if (nodes[i].id == nodeId) {
|
||||||
return (int) i;
|
return (int)i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
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) {
|
||||||
return (int)i;
|
return (int)i;
|
||||||
|
@ -619,22 +644,21 @@ int RawModel::GetSurfaceById(const long surfaceId) const
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3f RawModel::getFaceNormal(int verts[3]) const
|
Vec3f RawModel::getFaceNormal(int verts[3]) const {
|
||||||
{
|
const float l0 = (vertices[verts[1]].position - vertices[verts[0]].position).LengthSquared();
|
||||||
const float l0 = (vertices[verts[1]].position - vertices[verts[0]].position ).LengthSquared();
|
const float l1 = (vertices[verts[2]].position - vertices[verts[1]].position).LengthSquared();
|
||||||
const float l1 = (vertices[verts[2]].position - vertices[verts[1]].position ).LengthSquared();
|
const float l2 = (vertices[verts[0]].position - vertices[verts[2]].position).LengthSquared();
|
||||||
const float l2 = (vertices[verts[0]].position - vertices[verts[2]].position ).LengthSquared();
|
const int index = (l0 > l1) ? (l0 > l2 ? 2 : 1) : (l1 > l2 ? 0 : 1);
|
||||||
const int index = ( l0 > l1 ) ? ( l0 > l2 ? 2 : 1 ) : ( l1 > l2 ? 0 : 1 );
|
|
||||||
|
|
||||||
const Vec3f e0 = vertices[verts[(index + 1) % 3]].position - vertices[verts[index]].position;
|
const Vec3f e0 = vertices[verts[(index + 1) % 3]].position - vertices[verts[index]].position;
|
||||||
const Vec3f e1 = vertices[verts[(index + 2) % 3]].position - vertices[verts[index]].position;
|
const Vec3f e1 = vertices[verts[(index + 2) % 3]].position - vertices[verts[index]].position;
|
||||||
if (e0.LengthSquared() < FLT_MIN || e1.LengthSquared() < FLT_MIN) {
|
if (e0.LengthSquared() < FLT_MIN || e1.LengthSquared() < FLT_MIN) {
|
||||||
return Vec3f { 0.0f };
|
return Vec3f{0.0f};
|
||||||
}
|
}
|
||||||
auto result = Vec3f::CrossProduct(e0, e1);
|
auto result = Vec3f::CrossProduct(e0, e1);
|
||||||
auto resultLengthSquared = result.LengthSquared();
|
auto resultLengthSquared = result.LengthSquared();
|
||||||
if (resultLengthSquared < FLT_MIN) {
|
if (resultLengthSquared < FLT_MIN) {
|
||||||
return Vec3f { 0.0f };
|
return Vec3f{0.0f};
|
||||||
}
|
}
|
||||||
float edgeDot = std::max(-1.0f, std::min(1.0f, Vec3f::DotProduct(e0, e1)));
|
float edgeDot = std::max(-1.0f, std::min(1.0f, Vec3f::DotProduct(e0, e1)));
|
||||||
float angle = acos(edgeDot);
|
float angle = acos(edgeDot);
|
||||||
|
@ -642,23 +666,22 @@ Vec3f RawModel::getFaceNormal(int verts[3]) const
|
||||||
return result.Normalized() * angle * area;
|
return result.Normalized() * angle * area;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RawModel::CalculateNormals(bool onlyBroken)
|
size_t RawModel::CalculateNormals(bool onlyBroken) {
|
||||||
{
|
Vec3f averagePos = Vec3f{0.0f};
|
||||||
Vec3f averagePos = Vec3f { 0.0f };
|
|
||||||
std::set<int> brokenVerts;
|
std::set<int> brokenVerts;
|
||||||
for (int vertIx = 0; vertIx < vertices.size(); vertIx ++) {
|
for (int vertIx = 0; vertIx < vertices.size(); vertIx++) {
|
||||||
RawVertex &vertex = vertices[vertIx];
|
RawVertex& vertex = vertices[vertIx];
|
||||||
averagePos += (vertex.position / (float)vertices.size());
|
averagePos += (vertex.position / (float)vertices.size());
|
||||||
if (onlyBroken && (vertex.normal.LengthSquared() >= FLT_MIN)) {
|
if (onlyBroken && (vertex.normal.LengthSquared() >= FLT_MIN)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
vertex.normal = Vec3f { 0.0f };
|
vertex.normal = Vec3f{0.0f};
|
||||||
if (onlyBroken) {
|
if (onlyBroken) {
|
||||||
brokenVerts.emplace(vertIx);
|
brokenVerts.emplace(vertIx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &triangle : triangles) {
|
for (auto& triangle : triangles) {
|
||||||
bool relevant = false;
|
bool relevant = false;
|
||||||
for (int vertIx : triangle.verts) {
|
for (int vertIx : triangle.verts) {
|
||||||
relevant |= (brokenVerts.count(vertIx) > 0);
|
relevant |= (brokenVerts.count(vertIx) > 0);
|
||||||
|
@ -674,15 +697,15 @@ size_t RawModel::CalculateNormals(bool onlyBroken)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int vertIx = 0; vertIx < vertices.size(); vertIx ++) {
|
for (int vertIx = 0; vertIx < vertices.size(); vertIx++) {
|
||||||
if (onlyBroken && brokenVerts.count(vertIx) == 0) {
|
if (onlyBroken && brokenVerts.count(vertIx) == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
RawVertex &vertex = vertices[vertIx];
|
RawVertex& vertex = vertices[vertIx];
|
||||||
if (vertex.normal.LengthSquared() < FLT_MIN) {
|
if (vertex.normal.LengthSquared() < FLT_MIN) {
|
||||||
vertex.normal = vertex.position - averagePos;
|
vertex.normal = vertex.position - averagePos;
|
||||||
if (vertex.normal.LengthSquared() < FLT_MIN) {
|
if (vertex.normal.LengthSquared() < FLT_MIN) {
|
||||||
vertex.normal = Vec3f { 0.0f, 1.0f, 0.0f };
|
vertex.normal = Vec3f{0.0f, 1.0f, 0.0f};
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,15 +9,13 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "FBX2glTF.h"
|
#include "FBX2glTF.h"
|
||||||
|
|
||||||
|
enum RawVertexAttribute {
|
||||||
enum RawVertexAttribute
|
|
||||||
{
|
|
||||||
RAW_VERTEX_ATTRIBUTE_POSITION = 1 << 0,
|
RAW_VERTEX_ATTRIBUTE_POSITION = 1 << 0,
|
||||||
RAW_VERTEX_ATTRIBUTE_NORMAL = 1 << 1,
|
RAW_VERTEX_ATTRIBUTE_NORMAL = 1 << 1,
|
||||||
RAW_VERTEX_ATTRIBUTE_TANGENT = 1 << 2,
|
RAW_VERTEX_ATTRIBUTE_TANGENT = 1 << 2,
|
||||||
|
@ -31,75 +29,65 @@ enum RawVertexAttribute
|
||||||
RAW_VERTEX_ATTRIBUTE_AUTO = 1 << 31
|
RAW_VERTEX_ATTRIBUTE_AUTO = 1 << 31
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RawBlendVertex
|
struct RawBlendVertex {
|
||||||
{
|
Vec3f position{};
|
||||||
Vec3f position {};
|
Vec3f normal{};
|
||||||
Vec3f normal {};
|
Vec4f tangent{};
|
||||||
Vec4f tangent {};
|
|
||||||
|
|
||||||
bool operator==(const RawBlendVertex &other) const {
|
bool operator==(const RawBlendVertex& other) const {
|
||||||
return position == other.position &&
|
return position == other.position && normal == other.normal && tangent == other.tangent;
|
||||||
normal == other.normal &&
|
|
||||||
tangent == other.tangent;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RawVertex
|
struct RawVertex {
|
||||||
{
|
RawVertex() : polarityUv0(false), pad1(false), pad2(false), pad3(false) {}
|
||||||
RawVertex() :
|
|
||||||
polarityUv0(false),
|
|
||||||
pad1(false),
|
|
||||||
pad2(false),
|
|
||||||
pad3(false) {}
|
|
||||||
|
|
||||||
Vec3f position { 0.0f };
|
Vec3f position{0.0f};
|
||||||
Vec3f normal { 0.0f };
|
Vec3f normal{0.0f};
|
||||||
Vec3f binormal { 0.0f };
|
Vec3f binormal{0.0f};
|
||||||
Vec4f tangent { 0.0f };
|
Vec4f tangent{0.0f};
|
||||||
Vec4f color { 0.0f };
|
Vec4f color{0.0f};
|
||||||
Vec2f uv0 { 0.0f };
|
Vec2f uv0{0.0f};
|
||||||
Vec2f uv1 { 0.0f };
|
Vec2f uv1{0.0f};
|
||||||
Vec4i jointIndices { 0, 0, 0, 0 };
|
Vec4i jointIndices{0, 0, 0, 0};
|
||||||
Vec4f jointWeights { 0.0f };
|
Vec4f jointWeights{0.0f};
|
||||||
// end of members that directly correspond to vertex attributes
|
// end of members that directly correspond to vertex attributes
|
||||||
|
|
||||||
// if this vertex participates in a blend shape setup, the surfaceIx of its dedicated mesh; otherwise, -1
|
// if this vertex participates in a blend shape setup, the surfaceIx of its dedicated mesh;
|
||||||
|
// otherwise, -1
|
||||||
int blendSurfaceIx = -1;
|
int blendSurfaceIx = -1;
|
||||||
// the size of this vector is always identical to the size of the corresponding RawSurface.blendChannels
|
// the size of this vector is always identical to the size of the corresponding
|
||||||
std::vector<RawBlendVertex> blends { };
|
// RawSurface.blendChannels
|
||||||
|
std::vector<RawBlendVertex> blends{};
|
||||||
|
|
||||||
bool polarityUv0;
|
bool polarityUv0;
|
||||||
bool pad1;
|
bool pad1;
|
||||||
bool pad2;
|
bool pad2;
|
||||||
bool pad3;
|
bool pad3;
|
||||||
|
|
||||||
bool operator==(const RawVertex &other) const;
|
bool operator==(const RawVertex& other) const;
|
||||||
size_t Difference(const RawVertex &other) const;
|
size_t Difference(const RawVertex& other) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VertexHasher
|
class VertexHasher {
|
||||||
{
|
public:
|
||||||
public:
|
size_t operator()(const RawVertex& v) const {
|
||||||
size_t operator()(const RawVertex &v) const
|
|
||||||
{
|
|
||||||
size_t seed = 5381;
|
size_t seed = 5381;
|
||||||
const auto hasher = std::hash<float>{};
|
const auto hasher = std::hash<float>{};
|
||||||
seed ^= hasher(v.position[0]) + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
seed ^= hasher(v.position[0]) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||||
seed ^= hasher(v.position[1]) + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
seed ^= hasher(v.position[1]) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||||
seed ^= hasher(v.position[2]) + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
seed ^= hasher(v.position[2]) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||||
return seed;
|
return seed;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RawTriangle
|
struct RawTriangle {
|
||||||
{
|
|
||||||
int verts[3];
|
int verts[3];
|
||||||
int materialIndex;
|
int materialIndex;
|
||||||
int surfaceIndex;
|
int surfaceIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RawShadingModel
|
enum RawShadingModel {
|
||||||
{
|
|
||||||
RAW_SHADING_MODEL_UNKNOWN = -1,
|
RAW_SHADING_MODEL_UNKNOWN = -1,
|
||||||
RAW_SHADING_MODEL_CONSTANT,
|
RAW_SHADING_MODEL_CONSTANT,
|
||||||
RAW_SHADING_MODEL_LAMBERT,
|
RAW_SHADING_MODEL_LAMBERT,
|
||||||
|
@ -110,19 +98,26 @@ enum RawShadingModel
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::string Describe(RawShadingModel model) {
|
inline std::string Describe(RawShadingModel model) {
|
||||||
switch(model) {
|
switch (model) {
|
||||||
case RAW_SHADING_MODEL_UNKNOWN: return "<unknown>";
|
case RAW_SHADING_MODEL_UNKNOWN:
|
||||||
case RAW_SHADING_MODEL_CONSTANT: return "Constant";
|
return "<unknown>";
|
||||||
case RAW_SHADING_MODEL_LAMBERT: return "Lambert";
|
case RAW_SHADING_MODEL_CONSTANT:
|
||||||
case RAW_SHADING_MODEL_BLINN: return "Blinn";
|
return "Constant";
|
||||||
case RAW_SHADING_MODEL_PHONG: return "Phong";
|
case RAW_SHADING_MODEL_LAMBERT:
|
||||||
case RAW_SHADING_MODEL_PBR_MET_ROUGH: return "Metallic/Roughness";
|
return "Lambert";
|
||||||
case RAW_SHADING_MODEL_MAX: default: return "<unknown>";
|
case RAW_SHADING_MODEL_BLINN:
|
||||||
|
return "Blinn";
|
||||||
|
case RAW_SHADING_MODEL_PHONG:
|
||||||
|
return "Phong";
|
||||||
|
case RAW_SHADING_MODEL_PBR_MET_ROUGH:
|
||||||
|
return "Metallic/Roughness";
|
||||||
|
case RAW_SHADING_MODEL_MAX:
|
||||||
|
default:
|
||||||
|
return "<unknown>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RawTextureUsage
|
enum RawTextureUsage {
|
||||||
{
|
|
||||||
RAW_TEXTURE_USAGE_NONE = -1,
|
RAW_TEXTURE_USAGE_NONE = -1,
|
||||||
RAW_TEXTURE_USAGE_AMBIENT,
|
RAW_TEXTURE_USAGE_AMBIENT,
|
||||||
RAW_TEXTURE_USAGE_DIFFUSE,
|
RAW_TEXTURE_USAGE_DIFFUSE,
|
||||||
|
@ -138,32 +133,39 @@ enum RawTextureUsage
|
||||||
RAW_TEXTURE_USAGE_MAX
|
RAW_TEXTURE_USAGE_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::string Describe(RawTextureUsage usage)
|
inline std::string Describe(RawTextureUsage usage) {
|
||||||
{
|
|
||||||
switch (usage) {
|
switch (usage) {
|
||||||
case RAW_TEXTURE_USAGE_NONE: return "<none>";
|
case RAW_TEXTURE_USAGE_NONE:
|
||||||
case RAW_TEXTURE_USAGE_AMBIENT: return "ambient";
|
return "<none>";
|
||||||
case RAW_TEXTURE_USAGE_DIFFUSE: return "diffuse";
|
case RAW_TEXTURE_USAGE_AMBIENT:
|
||||||
case RAW_TEXTURE_USAGE_NORMAL: return "normal";
|
return "ambient";
|
||||||
case RAW_TEXTURE_USAGE_SPECULAR: return "specular";
|
case RAW_TEXTURE_USAGE_DIFFUSE:
|
||||||
case RAW_TEXTURE_USAGE_SHININESS: return "shininess";
|
return "diffuse";
|
||||||
case RAW_TEXTURE_USAGE_EMISSIVE: return "emissive";
|
case RAW_TEXTURE_USAGE_NORMAL:
|
||||||
case RAW_TEXTURE_USAGE_REFLECTION: return "reflection";
|
return "normal";
|
||||||
case RAW_TEXTURE_USAGE_OCCLUSION: return "occlusion";
|
case RAW_TEXTURE_USAGE_SPECULAR:
|
||||||
case RAW_TEXTURE_USAGE_ROUGHNESS: return "roughness";
|
return "specular";
|
||||||
case RAW_TEXTURE_USAGE_METALLIC: return "metallic";
|
case RAW_TEXTURE_USAGE_SHININESS:
|
||||||
case RAW_TEXTURE_USAGE_MAX:default: return "unknown";
|
return "shininess";
|
||||||
|
case RAW_TEXTURE_USAGE_EMISSIVE:
|
||||||
|
return "emissive";
|
||||||
|
case RAW_TEXTURE_USAGE_REFLECTION:
|
||||||
|
return "reflection";
|
||||||
|
case RAW_TEXTURE_USAGE_OCCLUSION:
|
||||||
|
return "occlusion";
|
||||||
|
case RAW_TEXTURE_USAGE_ROUGHNESS:
|
||||||
|
return "roughness";
|
||||||
|
case RAW_TEXTURE_USAGE_METALLIC:
|
||||||
|
return "metallic";
|
||||||
|
case RAW_TEXTURE_USAGE_MAX:
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RawTextureOcclusion
|
enum RawTextureOcclusion { RAW_TEXTURE_OCCLUSION_OPAQUE, RAW_TEXTURE_OCCLUSION_TRANSPARENT };
|
||||||
{
|
|
||||||
RAW_TEXTURE_OCCLUSION_OPAQUE,
|
|
||||||
RAW_TEXTURE_OCCLUSION_TRANSPARENT
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RawTexture
|
struct RawTexture {
|
||||||
{
|
|
||||||
std::string name; // logical name in FBX file
|
std::string name; // logical name in FBX file
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
|
@ -174,8 +176,7 @@ struct RawTexture
|
||||||
std::string fileLocation; // inferred path in local filesystem, or ""
|
std::string fileLocation; // inferred path in local filesystem, or ""
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RawMaterialType
|
enum RawMaterialType {
|
||||||
{
|
|
||||||
RAW_MATERIAL_TYPE_OPAQUE,
|
RAW_MATERIAL_TYPE_OPAQUE,
|
||||||
RAW_MATERIAL_TYPE_TRANSPARENT,
|
RAW_MATERIAL_TYPE_TRANSPARENT,
|
||||||
RAW_MATERIAL_TYPE_SKINNED_OPAQUE,
|
RAW_MATERIAL_TYPE_SKINNED_OPAQUE,
|
||||||
|
@ -183,30 +184,31 @@ enum RawMaterialType
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RawMatProps {
|
struct RawMatProps {
|
||||||
explicit RawMatProps(RawShadingModel shadingModel)
|
explicit RawMatProps(RawShadingModel shadingModel) : shadingModel(shadingModel) {}
|
||||||
: shadingModel(shadingModel)
|
|
||||||
{}
|
|
||||||
const RawShadingModel shadingModel;
|
const RawShadingModel shadingModel;
|
||||||
|
|
||||||
virtual bool operator!=(const RawMatProps &other) const { return !(*this == other); }
|
virtual bool operator!=(const RawMatProps& other) const {
|
||||||
virtual bool operator==(const RawMatProps &other) const { return shadingModel == other.shadingModel; };
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
virtual bool operator==(const RawMatProps& other) const {
|
||||||
|
return shadingModel == other.shadingModel;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RawTraditionalMatProps : RawMatProps {
|
struct RawTraditionalMatProps : RawMatProps {
|
||||||
RawTraditionalMatProps(
|
RawTraditionalMatProps(
|
||||||
RawShadingModel shadingModel,
|
RawShadingModel shadingModel,
|
||||||
const Vec3f &&ambientFactor,
|
const Vec3f&& ambientFactor,
|
||||||
const Vec4f &&diffuseFactor,
|
const Vec4f&& diffuseFactor,
|
||||||
const Vec3f &&emissiveFactor,
|
const Vec3f&& emissiveFactor,
|
||||||
const Vec3f &&specularFactor,
|
const Vec3f&& specularFactor,
|
||||||
const float shininess
|
const float shininess)
|
||||||
) : RawMatProps(shadingModel),
|
: RawMatProps(shadingModel),
|
||||||
ambientFactor(ambientFactor),
|
ambientFactor(ambientFactor),
|
||||||
diffuseFactor(diffuseFactor),
|
diffuseFactor(diffuseFactor),
|
||||||
emissiveFactor(emissiveFactor),
|
emissiveFactor(emissiveFactor),
|
||||||
specularFactor(specularFactor),
|
specularFactor(specularFactor),
|
||||||
shininess(shininess)
|
shininess(shininess) {}
|
||||||
{}
|
|
||||||
|
|
||||||
const Vec3f ambientFactor;
|
const Vec3f ambientFactor;
|
||||||
const Vec4f diffuseFactor;
|
const Vec4f diffuseFactor;
|
||||||
|
@ -214,13 +216,11 @@ struct RawTraditionalMatProps : RawMatProps {
|
||||||
const Vec3f specularFactor;
|
const Vec3f specularFactor;
|
||||||
const float shininess;
|
const float shininess;
|
||||||
|
|
||||||
bool operator==(const RawMatProps &other) const override {
|
bool operator==(const RawMatProps& other) const override {
|
||||||
if (RawMatProps::operator==(other)) {
|
if (RawMatProps::operator==(other)) {
|
||||||
const auto &typed = (RawTraditionalMatProps &) other;
|
const auto& typed = (RawTraditionalMatProps&)other;
|
||||||
return ambientFactor == typed.ambientFactor &&
|
return ambientFactor == typed.ambientFactor && diffuseFactor == typed.diffuseFactor &&
|
||||||
diffuseFactor == typed.diffuseFactor &&
|
specularFactor == typed.specularFactor && emissiveFactor == typed.emissiveFactor &&
|
||||||
specularFactor == typed.specularFactor &&
|
|
||||||
emissiveFactor == typed.emissiveFactor &&
|
|
||||||
shininess == typed.shininess;
|
shininess == typed.shininess;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -230,40 +230,35 @@ struct RawTraditionalMatProps : RawMatProps {
|
||||||
struct RawMetRoughMatProps : RawMatProps {
|
struct RawMetRoughMatProps : RawMatProps {
|
||||||
RawMetRoughMatProps(
|
RawMetRoughMatProps(
|
||||||
RawShadingModel shadingModel,
|
RawShadingModel shadingModel,
|
||||||
const Vec4f &&diffuseFactor,
|
const Vec4f&& diffuseFactor,
|
||||||
const Vec3f &&emissiveFactor,
|
const Vec3f&& emissiveFactor,
|
||||||
float emissiveIntensity,
|
float emissiveIntensity,
|
||||||
float metallic,
|
float metallic,
|
||||||
float roughness
|
float roughness)
|
||||||
) : RawMatProps(shadingModel),
|
: RawMatProps(shadingModel),
|
||||||
diffuseFactor(diffuseFactor),
|
diffuseFactor(diffuseFactor),
|
||||||
emissiveFactor(emissiveFactor),
|
emissiveFactor(emissiveFactor),
|
||||||
emissiveIntensity(emissiveIntensity),
|
emissiveIntensity(emissiveIntensity),
|
||||||
metallic(metallic),
|
metallic(metallic),
|
||||||
roughness(roughness)
|
roughness(roughness) {}
|
||||||
{}
|
|
||||||
const Vec4f diffuseFactor;
|
const Vec4f diffuseFactor;
|
||||||
const Vec3f emissiveFactor;
|
const Vec3f emissiveFactor;
|
||||||
const float emissiveIntensity;
|
const float emissiveIntensity;
|
||||||
const float metallic;
|
const float metallic;
|
||||||
const float roughness;
|
const float roughness;
|
||||||
|
|
||||||
bool operator==(const RawMatProps &other) const override {
|
bool operator==(const RawMatProps& other) const override {
|
||||||
if (RawMatProps::operator==(other)) {
|
if (RawMatProps::operator==(other)) {
|
||||||
const auto &typed = (RawMetRoughMatProps &) other;
|
const auto& typed = (RawMetRoughMatProps&)other;
|
||||||
return diffuseFactor == typed.diffuseFactor &&
|
return diffuseFactor == typed.diffuseFactor && emissiveFactor == typed.emissiveFactor &&
|
||||||
emissiveFactor == typed.emissiveFactor &&
|
emissiveIntensity == typed.emissiveIntensity && metallic == typed.metallic &&
|
||||||
emissiveIntensity == typed.emissiveIntensity &&
|
|
||||||
metallic == typed.metallic &&
|
|
||||||
roughness == typed.roughness;
|
roughness == typed.roughness;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RawMaterial {
|
||||||
struct RawMaterial
|
|
||||||
{
|
|
||||||
std::string name;
|
std::string name;
|
||||||
RawMaterialType type;
|
RawMaterialType type;
|
||||||
std::shared_ptr<RawMatProps> info;
|
std::shared_ptr<RawMatProps> info;
|
||||||
|
@ -271,15 +266,13 @@ struct RawMaterial
|
||||||
std::vector<std::string> userProperties;
|
std::vector<std::string> userProperties;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RawLightType
|
enum RawLightType {
|
||||||
{
|
|
||||||
RAW_LIGHT_TYPE_DIRECTIONAL,
|
RAW_LIGHT_TYPE_DIRECTIONAL,
|
||||||
RAW_LIGHT_TYPE_POINT,
|
RAW_LIGHT_TYPE_POINT,
|
||||||
RAW_LIGHT_TYPE_SPOT,
|
RAW_LIGHT_TYPE_SPOT,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RawLight
|
struct RawLight {
|
||||||
{
|
|
||||||
std::string name;
|
std::string name;
|
||||||
RawLightType type;
|
RawLightType type;
|
||||||
Vec3f color;
|
Vec3f color;
|
||||||
|
@ -288,16 +281,14 @@ struct RawLight
|
||||||
float outerConeAngle; // only meaningful for spot
|
float outerConeAngle; // only meaningful for spot
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RawBlendChannel
|
struct RawBlendChannel {
|
||||||
{
|
|
||||||
float defaultDeform;
|
float defaultDeform;
|
||||||
bool hasNormals;
|
bool hasNormals;
|
||||||
bool hasTangents;
|
bool hasTangents;
|
||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RawSurface
|
struct RawSurface {
|
||||||
{
|
|
||||||
long id;
|
long id;
|
||||||
std::string name; // The name of this surface
|
std::string name; // The name of this surface
|
||||||
long skeletonRootId; // The id of the root node of the skeleton.
|
long skeletonRootId; // The id of the root node of the skeleton.
|
||||||
|
@ -310,8 +301,7 @@ struct RawSurface
|
||||||
bool discrete;
|
bool discrete;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RawChannel
|
struct RawChannel {
|
||||||
{
|
|
||||||
int nodeIndex;
|
int nodeIndex;
|
||||||
std::vector<Vec3f> translations;
|
std::vector<Vec3f> translations;
|
||||||
std::vector<Quatf> rotations;
|
std::vector<Quatf> rotations;
|
||||||
|
@ -319,26 +309,19 @@ struct RawChannel
|
||||||
std::vector<float> weights;
|
std::vector<float> weights;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RawAnimation
|
struct RawAnimation {
|
||||||
{
|
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<float> times;
|
std::vector<float> times;
|
||||||
std::vector<RawChannel> channels;
|
std::vector<RawChannel> channels;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RawCamera
|
struct RawCamera {
|
||||||
{
|
|
||||||
std::string name;
|
std::string name;
|
||||||
long nodeId;
|
long nodeId;
|
||||||
|
|
||||||
enum
|
enum { CAMERA_MODE_PERSPECTIVE, CAMERA_MODE_ORTHOGRAPHIC } mode;
|
||||||
{
|
|
||||||
CAMERA_MODE_PERSPECTIVE,
|
|
||||||
CAMERA_MODE_ORTHOGRAPHIC
|
|
||||||
} mode;
|
|
||||||
|
|
||||||
struct
|
struct {
|
||||||
{
|
|
||||||
float aspectRatio;
|
float aspectRatio;
|
||||||
float fovDegreesX;
|
float fovDegreesX;
|
||||||
float fovDegreesY;
|
float fovDegreesY;
|
||||||
|
@ -346,8 +329,7 @@ struct RawCamera
|
||||||
float farZ;
|
float farZ;
|
||||||
} perspective;
|
} perspective;
|
||||||
|
|
||||||
struct
|
struct {
|
||||||
{
|
|
||||||
float magX;
|
float magX;
|
||||||
float magY;
|
float magY;
|
||||||
float nearZ;
|
float nearZ;
|
||||||
|
@ -355,8 +337,7 @@ struct RawCamera
|
||||||
} orthographic;
|
} orthographic;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RawNode
|
struct RawNode {
|
||||||
{
|
|
||||||
bool isJoint;
|
bool isJoint;
|
||||||
long id;
|
long id;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
@ -370,99 +351,176 @@ struct RawNode
|
||||||
std::vector<std::string> userProperties;
|
std::vector<std::string> userProperties;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RawModel
|
class RawModel {
|
||||||
{
|
public:
|
||||||
public:
|
|
||||||
RawModel();
|
RawModel();
|
||||||
|
|
||||||
// Add geometry.
|
// Add geometry.
|
||||||
void AddVertexAttribute(const RawVertexAttribute attrib);
|
void AddVertexAttribute(const RawVertexAttribute attrib);
|
||||||
int AddVertex(const RawVertex &vertex);
|
int AddVertex(const RawVertex& vertex);
|
||||||
int AddTriangle(const int v0, const int v1, const int v2, const int materialIndex, const int surfaceIndex);
|
int AddTriangle(
|
||||||
int AddTexture(const std::string &name, const std::string &fileName, const std::string &fileLocation, RawTextureUsage usage);
|
const int v0,
|
||||||
int AddMaterial(const RawMaterial &material);
|
const int v1,
|
||||||
|
const int v2,
|
||||||
|
const int materialIndex,
|
||||||
|
const int surfaceIndex);
|
||||||
|
int AddTexture(
|
||||||
|
const std::string& name,
|
||||||
|
const std::string& fileName,
|
||||||
|
const std::string& fileLocation,
|
||||||
|
RawTextureUsage usage);
|
||||||
|
int AddMaterial(const RawMaterial& material);
|
||||||
int AddMaterial(
|
int AddMaterial(
|
||||||
const char *name, const RawMaterialType materialType, const int textures[RAW_TEXTURE_USAGE_MAX],
|
const char* name,
|
||||||
std::shared_ptr<RawMatProps> materialInfo, const std::vector<std::string>& userProperties);
|
const RawMaterialType materialType,
|
||||||
int AddLight(const char *name, RawLightType lightType, Vec3f color, float intensity,
|
const int textures[RAW_TEXTURE_USAGE_MAX],
|
||||||
float innerConeAngle, float outerConeAngle);
|
std::shared_ptr<RawMatProps> materialInfo,
|
||||||
int AddSurface(const RawSurface &suface);
|
const std::vector<std::string>& userProperties);
|
||||||
int AddSurface(const char *name, long surfaceId);
|
int AddLight(
|
||||||
int AddAnimation(const RawAnimation &animation);
|
const char* name,
|
||||||
|
RawLightType lightType,
|
||||||
|
Vec3f color,
|
||||||
|
float intensity,
|
||||||
|
float innerConeAngle,
|
||||||
|
float outerConeAngle);
|
||||||
|
int AddSurface(const RawSurface& suface);
|
||||||
|
int AddSurface(const char* name, long surfaceId);
|
||||||
|
int AddAnimation(const RawAnimation& animation);
|
||||||
int AddCameraPerspective(
|
int AddCameraPerspective(
|
||||||
const char *name, const long nodeId, const float aspectRatio, const float fovDegreesX, const float fovDegreesY,
|
const char* name,
|
||||||
const float nearZ, const float farZ);
|
const long nodeId,
|
||||||
int
|
const float aspectRatio,
|
||||||
AddCameraOrthographic(const char *name, const long nodeId, const float magX, const float magY, const float nearZ, const float farZ);
|
const float fovDegreesX,
|
||||||
int AddNode(const RawNode &node);
|
const float fovDegreesY,
|
||||||
int AddNode(const long id, const char *name, const long parentId);
|
const float nearZ,
|
||||||
void SetRootNode(const long nodeId) { rootNodeId = nodeId; }
|
const float farZ);
|
||||||
const long GetRootNode() const { return rootNodeId; }
|
int AddCameraOrthographic(
|
||||||
|
const char* name,
|
||||||
|
const long nodeId,
|
||||||
|
const float magX,
|
||||||
|
const float magY,
|
||||||
|
const float nearZ,
|
||||||
|
const float farZ);
|
||||||
|
int AddNode(const RawNode& node);
|
||||||
|
int AddNode(const long id, const char* name, const long parentId);
|
||||||
|
void SetRootNode(const long nodeId) {
|
||||||
|
rootNodeId = nodeId;
|
||||||
|
}
|
||||||
|
const long GetRootNode() const {
|
||||||
|
return rootNodeId;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove unused vertices, textures or materials after removing vertex attributes, textures, materials or surfaces.
|
// Remove unused vertices, textures or materials after removing vertex attributes, textures,
|
||||||
|
// materials or surfaces.
|
||||||
void Condense();
|
void Condense();
|
||||||
|
|
||||||
void TransformGeometry(ComputeNormalsOption);
|
void TransformGeometry(ComputeNormalsOption);
|
||||||
|
|
||||||
void TransformTextures(const std::vector<std::function<Vec2f(Vec2f)>> &transforms);
|
void TransformTextures(const std::vector<std::function<Vec2f(Vec2f)>>& transforms);
|
||||||
|
|
||||||
size_t CalculateNormals(bool);
|
size_t CalculateNormals(bool);
|
||||||
|
|
||||||
// Get the attributes stored per vertex.
|
// Get the attributes stored per vertex.
|
||||||
int GetVertexAttributes() const { return vertexAttributes; }
|
int GetVertexAttributes() const {
|
||||||
|
return vertexAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate over the vertices.
|
// Iterate over the vertices.
|
||||||
int GetVertexCount() const { return (int) vertices.size(); }
|
int GetVertexCount() const {
|
||||||
const RawVertex &GetVertex(const int index) const { return vertices[index]; }
|
return (int)vertices.size();
|
||||||
|
}
|
||||||
|
const RawVertex& GetVertex(const int index) const {
|
||||||
|
return vertices[index];
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate over the triangles.
|
// Iterate over the triangles.
|
||||||
int GetTriangleCount() const { return (int) triangles.size(); }
|
int GetTriangleCount() const {
|
||||||
const RawTriangle &GetTriangle(const int index) const { return triangles[index]; }
|
return (int)triangles.size();
|
||||||
|
}
|
||||||
|
const RawTriangle& GetTriangle(const int index) const {
|
||||||
|
return triangles[index];
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate over the textures.
|
// Iterate over the textures.
|
||||||
int GetTextureCount() const { return (int) textures.size(); }
|
int GetTextureCount() const {
|
||||||
const RawTexture &GetTexture(const int index) const { return textures[index]; }
|
return (int)textures.size();
|
||||||
|
}
|
||||||
|
const RawTexture& GetTexture(const int index) const {
|
||||||
|
return textures[index];
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate over the materials.
|
// Iterate over the materials.
|
||||||
int GetMaterialCount() const { return (int) materials.size(); }
|
int GetMaterialCount() const {
|
||||||
const RawMaterial &GetMaterial(const int index) const { return materials[index]; }
|
return (int)materials.size();
|
||||||
|
}
|
||||||
|
const RawMaterial& GetMaterial(const int index) const {
|
||||||
|
return materials[index];
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate over the surfaces.
|
// Iterate over the surfaces.
|
||||||
int GetSurfaceCount() const { return (int) surfaces.size(); }
|
int GetSurfaceCount() const {
|
||||||
const RawSurface &GetSurface(const int index) const { return surfaces[index]; }
|
return (int)surfaces.size();
|
||||||
RawSurface &GetSurface(const int index) { return surfaces[index]; }
|
}
|
||||||
|
const RawSurface& GetSurface(const int index) const {
|
||||||
|
return surfaces[index];
|
||||||
|
}
|
||||||
|
RawSurface& GetSurface(const int index) {
|
||||||
|
return surfaces[index];
|
||||||
|
}
|
||||||
int GetSurfaceById(const long id) const;
|
int GetSurfaceById(const long id) const;
|
||||||
|
|
||||||
// Iterate over the animations.
|
// Iterate over the animations.
|
||||||
int GetAnimationCount() const { return (int) animations.size(); }
|
int GetAnimationCount() const {
|
||||||
const RawAnimation &GetAnimation(const int index) const { return animations[index]; }
|
return (int)animations.size();
|
||||||
|
}
|
||||||
|
const RawAnimation& GetAnimation(const int index) const {
|
||||||
|
return animations[index];
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate over the cameras.
|
// Iterate over the cameras.
|
||||||
int GetCameraCount() const { return (int) cameras.size(); }
|
int GetCameraCount() const {
|
||||||
const RawCamera &GetCamera(const int index) const { return cameras[index]; }
|
return (int)cameras.size();
|
||||||
|
}
|
||||||
|
const RawCamera& GetCamera(const int index) const {
|
||||||
|
return cameras[index];
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate over the lights.
|
// Iterate over the lights.
|
||||||
int GetLightCount() const { return (int) lights.size(); }
|
int GetLightCount() const {
|
||||||
const RawLight &GetLight(const int index) const { return lights[index]; }
|
return (int)lights.size();
|
||||||
|
}
|
||||||
|
const RawLight& GetLight(const int index) const {
|
||||||
|
return lights[index];
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate over the nodes.
|
// Iterate over the nodes.
|
||||||
int GetNodeCount() const { return (int) nodes.size(); }
|
int GetNodeCount() const {
|
||||||
const RawNode &GetNode(const int index) const { return nodes[index]; }
|
return (int)nodes.size();
|
||||||
RawNode &GetNode(const int index) { return nodes[index]; }
|
}
|
||||||
|
const RawNode& GetNode(const int index) const {
|
||||||
|
return nodes[index];
|
||||||
|
}
|
||||||
|
RawNode& GetNode(const int index) {
|
||||||
|
return nodes[index];
|
||||||
|
}
|
||||||
int GetNodeById(const long nodeId) const;
|
int GetNodeById(const long nodeId) 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.
|
||||||
template<typename _attrib_type_>
|
template <typename _attrib_type_>
|
||||||
void GetAttributeArray(std::vector<_attrib_type_> &out, const _attrib_type_ RawVertex::* ptr) const;
|
void GetAttributeArray(std::vector<_attrib_type_>& out, const _attrib_type_ RawVertex::*ptr)
|
||||||
|
const;
|
||||||
|
|
||||||
// Create an array with a raw model for each material.
|
// Create an array with a raw model for each material.
|
||||||
// Multiple surfaces with the same material will turn into a single model.
|
// Multiple surfaces with the same material will turn into a single model.
|
||||||
// However, surfaces that are marked as 'discrete' will turn into separate models.
|
// However, surfaces that are marked as 'discrete' will turn into separate models.
|
||||||
void CreateMaterialModels(
|
void CreateMaterialModels(
|
||||||
std::vector<RawModel> &materialModels, bool shortIndices, const int keepAttribs, const bool forceDiscrete) const;
|
std::vector<RawModel>& materialModels,
|
||||||
|
bool shortIndices,
|
||||||
|
const int keepAttribs,
|
||||||
|
const bool forceDiscrete) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vec3f getFaceNormal(int verts[3]) const;
|
Vec3f getFaceNormal(int verts[3]) const;
|
||||||
|
|
||||||
long rootNodeId;
|
long rootNodeId;
|
||||||
|
@ -479,9 +537,10 @@ private:
|
||||||
std::vector<RawNode> nodes;
|
std::vector<RawNode> nodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename _attrib_type_>
|
template <typename _attrib_type_>
|
||||||
void RawModel::GetAttributeArray(std::vector<_attrib_type_> &out, const _attrib_type_ RawVertex::* ptr) const
|
void RawModel::GetAttributeArray(
|
||||||
{
|
std::vector<_attrib_type_>& out,
|
||||||
|
const _attrib_type_ RawVertex::*ptr) const {
|
||||||
out.resize(vertices.size());
|
out.resize(vertices.size());
|
||||||
for (size_t i = 0; i < vertices.size(); i++) {
|
for (size_t i = 0; i < vertices.size(); i++) {
|
||||||
out[i] = vertices[i].*ptr;
|
out[i] = vertices[i].*ptr;
|
||||||
|
|
|
@ -9,24 +9,24 @@
|
||||||
|
|
||||||
#include "File_Utils.hpp"
|
#include "File_Utils.hpp"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#if defined( __unix__ ) || defined ( __APPLE__ )
|
#if defined(__unix__) || defined(__APPLE__)
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#define _getcwd getcwd
|
#define _getcwd getcwd
|
||||||
#define _mkdir(a) mkdir(a, 0777)
|
#define _mkdir(a) mkdir(a, 0777)
|
||||||
#elif defined( _WIN32 )
|
#elif defined(_WIN32)
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
#include <process.h>
|
#include <process.h>
|
||||||
#else
|
#else
|
||||||
|
@ -41,8 +41,7 @@
|
||||||
|
|
||||||
namespace FileUtils {
|
namespace FileUtils {
|
||||||
|
|
||||||
std::string GetCurrentFolder()
|
std::string GetCurrentFolder() {
|
||||||
{
|
|
||||||
char cwd[StringUtils::MAX_PATH_LENGTH];
|
char cwd[StringUtils::MAX_PATH_LENGTH];
|
||||||
if (!_getcwd(cwd, sizeof(cwd))) {
|
if (!_getcwd(cwd, sizeof(cwd))) {
|
||||||
return std::string();
|
return std::string();
|
||||||
|
@ -55,65 +54,62 @@ namespace FileUtils {
|
||||||
cwd[length + 1] = '\0';
|
cwd[length + 1] = '\0';
|
||||||
}
|
}
|
||||||
return std::string(cwd);
|
return std::string(cwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileExists(const std::string &filePath)
|
bool FileExists(const std::string& filePath) {
|
||||||
{
|
|
||||||
std::ifstream stream(filePath);
|
std::ifstream stream(filePath);
|
||||||
return stream.good();
|
return stream.good();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FolderExists(const std::string &folderPath)
|
bool FolderExists(const std::string& folderPath) {
|
||||||
{
|
#if defined(__unix__) || defined(__APPLE__)
|
||||||
#if defined( __unix__ ) || defined( __APPLE__ )
|
DIR* dir = opendir(folderPath.c_str());
|
||||||
DIR *dir = opendir(folderPath.c_str());
|
|
||||||
if (dir) {
|
if (dir) {
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
const DWORD ftyp = GetFileAttributesA( folderPath.c_str() );
|
const DWORD ftyp = GetFileAttributesA(folderPath.c_str());
|
||||||
if ( ftyp == INVALID_FILE_ATTRIBUTES )
|
if (ftyp == INVALID_FILE_ATTRIBUTES) {
|
||||||
{
|
|
||||||
return false; // bad path
|
return false; // bad path
|
||||||
}
|
}
|
||||||
return ( ftyp & FILE_ATTRIBUTE_DIRECTORY ) != 0;
|
return (ftyp & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MatchExtension(const char *fileExtension, const char *matchExtensions)
|
bool MatchExtension(const char* fileExtension, const char* matchExtensions) {
|
||||||
{
|
|
||||||
if (matchExtensions[0] == '\0') {
|
if (matchExtensions[0] == '\0') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (fileExtension[0] == '.') {
|
if (fileExtension[0] == '.') {
|
||||||
fileExtension++;
|
fileExtension++;
|
||||||
}
|
}
|
||||||
for (const char *end = matchExtensions; end[0] != '\0';) {
|
for (const char* end = matchExtensions; end[0] != '\0';) {
|
||||||
for (; end[0] == ';'; end++) {}
|
for (; end[0] == ';'; end++) {
|
||||||
const char *ext = end;
|
}
|
||||||
for (; end[0] != ';' && end[0] != '\0'; end++) {}
|
const char* ext = end;
|
||||||
#if defined( __unix__ ) || defined( __APPLE__ )
|
for (; end[0] != ';' && end[0] != '\0'; end++) {
|
||||||
|
}
|
||||||
|
#if defined(__unix__) || defined(__APPLE__)
|
||||||
if (strncasecmp(fileExtension, ext, end - ext) == 0)
|
if (strncasecmp(fileExtension, ext, end - ext) == 0)
|
||||||
#else
|
#else
|
||||||
if ( _strnicmp( fileExtension, ext, end - ext ) == 0 )
|
if (_strnicmp(fileExtension, ext, end - ext) == 0)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> ListFolderFiles(const char *folder, const char *matchExtensions)
|
std::vector<std::string> ListFolderFiles(const char* folder, const char* matchExtensions) {
|
||||||
{
|
|
||||||
std::vector<std::string> fileList;
|
std::vector<std::string> fileList;
|
||||||
#if defined( __unix__ ) || defined( __APPLE__ )
|
#if defined(__unix__) || defined(__APPLE__)
|
||||||
DIR *dir = opendir(strlen(folder) > 0 ? folder : ".");
|
DIR* dir = opendir(strlen(folder) > 0 ? folder : ".");
|
||||||
if (dir != nullptr) {
|
if (dir != nullptr) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
struct dirent *dp = readdir(dir);
|
struct dirent* dp = readdir(dir);
|
||||||
if (dp == nullptr) {
|
if (dp == nullptr) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -122,8 +118,8 @@ namespace FileUtils {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *fileName = dp->d_name;
|
const char* fileName = dp->d_name;
|
||||||
const char *fileExt = strrchr(fileName, '.');
|
const char* fileExt = strrchr(fileName, '.');
|
||||||
|
|
||||||
if (!fileExt || !MatchExtension(fileExt, matchExtensions)) {
|
if (!fileExt || !MatchExtension(fileExt, matchExtensions)) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -139,11 +135,9 @@ namespace FileUtils {
|
||||||
pathStr += "*";
|
pathStr += "*";
|
||||||
|
|
||||||
WIN32_FIND_DATA FindFileData;
|
WIN32_FIND_DATA FindFileData;
|
||||||
HANDLE hFind = FindFirstFile( pathStr.c_str(), &FindFileData );
|
HANDLE hFind = FindFirstFile(pathStr.c_str(), &FindFileData);
|
||||||
if ( hFind != INVALID_HANDLE_VALUE )
|
if (hFind != INVALID_HANDLE_VALUE) {
|
||||||
{
|
do {
|
||||||
do
|
|
||||||
{
|
|
||||||
if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
|
if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
|
||||||
std::string fileName = FindFileData.cFileName;
|
std::string fileName = FindFileData.cFileName;
|
||||||
std::string::size_type extPos = fileName.rfind('.');
|
std::string::size_type extPos = fileName.rfind('.');
|
||||||
|
@ -152,17 +146,16 @@ namespace FileUtils {
|
||||||
fileList.push_back(fileName);
|
fileList.push_back(fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while ( FindNextFile( hFind, &FindFileData ) );
|
} while (FindNextFile(hFind, &FindFileData));
|
||||||
|
|
||||||
FindClose( hFind );
|
FindClose(hFind);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return fileList;
|
return fileList;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CreatePath(const char *path)
|
bool CreatePath(const char* path) {
|
||||||
{
|
#if defined(__unix__) || defined(__APPLE__)
|
||||||
#if defined( __unix__ ) || defined( __APPLE__ )
|
|
||||||
StringUtils::PathSeparator separator = StringUtils::PATH_UNIX;
|
StringUtils::PathSeparator separator = StringUtils::PATH_UNIX;
|
||||||
#else
|
#else
|
||||||
StringUtils::PathSeparator separator = StringUtils::PATH_WIN;
|
StringUtils::PathSeparator separator = StringUtils::PATH_WIN;
|
||||||
|
@ -170,7 +163,7 @@ namespace FileUtils {
|
||||||
std::string folder = StringUtils::GetFolderString(path);
|
std::string folder = StringUtils::GetFolderString(path);
|
||||||
std::string clean = StringUtils::GetCleanPathString(folder, separator);
|
std::string clean = StringUtils::GetCleanPathString(folder, separator);
|
||||||
std::string build = clean;
|
std::string build = clean;
|
||||||
for (int i = 0; i < clean.length(); i ++) {
|
for (int i = 0; i < clean.length(); i++) {
|
||||||
if (clean[i] == separator && i > 0) {
|
if (clean[i] == separator && i > 0) {
|
||||||
build[i] = '\0';
|
build[i] = '\0';
|
||||||
if (i > 1 || build[1] != ':') {
|
if (i > 1 || build[1] != ':') {
|
||||||
|
@ -182,9 +175,9 @@ namespace FileUtils {
|
||||||
build[i] = clean[i];
|
build[i] = clean[i];
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CopyFile(const std::string &srcFilename, const std::string &dstFilename, bool createPath) {
|
bool CopyFile(const std::string& srcFilename, const std::string& dstFilename, bool createPath) {
|
||||||
std::ifstream srcFile(srcFilename, std::ios::binary);
|
std::ifstream srcFile(srcFilename, std::ios::binary);
|
||||||
if (!srcFile) {
|
if (!srcFile) {
|
||||||
fmt::printf("Warning: Couldn't open file %s for reading.\n", srcFilename);
|
fmt::printf("Warning: Couldn't open file %s for reading.\n", srcFilename);
|
||||||
|
@ -210,7 +203,12 @@ namespace FileUtils {
|
||||||
if (srcSize == dstSize) {
|
if (srcSize == dstSize) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
fmt::printf("Warning: Only copied %lu bytes to %s, when %s is %lu bytes long.\n", dstSize, dstFilename, srcFilename, srcSize);
|
fmt::printf(
|
||||||
|
"Warning: Only copied %lu bytes to %s, when %s is %lu bytes long.\n",
|
||||||
|
dstSize,
|
||||||
|
dstFilename,
|
||||||
|
srcFilename,
|
||||||
|
srcSize);
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} // namespace FileUtils
|
||||||
|
|
|
@ -14,15 +14,18 @@
|
||||||
|
|
||||||
namespace FileUtils {
|
namespace FileUtils {
|
||||||
|
|
||||||
std::string GetCurrentFolder();
|
std::string GetCurrentFolder();
|
||||||
|
|
||||||
bool FileExists(const std::string &folderPath);
|
bool FileExists(const std::string& folderPath);
|
||||||
bool FolderExists(const std::string &folderPath);
|
bool FolderExists(const std::string& folderPath);
|
||||||
|
|
||||||
bool MatchExtension(const char *fileExtension, const char *matchExtensions);
|
bool MatchExtension(const char* fileExtension, const char* matchExtensions);
|
||||||
std::vector<std::string> ListFolderFiles(const char *folder, const char *matchExtensions);
|
std::vector<std::string> ListFolderFiles(const char* folder, const char* matchExtensions);
|
||||||
|
|
||||||
bool CreatePath(const char *path);
|
bool CreatePath(const char* path);
|
||||||
|
|
||||||
bool CopyFile(const std::string &srcFilename, const std::string &dstFilename, bool createPath = false);
|
bool CopyFile(
|
||||||
}
|
const std::string& srcFilename,
|
||||||
|
const std::string& dstFilename,
|
||||||
|
bool createPath = false);
|
||||||
|
} // namespace FileUtils
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
|
|
||||||
#include "Image_Utils.hpp"
|
#include "Image_Utils.hpp"
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
|
||||||
|
@ -22,11 +22,10 @@
|
||||||
|
|
||||||
namespace ImageUtils {
|
namespace ImageUtils {
|
||||||
|
|
||||||
static bool imageHasTransparentPixels(FILE *f)
|
static bool imageHasTransparentPixels(FILE* f) {
|
||||||
{
|
|
||||||
int width, height, channels;
|
int width, height, channels;
|
||||||
// RGBA: we have to load the pixels to figure out if the image is fully opaque
|
// RGBA: we have to load the pixels to figure out if the image is fully opaque
|
||||||
uint8_t *pixels = stbi_load_from_file(f, &width, &height, &channels, 0);
|
uint8_t* pixels = stbi_load_from_file(f, &width, &height, &channels, 0);
|
||||||
if (pixels != nullptr) {
|
if (pixels != nullptr) {
|
||||||
int pixelCount = width * height;
|
int pixelCount = width * height;
|
||||||
for (int ix = 0; ix < pixelCount; ix++) {
|
for (int ix = 0; ix < pixelCount; ix++) {
|
||||||
|
@ -37,17 +36,16 @@ namespace ImageUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageProperties GetImageProperties(char const *filePath)
|
ImageProperties GetImageProperties(char const* filePath) {
|
||||||
{
|
|
||||||
ImageProperties result = {
|
ImageProperties result = {
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
IMAGE_OPAQUE,
|
IMAGE_OPAQUE,
|
||||||
};
|
};
|
||||||
|
|
||||||
FILE *f = fopen(filePath, "rb");
|
FILE* f = fopen(filePath, "rb");
|
||||||
if (f == nullptr) {
|
if (f == nullptr) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -59,10 +57,9 @@ namespace ImageUtils {
|
||||||
result.occlusion = IMAGE_TRANSPARENT;
|
result.occlusion = IMAGE_TRANSPARENT;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string suffixToMimeType(std::string suffix)
|
std::string suffixToMimeType(std::string suffix) {
|
||||||
{
|
|
||||||
std::transform(suffix.begin(), suffix.end(), suffix.begin(), ::tolower);
|
std::transform(suffix.begin(), suffix.end(), suffix.begin(), ::tolower);
|
||||||
|
|
||||||
if (suffix == "jpg" || suffix == "jpeg") {
|
if (suffix == "jpg" || suffix == "jpeg") {
|
||||||
|
@ -72,6 +69,6 @@ namespace ImageUtils {
|
||||||
return "image/png";
|
return "image/png";
|
||||||
}
|
}
|
||||||
return "image/unknown";
|
return "image/unknown";
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace ImageUtils
|
||||||
|
|
|
@ -13,25 +13,20 @@
|
||||||
|
|
||||||
namespace ImageUtils {
|
namespace ImageUtils {
|
||||||
|
|
||||||
enum ImageOcclusion
|
enum ImageOcclusion { IMAGE_OPAQUE, IMAGE_TRANSPARENT };
|
||||||
{
|
|
||||||
IMAGE_OPAQUE,
|
|
||||||
IMAGE_TRANSPARENT
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ImageProperties
|
struct ImageProperties {
|
||||||
{
|
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
ImageOcclusion occlusion;
|
ImageOcclusion occlusion;
|
||||||
};
|
};
|
||||||
|
|
||||||
ImageProperties GetImageProperties(char const *filePath);
|
ImageProperties GetImageProperties(char const* filePath);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Very simple method for mapping filename suffix to mime type. The glTF 2.0 spec only accepts values
|
* Very simple method for mapping filename suffix to mime type. The glTF 2.0 spec only accepts
|
||||||
* "image/jpeg" and "image/png" so we don't need to get too fancy.
|
* values "image/jpeg" and "image/png" so we don't need to get too fancy.
|
||||||
*/
|
*/
|
||||||
std::string suffixToMimeType(std::string suffix);
|
std::string suffixToMimeType(std::string suffix);
|
||||||
|
|
||||||
}
|
} // namespace ImageUtils
|
||||||
|
|
|
@ -11,77 +11,70 @@
|
||||||
|
|
||||||
namespace StringUtils {
|
namespace StringUtils {
|
||||||
|
|
||||||
PathSeparator operator!(const PathSeparator &s)
|
PathSeparator operator!(const PathSeparator& s) {
|
||||||
{
|
|
||||||
return (s == PATH_WIN) ? PATH_UNIX : PATH_WIN;
|
return (s == PATH_WIN) ? PATH_UNIX : PATH_WIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
PathSeparator GetPathSeparator() {
|
PathSeparator GetPathSeparator() {
|
||||||
#if defined( __unix__ ) || defined( __APPLE__ )
|
#if defined(__unix__) || defined(__APPLE__)
|
||||||
return PATH_UNIX;
|
return PATH_UNIX;
|
||||||
#else
|
#else
|
||||||
return PATH_WIN;
|
return PATH_WIN;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
const std::string NormalizePath(const std::string &path)
|
const std::string NormalizePath(const std::string& path) {
|
||||||
{
|
|
||||||
PathSeparator separator = GetPathSeparator();
|
PathSeparator separator = GetPathSeparator();
|
||||||
char replace;
|
char replace;
|
||||||
if (separator == PATH_WIN) {
|
if (separator == PATH_WIN) {
|
||||||
replace = PATH_UNIX;
|
replace = PATH_UNIX;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
replace = PATH_WIN;
|
replace = PATH_WIN;
|
||||||
}
|
}
|
||||||
std::string normalizedPath = path;
|
std::string normalizedPath = path;
|
||||||
for (size_t s = normalizedPath.find(replace, 0); s != std::string::npos; s = normalizedPath.find(replace, s)) {
|
for (size_t s = normalizedPath.find(replace, 0); s != std::string::npos;
|
||||||
|
s = normalizedPath.find(replace, s)) {
|
||||||
normalizedPath[s] = separator;
|
normalizedPath[s] = separator;
|
||||||
}
|
}
|
||||||
return normalizedPath;
|
return normalizedPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string GetFolderString(const std::string &path)
|
const std::string GetFolderString(const std::string& path) {
|
||||||
{
|
|
||||||
size_t s = path.rfind(PATH_WIN);
|
size_t s = path.rfind(PATH_WIN);
|
||||||
s = (s != std::string::npos) ? s : path.rfind(PATH_UNIX);
|
s = (s != std::string::npos) ? s : path.rfind(PATH_UNIX);
|
||||||
return path.substr(0, s + 1);
|
return path.substr(0, s + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string GetCleanPathString(const std::string &path, const PathSeparator separator)
|
const std::string GetCleanPathString(const std::string& path, const PathSeparator separator) {
|
||||||
{
|
|
||||||
std::string cleanPath = path;
|
std::string cleanPath = path;
|
||||||
for (size_t s = cleanPath.find(!separator, 0); s != std::string::npos; s = cleanPath.find(!separator, s)) {
|
for (size_t s = cleanPath.find(!separator, 0); s != std::string::npos;
|
||||||
|
s = cleanPath.find(!separator, s)) {
|
||||||
cleanPath[s] = separator;
|
cleanPath[s] = separator;
|
||||||
}
|
}
|
||||||
return cleanPath;
|
return cleanPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string GetFileNameString(const std::string &path)
|
const std::string GetFileNameString(const std::string& path) {
|
||||||
{
|
|
||||||
size_t s = path.rfind(PATH_WIN);
|
size_t s = path.rfind(PATH_WIN);
|
||||||
s = (s != std::string::npos) ? s : path.rfind(PATH_UNIX);
|
s = (s != std::string::npos) ? s : path.rfind(PATH_UNIX);
|
||||||
return path.substr(s + 1, std::string::npos);
|
return path.substr(s + 1, std::string::npos);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string GetFileBaseString(const std::string &path)
|
const std::string GetFileBaseString(const std::string& path) {
|
||||||
{
|
|
||||||
const std::string fileName = GetFileNameString(path);
|
const std::string fileName = GetFileNameString(path);
|
||||||
return fileName.substr(0, fileName.rfind('.')).c_str();
|
return fileName.substr(0, fileName.rfind('.')).c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string GetFileSuffixString(const std::string &path)
|
const std::string GetFileSuffixString(const std::string& path) {
|
||||||
{
|
|
||||||
const std::string fileName = GetFileNameString(path);
|
const std::string fileName = GetFileNameString(path);
|
||||||
size_t pos = fileName.rfind('.');
|
size_t pos = fileName.rfind('.');
|
||||||
if (pos == std::string::npos) {
|
if (pos == std::string::npos) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return fileName.substr(++pos);
|
return fileName.substr(++pos);
|
||||||
}
|
|
||||||
|
|
||||||
int CompareNoCase(const std::string &s1, const std::string &s2)
|
|
||||||
{
|
|
||||||
return strncasecmp(s1.c_str(), s2.c_str(), MAX_PATH_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CompareNoCase(const std::string& s1, const std::string& s2) {
|
||||||
|
return strncasecmp(s1.c_str(), s2.c_str(), MAX_PATH_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace StringUtils
|
||||||
|
|
|
@ -9,49 +9,46 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <cstdarg>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdarg>
|
#include <string>
|
||||||
|
|
||||||
#if defined( _MSC_VER )
|
#if defined(_MSC_VER)
|
||||||
#define strncasecmp _strnicmp
|
#define strncasecmp _strnicmp
|
||||||
#define strcasecmp _stricmp
|
#define strcasecmp _stricmp
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace StringUtils {
|
namespace StringUtils {
|
||||||
|
|
||||||
static const unsigned int MAX_PATH_LENGTH = 1024;
|
static const unsigned int MAX_PATH_LENGTH = 1024;
|
||||||
|
|
||||||
enum PathSeparator
|
enum PathSeparator { PATH_WIN = '\\', PATH_UNIX = '/' };
|
||||||
{
|
|
||||||
PATH_WIN = '\\',
|
|
||||||
PATH_UNIX = '/'
|
|
||||||
};
|
|
||||||
|
|
||||||
PathSeparator operator!(const PathSeparator &s);
|
PathSeparator operator!(const PathSeparator& s);
|
||||||
|
|
||||||
PathSeparator GetPathSeparator();
|
PathSeparator GetPathSeparator();
|
||||||
const std::string NormalizePath(const std::string &path);
|
const std::string NormalizePath(const std::string& path);
|
||||||
|
|
||||||
const std::string GetCleanPathString(const std::string &path, const PathSeparator separator = PATH_WIN);
|
const std::string GetCleanPathString(
|
||||||
|
const std::string& path,
|
||||||
|
const PathSeparator separator = PATH_WIN);
|
||||||
|
|
||||||
template<size_t size>
|
template <size_t size>
|
||||||
void GetCleanPath(char (&dest)[size], const char *path, const PathSeparator separator = PATH_WIN)
|
void GetCleanPath(char (&dest)[size], const char* path, const PathSeparator separator = PATH_WIN) {
|
||||||
{
|
|
||||||
size_t len = size - 1;
|
size_t len = size - 1;
|
||||||
strncpy(dest, path, len);
|
strncpy(dest, path, len);
|
||||||
char *destPtr = dest;
|
char* destPtr = dest;
|
||||||
while ((destPtr = strchr(destPtr, !separator)) != nullptr) {
|
while ((destPtr = strchr(destPtr, !separator)) != nullptr) {
|
||||||
*destPtr = separator;
|
*destPtr = separator;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const std::string GetFolderString(const std::string &path);
|
|
||||||
const std::string GetFileNameString(const std::string &path);
|
|
||||||
const std::string GetFileBaseString(const std::string &path);
|
|
||||||
const std::string GetFileSuffixString(const std::string &path);
|
|
||||||
|
|
||||||
int CompareNoCase(const std::string &s1, const std::string &s2);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string GetFolderString(const std::string& path);
|
||||||
|
const std::string GetFileNameString(const std::string& path);
|
||||||
|
const std::string GetFileBaseString(const std::string& path);
|
||||||
|
const std::string GetFileSuffixString(const std::string& path);
|
||||||
|
|
||||||
|
int CompareNoCase(const std::string& s1, const std::string& s2);
|
||||||
|
|
||||||
|
} // namespace StringUtils
|
||||||
|
|
Loading…
Reference in New Issue