mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 17:14:59 +02:00
Merge pull request #16359 from samcake/instancing
DNM: Instancing: Rendering correctly the DEFORMED hfm::SHapes
This commit is contained in:
commit
78cb3ac1c3
19 changed files with 396 additions and 306 deletions
|
@ -30,6 +30,34 @@ AnimSkeleton::AnimSkeleton(const HFMModel& hfmModel) {
|
|||
|
||||
// we make a copy of the inverseBindMatrices in order to prevent mutating the model bind pose
|
||||
// when we are dealing with a joint offset in the model
|
||||
for (int i = 0; i < (int)hfmModel.skinDeformers.size(); i++) {
|
||||
const auto& defor = hfmModel.skinDeformers[i];
|
||||
std::vector<HFMCluster> dummyClustersList;
|
||||
|
||||
for (int j = 0; j < defor.clusters.size(); j++) {
|
||||
std::vector<glm::mat4> bindMatrices;
|
||||
// cast into a non-const reference, so we can mutate the FBXCluster
|
||||
HFMCluster& cluster = const_cast<HFMCluster&>(defor.clusters.at(j));
|
||||
|
||||
HFMCluster localCluster;
|
||||
localCluster.jointIndex = cluster.jointIndex;
|
||||
localCluster.inverseBindMatrix = cluster.inverseBindMatrix;
|
||||
localCluster.inverseBindTransform.evalFromRawMatrix(localCluster.inverseBindMatrix);
|
||||
|
||||
// if we have a joint offset in the fst file then multiply its inverse by the
|
||||
// model cluster inverse bind matrix
|
||||
if (hfmModel.jointRotationOffsets.contains(cluster.jointIndex)) {
|
||||
AnimPose localOffset(hfmModel.jointRotationOffsets[cluster.jointIndex], glm::vec3());
|
||||
localCluster.inverseBindMatrix = (glm::mat4)localOffset.inverse() * cluster.inverseBindMatrix;
|
||||
localCluster.inverseBindTransform.evalFromRawMatrix(localCluster.inverseBindMatrix);
|
||||
}
|
||||
dummyClustersList.push_back(localCluster);
|
||||
}
|
||||
_clusterBindMatrixOriginalValues.push_back(dummyClustersList);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
for (int i = 0; i < (int)hfmModel.meshes.size(); i++) {
|
||||
const HFMMesh& mesh = hfmModel.meshes.at(i);
|
||||
std::vector<HFMCluster> dummyClustersList;
|
||||
|
@ -55,6 +83,7 @@ AnimSkeleton::AnimSkeleton(const HFMModel& hfmModel) {
|
|||
}
|
||||
_clusterBindMatrixOriginalValues.push_back(dummyClustersList);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
AnimSkeleton::AnimSkeleton(const std::vector<HFMJoint>& joints, const QMap<int, glm::quat> jointOffsets) {
|
||||
|
|
|
@ -70,6 +70,8 @@ public:
|
|||
std::vector<int> lookUpJointIndices(const std::vector<QString>& jointNames) const;
|
||||
const HFMCluster getClusterBindMatricesOriginalValues(const int meshIndex, const int clusterIndex) const { return _clusterBindMatrixOriginalValues[meshIndex][clusterIndex]; }
|
||||
|
||||
// const HFMCluster getClusterBindMatricesOriginalValues(const int meshIndex, const int clusterIndex) const { return _clusterBindMatrixOriginalValues[meshIndex][clusterIndex]; }
|
||||
|
||||
protected:
|
||||
void buildSkeletonFromJoints(const std::vector<HFMJoint>& joints, const QMap<int, glm::quat> jointOffsets);
|
||||
|
||||
|
|
|
@ -1463,9 +1463,6 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
|
|||
// see if any materials have texture children
|
||||
bool materialsHaveTextures = checkMaterialsHaveTextures(_hfmMaterials, _textureFilenames, _connectionChildMap);
|
||||
|
||||
// Note that the transforms in the TransformNodes are initially in world-space, and need to be converted to parent-space
|
||||
std::vector<hfm::TransformNode> transformNodes;
|
||||
|
||||
for (QMap<QString, ExtractedMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) {
|
||||
const QString& meshID = it.key();
|
||||
const ExtractedMesh& extracted = it.value();
|
||||
|
@ -1505,7 +1502,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
|
|||
hfm::Shape& shape = partShapes[i];
|
||||
shape.mesh = meshIndex;
|
||||
shape.meshPart = i;
|
||||
shape.transform = transformIndex;
|
||||
shape.joint = transformIndex;
|
||||
|
||||
auto matName = mesh.parts[i].materialID;
|
||||
auto materialIt = materialNameToID.find(matName.toStdString());
|
||||
|
@ -1595,10 +1592,10 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
|
|||
}
|
||||
|
||||
// whether we're skinned depends on how many clusters are attached
|
||||
if (clusterIDs.size() > 1) {
|
||||
hfm::DynamicTransform dynamicTransform;
|
||||
auto& clusters = dynamicTransform.clusters;
|
||||
std::vector<hfm::Deformer> deformers;
|
||||
if (clusterIDs.size() > 0) {
|
||||
hfm::SkinDeformer skinDeformer;
|
||||
auto& clusters = skinDeformer.clusters;
|
||||
std::vector<hfm::SkinCluster> skinClusters;
|
||||
for (const auto& clusterID : clusterIDs) {
|
||||
HFMCluster hfmCluster;
|
||||
const Cluster& fbxCluster = fbxClusters[clusterID];
|
||||
|
@ -1642,38 +1639,43 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
|
|||
clusters.push_back(cluster);
|
||||
|
||||
// Skinned mesh instances have a dynamic transform
|
||||
dynamicTransform.deformers.reserve(clusterIDs.size());
|
||||
clusters.reserve(clusterIDs.size());
|
||||
skinDeformer.skinClusterIndices.reserve(clusterIDs.size());
|
||||
for (const auto& clusterID : clusterIDs) {
|
||||
const Cluster& fbxCluster = fbxClusters[clusterID];
|
||||
dynamicTransform.deformers.emplace_back();
|
||||
deformers.emplace_back();
|
||||
hfm::Deformer& deformer = deformers.back();
|
||||
skinDeformer.skinClusterIndices.emplace_back();
|
||||
skinClusters.emplace_back();
|
||||
hfm::SkinCluster& skinCluster = skinClusters.back();
|
||||
size_t indexWeightPairs = (size_t)std::min(fbxCluster.indices.size(), fbxCluster.weights.size());
|
||||
deformer.indices.reserve(indexWeightPairs);
|
||||
deformer.weights.reserve(indexWeightPairs);
|
||||
for (int i = 0; i < (int)indexWeightPairs; i++) {
|
||||
int oldIndex = fbxCluster.indices[i];
|
||||
uint32_t newIndex = (uint32_t)extracted.newIndices.value(oldIndex);
|
||||
deformer.indices.push_back(newIndex);
|
||||
deformer.indices.push_back((float)fbxCluster.weights[i]);
|
||||
skinCluster.indices.reserve(indexWeightPairs);
|
||||
skinCluster.weights.reserve(indexWeightPairs);
|
||||
|
||||
for (int j = 0; j < fbxCluster.indices.size(); j++) {
|
||||
int oldIndex = fbxCluster.indices.at(j);
|
||||
float weight = fbxCluster.weights.at(j);
|
||||
for (QMultiHash<int, int>::const_iterator it = extracted.newIndices.constFind(oldIndex);
|
||||
it != extracted.newIndices.end() && it.key() == oldIndex; it++) {
|
||||
int newIndex = it.value();
|
||||
|
||||
skinCluster.indices.push_back(newIndex);
|
||||
skinCluster.weights.push_back(weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store this model's deformers, this dynamic transform's deformer IDs
|
||||
uint32_t deformerMinID = (uint32_t)hfmModel.deformers.size();
|
||||
hfmModel.deformers.insert(hfmModel.deformers.end(), deformers.cbegin(), deformers.cend());
|
||||
dynamicTransform.deformers.resize(deformers.size());
|
||||
std::iota(dynamicTransform.deformers.begin(), dynamicTransform.deformers.end(), deformerMinID);
|
||||
uint32_t deformerMinID = (uint32_t)hfmModel.skinClusters.size();
|
||||
hfmModel.skinClusters.insert(hfmModel.skinClusters.end(), skinClusters.cbegin(), skinClusters.cend());
|
||||
skinDeformer.skinClusterIndices.resize(skinClusters.size());
|
||||
std::iota(skinDeformer.skinClusterIndices.begin(), skinDeformer.skinClusterIndices.end(), deformerMinID);
|
||||
|
||||
// Store the model's dynamic transform, and put its ID in the shapes
|
||||
hfmModel.dynamicTransforms.push_back(dynamicTransform);
|
||||
uint32_t dynamicTransformID = (uint32_t)(hfmModel.dynamicTransforms.size() - 1);
|
||||
hfmModel.skinDeformers.push_back(skinDeformer);
|
||||
uint32_t skinDeformerID = (uint32_t)(hfmModel.skinDeformers.size() - 1);
|
||||
for (hfm::Shape& shape : partShapes) {
|
||||
shape.dynamicTransform = dynamicTransformID;
|
||||
shape.skinDeformer = skinDeformerID;
|
||||
}
|
||||
} else {
|
||||
// this is a single-joint mesh
|
||||
// this is a no cluster mesh
|
||||
HFMJoint& joint = hfmModel.joints[rootJointIndex];
|
||||
|
||||
// Apply geometric offset, if present, by transforming the vertices directly
|
||||
|
|
|
@ -242,17 +242,20 @@ public:
|
|||
QVector<glm::vec3> colors;
|
||||
QVector<glm::vec2> texCoords;
|
||||
QVector<glm::vec2> texCoords1;
|
||||
QVector<uint16_t> clusterIndices; // DEPRECATED (see hfm::Shape::dynamicTransform, hfm::DynamicTransform::deformers, hfm::Deformer)
|
||||
QVector<uint16_t> clusterWeights; // DEPRECATED (see hfm::Shape::dynamicTransform, hfm::DynamicTransform::deformers, hfm::Deformer)
|
||||
QVector<int32_t> originalIndices;
|
||||
|
||||
QVector<Cluster> clusters; // DEPRECATED (see hfm::Shape::dynamicTransform, hfm::DynamicTransform::clusters)
|
||||
|
||||
Extents meshExtents; // DEPRECATED (see hfm::Shape::transformedExtents)
|
||||
glm::mat4 modelTransform; // DEPRECATED (see hfm::Joint::globalTransform, hfm::Shape::transform, hfm::Model::joints)
|
||||
|
||||
// Skinning cluster attributes
|
||||
QVector<uint16_t> clusterIndices;
|
||||
QVector<uint16_t> clusterWeights;
|
||||
|
||||
// Blendshape attributes
|
||||
QVector<Blendshape> blendshapes;
|
||||
|
||||
|
||||
QVector<int32_t> originalIndices; // Original indices of the vertices
|
||||
unsigned int meshIndex; // the order the meshes appeared in the object file
|
||||
|
||||
graphics::MeshPointer _mesh;
|
||||
|
@ -293,26 +296,17 @@ public:
|
|||
bool shouldInitCollisions() const { return _collisionsConfig.size() > 0; }
|
||||
};
|
||||
|
||||
// DEPRECATED in favor of using hfm::Joint
|
||||
class TransformNode {
|
||||
public:
|
||||
uint32_t parent { 0 };
|
||||
Transform transform;
|
||||
};
|
||||
|
||||
// Formerly contained in hfm::Mesh
|
||||
class Deformer {
|
||||
class SkinCluster {
|
||||
public:
|
||||
std::vector<uint32_t> indices;
|
||||
std::vector<float> weights;
|
||||
};
|
||||
|
||||
class DynamicTransform {
|
||||
class SkinDeformer {
|
||||
public:
|
||||
std::vector<uint16_t> deformers;
|
||||
std::vector<Cluster> clusters; // affect the deformer of the same index
|
||||
std::vector<uint32_t> blendshapes;
|
||||
// There are also the meshExtents and modelTransform, which for now are left in hfm::Mesh
|
||||
std::vector<uint16_t> skinClusterIndices;
|
||||
std::vector<Cluster> clusters;
|
||||
};
|
||||
|
||||
// The lightweight model part description.
|
||||
|
@ -321,10 +315,10 @@ public:
|
|||
uint32_t mesh { UNDEFINED_KEY };
|
||||
uint32_t meshPart { UNDEFINED_KEY };
|
||||
uint32_t material { UNDEFINED_KEY };
|
||||
uint32_t transform { UNDEFINED_KEY }; // The hfm::Joint associated with this shape, containing transform information
|
||||
uint32_t joint { UNDEFINED_KEY }; // The hfm::Joint associated with this shape, containing transform information
|
||||
// TODO: Have all serializers calculate hfm::Shape::transformedExtents in world space where they previously calculated hfm::Mesh::meshExtents. Change all code that uses hfm::Mesh::meshExtents to use this instead.
|
||||
Extents transformedExtents; // The precise extents of the meshPart vertices in world space, after transform information is applied, while not taking into account rigging/skinning
|
||||
uint32_t dynamicTransform { UNDEFINED_KEY };
|
||||
uint32_t skinDeformer { UNDEFINED_KEY };
|
||||
};
|
||||
|
||||
/// The runtime model format.
|
||||
|
@ -341,10 +335,9 @@ public:
|
|||
|
||||
std::vector<Mesh> meshes;
|
||||
std::vector<Material> materials;
|
||||
std::vector<Deformer> deformers;
|
||||
|
||||
std::vector<TransformNode> transforms;
|
||||
std::vector<DynamicTransform> dynamicTransforms;
|
||||
std::vector<SkinDeformer> skinDeformers;
|
||||
std::vector<SkinCluster> skinClusters;
|
||||
|
||||
std::vector<Joint> joints;
|
||||
QHash<QString, int> jointIndices; ///< 1-based, so as to more easily detect missing indices
|
||||
|
|
|
@ -29,7 +29,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::DynamicTransform>, std::vector<hfm::Deformer>>;
|
||||
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 JobModel = Job::ModelIO<GetModelPartsTask, Input, Output>;
|
||||
|
||||
void run(const BakeContextPointer& context, const Input& input, Output& output) {
|
||||
|
@ -44,8 +44,8 @@ namespace baker {
|
|||
}
|
||||
output.edit4() = hfmModelIn->joints;
|
||||
output.edit5() = hfmModelIn->shapes;
|
||||
output.edit6() = hfmModelIn->dynamicTransforms;
|
||||
output.edit7() = hfmModelIn->deformers;
|
||||
output.edit6() = hfmModelIn->skinDeformers;
|
||||
output.edit7() = hfmModelIn->skinClusters;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -143,7 +143,7 @@ namespace baker {
|
|||
const auto blendshapesPerMeshIn = modelPartsIn.getN<GetModelPartsTask::Output>(3);
|
||||
const auto jointsIn = modelPartsIn.getN<GetModelPartsTask::Output>(4);
|
||||
const auto shapesIn = modelPartsIn.getN<GetModelPartsTask::Output>(5);
|
||||
const auto dynamicTransformsIn = modelPartsIn.getN<GetModelPartsTask::Output>(6);
|
||||
const auto skinDeformersIn = modelPartsIn.getN<GetModelPartsTask::Output>(6);
|
||||
const auto deformersIn = modelPartsIn.getN<GetModelPartsTask::Output>(7);
|
||||
|
||||
// Calculate normals and tangents for meshes and blendshapes if they do not exist
|
||||
|
@ -158,14 +158,14 @@ 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, dynamicTransformsIn, deformersIn).asVarying();
|
||||
const auto reweightDeformersInputs = ReweightDeformersTask::Input(meshesIn, shapesIn, skinDeformersIn, deformersIn).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, dynamicTransformsIn, reweightedDeformers).asVarying();
|
||||
const auto collectShapeVerticesInputs = CollectShapeVerticesTask::Input(meshesIn, shapesIn, jointsIn, skinDeformersIn, reweightedDeformers).asVarying();
|
||||
const auto shapeVerticesPerJoint = model.addJob<CollectShapeVerticesTask>("CollectShapeVertices", collectShapeVerticesInputs);
|
||||
|
||||
// Build the graphics::MeshPointer for each hfm::Mesh
|
||||
const auto buildGraphicsMeshInputs = BuildGraphicsMeshTask::Input(meshesIn, url, meshIndicesToModelNames, normalsPerMesh, tangentsPerMesh, shapesIn, dynamicTransformsIn, reweightedDeformers).asVarying();
|
||||
const auto buildGraphicsMeshInputs = BuildGraphicsMeshTask::Input(meshesIn, url, meshIndicesToModelNames, normalsPerMesh, tangentsPerMesh, shapesIn, skinDeformersIn, reweightedDeformers).asVarying();
|
||||
const auto graphicsMeshes = model.addJob<BuildGraphicsMeshTask>("BuildGraphicsMesh", buildGraphicsMeshInputs);
|
||||
|
||||
// Prepare joint information
|
||||
|
|
|
@ -95,7 +95,7 @@ void buildGraphicsMesh(const hfm::Mesh& hfmMesh, graphics::MeshPointer& graphics
|
|||
HIFI_FCDEBUG_ID(model_baker(), repeatMessageID, "BuildGraphicsMeshTask -- The number of indices and weights for a deformer had different sizes and have been trimmed to match");
|
||||
}
|
||||
// Record cluster sizes
|
||||
const size_t numVertClusters = (reweightedDeformers.weightsPerVertex ? hfmMesh.clusterIndices.size() / reweightedDeformers.weightsPerVertex : 0);
|
||||
const size_t numVertClusters = (reweightedDeformers.weightsPerVertex ? reweightedDeformers.indices.size() / reweightedDeformers.weightsPerVertex : 0);
|
||||
const size_t clusterIndicesSize = numVertClusters * clusterIndiceElement.getSize();
|
||||
const size_t clusterWeightsSize = numVertClusters * clusterWeightElement.getSize();
|
||||
|
||||
|
@ -381,16 +381,16 @@ void BuildGraphicsMeshTask::run(const baker::BakeContextPointer& context, const
|
|||
const auto& normalsPerMesh = input.get3();
|
||||
const auto& tangentsPerMesh = input.get4();
|
||||
const auto& shapes = input.get5();
|
||||
const auto& dynamicTransforms = input.get6();
|
||||
const auto& skinDeformers = input.get6();
|
||||
const auto& reweightedDeformersPerMesh = input.get7();
|
||||
|
||||
// Currently, there is only (at most) one dynamicTransform per mesh
|
||||
// An undefined shape.dynamicTransform has the value hfm::UNDEFINED_KEY
|
||||
std::vector<uint32_t> dynamicTransformPerMesh;
|
||||
dynamicTransformPerMesh.resize(meshes.size(), hfm::UNDEFINED_KEY);
|
||||
// Currently, there is only (at most) one skinDeformer per mesh
|
||||
// An undefined shape.skinDeformer has the value hfm::UNDEFINED_KEY
|
||||
std::vector<uint32_t> skinDeformerPerMesh;
|
||||
skinDeformerPerMesh.resize(meshes.size(), hfm::UNDEFINED_KEY);
|
||||
for (const auto& shape : shapes) {
|
||||
uint32_t dynamicTransformIndex = shape.dynamicTransform;
|
||||
dynamicTransformPerMesh[shape.mesh] = dynamicTransformIndex;
|
||||
uint32_t skinDeformerIndex = shape.skinDeformer;
|
||||
skinDeformerPerMesh[shape.mesh] = skinDeformerIndex;
|
||||
}
|
||||
|
||||
auto& graphicsMeshes = output;
|
||||
|
@ -403,10 +403,10 @@ void BuildGraphicsMeshTask::run(const baker::BakeContextPointer& context, const
|
|||
|
||||
uint16_t numDeformerControllers = 0;
|
||||
if (reweightedDeformers.weightsPerVertex != 0) {
|
||||
uint32_t dynamicTransformIndex = dynamicTransformPerMesh[i];
|
||||
if (dynamicTransformIndex != hfm::UNDEFINED_KEY) {
|
||||
const hfm::DynamicTransform& dynamicTransform = dynamicTransforms[dynamicTransformIndex];
|
||||
numDeformerControllers = (uint16_t)dynamicTransform.deformers.size();
|
||||
uint32_t skinDeformerIndex = skinDeformerPerMesh[i];
|
||||
if (skinDeformerIndex != hfm::UNDEFINED_KEY) {
|
||||
const hfm::SkinDeformer& skinDeformer = skinDeformers[skinDeformerIndex];
|
||||
numDeformerControllers = (uint16_t)skinDeformer.skinClusterIndices.size();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
class BuildGraphicsMeshTask {
|
||||
public:
|
||||
using Input = baker::VaryingSet8<std::vector<hfm::Mesh>, hifi::URL, baker::MeshIndicesToModelNames, baker::NormalsPerMesh, baker::TangentsPerMesh, std::vector<hfm::Shape>, std::vector<hfm::DynamicTransform>, std::vector<baker::ReweightedDeformers>>;
|
||||
using Input = baker::VaryingSet8<std::vector<hfm::Mesh>, hifi::URL, baker::MeshIndicesToModelNames, baker::NormalsPerMesh, baker::TangentsPerMesh, std::vector<hfm::Shape>, std::vector<hfm::SkinDeformer>, std::vector<baker::ReweightedDeformers>>;
|
||||
using Output = std::vector<graphics::MeshPointer>;
|
||||
using JobModel = baker::Job::ModelIO<BuildGraphicsMeshTask, Input, Output>;
|
||||
|
||||
|
|
|
@ -13,15 +13,15 @@
|
|||
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
// Used to track and avoid duplicate shape vertices, as multiple shapes can have the same mesh and dynamicTransform
|
||||
// Used to track and avoid duplicate shape vertices, as multiple shapes can have the same mesh and skinDeformer
|
||||
class VertexSource {
|
||||
public:
|
||||
uint32_t mesh;
|
||||
uint32_t dynamicTransform;
|
||||
uint32_t skinDeformer;
|
||||
|
||||
bool operator==(const VertexSource& other) const {
|
||||
return mesh == other.mesh &&
|
||||
dynamicTransform == other.dynamicTransform;
|
||||
skinDeformer == other.skinDeformer;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -29,7 +29,7 @@ void CollectShapeVerticesTask::run(const baker::BakeContextPointer& context, con
|
|||
const auto& meshes = input.get0();
|
||||
const auto& shapes = input.get1();
|
||||
const auto& joints = input.get2();
|
||||
const auto& dynamicTransforms = input.get3();
|
||||
const auto& skinDeformers = input.get3();
|
||||
const auto& reweightedDeformers = input.get4();
|
||||
auto& shapeVerticesPerJoint = output;
|
||||
|
||||
|
@ -38,18 +38,18 @@ void CollectShapeVerticesTask::run(const baker::BakeContextPointer& context, con
|
|||
vertexSourcesPerJoint.resize(joints.size());
|
||||
for (size_t i = 0; i < shapes.size(); ++i) {
|
||||
const auto& shape = shapes[i];
|
||||
const uint32_t dynamicTransformKey = shape.dynamicTransform;
|
||||
if (dynamicTransformKey == hfm::UNDEFINED_KEY) {
|
||||
const uint32_t skinDeformerKey = shape.skinDeformer;
|
||||
if (skinDeformerKey == hfm::UNDEFINED_KEY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
VertexSource vertexSource;
|
||||
vertexSource.mesh = shape.mesh;
|
||||
vertexSource.dynamicTransform = dynamicTransformKey;
|
||||
vertexSource.skinDeformer = skinDeformerKey;
|
||||
|
||||
const auto& dynamicTransform = dynamicTransforms[dynamicTransformKey];
|
||||
for (size_t j = 0; j < dynamicTransform.clusters.size(); ++j) {
|
||||
const auto& cluster = dynamicTransform.clusters[j];
|
||||
const auto& skinDeformer = skinDeformers[skinDeformerKey];
|
||||
for (size_t j = 0; j < skinDeformer.clusters.size(); ++j) {
|
||||
const auto& cluster = skinDeformer.clusters[j];
|
||||
const uint32_t jointIndex = cluster.jointIndex;
|
||||
|
||||
auto& vertexSources = vertexSourcesPerJoint[jointIndex];
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
class CollectShapeVerticesTask {
|
||||
public:
|
||||
using Input = baker::VaryingSet5<std::vector<hfm::Mesh>, std::vector<hfm::Shape>, std::vector<hfm::Joint>, std::vector<hfm::DynamicTransform>, std::vector<baker::ReweightedDeformers>>;
|
||||
using Input = baker::VaryingSet5<std::vector<hfm::Mesh>, std::vector<hfm::Shape>, std::vector<hfm::Joint>, std::vector<hfm::SkinDeformer>, std::vector<baker::ReweightedDeformers>>;
|
||||
using Output = std::vector<ShapeVertices>;
|
||||
using JobModel = baker::Job::ModelIO<CollectShapeVerticesTask, Input, Output>;
|
||||
|
||||
|
|
|
@ -11,30 +11,30 @@
|
|||
|
||||
#include "ReweightDeformersTask.h"
|
||||
|
||||
baker::ReweightedDeformers getReweightedDeformers(size_t numMeshVertices, const std::vector<const hfm::Deformer*> deformers, const uint16_t weightsPerVertex) {
|
||||
baker::ReweightedDeformers getReweightedDeformers(size_t numMeshVertices, const std::vector<const hfm::SkinCluster*> skinClusters, const uint16_t weightsPerVertex) {
|
||||
baker::ReweightedDeformers reweightedDeformers;
|
||||
if (deformers.size() == 0) {
|
||||
if (skinClusters.size() == 0) {
|
||||
return reweightedDeformers;
|
||||
}
|
||||
|
||||
size_t numClusterIndices = numMeshVertices * weightsPerVertex;
|
||||
reweightedDeformers.weightsPerVertex = weightsPerVertex;
|
||||
// TODO: Consider having a rootCluster property in the DynamicTransform rather than appending the root to the end of the cluster list.
|
||||
reweightedDeformers.indices.resize(numClusterIndices, (uint16_t)(deformers.size() - 1));
|
||||
reweightedDeformers.indices.resize(numClusterIndices, (uint16_t)(skinClusters.size() - 1));
|
||||
reweightedDeformers.weights.resize(numClusterIndices, 0);
|
||||
|
||||
std::vector<float> weightAccumulators;
|
||||
weightAccumulators.resize(numClusterIndices, 0.0f);
|
||||
for (uint16_t i = 0; i < (uint16_t)deformers.size(); ++i) {
|
||||
const hfm::Deformer& deformer = *deformers[i];
|
||||
for (uint16_t i = 0; i < (uint16_t)skinClusters.size(); ++i) {
|
||||
const hfm::SkinCluster& skinCluster = *skinClusters[i];
|
||||
|
||||
if (deformer.indices.size() != deformer.weights.size()) {
|
||||
if (skinCluster.indices.size() != skinCluster.weights.size()) {
|
||||
reweightedDeformers.trimmedToMatch = true;
|
||||
}
|
||||
size_t numIndicesOrWeights = std::min(deformer.indices.size(), deformer.weights.size());
|
||||
size_t numIndicesOrWeights = std::min(skinCluster.indices.size(), skinCluster.weights.size());
|
||||
for (size_t j = 0; j < numIndicesOrWeights; ++j) {
|
||||
uint32_t index = deformer.indices[j];
|
||||
float weight = deformer.weights[j];
|
||||
uint32_t index = skinCluster.indices[j];
|
||||
float weight = skinCluster.weights[j];
|
||||
|
||||
// look for an unused slot in the weights vector
|
||||
uint32_t weightIndex = index * weightsPerVertex;
|
||||
|
@ -90,34 +90,34 @@ void ReweightDeformersTask::run(const baker::BakeContextPointer& context, const
|
|||
|
||||
const auto& meshes = input.get0();
|
||||
const auto& shapes = input.get1();
|
||||
const auto& dynamicTransforms = input.get2();
|
||||
const auto& deformers = input.get3();
|
||||
const auto& skinDeformers = input.get2();
|
||||
const auto& skinClusters = input.get3();
|
||||
auto& reweightedDeformers = output;
|
||||
|
||||
// Currently, there is only (at most) one dynamicTransform per mesh
|
||||
// An undefined shape.dynamicTransform has the value hfm::UNDEFINED_KEY
|
||||
std::vector<uint32_t> dynamicTransformPerMesh;
|
||||
dynamicTransformPerMesh.resize(meshes.size(), hfm::UNDEFINED_KEY);
|
||||
// Currently, there is only (at most) one skinDeformer per mesh
|
||||
// An undefined shape.skinDeformer has the value hfm::UNDEFINED_KEY
|
||||
std::vector<uint32_t> skinDeformerPerMesh;
|
||||
skinDeformerPerMesh.resize(meshes.size(), hfm::UNDEFINED_KEY);
|
||||
for (const auto& shape : shapes) {
|
||||
uint32_t dynamicTransformIndex = shape.dynamicTransform;
|
||||
dynamicTransformPerMesh[shape.mesh] = dynamicTransformIndex;
|
||||
uint32_t skinDeformerIndex = shape.skinDeformer;
|
||||
skinDeformerPerMesh[shape.mesh] = skinDeformerIndex;
|
||||
}
|
||||
|
||||
reweightedDeformers.reserve(meshes.size());
|
||||
for (size_t i = 0; i < meshes.size(); ++i) {
|
||||
const auto& mesh = meshes[i];
|
||||
uint32_t dynamicTransformIndex = dynamicTransformPerMesh[i];
|
||||
uint32_t skinDeformerIndex = skinDeformerPerMesh[i];
|
||||
|
||||
const hfm::DynamicTransform* dynamicTransform = nullptr;
|
||||
std::vector<const hfm::Deformer*> meshDeformers;
|
||||
if (dynamicTransformIndex != hfm::UNDEFINED_KEY) {
|
||||
dynamicTransform = &dynamicTransforms[dynamicTransformIndex];
|
||||
for (const auto& deformerIndex : dynamicTransform->deformers) {
|
||||
const auto& deformer = deformers[deformerIndex];
|
||||
meshDeformers.push_back(&deformer);
|
||||
const hfm::SkinDeformer* skinDeformer = nullptr;
|
||||
std::vector<const hfm::SkinCluster*> meshSkinClusters;
|
||||
if (skinDeformerIndex != hfm::UNDEFINED_KEY) {
|
||||
skinDeformer = &skinDeformers[skinDeformerIndex];
|
||||
for (const auto& skinClusterIndex : skinDeformer->skinClusterIndices) {
|
||||
const auto& skinCluster = skinClusters[skinClusterIndex];
|
||||
meshSkinClusters.push_back(&skinCluster);
|
||||
}
|
||||
}
|
||||
|
||||
reweightedDeformers.push_back(getReweightedDeformers((size_t)mesh.vertices.size(), meshDeformers, NUM_WEIGHTS_PER_VERTEX));
|
||||
reweightedDeformers.push_back(getReweightedDeformers((size_t)mesh.vertices.size(), meshSkinClusters, NUM_WEIGHTS_PER_VERTEX));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
class ReweightDeformersTask {
|
||||
public:
|
||||
using Input = baker::VaryingSet4<std::vector<hfm::Mesh>, std::vector<hfm::Shape>, std::vector<hfm::DynamicTransform>, std::vector<hfm::Deformer>>;
|
||||
using Input = baker::VaryingSet4<std::vector<hfm::Mesh>, std::vector<hfm::Shape>, std::vector<hfm::SkinDeformer>, std::vector<hfm::SkinCluster>>;
|
||||
using Output = std::vector<baker::ReweightedDeformers>;
|
||||
using JobModel = baker::Job::ModelIO<ReweightDeformersTask, Input, Output>;
|
||||
|
||||
|
|
|
@ -295,7 +295,6 @@ void ModelResource::onGeometryMappingLoaded(bool success) {
|
|||
if (success && _modelResource) {
|
||||
_hfmModel = _modelResource->_hfmModel;
|
||||
_materialMapping = _modelResource->_materialMapping;
|
||||
// _meshParts = _modelResource->_meshParts;
|
||||
_meshes = _modelResource->_meshes;
|
||||
_materials = _modelResource->_materials;
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
|
||||
using namespace render;
|
||||
|
||||
CauterizedMeshPartPayload::CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform)
|
||||
: ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, offsetTransform) {}
|
||||
CauterizedMeshPartPayload::CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform)
|
||||
: ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform) {}
|
||||
|
||||
void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices,
|
||||
const std::vector<glm::mat4>& cauterizedClusterMatrices) {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
class CauterizedMeshPartPayload : public ModelMeshPartPayload {
|
||||
public:
|
||||
CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform);
|
||||
CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform);
|
||||
|
||||
// matrix palette skinning
|
||||
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices,
|
||||
|
|
|
@ -32,8 +32,40 @@ bool CauterizedModel::updateGeometry() {
|
|||
bool needsFullUpdate = Model::updateGeometry();
|
||||
if (_isCauterized && needsFullUpdate) {
|
||||
assert(_cauterizeMeshStates.empty());
|
||||
/* const HFMModel& hfmModel = getHFMModel();
|
||||
const auto& hfmDynamicTransforms = hfmModel.skinDeformers;
|
||||
for (int i = 0; i < hfmDynamicTransforms.size(); i++) {
|
||||
const auto& dynT = hfmDynamicTransforms[i];
|
||||
MeshState state;
|
||||
if (_useDualQuaternionSkinning) {
|
||||
state.clusterDualQuaternions.resize(dynT.clusters.size());
|
||||
} else {
|
||||
state.clusterMatrices.resize(dynT.clusters.size());
|
||||
}
|
||||
_cauterizeMeshStates.append(state);
|
||||
_meshStates.push_back(state);
|
||||
}*/
|
||||
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
foreach (const HFMMesh& mesh, hfmModel.meshes) {
|
||||
const auto& hfmDynamicTransforms = hfmModel.skinDeformers;
|
||||
int i = 0;
|
||||
/* for (const auto& mesh: hfmModel.meshes) {
|
||||
MeshState state;
|
||||
state.clusterDualQuaternions.resize(mesh.clusters.size());
|
||||
state.clusterMatrices.resize(mesh.clusters.size());
|
||||
_meshStates.push_back(state);
|
||||
i++;
|
||||
}
|
||||
*/
|
||||
for (int i = 0; i < hfmDynamicTransforms.size(); i++) {
|
||||
const auto& dynT = hfmDynamicTransforms[i];
|
||||
MeshState state;
|
||||
state.clusterDualQuaternions.resize(dynT.clusters.size());
|
||||
state.clusterMatrices.resize(dynT.clusters.size());
|
||||
_cauterizeMeshStates.push_back(state);
|
||||
}
|
||||
|
||||
/* foreach (const HFMMesh& mesh, hfmModel.meshes) {
|
||||
Model::MeshState state;
|
||||
if (_useDualQuaternionSkinning) {
|
||||
state.clusterDualQuaternions.resize(mesh.clusters.size());
|
||||
|
@ -42,7 +74,7 @@ bool CauterizedModel::updateGeometry() {
|
|||
state.clusterMatrices.resize(mesh.clusters.size());
|
||||
_cauterizeMeshStates.append(state);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
return needsFullUpdate;
|
||||
}
|
||||
|
@ -52,11 +84,6 @@ void CauterizedModel::createRenderItemSet() {
|
|||
assert(isLoaded());
|
||||
const auto& meshes = _renderGeometry->getMeshes();
|
||||
|
||||
// all of our mesh vectors must match in size
|
||||
if (meshes.size() != _meshStates.size()) {
|
||||
qCDebug(renderutils) << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet.";
|
||||
return;
|
||||
}
|
||||
|
||||
// We should not have any existing renderItems if we enter this section of code
|
||||
Q_ASSERT(_modelMeshRenderItems.isEmpty());
|
||||
|
@ -73,8 +100,23 @@ void CauterizedModel::createRenderItemSet() {
|
|||
offset.setScale(_scale);
|
||||
offset.postTranslate(_offset);
|
||||
|
||||
Transform::mult(transform, transform, offset);
|
||||
|
||||
// Run through all of the meshes, and place them into their segregated, but unsorted buckets
|
||||
// Run through all of the meshes, and place them into their segregated, but unsorted buckets
|
||||
int shapeID = 0;
|
||||
const auto& shapes = _renderGeometry->getHFMModel().shapes;
|
||||
for (shapeID; shapeID < shapes.size(); shapeID++) {
|
||||
const auto& shape = shapes[shapeID];
|
||||
|
||||
_modelMeshRenderItems << std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), shape.mesh, shape.meshPart, shapeID, transform);
|
||||
|
||||
auto material = getNetworkModel()->getShapeMaterial(shapeID);
|
||||
_modelMeshMaterialNames.push_back(material ? material->getName() : "");
|
||||
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)shape.mesh, shape.skinDeformer });
|
||||
}
|
||||
|
||||
/* int shapeID = 0;
|
||||
uint32_t numMeshes = (uint32_t)meshes.size();
|
||||
for (uint32_t i = 0; i < numMeshes; i++) {
|
||||
const auto& mesh = meshes.at(i);
|
||||
|
@ -85,14 +127,14 @@ void CauterizedModel::createRenderItemSet() {
|
|||
// Create the render payloads
|
||||
int numParts = (int)mesh->getNumParts();
|
||||
for (int partIndex = 0; partIndex < numParts; partIndex++) {
|
||||
auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
|
||||
auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform);
|
||||
_modelMeshRenderItems << std::static_pointer_cast<ModelMeshPartPayload>(ptr);
|
||||
auto material = getNetworkModel()->getShapeMaterial(shapeID);
|
||||
_modelMeshMaterialNames.push_back(material ? material->getName() : "");
|
||||
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });
|
||||
shapeID++;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
} else {
|
||||
Model::createRenderItemSet();
|
||||
}
|
||||
|
@ -108,6 +150,38 @@ void CauterizedModel::updateClusterMatrices() {
|
|||
updateShapeStatesFromRig();
|
||||
|
||||
_needsUpdateClusterMatrices = false;
|
||||
|
||||
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
const auto& hfmDynamicTransforms = hfmModel.skinDeformers;
|
||||
for (int i = 0; i < (int)_meshStates.size(); i++) {
|
||||
MeshState& state = _meshStates[i];
|
||||
const auto& deformer = hfmDynamicTransforms[i];
|
||||
|
||||
int meshIndex = i;
|
||||
int clusterIndex = 0;
|
||||
|
||||
for (int d = 0; d < deformer.clusters.size(); d++) {
|
||||
const auto& cluster = deformer.clusters[d];
|
||||
clusterIndex = d;
|
||||
|
||||
const auto& cbmov = _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex);
|
||||
|
||||
if (_useDualQuaternionSkinning) {
|
||||
auto jointPose = _rig.getJointPose(cluster.jointIndex);
|
||||
Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans());
|
||||
Transform clusterTransform;
|
||||
Transform::mult(clusterTransform, jointTransform, cbmov.inverseBindTransform);
|
||||
state.clusterDualQuaternions[d] = Model::TransformDualQuaternion(clusterTransform);
|
||||
}
|
||||
else {
|
||||
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
|
||||
glm_mat4u_mul(jointMatrix, cbmov.inverseBindMatrix, state.clusterMatrices[d]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/*
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
for (int i = 0; i < (int)_meshStates.size(); i++) {
|
||||
Model::MeshState& state = _meshStates[i];
|
||||
|
@ -131,7 +205,7 @@ void CauterizedModel::updateClusterMatrices() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
// as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty.
|
||||
if (!_cauterizeBoneSet.empty()) {
|
||||
|
||||
|
@ -224,64 +298,69 @@ void CauterizedModel::updateRenderItems() {
|
|||
auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
|
||||
|
||||
const auto& shapeState = self->getShapeState(i);
|
||||
const auto& meshState = self->getMeshState(meshIndex);
|
||||
const auto& cauterizedMeshState = self->getCauterizeMeshState(meshIndex);
|
||||
|
||||
auto deformerIndex = self->_modelMeshRenderItemShapes[i].deformerIndex;
|
||||
bool isDeformed = (deformerIndex != hfm::UNDEFINED_KEY);
|
||||
|
||||
|
||||
// auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
|
||||
// auto deformerIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
|
||||
|
||||
// const auto& shapeState = self->getShapeState(i);
|
||||
|
||||
|
||||
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
|
||||
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
|
||||
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey,
|
||||
primitiveMode, renderItemKeyGlobalFlags, enableCauterization](ModelMeshPartPayload& mmppData) {
|
||||
CauterizedMeshPartPayload& data = static_cast<CauterizedMeshPartPayload&>(mmppData);
|
||||
if (useDualQuaternionSkinning) {
|
||||
data.updateClusterBuffer(meshState.clusterDualQuaternions,
|
||||
cauterizedMeshState.clusterDualQuaternions);
|
||||
data.computeAdjustedLocalBound(meshState.clusterDualQuaternions);
|
||||
} else {
|
||||
data.updateClusterBuffer(meshState.clusterMatrices,
|
||||
cauterizedMeshState.clusterMatrices);
|
||||
data.computeAdjustedLocalBound(meshState.clusterMatrices);
|
||||
}
|
||||
|
||||
Transform renderTransform = modelTransform;
|
||||
/*if (useDualQuaternionSkinning) {
|
||||
if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) {
|
||||
const auto& dq = meshState.clusterDualQuaternions[0];
|
||||
Transform transform(dq.getRotation(),
|
||||
dq.getScale(),
|
||||
dq.getTranslation());
|
||||
renderTransform = modelTransform.worldTransform(transform);
|
||||
}
|
||||
} else {
|
||||
if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) {
|
||||
renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0]));
|
||||
}
|
||||
}*/
|
||||
if (meshState.clusterMatrices.size() <= 1) {
|
||||
|
||||
if (isDeformed) {
|
||||
|
||||
const auto& meshState = self->getMeshState(deformerIndex);
|
||||
const auto& cauterizedMeshState = self->getCauterizeMeshState(deformerIndex);
|
||||
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID,
|
||||
[modelTransform, shapeState, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey,
|
||||
primitiveMode, renderItemKeyGlobalFlags, enableCauterization](ModelMeshPartPayload& mmppData) {
|
||||
CauterizedMeshPartPayload& data = static_cast<CauterizedMeshPartPayload&>(mmppData);
|
||||
if (useDualQuaternionSkinning) {
|
||||
data.updateClusterBuffer(meshState.clusterDualQuaternions,
|
||||
cauterizedMeshState.clusterDualQuaternions);
|
||||
} else {
|
||||
data.updateClusterBuffer(meshState.clusterMatrices,
|
||||
cauterizedMeshState.clusterMatrices);
|
||||
}
|
||||
|
||||
Transform renderTransform = modelTransform;
|
||||
// if (meshState.clusterMatrices.size() <= 2) {
|
||||
// renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform);
|
||||
// }
|
||||
data.updateTransform(renderTransform);
|
||||
data.updateTransformForCauterizedMesh(renderTransform);
|
||||
data.updateTransformAndBound(modelTransform.worldTransform(shapeState._rootFromJointTransform));
|
||||
|
||||
data.setEnableCauterization(enableCauterization);
|
||||
data.updateKey(renderItemKeyGlobalFlags);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning);
|
||||
});
|
||||
} else {
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID,
|
||||
[modelTransform, shapeState, invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, enableCauterization]
|
||||
(ModelMeshPartPayload& mmppData) {
|
||||
CauterizedMeshPartPayload& data = static_cast<CauterizedMeshPartPayload&>(mmppData);
|
||||
|
||||
Transform renderTransform = modelTransform;
|
||||
|
||||
renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform);
|
||||
}
|
||||
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
|
||||
data.updateTransform(renderTransform);
|
||||
data.updateTransformForCauterizedMesh(renderTransform);
|
||||
|
||||
renderTransform = modelTransform;
|
||||
if (useDualQuaternionSkinning) {
|
||||
if (cauterizedMeshState.clusterDualQuaternions.size() == 1 || cauterizedMeshState.clusterDualQuaternions.size() == 2) {
|
||||
const auto& dq = cauterizedMeshState.clusterDualQuaternions[0];
|
||||
Transform transform(dq.getRotation(),
|
||||
dq.getScale(),
|
||||
dq.getTranslation());
|
||||
renderTransform = modelTransform.worldTransform(Transform(transform));
|
||||
}
|
||||
} else {
|
||||
if (cauterizedMeshState.clusterMatrices.size() == 1 || cauterizedMeshState.clusterMatrices.size() == 2) {
|
||||
renderTransform = modelTransform.worldTransform(Transform(cauterizedMeshState.clusterMatrices[0]));
|
||||
}
|
||||
}
|
||||
data.updateTransformForCauterizedMesh(renderTransform);
|
||||
|
||||
data.setEnableCauterization(enableCauterization);
|
||||
data.updateKey(renderItemKeyGlobalFlags);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning);
|
||||
});
|
||||
data.setEnableCauterization(enableCauterization);
|
||||
data.updateKey(renderItemKeyGlobalFlags);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, false);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
scene->enqueueTransaction(transaction);
|
||||
|
|
|
@ -64,11 +64,15 @@ void MeshPartPayload::updateMeshPart(const std::shared_ptr<const graphics::Mesh>
|
|||
}
|
||||
}
|
||||
|
||||
void MeshPartPayload::updateTransform(const Transform& transform, const Transform& offsetTransform) {
|
||||
_transform = transform;
|
||||
Transform::mult(_drawTransform, _transform, offsetTransform);
|
||||
void MeshPartPayload::updateTransform(const Transform& transform) {
|
||||
_worldFromLocalTransform = transform;
|
||||
_worldBound = _localBound;
|
||||
_worldBound.transform(_drawTransform);
|
||||
_worldBound.transform(_worldFromLocalTransform);
|
||||
}
|
||||
|
||||
void MeshPartPayload::updateTransformAndBound(const Transform& transform) {
|
||||
_worldBound = _localBound;
|
||||
_worldBound.transform(transform);
|
||||
}
|
||||
|
||||
void MeshPartPayload::addMaterial(graphics::MaterialLayer material) {
|
||||
|
@ -134,7 +138,7 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) {
|
|||
}
|
||||
|
||||
void MeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const {
|
||||
batch.setModelTransform(_drawTransform);
|
||||
batch.setModelTransform(_worldFromLocalTransform);
|
||||
}
|
||||
|
||||
|
||||
|
@ -196,7 +200,7 @@ template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, Ren
|
|||
|
||||
}
|
||||
|
||||
ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) :
|
||||
ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform) :
|
||||
_meshIndex(meshIndex),
|
||||
_shapeID(shapeIndex) {
|
||||
|
||||
|
@ -210,38 +214,16 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
|
|||
|
||||
auto& modelMesh = model->getNetworkModel()->getMeshes().at(_meshIndex);
|
||||
_meshNumVertices = (int)modelMesh->getNumVertices();
|
||||
const Model::MeshState& state = model->getMeshState(_meshIndex);
|
||||
// const Model::MeshState& state = model->getMeshState(_meshIndex);
|
||||
|
||||
updateMeshPart(modelMesh, partIndex);
|
||||
|
||||
if (useDualQuaternionSkinning) {
|
||||
computeAdjustedLocalBound(state.clusterDualQuaternions);
|
||||
} else {
|
||||
computeAdjustedLocalBound(state.clusterMatrices);
|
||||
}
|
||||
|
||||
updateTransform(transform, offsetTransform);
|
||||
|
||||
Transform renderTransform = transform;
|
||||
|
||||
/* if (useDualQuaternionSkinning) {
|
||||
if (state.clusterDualQuaternions.size() == 1) {
|
||||
const auto& dq = state.clusterDualQuaternions[0];
|
||||
Transform transform(dq.getRotation(),
|
||||
dq.getScale(),
|
||||
dq.getTranslation());
|
||||
renderTransform = transform.worldTransform(Transform(transform));
|
||||
}
|
||||
} else {
|
||||
if (state.clusterMatrices.size() == 1) {
|
||||
renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0]));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
Transform renderTransform = transform;
|
||||
const Model::ShapeState& shapeState = model->getShapeState(shapeIndex);
|
||||
renderTransform = transform.worldTransform(shapeState._rootFromJointTransform);
|
||||
updateTransformForSkinnedMesh(renderTransform, transform);
|
||||
updateTransform(renderTransform);
|
||||
|
||||
_deformerIndex = shape.skinDeformer;
|
||||
|
||||
initCache(model);
|
||||
|
||||
|
@ -264,7 +246,9 @@ void ModelMeshPartPayload::initCache(const ModelPointer& model) {
|
|||
if (_drawMesh) {
|
||||
auto vertexFormat = _drawMesh->getVertexFormat();
|
||||
_hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR);
|
||||
_isSkinned = vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT) && vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_INDEX);
|
||||
if (_deformerIndex != hfm::UNDEFINED_KEY) {
|
||||
_isSkinned = vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT) && vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_INDEX);
|
||||
}
|
||||
|
||||
const HFMModel& hfmModel = model->getHFMModel();
|
||||
const HFMMesh& mesh = hfmModel.meshes.at(_meshIndex);
|
||||
|
@ -323,13 +307,6 @@ void ModelMeshPartPayload::updateClusterBuffer(const std::vector<Model::Transfor
|
|||
}
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform) {
|
||||
_transform = renderTransform;
|
||||
_worldBound = _adjustedLocalBound;
|
||||
// _worldBound.transform(boundTransform);
|
||||
_worldBound.transform(renderTransform);
|
||||
}
|
||||
|
||||
// Note that this method is called for models but not for shapes
|
||||
void ModelMeshPartPayload::updateKey(const render::ItemKey& key) {
|
||||
ItemKey::Builder builder(key);
|
||||
|
@ -420,7 +397,7 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMo
|
|||
if (_clusterBuffer) {
|
||||
batch.setUniformBuffer(graphics::slot::buffer::Skinning, _clusterBuffer);
|
||||
}
|
||||
batch.setModelTransform(_transform);
|
||||
batch.setModelTransform(_worldFromLocalTransform);
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::render(RenderArgs* args) {
|
||||
|
@ -458,38 +435,6 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
|
|||
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices) {
|
||||
_adjustedLocalBound = _localBound;
|
||||
if (clusterMatrices.size() > 0) {
|
||||
_adjustedLocalBound.transform(clusterMatrices.back());
|
||||
|
||||
for (int i = 0; i < (int)clusterMatrices.size() - 1; ++i) {
|
||||
AABox clusterBound = _localBound;
|
||||
clusterBound.transform(clusterMatrices[i]);
|
||||
_adjustedLocalBound += clusterBound;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions) {
|
||||
_adjustedLocalBound = _localBound;
|
||||
if (clusterDualQuaternions.size() > 0) {
|
||||
Transform rootTransform(clusterDualQuaternions.back().getRotation(),
|
||||
clusterDualQuaternions.back().getScale(),
|
||||
clusterDualQuaternions.back().getTranslation());
|
||||
_adjustedLocalBound.transform(rootTransform);
|
||||
|
||||
for (int i = 0; i < (int)clusterDualQuaternions.size() - 1; ++i) {
|
||||
AABox clusterBound = _localBound;
|
||||
Transform transform(clusterDualQuaternions[i].getRotation(),
|
||||
clusterDualQuaternions[i].getScale(),
|
||||
clusterDualQuaternions[i].getTranslation());
|
||||
clusterBound.transform(transform);
|
||||
_adjustedLocalBound += clusterBound;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::setBlendshapeBuffer(const std::unordered_map<int, gpu::BufferPointer>& blendshapeBuffers, const QVector<int>& blendedMeshSizes) {
|
||||
if (_meshIndex < blendedMeshSizes.length() && blendedMeshSizes.at(_meshIndex) == _meshNumVertices) {
|
||||
auto blendshapeBuffer = blendshapeBuffers.find(_meshIndex);
|
||||
|
|
|
@ -38,7 +38,8 @@ public:
|
|||
virtual void updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex);
|
||||
|
||||
virtual void notifyLocationChanged() {}
|
||||
void updateTransform(const Transform& transform, const Transform& offsetTransform);
|
||||
void updateTransform(const Transform& transform);
|
||||
void updateTransformAndBound(const Transform& transform );
|
||||
|
||||
// Render Item interface
|
||||
virtual render::ItemKey getKey() const;
|
||||
|
@ -52,13 +53,11 @@ public:
|
|||
virtual void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const;
|
||||
|
||||
// Payload resource cached values
|
||||
Transform _drawTransform;
|
||||
Transform _transform;
|
||||
Transform _worldFromLocalTransform;
|
||||
int _partIndex = 0;
|
||||
bool _hasColorAttrib { false };
|
||||
|
||||
graphics::Box _localBound;
|
||||
graphics::Box _adjustedLocalBound;
|
||||
mutable graphics::Box _worldBound;
|
||||
std::shared_ptr<const graphics::Mesh> _drawMesh;
|
||||
|
||||
|
@ -86,7 +85,7 @@ namespace render {
|
|||
|
||||
class ModelMeshPartPayload : public MeshPartPayload {
|
||||
public:
|
||||
ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform);
|
||||
ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform);
|
||||
|
||||
typedef render::Payload<ModelMeshPartPayload> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
@ -100,7 +99,6 @@ public:
|
|||
|
||||
// dual quaternion skinning
|
||||
void updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions);
|
||||
void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform);
|
||||
|
||||
// Render Item interface
|
||||
render::ShapeKey getShapeKey() const override; // shape interface
|
||||
|
@ -113,12 +111,6 @@ public:
|
|||
void bindMesh(gpu::Batch& batch) override;
|
||||
void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const override;
|
||||
|
||||
// matrix palette skinning
|
||||
void computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices);
|
||||
|
||||
// dual quaternion skinning
|
||||
void computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions);
|
||||
|
||||
gpu::BufferPointer _clusterBuffer;
|
||||
|
||||
enum class ClusterBufferType { Matrices, DualQuaternions };
|
||||
|
@ -126,6 +118,7 @@ public:
|
|||
|
||||
int _meshIndex;
|
||||
int _shapeID;
|
||||
int _deformerIndex;
|
||||
|
||||
bool _isSkinned{ false };
|
||||
bool _isBlendShaped { false };
|
||||
|
|
|
@ -186,7 +186,7 @@ bool Model::shouldInvalidatePayloadShapeKey(int meshIndex) {
|
|||
const auto& networkMeshes = getNetworkModel()->getMeshes();
|
||||
// if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
|
||||
// to false to rebuild out mesh groups.
|
||||
if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)hfmModel.meshes.size() || meshIndex >= (int)_meshStates.size()) {
|
||||
if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)hfmModel.meshes.size() /* || meshIndex >= (int)_meshStates.size()*/) {
|
||||
_needsFixupInScene = true; // trigger remove/add cycle
|
||||
invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
|
||||
return true;
|
||||
|
@ -233,45 +233,52 @@ void Model::updateRenderItems() {
|
|||
auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
|
||||
|
||||
const auto& shapeState = self->getShapeState(i);
|
||||
const auto& meshState = self->getMeshState(meshIndex);
|
||||
|
||||
auto deformerIndex = self->_modelMeshRenderItemShapes[i].deformerIndex;
|
||||
bool isDeformed = (deformerIndex != hfm::UNDEFINED_KEY);
|
||||
|
||||
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
|
||||
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
|
||||
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning,
|
||||
invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, cauterized](ModelMeshPartPayload& data) {
|
||||
if (useDualQuaternionSkinning) {
|
||||
data.updateClusterBuffer(meshState.clusterDualQuaternions);
|
||||
data.computeAdjustedLocalBound(meshState.clusterDualQuaternions);
|
||||
} else {
|
||||
data.updateClusterBuffer(meshState.clusterMatrices);
|
||||
data.computeAdjustedLocalBound(meshState.clusterMatrices);
|
||||
}
|
||||
|
||||
if (isDeformed) {
|
||||
|
||||
Transform renderTransform = modelTransform;
|
||||
const auto& meshState = self->getMeshState(deformerIndex);
|
||||
// MeshState meshState;
|
||||
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
|
||||
|
||||
/*if (useDualQuaternionSkinning) {
|
||||
if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) {
|
||||
const auto& dq = meshState.clusterDualQuaternions[0];
|
||||
Transform transform(dq.getRotation(),
|
||||
dq.getScale(),
|
||||
dq.getTranslation());
|
||||
renderTransform = modelTransform.worldTransform(Transform(transform));
|
||||
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning,
|
||||
invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, cauterized](ModelMeshPartPayload& data) {
|
||||
if (useDualQuaternionSkinning) {
|
||||
data.updateClusterBuffer(meshState.clusterDualQuaternions);
|
||||
} else {
|
||||
data.updateClusterBuffer(meshState.clusterMatrices);
|
||||
}
|
||||
} else {
|
||||
if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) {
|
||||
renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0]));
|
||||
}
|
||||
}*/
|
||||
if (meshState.clusterMatrices.size() <= 1) {
|
||||
|
||||
Transform renderTransform = modelTransform;
|
||||
// if (meshState.clusterMatrices.size() <= 1) {
|
||||
// renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform);
|
||||
// }
|
||||
data.updateTransform(renderTransform);
|
||||
data.updateTransformAndBound(modelTransform.worldTransform(shapeState._rootFromJointTransform));
|
||||
|
||||
data.setCauterized(cauterized);
|
||||
data.updateKey(renderItemKeyGlobalFlags);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning);
|
||||
});
|
||||
} else {
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, shapeState, invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags](ModelMeshPartPayload& data) {
|
||||
|
||||
Transform renderTransform = modelTransform;
|
||||
// if (meshState.clusterMatrices.size() <= 1) {
|
||||
renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform);
|
||||
}
|
||||
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
|
||||
// }
|
||||
data.updateTransform(renderTransform);
|
||||
|
||||
data.setCauterized(cauterized);
|
||||
data.updateKey(renderItemKeyGlobalFlags);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning);
|
||||
});
|
||||
data.updateKey(renderItemKeyGlobalFlags);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
|
||||
|
@ -304,9 +311,9 @@ void Model::updateShapeStatesFromRig() {
|
|||
const auto& shapes = hfmModel.shapes;
|
||||
_shapeStates.resize(shapes.size());
|
||||
for (int s = 0; s < shapes.size(); ++s) {
|
||||
uint32_t jointId = shapes[s].transform;
|
||||
if (jointId < _rig.getJointStateCount()) {
|
||||
_shapeStates[s]._rootFromJointTransform = _rig.getJointTransform(shapes[s].transform);
|
||||
uint32_t jointId = shapes[s].joint;
|
||||
if (jointId < (uint32_t) _rig.getJointStateCount()) {
|
||||
_shapeStates[s]._rootFromJointTransform = _rig.getJointTransform(jointId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -329,14 +336,24 @@ bool Model::updateGeometry() {
|
|||
updateShapeStatesFromRig();
|
||||
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
const auto& hfmSkinDeformers = hfmModel.skinDeformers;
|
||||
int i = 0;
|
||||
foreach (const HFMMesh& mesh, hfmModel.meshes) {
|
||||
/* for (const auto& mesh: hfmModel.meshes) {
|
||||
MeshState state;
|
||||
state.clusterDualQuaternions.resize(mesh.clusters.size());
|
||||
state.clusterMatrices.resize(mesh.clusters.size());
|
||||
_meshStates.push_back(state);
|
||||
i++;
|
||||
}
|
||||
*/
|
||||
for (int i = 0; i < hfmSkinDeformers.size(); i++) {
|
||||
const auto& dynT = hfmSkinDeformers[i];
|
||||
MeshState state;
|
||||
state.clusterDualQuaternions.resize(dynT.clusters.size());
|
||||
state.clusterMatrices.resize(dynT.clusters.size());
|
||||
_meshStates.push_back(state);
|
||||
}
|
||||
|
||||
needFullUpdate = true;
|
||||
emit rigReady();
|
||||
}
|
||||
|
@ -1410,8 +1427,34 @@ void Model::updateClusterMatrices() {
|
|||
|
||||
_needsUpdateClusterMatrices = false;
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
const auto& hfmSkinDeformers = hfmModel.skinDeformers;
|
||||
for (int i = 0; i < (int) _meshStates.size(); i++) {
|
||||
MeshState& state = _meshStates[i];
|
||||
const auto& deformer = hfmSkinDeformers[i];
|
||||
|
||||
int meshIndex = i;
|
||||
int clusterIndex = 0;
|
||||
|
||||
for (int d = 0; d < deformer.clusters.size(); d++) {
|
||||
const auto& cluster = deformer.clusters[d];
|
||||
clusterIndex = d;
|
||||
|
||||
const auto& cbmov = _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex);
|
||||
|
||||
if (_useDualQuaternionSkinning) {
|
||||
auto jointPose = _rig.getJointPose(cluster.jointIndex);
|
||||
Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans());
|
||||
Transform clusterTransform;
|
||||
Transform::mult(clusterTransform, jointTransform, cbmov.inverseBindTransform);
|
||||
state.clusterDualQuaternions[d] = Model::TransformDualQuaternion(clusterTransform);
|
||||
}
|
||||
else {
|
||||
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
|
||||
glm_mat4u_mul(jointMatrix, cbmov.inverseBindMatrix, state.clusterMatrices[d]);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
int meshIndex = i;
|
||||
const HFMMesh& mesh = hfmModel.meshes.at(i);
|
||||
for (int j = 0; j < mesh.clusters.size(); j++) {
|
||||
|
@ -1428,7 +1471,7 @@ void Model::updateClusterMatrices() {
|
|||
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
|
||||
glm_mat4u_mul(jointMatrix, _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex).inverseBindMatrix, state.clusterMatrices[j]);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
// post the blender if we're not currently waiting for one to finish
|
||||
|
@ -1477,12 +1520,6 @@ void Model::createRenderItemSet() {
|
|||
assert(isLoaded());
|
||||
const auto& meshes = _renderGeometry->getMeshes();
|
||||
|
||||
// all of our mesh vectors must match in size
|
||||
if (meshes.size() != _meshStates.size()) {
|
||||
qCDebug(renderutils) << "WARNING!!!! Mesh Sizes don't match! " << meshes.size() << _meshStates.size() << " We will not segregate mesh groups yet.";
|
||||
return;
|
||||
}
|
||||
|
||||
// We should not have any existing renderItems if we enter this section of code
|
||||
Q_ASSERT(_modelMeshRenderItems.isEmpty());
|
||||
|
||||
|
@ -1500,6 +1537,17 @@ void Model::createRenderItemSet() {
|
|||
|
||||
// Run through all of the meshes, and place them into their segregated, but unsorted buckets
|
||||
int shapeID = 0;
|
||||
const auto& shapes = _renderGeometry->getHFMModel().shapes;
|
||||
for (shapeID; shapeID < shapes.size(); shapeID++) {
|
||||
const auto& shape = shapes[shapeID];
|
||||
|
||||
_modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), shape.mesh, shape.meshPart, shapeID, transform);
|
||||
|
||||
auto material = getNetworkModel()->getShapeMaterial(shapeID);
|
||||
_modelMeshMaterialNames.push_back(material ? material->getName() : "");
|
||||
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)shape.mesh, shape.skinDeformer });
|
||||
}
|
||||
/*
|
||||
uint32_t numMeshes = (uint32_t)meshes.size();
|
||||
for (uint32_t i = 0; i < numMeshes; i++) {
|
||||
const auto& mesh = meshes.at(i);
|
||||
|
@ -1510,17 +1558,17 @@ void Model::createRenderItemSet() {
|
|||
// Create the render payloads
|
||||
int numParts = (int)mesh->getNumParts();
|
||||
for (int partIndex = 0; partIndex < numParts; partIndex++) {
|
||||
_modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
|
||||
_modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform);
|
||||
auto material = getNetworkModel()->getShapeMaterial(shapeID);
|
||||
_modelMeshMaterialNames.push_back(material ? material->getName() : "");
|
||||
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });
|
||||
shapeID++;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
bool Model::isRenderable() const {
|
||||
return (!_shapeStates.empty() && !_meshStates.empty()) || (isLoaded() && _renderGeometry->getMeshes().empty());
|
||||
return (!_shapeStates.empty() /* && !_meshStates.empty()*/) || (isLoaded() && _renderGeometry->getMeshes().empty());
|
||||
}
|
||||
|
||||
std::set<unsigned int> Model::getMeshIDsFromMaterialID(QString parentMaterialName) {
|
||||
|
|
|
@ -473,7 +473,7 @@ protected:
|
|||
QVector<std::shared_ptr<ModelMeshPartPayload>> _modelMeshRenderItems;
|
||||
QMap<render::ItemID, render::PayloadPointer> _modelMeshRenderItemsMap;
|
||||
render::ItemIDs _modelMeshRenderItemIDs;
|
||||
using ShapeInfo = struct { int meshIndex; };
|
||||
using ShapeInfo = struct { int meshIndex; uint32_t deformerIndex{ hfm::UNDEFINED_KEY }; };
|
||||
std::vector<ShapeInfo> _modelMeshRenderItemShapes;
|
||||
std::vector<std::string> _modelMeshMaterialNames;
|
||||
|
||||
|
|
Loading…
Reference in a new issue