mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 06:17:28 +02:00
Merge branch 'instancing' of github.com:highfidelity/hifi into instancing
This commit is contained in:
commit
01bb8fa601
11 changed files with 1289 additions and 955 deletions
|
@ -1485,7 +1485,11 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
|
||||||
}
|
}
|
||||||
for (const QString& modelID : instanceModelIDs) {
|
for (const QString& modelID : instanceModelIDs) {
|
||||||
// The transform node has the same indexing order as the joints
|
// The transform node has the same indexing order as the joints
|
||||||
const uint32_t transformIndex = (uint32_t)modelIDs.indexOf(modelID);
|
int indexOfModelID = modelIDs.indexOf(modelID);
|
||||||
|
if (indexOfModelID == -1) {
|
||||||
|
qCDebug(modelformat) << "Model not in model list: " << modelID;
|
||||||
|
}
|
||||||
|
const uint32_t transformIndex = (indexOfModelID == -1) ? 0 : (uint32_t)indexOfModelID;
|
||||||
|
|
||||||
// accumulate local transforms
|
// accumulate local transforms
|
||||||
glm::mat4 globalTransform = hfmModel.joints[transformIndex].globalTransform;
|
glm::mat4 globalTransform = hfmModel.joints[transformIndex].globalTransform;
|
||||||
|
@ -1585,12 +1589,6 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rootJointIndex = modelIDs.indexOf(modelID);
|
|
||||||
if (rootJointIndex == -1) {
|
|
||||||
qCDebug(modelformat) << "Model not in model list: " << modelID;
|
|
||||||
rootJointIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// whether we're skinned depends on how many clusters are attached
|
// whether we're skinned depends on how many clusters are attached
|
||||||
if (clusterIDs.size() > 0) {
|
if (clusterIDs.size() > 0) {
|
||||||
hfm::SkinDeformer skinDeformer;
|
hfm::SkinDeformer skinDeformer;
|
||||||
|
@ -1603,10 +1601,12 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
|
||||||
// see http://stackoverflow.com/questions/13566608/loading-skinning-information-from-fbx for a discussion
|
// see http://stackoverflow.com/questions/13566608/loading-skinning-information-from-fbx for a discussion
|
||||||
// of skinning information in FBX
|
// of skinning information in FBX
|
||||||
QString jointID = _connectionChildMap.value(clusterID);
|
QString jointID = _connectionChildMap.value(clusterID);
|
||||||
hfmCluster.jointIndex = modelIDs.indexOf(jointID);
|
int indexOfJointID = modelIDs.indexOf(jointID);
|
||||||
if (hfmCluster.jointIndex == -1) {
|
if (indexOfJointID == -1) {
|
||||||
qCDebug(modelformat) << "Joint not in model list: " << jointID;
|
qCDebug(modelformat) << "Joint not in model list: " << jointID;
|
||||||
hfmCluster.jointIndex = 0;
|
hfmCluster.jointIndex = 0;
|
||||||
|
} else {
|
||||||
|
hfmCluster.jointIndex = (uint32_t)indexOfJointID;
|
||||||
}
|
}
|
||||||
|
|
||||||
hfmCluster.inverseBindMatrix = glm::inverse(fbxCluster.transformLink) * globalTransform;
|
hfmCluster.inverseBindMatrix = glm::inverse(fbxCluster.transformLink) * globalTransform;
|
||||||
|
@ -1635,7 +1635,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
|
||||||
|
|
||||||
// the last cluster is the root cluster
|
// the last cluster is the root cluster
|
||||||
HFMCluster cluster;
|
HFMCluster cluster;
|
||||||
cluster.jointIndex = rootJointIndex;
|
cluster.jointIndex = transformIndex;
|
||||||
clusters.push_back(cluster);
|
clusters.push_back(cluster);
|
||||||
|
|
||||||
// Skinned mesh instances have a dynamic transform
|
// Skinned mesh instances have a dynamic transform
|
||||||
|
@ -1676,7 +1676,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// this is a no cluster mesh
|
// this is a no cluster mesh
|
||||||
HFMJoint& joint = hfmModel.joints[rootJointIndex];
|
HFMJoint& joint = hfmModel.joints[transformIndex];
|
||||||
|
|
||||||
// Apply geometric offset, if present, by transforming the vertices directly
|
// Apply geometric offset, if present, by transforming the vertices directly
|
||||||
if (joint.hasGeometricOffset) {
|
if (joint.hasGeometricOffset) {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -38,14 +38,14 @@ struct GLTFAsset {
|
||||||
|
|
||||||
struct GLTFNode {
|
struct GLTFNode {
|
||||||
QString name;
|
QString name;
|
||||||
int camera;
|
int camera{ -1 };
|
||||||
int mesh;
|
int mesh{ -1 };
|
||||||
QVector<int> children;
|
QVector<int> children;
|
||||||
QVector<double> translation;
|
QVector<double> translation;
|
||||||
QVector<double> rotation;
|
QVector<double> rotation;
|
||||||
QVector<double> scale;
|
QVector<double> scale;
|
||||||
QVector<double> matrix;
|
QVector<double> matrix;
|
||||||
QVector<glm::mat4> transforms;
|
glm::mat4 transform;
|
||||||
int skin;
|
int skin;
|
||||||
QVector<int> skeletons;
|
QVector<int> skeletons;
|
||||||
QString jointName;
|
QString jointName;
|
||||||
|
@ -85,6 +85,8 @@ struct GLTFNode {
|
||||||
qCDebug(modelformat) << "skeletons: " << skeletons;
|
qCDebug(modelformat) << "skeletons: " << skeletons;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void normalizeTransform();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Meshes
|
// Meshes
|
||||||
|
@ -460,15 +462,56 @@ struct GLTFMaterial {
|
||||||
// Accesors
|
// Accesors
|
||||||
|
|
||||||
namespace GLTFAccessorType {
|
namespace GLTFAccessorType {
|
||||||
enum Values {
|
enum Value {
|
||||||
SCALAR = 0,
|
SCALAR = 1,
|
||||||
VEC2,
|
VEC2 = 2,
|
||||||
VEC3,
|
VEC3 = 3,
|
||||||
VEC4,
|
VEC4 = 4,
|
||||||
MAT2,
|
MAT2 = 5,
|
||||||
MAT3,
|
MAT3 = 9,
|
||||||
MAT4
|
MAT4 = 16
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline int count(Value value) {
|
||||||
|
if (value == MAT2) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
return (int)value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace GLTFVertexAttribute {
|
||||||
|
enum Value {
|
||||||
|
UNKNOWN = -1,
|
||||||
|
POSITION = 0,
|
||||||
|
NORMAL,
|
||||||
|
TANGENT,
|
||||||
|
TEXCOORD_0,
|
||||||
|
TEXCOORD_1,
|
||||||
|
COLOR_0,
|
||||||
|
JOINTS_0,
|
||||||
|
WEIGHTS_0,
|
||||||
|
};
|
||||||
|
inline Value fromString(const QString& key) {
|
||||||
|
if (key == "POSITION") {
|
||||||
|
return POSITION;
|
||||||
|
} else if (key == "NORMAL") {
|
||||||
|
return NORMAL;
|
||||||
|
} else if (key == "TANGENT") {
|
||||||
|
return TANGENT;
|
||||||
|
} else if (key == "TEXCOORD_0") {
|
||||||
|
return TEXCOORD_0;
|
||||||
|
} else if (key == "TEXCOORD_1") {
|
||||||
|
return TEXCOORD_1;
|
||||||
|
} else if (key == "COLOR_0") {
|
||||||
|
return COLOR_0;
|
||||||
|
} else if (key == "JOINTS_0") {
|
||||||
|
return JOINTS_0;
|
||||||
|
} else if (key == "WEIGHTS_0") {
|
||||||
|
return WEIGHTS_0;
|
||||||
|
}
|
||||||
|
return UNKNOWN;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
namespace GLTFAccessorComponentType {
|
namespace GLTFAccessorComponentType {
|
||||||
enum Values {
|
enum Values {
|
||||||
|
@ -760,6 +803,13 @@ struct GLTFFile {
|
||||||
foreach(auto tex, textures) tex.dump();
|
foreach(auto tex, textures) tex.dump();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void populateMaterialNames();
|
||||||
|
void sortNodes();
|
||||||
|
void normalizeNodeTransforms();
|
||||||
|
private:
|
||||||
|
void reorderNodes(const std::unordered_map<int, int>& reorderMap);
|
||||||
};
|
};
|
||||||
|
|
||||||
class GLTFSerializer : public QObject, public HFMSerializer {
|
class GLTFSerializer : public QObject, public HFMSerializer {
|
||||||
|
@ -774,7 +824,7 @@ private:
|
||||||
hifi::URL _url;
|
hifi::URL _url;
|
||||||
hifi::ByteArray _glbBinary;
|
hifi::ByteArray _glbBinary;
|
||||||
|
|
||||||
glm::mat4 getModelTransform(const GLTFNode& node);
|
const glm::mat4& getModelTransform(const GLTFNode& node);
|
||||||
void getSkinInverseBindMatrices(std::vector<std::vector<float>>& inverseBindMatrixValues);
|
void getSkinInverseBindMatrices(std::vector<std::vector<float>>& inverseBindMatrixValues);
|
||||||
void generateTargetData(int index, float weight, QVector<glm::vec3>& returnVector);
|
void generateTargetData(int index, float weight, QVector<glm::vec3>& returnVector);
|
||||||
|
|
||||||
|
@ -843,6 +893,9 @@ private:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool addArrayFromAccessor(GLTFAccessor& accessor, QVector<T>& outarray);
|
bool addArrayFromAccessor(GLTFAccessor& accessor, QVector<T>& outarray);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool addArrayFromAttribute(GLTFVertexAttribute::Value vertexAttribute, GLTFAccessor& accessor, QVector<T>& outarray);
|
||||||
|
|
||||||
void retriangulate(const QVector<int>& in_indices, const QVector<glm::vec3>& in_vertices,
|
void retriangulate(const QVector<int>& in_indices, const QVector<glm::vec3>& in_vertices,
|
||||||
const QVector<glm::vec3>& in_normals, QVector<int>& out_indices,
|
const QVector<glm::vec3>& in_normals, QVector<int>& out_indices,
|
||||||
QVector<glm::vec3>& out_vertices, QVector<glm::vec3>& out_normals);
|
QVector<glm::vec3>& out_vertices, QVector<glm::vec3>& out_normals);
|
||||||
|
|
66
libraries/hfm/src/hfm/HFMModelMath.cpp
Normal file
66
libraries/hfm/src/hfm/HFMModelMath.cpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
//
|
||||||
|
// HFMModelMath.cpp
|
||||||
|
// model-baker/src/model-baker
|
||||||
|
//
|
||||||
|
// Created by Sabrina Shanman on 2019/10/04.
|
||||||
|
// Copyright 2019 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "HFMModelMath.h"
|
||||||
|
|
||||||
|
namespace hfm {
|
||||||
|
|
||||||
|
void forEachIndex(const hfm::MeshPart& meshPart, std::function<void(uint32_t)> func) {
|
||||||
|
for (int i = 0; i <= meshPart.quadIndices.size() - 4; i += 4) {
|
||||||
|
func((uint32_t)meshPart.quadIndices[i]);
|
||||||
|
func((uint32_t)meshPart.quadIndices[i+1]);
|
||||||
|
func((uint32_t)meshPart.quadIndices[i+2]);
|
||||||
|
func((uint32_t)meshPart.quadIndices[i+3]);
|
||||||
|
}
|
||||||
|
for (int i = 0; i <= meshPart.triangleIndices.size() - 3; i += 3) {
|
||||||
|
func((uint32_t)meshPart.triangleIndices[i]);
|
||||||
|
func((uint32_t)meshPart.triangleIndices[i+1]);
|
||||||
|
func((uint32_t)meshPart.triangleIndices[i+2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void thickenFlatExtents(Extents& extents) {
|
||||||
|
// Add epsilon to extents to compensate for flat plane
|
||||||
|
extents.minimum -= glm::vec3(EPSILON, EPSILON, EPSILON);
|
||||||
|
extents.maximum += glm::vec3(EPSILON, EPSILON, EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
void calculateExtentsForShape(hfm::Shape& shape, const std::vector<hfm::Mesh>& meshes, const std::vector<hfm::Joint> joints) {
|
||||||
|
auto& shapeExtents = shape.transformedExtents;
|
||||||
|
shapeExtents.reset();
|
||||||
|
|
||||||
|
const auto& mesh = meshes[shape.mesh];
|
||||||
|
const auto& meshPart = mesh.parts[shape.meshPart];
|
||||||
|
|
||||||
|
glm::mat4 globalTransform = joints[shape.joint].globalTransform;
|
||||||
|
forEachIndex(meshPart, [&](int32_t idx){
|
||||||
|
if (mesh.vertices.size() <= idx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const glm::vec3& vertex = mesh.vertices[idx];
|
||||||
|
const glm::vec3 transformedVertex = glm::vec3(globalTransform * glm::vec4(vertex, 1.0f));
|
||||||
|
shapeExtents.addPoint(transformedVertex);
|
||||||
|
});
|
||||||
|
|
||||||
|
thickenFlatExtents(shapeExtents);
|
||||||
|
}
|
||||||
|
|
||||||
|
void calculateExtentsForModel(Extents& modelExtents, const std::vector<hfm::Shape>& shapes) {
|
||||||
|
modelExtents.reset();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < shapes.size(); ++i) {
|
||||||
|
const auto& shape = shapes[i];
|
||||||
|
const auto& shapeExtents = shape.transformedExtents;
|
||||||
|
modelExtents.addExtents(shapeExtents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
30
libraries/hfm/src/hfm/HFMModelMath.h
Normal file
30
libraries/hfm/src/hfm/HFMModelMath.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// HFMModelMath.h
|
||||||
|
// model-baker/src/model-baker
|
||||||
|
//
|
||||||
|
// Created by Sabrina Shanman on 2019/10/04.
|
||||||
|
// Copyright 2019 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_hfm_ModelMath_h
|
||||||
|
#define hifi_hfm_ModelMath_h
|
||||||
|
|
||||||
|
#include "HFM.h"
|
||||||
|
|
||||||
|
namespace hfm {
|
||||||
|
|
||||||
|
void forEachIndex(const hfm::MeshPart& meshPart, std::function<void(uint32_t)> func);
|
||||||
|
|
||||||
|
void initializeExtents(Extents& extents);
|
||||||
|
|
||||||
|
// This can't be moved to model-baker until
|
||||||
|
void calculateExtentsForShape(hfm::Shape& shape, const std::vector<hfm::Mesh>& meshes, const std::vector<hfm::Joint> joints);
|
||||||
|
|
||||||
|
void calculateExtentsForModel(Extents& modelExtents, const std::vector<hfm::Shape>& shapes);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // #define hifi_hfm_ModelMath_h
|
|
@ -21,6 +21,7 @@
|
||||||
#include "CalculateBlendshapeNormalsTask.h"
|
#include "CalculateBlendshapeNormalsTask.h"
|
||||||
#include "CalculateBlendshapeTangentsTask.h"
|
#include "CalculateBlendshapeTangentsTask.h"
|
||||||
#include "PrepareJointsTask.h"
|
#include "PrepareJointsTask.h"
|
||||||
|
#include "CalculateExtentsTask.h"
|
||||||
#include "BuildDracoMeshTask.h"
|
#include "BuildDracoMeshTask.h"
|
||||||
#include "ParseFlowDataTask.h"
|
#include "ParseFlowDataTask.h"
|
||||||
|
|
||||||
|
@ -29,7 +30,7 @@ namespace baker {
|
||||||
class GetModelPartsTask {
|
class GetModelPartsTask {
|
||||||
public:
|
public:
|
||||||
using Input = hfm::Model::Pointer;
|
using Input = hfm::Model::Pointer;
|
||||||
using Output = VaryingSet8<std::vector<hfm::Mesh>, hifi::URL, baker::MeshIndicesToModelNames, baker::BlendshapesPerMesh, std::vector<hfm::Joint>, std::vector<hfm::Shape>, std::vector<hfm::SkinDeformer>, std::vector<hfm::SkinCluster>>;
|
using Output = VaryingSet9<std::vector<hfm::Mesh>, hifi::URL, baker::MeshIndicesToModelNames, baker::BlendshapesPerMesh, std::vector<hfm::Joint>, std::vector<hfm::Shape>, std::vector<hfm::SkinDeformer>, std::vector<hfm::SkinCluster>, Extents>;
|
||||||
using JobModel = Job::ModelIO<GetModelPartsTask, Input, Output>;
|
using JobModel = Job::ModelIO<GetModelPartsTask, Input, Output>;
|
||||||
|
|
||||||
void run(const BakeContextPointer& context, const Input& input, Output& output) {
|
void run(const BakeContextPointer& context, const Input& input, Output& output) {
|
||||||
|
@ -46,6 +47,7 @@ namespace baker {
|
||||||
output.edit5() = hfmModelIn->shapes;
|
output.edit5() = hfmModelIn->shapes;
|
||||||
output.edit6() = hfmModelIn->skinDeformers;
|
output.edit6() = hfmModelIn->skinDeformers;
|
||||||
output.edit7() = hfmModelIn->skinClusters;
|
output.edit7() = hfmModelIn->skinClusters;
|
||||||
|
output.edit8() = hfmModelIn->meshExtents;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -106,7 +108,7 @@ namespace baker {
|
||||||
|
|
||||||
class BuildModelTask {
|
class BuildModelTask {
|
||||||
public:
|
public:
|
||||||
using Input = VaryingSet7<hfm::Model::Pointer, std::vector<hfm::Mesh>, std::vector<hfm::Joint>, QMap<int, glm::quat>, QHash<QString, int>, FlowData, std::vector<ShapeVertices>>;
|
using Input = VaryingSet9<hfm::Model::Pointer, std::vector<hfm::Mesh>, std::vector<hfm::Joint>, QMap<int, glm::quat>, QHash<QString, int>, FlowData, std::vector<ShapeVertices>, std::vector<hfm::Shape>, Extents>;
|
||||||
using Output = hfm::Model::Pointer;
|
using Output = hfm::Model::Pointer;
|
||||||
using JobModel = Job::ModelIO<BuildModelTask, Input, Output>;
|
using JobModel = Job::ModelIO<BuildModelTask, Input, Output>;
|
||||||
|
|
||||||
|
@ -118,6 +120,8 @@ namespace baker {
|
||||||
hfmModelOut->jointIndices = input.get4();
|
hfmModelOut->jointIndices = input.get4();
|
||||||
hfmModelOut->flowData = input.get5();
|
hfmModelOut->flowData = input.get5();
|
||||||
hfmModelOut->shapeVertices = input.get6();
|
hfmModelOut->shapeVertices = input.get6();
|
||||||
|
hfmModelOut->shapes = input.get7();
|
||||||
|
hfmModelOut->meshExtents = input.get8();
|
||||||
// These depend on the ShapeVertices
|
// These depend on the ShapeVertices
|
||||||
// TODO: Create a task for this rather than calculating it here
|
// TODO: Create a task for this rather than calculating it here
|
||||||
hfmModelOut->computeKdops();
|
hfmModelOut->computeKdops();
|
||||||
|
@ -144,7 +148,8 @@ namespace baker {
|
||||||
const auto jointsIn = modelPartsIn.getN<GetModelPartsTask::Output>(4);
|
const auto jointsIn = modelPartsIn.getN<GetModelPartsTask::Output>(4);
|
||||||
const auto shapesIn = modelPartsIn.getN<GetModelPartsTask::Output>(5);
|
const auto shapesIn = modelPartsIn.getN<GetModelPartsTask::Output>(5);
|
||||||
const auto skinDeformersIn = modelPartsIn.getN<GetModelPartsTask::Output>(6);
|
const auto skinDeformersIn = modelPartsIn.getN<GetModelPartsTask::Output>(6);
|
||||||
const auto deformersIn = modelPartsIn.getN<GetModelPartsTask::Output>(7);
|
const auto skinClustersIn = modelPartsIn.getN<GetModelPartsTask::Output>(7);
|
||||||
|
const auto modelExtentsIn = modelPartsIn.getN<GetModelPartsTask::Output>(8);
|
||||||
|
|
||||||
// Calculate normals and tangents for meshes and blendshapes if they do not exist
|
// Calculate normals and tangents for meshes and blendshapes if they do not exist
|
||||||
// Note: Normals are never calculated here for OBJ models. OBJ files optionally define normals on a per-face basis, so for consistency normals are calculated beforehand in OBJSerializer.
|
// Note: Normals are never calculated here for OBJ models. OBJ files optionally define normals on a per-face basis, so for consistency normals are calculated beforehand in OBJSerializer.
|
||||||
|
@ -158,7 +163,7 @@ namespace baker {
|
||||||
|
|
||||||
// Skinning weight calculations
|
// Skinning weight calculations
|
||||||
// NOTE: Due to limitations in the current graphics::MeshPointer representation, the output list of ReweightedDeformers is per-mesh. An element is empty if there are no deformers for the mesh of the same index.
|
// NOTE: Due to limitations in the current graphics::MeshPointer representation, the output list of ReweightedDeformers is per-mesh. An element is empty if there are no deformers for the mesh of the same index.
|
||||||
const auto reweightDeformersInputs = ReweightDeformersTask::Input(meshesIn, shapesIn, skinDeformersIn, deformersIn).asVarying();
|
const auto reweightDeformersInputs = ReweightDeformersTask::Input(meshesIn, shapesIn, skinDeformersIn, skinClustersIn).asVarying();
|
||||||
const auto reweightedDeformers = model.addJob<ReweightDeformersTask>("ReweightDeformers", reweightDeformersInputs);
|
const auto reweightedDeformers = model.addJob<ReweightDeformersTask>("ReweightDeformers", reweightDeformersInputs);
|
||||||
// Shape vertices are included/rejected based on skinning weight, and thus must use the reweighted deformers.
|
// Shape vertices are included/rejected based on skinning weight, and thus must use the reweighted deformers.
|
||||||
const auto collectShapeVerticesInputs = CollectShapeVerticesTask::Input(meshesIn, shapesIn, jointsIn, skinDeformersIn, reweightedDeformers).asVarying();
|
const auto collectShapeVerticesInputs = CollectShapeVerticesTask::Input(meshesIn, shapesIn, jointsIn, skinDeformersIn, reweightedDeformers).asVarying();
|
||||||
|
@ -175,6 +180,12 @@ namespace baker {
|
||||||
const auto jointRotationOffsets = jointInfoOut.getN<PrepareJointsTask::Output>(1);
|
const auto jointRotationOffsets = jointInfoOut.getN<PrepareJointsTask::Output>(1);
|
||||||
const auto jointIndices = jointInfoOut.getN<PrepareJointsTask::Output>(2);
|
const auto jointIndices = jointInfoOut.getN<PrepareJointsTask::Output>(2);
|
||||||
|
|
||||||
|
// Use transform information to compute extents
|
||||||
|
const auto calculateExtentsInputs = CalculateExtentsTask::Input(modelExtentsIn, meshesIn, shapesIn, jointsOut).asVarying();
|
||||||
|
const auto calculateExtentsOutputs = model.addJob<CalculateExtentsTask>("CalculateExtents", calculateExtentsInputs);
|
||||||
|
const auto modelExtentsOut = calculateExtentsOutputs.getN<CalculateExtentsTask::Output>(0);
|
||||||
|
const auto shapesOut = calculateExtentsOutputs.getN<CalculateExtentsTask::Output>(1);
|
||||||
|
|
||||||
// Parse material mapping
|
// Parse material mapping
|
||||||
const auto parseMaterialMappingInputs = ParseMaterialMappingTask::Input(mapping, materialMappingBaseURL).asVarying();
|
const auto parseMaterialMappingInputs = ParseMaterialMappingTask::Input(mapping, materialMappingBaseURL).asVarying();
|
||||||
const auto materialMapping = model.addJob<ParseMaterialMappingTask>("ParseMaterialMapping", parseMaterialMappingInputs);
|
const auto materialMapping = model.addJob<ParseMaterialMappingTask>("ParseMaterialMapping", parseMaterialMappingInputs);
|
||||||
|
@ -198,7 +209,7 @@ namespace baker {
|
||||||
const auto blendshapesPerMeshOut = model.addJob<BuildBlendshapesTask>("BuildBlendshapes", buildBlendshapesInputs);
|
const auto blendshapesPerMeshOut = model.addJob<BuildBlendshapesTask>("BuildBlendshapes", buildBlendshapesInputs);
|
||||||
const auto buildMeshesInputs = BuildMeshesTask::Input(meshesIn, graphicsMeshes, normalsPerMesh, tangentsPerMesh, blendshapesPerMeshOut).asVarying();
|
const auto buildMeshesInputs = BuildMeshesTask::Input(meshesIn, graphicsMeshes, normalsPerMesh, tangentsPerMesh, blendshapesPerMeshOut).asVarying();
|
||||||
const auto meshesOut = model.addJob<BuildMeshesTask>("BuildMeshes", buildMeshesInputs);
|
const auto meshesOut = model.addJob<BuildMeshesTask>("BuildMeshes", buildMeshesInputs);
|
||||||
const auto buildModelInputs = BuildModelTask::Input(hfmModelIn, meshesOut, jointsOut, jointRotationOffsets, jointIndices, flowData, shapeVerticesPerJoint).asVarying();
|
const auto buildModelInputs = BuildModelTask::Input(hfmModelIn, meshesOut, jointsOut, jointRotationOffsets, jointIndices, flowData, shapeVerticesPerJoint, shapesOut, modelExtentsOut).asVarying();
|
||||||
const auto hfmModelOut = model.addJob<BuildModelTask>("BuildModel", buildModelInputs);
|
const auto hfmModelOut = model.addJob<BuildModelTask>("BuildModel", buildModelInputs);
|
||||||
|
|
||||||
output = Output(hfmModelOut, materialMapping, dracoMeshes, dracoErrors, materialList);
|
output = Output(hfmModelOut, materialMapping, dracoMeshes, dracoErrors, materialList);
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
//
|
||||||
|
// CalculateExtentsTask.cpp
|
||||||
|
// model-baker/src/model-baker
|
||||||
|
//
|
||||||
|
// Created by Sabrina Shanman on 2019/10/04.
|
||||||
|
// Copyright 2019 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "CalculateExtentsTask.h"
|
||||||
|
|
||||||
|
#include "hfm/HFMModelMath.h"
|
||||||
|
|
||||||
|
void CalculateExtentsTask::run(const baker::BakeContextPointer& context, const Input& input, Output& output) {
|
||||||
|
const auto& modelExtentsIn = input.get0();
|
||||||
|
const auto& meshes = input.get1();
|
||||||
|
const auto& shapesIn = input.get2();
|
||||||
|
const auto& joints = input.get3();
|
||||||
|
auto& modelExtentsOut = output.edit0();
|
||||||
|
auto& shapesOut = output.edit1();
|
||||||
|
|
||||||
|
shapesOut.reserve(shapesIn.size());
|
||||||
|
for (size_t i = 0; i < shapesIn.size(); ++i) {
|
||||||
|
shapesOut.push_back(shapesIn[i]);
|
||||||
|
auto& shapeOut = shapesOut.back();
|
||||||
|
|
||||||
|
auto& shapeExtents = shapeOut.transformedExtents;
|
||||||
|
if (shapeExtents.isValid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
hfm::calculateExtentsForShape(shapeOut, meshes, joints);
|
||||||
|
}
|
||||||
|
|
||||||
|
modelExtentsOut = modelExtentsIn;
|
||||||
|
if (!modelExtentsOut.isValid()) {
|
||||||
|
hfm::calculateExtentsForModel(modelExtentsOut, shapesOut);
|
||||||
|
}
|
||||||
|
}
|
29
libraries/model-baker/src/model-baker/CalculateExtentsTask.h
Normal file
29
libraries/model-baker/src/model-baker/CalculateExtentsTask.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
//
|
||||||
|
// CalculateExtentsTask.h
|
||||||
|
// model-baker/src/model-baker
|
||||||
|
//
|
||||||
|
// Created by Sabrina Shanman on 2019/10/04.
|
||||||
|
// Copyright 2019 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_CalculateExtentsTask_h
|
||||||
|
#define hifi_CalculateExtentsTask_h
|
||||||
|
|
||||||
|
#include "Engine.h"
|
||||||
|
#include "hfm/HFM.h"
|
||||||
|
|
||||||
|
// Calculates any undefined extents in the shapes and the model. Precalculated extents will be left alone.
|
||||||
|
// Bind extents will currently not be calculated
|
||||||
|
class CalculateExtentsTask {
|
||||||
|
public:
|
||||||
|
using Input = baker::VaryingSet4<Extents, std::vector<hfm::Mesh>, std::vector<hfm::Shape>, std::vector<hfm::Joint>>;
|
||||||
|
using Output = baker::VaryingSet2<Extents, std::vector<hfm::Shape>>;
|
||||||
|
using JobModel = baker::Job::ModelIO<CalculateExtentsTask, Input, Output>;
|
||||||
|
|
||||||
|
void run(const baker::BakeContextPointer& context, const Input& input, Output& output);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_CalculateExtentsTask_h
|
|
@ -30,7 +30,7 @@ void CalculateMeshTangentsTask::run(const baker::BakeContextPointer& context, co
|
||||||
// Otherwise confirm if we have the normals and texcoords needed
|
// Otherwise confirm if we have the normals and texcoords needed
|
||||||
if (!tangentsIn.empty()) {
|
if (!tangentsIn.empty()) {
|
||||||
tangentsOut = tangentsIn.toStdVector();
|
tangentsOut = tangentsIn.toStdVector();
|
||||||
} else if (!normals.empty() && mesh.vertices.size() == mesh.texCoords.size()) {
|
} else if (!normals.empty() && mesh.vertices.size() <= mesh.texCoords.size()) {
|
||||||
tangentsOut.resize(normals.size());
|
tangentsOut.resize(normals.size());
|
||||||
baker::calculateTangents(mesh,
|
baker::calculateTangents(mesh,
|
||||||
[&mesh, &normals, &tangentsOut](int firstIndex, int secondIndex, glm::vec3* outVertices, glm::vec2* outTexCoords, glm::vec3& outNormal) {
|
[&mesh, &normals, &tangentsOut](int firstIndex, int secondIndex, glm::vec3* outVertices, glm::vec2* outTexCoords, glm::vec3& outNormal) {
|
||||||
|
|
11
tests-manual/fbx/CMakeLists.txt
Normal file
11
tests-manual/fbx/CMakeLists.txt
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
set(TARGET_NAME fbx-test)
|
||||||
|
# This is not a testcase -- just set it up as a regular hifi project
|
||||||
|
setup_hifi_project(Quick Gui)
|
||||||
|
setup_memory_debugger()
|
||||||
|
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||||
|
|
||||||
|
file(GLOB_RECURSE GLB_TEST_FILES "c:/Users/bdavi/git/glTF-Sample-Models/2.0/*.glb")
|
||||||
|
list(JOIN GLB_TEST_FILES "|" GLB_TEST_FILES)
|
||||||
|
target_compile_definitions(${TARGET_NAME} PRIVATE -DGLB_TEST_FILES="${GLB_TEST_FILES}")
|
||||||
|
link_hifi_libraries(shared graphics networking image gpu hfm fbx)
|
||||||
|
package_libraries_for_deployment()
|
77
tests-manual/fbx/src/main.cpp
Normal file
77
tests-manual/fbx/src/main.cpp
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2018/01/11
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QtCore/qglobal.h>
|
||||||
|
#include <QtCore/QFile>
|
||||||
|
|
||||||
|
#include <QtGui/QGuiApplication>
|
||||||
|
|
||||||
|
#include <GLTFSerializer.h>
|
||||||
|
#include <shared/FileUtils.h>
|
||||||
|
#include <ResourceManager.h>
|
||||||
|
#include <DependencyManager.h>
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
// Currently only used by testing code
|
||||||
|
inline std::list<std::string> splitString(const std::string& source, const char delimiter = ' ') {
|
||||||
|
std::list<std::string> result;
|
||||||
|
size_t start = 0, next;
|
||||||
|
|
||||||
|
while (std::string::npos != (next = source.find(delimiter, start))) {
|
||||||
|
std::string sub = source.substr(start, next - start);
|
||||||
|
if (!sub.empty()) {
|
||||||
|
result.push_back(sub);
|
||||||
|
}
|
||||||
|
start = next + 1;
|
||||||
|
}
|
||||||
|
if (source.size() > start) {
|
||||||
|
result.push_back(source.substr(start));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<std::string> getGlbTestFiles() {
|
||||||
|
return splitString(GLB_TEST_FILES, '|');
|
||||||
|
}
|
||||||
|
|
||||||
|
QtMessageHandler originalHandler;
|
||||||
|
|
||||||
|
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
OutputDebugStringA(message.toStdString().c_str());
|
||||||
|
OutputDebugStringA("\n");
|
||||||
|
#endif
|
||||||
|
originalHandler(type, context, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray readFileBytes(const std::string& filename) {
|
||||||
|
QFile file(filename.c_str());
|
||||||
|
file.open(QFile::ReadOnly);
|
||||||
|
QByteArray result = file.readAll();
|
||||||
|
file.close();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void processFile(const std::string& filename) {
|
||||||
|
qDebug() << filename.c_str();
|
||||||
|
GLTFSerializer().read(readFileBytes(filename), {}, QUrl::fromLocalFile(filename.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
QCoreApplication app{ argc, argv };
|
||||||
|
originalHandler = qInstallMessageHandler(messageHandler);
|
||||||
|
|
||||||
|
DependencyManager::set<ResourceManager>(false);
|
||||||
|
|
||||||
|
//processFile("c:/Users/bdavi/git/glTF-Sample-Models/2.0/Box/glTF-Binary/Box.glb");
|
||||||
|
|
||||||
|
for (const auto& testFile : getGlbTestFiles()) {
|
||||||
|
processFile(testFile);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue