mirror of
https://github.com/lubosz/overte.git
synced 2025-04-08 22:42:31 +02:00
Merge pull request #16324 from sabrina-shanman/instancing_gltf
(DEV-561) Enable instancing for GLTF static meshes (WIP)
This commit is contained in:
commit
f402dbbf2b
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) {
|
||||
// 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
|
||||
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
|
||||
if (clusterIDs.size() > 0) {
|
||||
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
|
||||
// of skinning information in FBX
|
||||
QString jointID = _connectionChildMap.value(clusterID);
|
||||
hfmCluster.jointIndex = modelIDs.indexOf(jointID);
|
||||
if (hfmCluster.jointIndex == -1) {
|
||||
int indexOfJointID = modelIDs.indexOf(jointID);
|
||||
if (indexOfJointID == -1) {
|
||||
qCDebug(modelformat) << "Joint not in model list: " << jointID;
|
||||
hfmCluster.jointIndex = 0;
|
||||
} else {
|
||||
hfmCluster.jointIndex = (uint32_t)indexOfJointID;
|
||||
}
|
||||
|
||||
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
|
||||
HFMCluster cluster;
|
||||
cluster.jointIndex = rootJointIndex;
|
||||
cluster.jointIndex = transformIndex;
|
||||
clusters.push_back(cluster);
|
||||
|
||||
// Skinned mesh instances have a dynamic transform
|
||||
|
@ -1676,7 +1676,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
|
|||
}
|
||||
} else {
|
||||
// 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
|
||||
if (joint.hasGeometricOffset) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -38,14 +38,14 @@ struct GLTFAsset {
|
|||
|
||||
struct GLTFNode {
|
||||
QString name;
|
||||
int camera;
|
||||
int mesh;
|
||||
int camera{ -1 };
|
||||
int mesh{ -1 };
|
||||
QVector<int> children;
|
||||
QVector<double> translation;
|
||||
QVector<double> rotation;
|
||||
QVector<double> scale;
|
||||
QVector<double> matrix;
|
||||
QVector<glm::mat4> transforms;
|
||||
glm::mat4 transform;
|
||||
int skin;
|
||||
QVector<int> skeletons;
|
||||
QString jointName;
|
||||
|
@ -85,6 +85,8 @@ struct GLTFNode {
|
|||
qCDebug(modelformat) << "skeletons: " << skeletons;
|
||||
}
|
||||
}
|
||||
|
||||
void normalizeTransform();
|
||||
};
|
||||
|
||||
// Meshes
|
||||
|
@ -460,15 +462,56 @@ struct GLTFMaterial {
|
|||
// Accesors
|
||||
|
||||
namespace GLTFAccessorType {
|
||||
enum Values {
|
||||
SCALAR = 0,
|
||||
VEC2,
|
||||
VEC3,
|
||||
VEC4,
|
||||
MAT2,
|
||||
MAT3,
|
||||
MAT4
|
||||
enum Value {
|
||||
SCALAR = 1,
|
||||
VEC2 = 2,
|
||||
VEC3 = 3,
|
||||
VEC4 = 4,
|
||||
MAT2 = 5,
|
||||
MAT3 = 9,
|
||||
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 {
|
||||
enum Values {
|
||||
|
@ -760,6 +803,13 @@ struct GLTFFile {
|
|||
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 {
|
||||
|
@ -774,7 +824,7 @@ private:
|
|||
hifi::URL _url;
|
||||
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 generateTargetData(int index, float weight, QVector<glm::vec3>& returnVector);
|
||||
|
||||
|
@ -843,6 +893,9 @@ private:
|
|||
template <typename T>
|
||||
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,
|
||||
const QVector<glm::vec3>& in_normals, QVector<int>& out_indices,
|
||||
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 "CalculateBlendshapeTangentsTask.h"
|
||||
#include "PrepareJointsTask.h"
|
||||
#include "CalculateExtentsTask.h"
|
||||
#include "BuildDracoMeshTask.h"
|
||||
#include "ParseFlowDataTask.h"
|
||||
|
||||
|
@ -29,7 +30,7 @@ namespace baker {
|
|||
class GetModelPartsTask {
|
||||
public:
|
||||
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>;
|
||||
|
||||
void run(const BakeContextPointer& context, const Input& input, Output& output) {
|
||||
|
@ -46,6 +47,7 @@ namespace baker {
|
|||
output.edit5() = hfmModelIn->shapes;
|
||||
output.edit6() = hfmModelIn->skinDeformers;
|
||||
output.edit7() = hfmModelIn->skinClusters;
|
||||
output.edit8() = hfmModelIn->meshExtents;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -106,7 +108,7 @@ namespace baker {
|
|||
|
||||
class BuildModelTask {
|
||||
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 JobModel = Job::ModelIO<BuildModelTask, Input, Output>;
|
||||
|
||||
|
@ -118,6 +120,8 @@ namespace baker {
|
|||
hfmModelOut->jointIndices = input.get4();
|
||||
hfmModelOut->flowData = input.get5();
|
||||
hfmModelOut->shapeVertices = input.get6();
|
||||
hfmModelOut->shapes = input.get7();
|
||||
hfmModelOut->meshExtents = input.get8();
|
||||
// These depend on the ShapeVertices
|
||||
// TODO: Create a task for this rather than calculating it here
|
||||
hfmModelOut->computeKdops();
|
||||
|
@ -144,7 +148,8 @@ namespace baker {
|
|||
const auto jointsIn = modelPartsIn.getN<GetModelPartsTask::Output>(4);
|
||||
const auto shapesIn = modelPartsIn.getN<GetModelPartsTask::Output>(5);
|
||||
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
|
||||
// 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
|
||||
// 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);
|
||||
// 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();
|
||||
|
@ -175,6 +180,12 @@ namespace baker {
|
|||
const auto jointRotationOffsets = jointInfoOut.getN<PrepareJointsTask::Output>(1);
|
||||
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
|
||||
const auto parseMaterialMappingInputs = ParseMaterialMappingTask::Input(mapping, materialMappingBaseURL).asVarying();
|
||||
const auto materialMapping = model.addJob<ParseMaterialMappingTask>("ParseMaterialMapping", parseMaterialMappingInputs);
|
||||
|
@ -198,7 +209,7 @@ namespace baker {
|
|||
const auto blendshapesPerMeshOut = model.addJob<BuildBlendshapesTask>("BuildBlendshapes", buildBlendshapesInputs);
|
||||
const auto buildMeshesInputs = BuildMeshesTask::Input(meshesIn, graphicsMeshes, normalsPerMesh, tangentsPerMesh, blendshapesPerMeshOut).asVarying();
|
||||
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);
|
||||
|
||||
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
|
||||
if (!tangentsIn.empty()) {
|
||||
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());
|
||||
baker::calculateTangents(mesh,
|
||||
[&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