From 387f0a3f10e462f87009fa4d81ceec4e6bd5290a Mon Sep 17 00:00:00 2001 From: dooglifeSF <41022919+dooglifeSF@users.noreply.github.com> Date: Fri, 4 Oct 2019 15:28:35 -0700 Subject: [PATCH 01/10] add isInput* and isNotInput vars for use in json, and edit json to use them --- .../resources/avatar/avatar-animation.json | 110 +++++++++--------- interface/src/avatar/MySkeletonModel.cpp | 4 + libraries/animation/src/Rig.cpp | 42 +++++++ libraries/animation/src/Rig.h | 2 + 4 files changed, 103 insertions(+), 55 deletions(-) diff --git a/interface/resources/avatar/avatar-animation.json b/interface/resources/avatar/avatar-animation.json index 2b8b3eb9b3..1c3a603eb5 100644 --- a/interface/resources/avatar/avatar-animation.json +++ b/interface/resources/avatar/avatar-animation.json @@ -5244,23 +5244,23 @@ "transitions": [ { "state": "idle", - "var": "isNotMoving" + "var": "isNotInput" }, { "state": "WALKFWD", - "var": "isMovingForward" + "var": "isInputForward" }, { "state": "WALKBWD", - "var": "isMovingBackward" + "var": "isInputBackward" }, { "state": "STRAFERIGHT", - "var": "isMovingRight" + "var": "isInputRight" }, { "state": "STRAFELEFT", - "var": "isMovingLeft" + "var": "isInputLeft" }, { "state": "turnRight", @@ -5313,19 +5313,19 @@ "transitions": [ { "state": "WALKFWD", - "var": "isMovingForward" + "var": "isInputForward" }, { "state": "WALKBWD", - "var": "isMovingBackward" + "var": "isInputBackward" }, { "state": "STRAFERIGHT", - "var": "isMovingRight" + "var": "isInputRight" }, { "state": "STRAFELEFT", - "var": "isMovingLeft" + "var": "isInputLeft" }, { "state": "turnRight", @@ -5380,19 +5380,19 @@ }, { "state": "idle", - "var": "isNotMoving" + "var": "isNotInput" }, { "state": "WALKBWD", - "var": "isMovingBackward" + "var": "isInputBackward" }, { "state": "STRAFERIGHT", - "var": "isMovingRight" + "var": "isInputRight" }, { "state": "STRAFELEFT", - "var": "isMovingLeft" + "var": "isInputLeft" }, { "state": "turnRight", @@ -5469,19 +5469,19 @@ }, { "state": "WALKFWD", - "var": "isMovingForward" + "var": "isInputForward" }, { "state": "WALKBWD", - "var": "isMovingBackward" + "var": "isInputBackward" }, { "state": "STRAFERIGHT", - "var": "isMovingRight" + "var": "isInputRight" }, { "state": "STRAFELEFT", - "var": "isMovingLeft" + "var": "isInputLeft" }, { "state": "strafeRightHmd", @@ -5533,19 +5533,19 @@ "transitions": [ { "state": "idleSettle", - "var": "isNotMoving" + "var": "isNotInput" }, { "state": "WALKBWD", - "var": "isMovingBackward" + "var": "isInputBackward" }, { "state": "STRAFERIGHT", - "var": "isMovingRight" + "var": "isInputRight" }, { "state": "STRAFELEFT", - "var": "isMovingLeft" + "var": "isInputLeft" }, { "state": "turnRight", @@ -5597,19 +5597,19 @@ "transitions": [ { "state": "idleSettle", - "var": "isNotMoving" + "var": "isNotInput" }, { "state": "WALKFWD", - "var": "isMovingForward" + "var": "isInputForward" }, { "state": "STRAFERIGHT", - "var": "isMovingRight" + "var": "isInputRight" }, { "state": "STRAFELEFT", - "var": "isMovingLeft" + "var": "isInputLeft" }, { "state": "turnRight", @@ -5661,19 +5661,19 @@ "transitions": [ { "state": "idleSettle", - "var": "isNotMoving" + "var": "isNotInput" }, { "state": "WALKFWD", - "var": "isMovingForward" + "var": "isInputForward" }, { "state": "WALKBWD", - "var": "isMovingBackward" + "var": "isInputBackward" }, { "state": "STRAFELEFT", - "var": "isMovingLeft" + "var": "isInputLeft" }, { "state": "turnRight", @@ -5725,19 +5725,19 @@ "transitions": [ { "state": "idleSettle", - "var": "isNotMoving" + "var": "isNotInput" }, { "state": "WALKFWD", - "var": "isMovingForward" + "var": "isInputForward" }, { "state": "WALKBWD", - "var": "isMovingBackward" + "var": "isInputBackward" }, { "state": "STRAFERIGHT", - "var": "isMovingRight" + "var": "isInputRight" }, { "state": "turnRight", @@ -5794,19 +5794,19 @@ }, { "state": "WALKFWD", - "var": "isMovingForward" + "var": "isInputForward" }, { "state": "WALKBWD", - "var": "isMovingBackward" + "var": "isInputBackward" }, { "state": "STRAFERIGHT", - "var": "isMovingRight" + "var": "isInputRight" }, { "state": "STRAFELEFT", - "var": "isMovingLeft" + "var": "isInputLeft" }, { "state": "turnLeft", @@ -5859,19 +5859,19 @@ }, { "state": "WALKFWD", - "var": "isMovingForward" + "var": "isInputForward" }, { "state": "WALKBWD", - "var": "isMovingBackward" + "var": "isInputBackward" }, { "state": "STRAFERIGHT", - "var": "isMovingRight" + "var": "isInputRight" }, { "state": "STRAFELEFT", - "var": "isMovingLeft" + "var": "isInputLeft" }, { "state": "turnRight", @@ -5919,15 +5919,15 @@ "transitions": [ { "state": "idleSettle", - "var": "isNotMoving" + "var": "isNotInput" }, { "state": "WALKFWD", - "var": "isMovingForward" + "var": "isInputForward" }, { "state": "WALKBWD", - "var": "isMovingBackward" + "var": "isInputBackward" }, { "state": "strafeLeftHmd", @@ -5935,11 +5935,11 @@ }, { "state": "STRAFERIGHT", - "var": "isMovingRight" + "var": "isInputRight" }, { "state": "STRAFELEFT", - "var": "isMovingLeft" + "var": "isInputLeft" }, { "state": "turnRight", @@ -5983,15 +5983,15 @@ "transitions": [ { "state": "idleSettle", - "var": "isNotMoving" + "var": "isNotInput" }, { "state": "WALKFWD", - "var": "isMovingForward" + "var": "isInputForward" }, { "state": "WALKBWD", - "var": "isMovingBackward" + "var": "isInputBackward" }, { "state": "strafeRightHmd", @@ -5999,11 +5999,11 @@ }, { "state": "STRAFERIGHT", - "var": "isMovingRight" + "var": "isInputRight" }, { "state": "STRAFELEFT", - "var": "isMovingLeft" + "var": "isInputLeft" }, { "state": "turnRight", @@ -6128,19 +6128,19 @@ "transitions": [ { "state": "WALKFWD", - "var": "isMovingForward" + "var": "isInputForward" }, { "state": "WALKBWD", - "var": "isMovingBackward" + "var": "isInputBackward" }, { "state": "STRAFERIGHT", - "var": "isMovingRight" + "var": "isInputRight" }, { "state": "STRAFELEFT", - "var": "isMovingLeft" + "var": "isInputLeft" }, { "state": "turnRight", diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 38065c8095..8d92767321 100755 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -315,6 +315,10 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { const float TALKING_TIME_THRESHOLD = 0.75f; params.isTalking = head->getTimeWithoutTalking() <= TALKING_TIME_THRESHOLD; + //pass X and Z input key floats (-1 to 1) to rig + params.inputX = myAvatar->getDriveKey(MyAvatar::TRANSLATE_X); + params.inputZ = myAvatar->getDriveKey(MyAvatar::TRANSLATE_Z); + myAvatar->updateRigControllerParameters(params); _rig.updateFromControllerParameters(params, deltaTime); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index d63c2d6a9b..88b42285cd 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -2160,6 +2160,48 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo } } + //TODO: how to handle multiple inputs? Is there a trick to prioritize fwd/bwd with order of operations? + if (params.inputX) { + if (params.inputX > 0.0f) { + // left + _animVars.set("isInputForward", false); + _animVars.set("isInputBackward", false); + _animVars.set("isInputRight", true); + _animVars.set("isInputLeft", false); + _animVars.set("isNotInput", false); + } else { + // right + _animVars.set("isInputForward", false); + _animVars.set("isInputBackward", false); + _animVars.set("isInputRight", false); + _animVars.set("isInputLeft", true); + _animVars.set("isNotInput", false); + } + } else if (params.inputZ) { + if (params.inputZ > 0.0f) { + // forward + _animVars.set("isInputForward", true); + _animVars.set("isInputBackward", false); + _animVars.set("isInputRight", false); + _animVars.set("isInputLeft", false); + _animVars.set("isNotInput", false); + } else { + // backward + _animVars.set("isInputForward", false); + _animVars.set("isInputBackward", true); + _animVars.set("isInputRight", false); + _animVars.set("isInputLeft", false); + _animVars.set("isNotInput", false); + } + } else if (params.inputX == 0.0f && params.inputZ == 0.0f) { + // no WASD input + _animVars.set("isInputForward", false); + _animVars.set("isInputBackward", false); + _animVars.set("isInputRight", false); + _animVars.set("isInputLeft", false); + _animVars.set("isNotInput", true); + } + _headEnabled = params.primaryControllerFlags[PrimaryControllerType_Head] & (uint8_t)ControllerFlags::Enabled; bool leftHandEnabled = params.primaryControllerFlags[PrimaryControllerType_LeftHand] & (uint8_t)ControllerFlags::Enabled; bool rightHandEnabled = params.primaryControllerFlags[PrimaryControllerType_RightHand] & (uint8_t)ControllerFlags::Enabled; diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 98431e1dca..8f5eddac00 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -88,6 +88,8 @@ public: AnimPose secondaryControllerPoses[NumSecondaryControllerTypes]; // rig space uint8_t secondaryControllerFlags[NumSecondaryControllerTypes]; bool isTalking; + float inputX; + float inputZ; bool reactionEnabledFlags[NUM_AVATAR_BEGIN_END_REACTIONS]; bool reactionTriggers[NUM_AVATAR_TRIGGER_REACTIONS]; HFMJointShapeInfo hipsShapeInfo; From 09a8d69555837696397476f539af1adcfc14b692 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 4 Oct 2019 18:02:45 -0700 Subject: [PATCH 02/10] landing on the new code base --- libraries/fbx/src/FBXSerializer.cpp | 46 ++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index 78bc1836c3..1752c2f024 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -145,6 +145,42 @@ public: bool isLimbNode; // is this FBXModel transform is a "LimbNode" i.e. a joint }; + +glm::mat4 getGlobalTransform(const QMultiMap& _connectionParentMap, + const QHash& fbxModels, QString nodeID, bool mixamoHack, const QString& url) { + glm::mat4 globalTransform; + QVector visitedNodes; // Used to prevent following a cycle + while (!nodeID.isNull()) { + visitedNodes.append(nodeID); // Append each node we visit + + const FBXModel& fbxModel = fbxModels.value(nodeID); + globalTransform = glm::translate(fbxModel.translation) * fbxModel.preTransform * glm::mat4_cast(fbxModel.preRotation * + fbxModel.rotation * fbxModel.postRotation) * fbxModel.postTransform * globalTransform; + if (fbxModel.hasGeometricOffset) { + glm::mat4 geometricOffset = createMatFromScaleQuatAndPos(fbxModel.geometricScaling, fbxModel.geometricRotation, fbxModel.geometricTranslation); + globalTransform = globalTransform * geometricOffset; + } + + if (mixamoHack) { + // there's something weird about the models from Mixamo Fuse; they don't skin right with the full transform + return globalTransform; + } + QList parentIDs = _connectionParentMap.values(nodeID); + nodeID = QString(); + foreach(const QString& parentID, parentIDs) { + if (visitedNodes.contains(parentID)) { + qCWarning(modelformat) << "Ignoring loop detected in FBX connection map for" << url; + continue; + } + if (fbxModels.contains(parentID)) { + nodeID = parentID; + break; + } + } + } + return globalTransform; +} + std::vector getModelIDsForMeshID(const QString& meshID, const QHash& fbxModels, const QMultiMap& _connectionParentMap) { std::vector modelsForMesh; if (fbxModels.contains(meshID)) { @@ -1344,7 +1380,8 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const joint.globalTransform = glm::translate(joint.translation) * joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation * joint.postRotation) * joint.postTransform; if (joint.parentIndex != -1 && joint.parentIndex < (int)jointIndex && !needMixamoHack) { hfm::Joint& parentJoint = hfmModel.joints[joint.parentIndex]; - joint.globalTransform = joint.globalTransform * parentJoint.globalTransform; + // joint.globalTransform = joint.globalTransform * parentJoint.globalTransform; + joint.globalTransform = parentJoint.globalTransform * joint.globalTransform; if (parentJoint.hasGeometricOffset) { // Per the FBX standard, geometric offset should not propagate to children. // However, we must be careful when modifying the behavior of FBXSerializer. @@ -1359,6 +1396,13 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const joint.globalTransform = joint.globalTransform * geometricOffset; } + // accumulate local transforms + // QString modelID = fbxModels.contains(it.key()) ? it.key() : _connectionParentMap.value(it.key()); + glm::mat4 anotherModelTransform = getGlobalTransform(_connectionParentMap, fbxModels, modelID, hfmModel.applicationName == "mixamo.com", url); + /* if (anotherModelTransform != joint.globalTransform) { + joint.globalTransform = anotherModelTransform; + } +*/ hfmModel.joints.push_back(joint); } From 521ce3936bc689639c558e9a893756bb79738c6c Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 7 Oct 2019 15:19:23 -0700 Subject: [PATCH 03/10] I changed names! Renaming the Geometry to NetworkModel, the GeometryResource to ModelResource, i think there is no need for the 2, only one would be enough in my opinion... --- interface/src/avatar/AvatarDoctor.cpp | 4 +- interface/src/avatar/AvatarDoctor.h | 2 +- interface/src/raypick/CollisionPick.cpp | 6 +- interface/src/raypick/CollisionPick.h | 6 +- .../src/avatars-renderer/Avatar.cpp | 2 +- .../src/avatars-renderer/SkeletonModel.cpp | 2 +- .../src/RenderableModelEntityItem.cpp | 6 +- .../src/RenderableModelEntityItem.h | 2 +- .../RenderableParticleEffectEntityItem.cpp | 6 +- .../src/RenderableParticleEffectEntityItem.h | 4 +- libraries/entities/src/ZoneEntityItem.cpp | 4 +- libraries/entities/src/ZoneEntityItem.h | 2 +- libraries/fbx/src/FBXSerializer.cpp | 24 ++-- libraries/hfm/src/hfm/HFM.h | 1 + .../src/material-networking/MaterialCache.h | 2 +- .../src/model-networking/ModelCache.cpp | 119 +++++++++--------- .../src/model-networking/ModelCache.h | 46 +++---- .../render-utils/src/CauterizedModel.cpp | 2 +- .../render-utils/src/MeshPartPayload.cpp | 8 +- libraries/render-utils/src/Model.cpp | 24 ++-- libraries/render-utils/src/Model.h | 8 +- 21 files changed, 150 insertions(+), 130 deletions(-) diff --git a/interface/src/avatar/AvatarDoctor.cpp b/interface/src/avatar/AvatarDoctor.cpp index a12b4dfcc0..4ff6fb7553 100644 --- a/interface/src/avatar/AvatarDoctor.cpp +++ b/interface/src/avatar/AvatarDoctor.cpp @@ -79,7 +79,7 @@ void AvatarDoctor::startDiagnosing() { _missingTextureCount = 0; _unsupportedTextureCount = 0; - const auto resource = DependencyManager::get()->getGeometryResource(_avatarFSTFileUrl); + const auto resource = DependencyManager::get()->getModelResource(_avatarFSTFileUrl); resource->refresh(); const auto resourceLoaded = [this, resource](bool success) { @@ -297,7 +297,7 @@ void AvatarDoctor::startDiagnosing() { if (resource->isLoaded()) { resourceLoaded(!resource->isFailed()); } else { - connect(resource.data(), &GeometryResource::finished, this, resourceLoaded); + connect(resource.data(), &ModelResource::finished, this, resourceLoaded); } } else { addError("Model file cannot be opened", "missing-file"); diff --git a/interface/src/avatar/AvatarDoctor.h b/interface/src/avatar/AvatarDoctor.h index 1465a5defc..1e3c84e02f 100644 --- a/interface/src/avatar/AvatarDoctor.h +++ b/interface/src/avatar/AvatarDoctor.h @@ -53,7 +53,7 @@ private: int _materialMappingCount = 0; int _materialMappingLoadedCount = 0; - GeometryResource::Pointer _model; + ModelResource::Pointer _model; bool _isDiagnosing = false; }; diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp index fe943d5b84..9f8510c603 100644 --- a/interface/src/raypick/CollisionPick.cpp +++ b/interface/src/raypick/CollisionPick.cpp @@ -134,7 +134,7 @@ bool CollisionPick::getShapeInfoReady(const CollisionRegion& pick) { return _mathPick.loaded; } -void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) { +void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) { ShapeType type = shapeInfo.getType(); glm::vec3 dimensions = pick.transform.getScale(); QString modelURL = (resource ? resource->getURL().toString() : ""); @@ -147,7 +147,7 @@ void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick, } } -void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) { +void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) { // This code was copied and modified from RenderableModelEntityItem::computeShapeInfo // TODO: Move to some shared code area (in entities-renderer? model-networking?) // after we verify this is working and do a diff comparison with RenderableModelEntityItem::computeShapeInfo @@ -381,7 +381,7 @@ CollisionPick::CollisionPick(const PickFilter& filter, float maxDistance, bool e _scaleWithParent(scaleWithParent), _physicsEngine(physicsEngine) { if (collisionRegion.shouldComputeShapeInfo()) { - _cachedResource = DependencyManager::get()->getCollisionGeometryResource(collisionRegion.modelURL); + _cachedResource = DependencyManager::get()->getCollisionModelResource(collisionRegion.modelURL); } _mathPick.loaded = isLoaded(); } diff --git a/interface/src/raypick/CollisionPick.h b/interface/src/raypick/CollisionPick.h index 24317bf19a..115ee1727e 100644 --- a/interface/src/raypick/CollisionPick.h +++ b/interface/src/raypick/CollisionPick.h @@ -63,14 +63,14 @@ protected: bool isLoaded() const; // Returns true if _mathPick.shapeInfo is valid. Otherwise, attempts to get the _mathPick ready for use. bool getShapeInfoReady(const CollisionRegion& pick); - void computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); - void computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); + void computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); + void computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); void filterIntersections(std::vector& intersections) const; bool _scaleWithParent; PhysicsEnginePointer _physicsEngine; - QSharedPointer _cachedResource; + QSharedPointer _cachedResource; // Options for what information to get from collision results bool _includeNormals; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 75a7693de8..e9ae278710 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -955,7 +955,7 @@ void Avatar::simulateAttachments(float deltaTime) { bool texturesLoaded = _attachmentModelsTexturesLoaded.at(i); // Watch for texture loading - if (!texturesLoaded && model->getGeometry() && model->getGeometry()->areTexturesLoaded()) { + if (!texturesLoaded && model->getNetworkModel() && model->getNetworkModel()->areTexturesLoaded()) { _attachmentModelsTexturesLoaded[i] = true; model->updateRenderItems(); } diff --git a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp index ac9819803e..bda7fab0a4 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp @@ -177,7 +177,7 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { // FIXME: This texture loading logic should probably live in Avatar, to mirror RenderableModelEntityItem, // but Avatars don't get updates in the same way - if (!_texturesLoaded && getGeometry() && getGeometry()->areTexturesLoaded()) { + if (!_texturesLoaded && getNetworkModel() && getNetworkModel()->areTexturesLoaded()) { _texturesLoaded = true; updateRenderItems(); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 7c9e8e5f13..e75b28f9ed 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -282,7 +282,7 @@ bool RenderableModelEntityItem::findDetailedParabolaIntersection(const glm::vec3 } void RenderableModelEntityItem::fetchCollisionGeometryResource() { - _collisionGeometryResource = DependencyManager::get()->getCollisionGeometryResource(getCollisionShapeURL()); + _collisionGeometryResource = DependencyManager::get()->getCollisionModelResource(getCollisionShapeURL()); } bool RenderableModelEntityItem::unableToLoadCollisionShape() { @@ -504,7 +504,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { meshes.push_back(hfmMesh._mesh); } } else { - meshes = model->getGeometry()->getMeshes(); + meshes = model->getNetworkModel()->getMeshes(); } int32_t numMeshes = (int32_t)(meshes.size()); @@ -1431,7 +1431,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce } } - if (!_texturesLoaded && model->getGeometry() && model->getGeometry()->areTexturesLoaded()) { + if (!_texturesLoaded && model->getNetworkModel() && model->getNetworkModel()->areTexturesLoaded()) { withWriteLock([&] { _texturesLoaded = true; }); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index c32dad901f..d9a8c08890 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -120,7 +120,7 @@ private: bool readyToAnimate() const; void fetchCollisionGeometryResource(); - GeometryResource::Pointer _collisionGeometryResource; + ModelResource::Pointer _collisionGeometryResource; std::vector _jointMap; QVariantMap _originalTextures; bool _jointMapCompleted { false }; diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index a97cc7c84c..853a8385f0 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -194,7 +194,7 @@ float importanceSample3DDimension(float startDim) { } ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties, - const ShapeType& shapeType, const GeometryResource::Pointer& geometryResource, + const ShapeType& shapeType, const ModelResource::Pointer& geometryResource, const TriangleInfo& triangleInfo) { CpuParticle particle; @@ -379,7 +379,7 @@ void ParticleEffectEntityRenderer::stepSimulation() { particle::Properties particleProperties; ShapeType shapeType; - GeometryResource::Pointer geometryResource; + ModelResource::Pointer geometryResource; withReadLock([&] { particleProperties = _particleProperties; shapeType = _shapeType; @@ -482,7 +482,7 @@ void ParticleEffectEntityRenderer::fetchGeometryResource() { if (hullURL.isEmpty()) { _geometryResource.reset(); } else { - _geometryResource = DependencyManager::get()->getCollisionGeometryResource(hullURL); + _geometryResource = DependencyManager::get()->getCollisionModelResource(hullURL); } } diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index cc907f2b1d..d585104f5c 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -89,7 +89,7 @@ private: } _triangleInfo; static CpuParticle createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties, - const ShapeType& shapeType, const GeometryResource::Pointer& geometryResource, + const ShapeType& shapeType, const ModelResource::Pointer& geometryResource, const TriangleInfo& triangleInfo); void stepSimulation(); @@ -108,7 +108,7 @@ private: QString _compoundShapeURL; void fetchGeometryResource(); - GeometryResource::Pointer _geometryResource; + ModelResource::Pointer _geometryResource; NetworkTexturePointer _networkTexture; ScenePointer _scene; diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 0771d9ad54..d54998e74f 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -345,7 +345,7 @@ bool ZoneEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, c } bool ZoneEntityItem::contains(const glm::vec3& point) const { - GeometryResource::Pointer resource = _shapeResource; + ModelResource::Pointer resource = _shapeResource; if (_shapeType == SHAPE_TYPE_COMPOUND && resource) { if (resource->isLoaded()) { const HFMModel& hfmModel = resource->getHFMModel(); @@ -462,7 +462,7 @@ void ZoneEntityItem::fetchCollisionGeometryResource() { if (hullURL.isEmpty()) { _shapeResource.reset(); } else { - _shapeResource = DependencyManager::get()->getCollisionGeometryResource(hullURL); + _shapeResource = DependencyManager::get()->getCollisionModelResource(hullURL); } } diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 34ad47f095..d6647e701e 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -167,7 +167,7 @@ protected: static bool _zonesArePickable; void fetchCollisionGeometryResource(); - GeometryResource::Pointer _shapeResource; + ModelResource::Pointer _shapeResource; }; diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index 1752c2f024..0299648294 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -1377,11 +1377,13 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const // Now that we've initialized the joint, we can define the transform // modelIDs is ordered from parent to children, so we can safely get parent transforms from earlier joints as we iterate - joint.globalTransform = glm::translate(joint.translation) * joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation * joint.postRotation) * joint.postTransform; + joint.localTransform = glm::translate(joint.translation) * joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation * joint.postRotation) * joint.postTransform; + joint.globalTransform = joint.localTransform; if (joint.parentIndex != -1 && joint.parentIndex < (int)jointIndex && !needMixamoHack) { hfm::Joint& parentJoint = hfmModel.joints[joint.parentIndex]; - // joint.globalTransform = joint.globalTransform * parentJoint.globalTransform; - joint.globalTransform = parentJoint.globalTransform * joint.globalTransform; + // SG Change: i think this not correct and the [parent]*[local] is the correct answer here + //joint.globalTransform = joint.globalTransform * parentJoint.globalTransform; + joint.globalTransform = parentJoint.globalTransform * joint.localTransform; if (parentJoint.hasGeometricOffset) { // Per the FBX standard, geometric offset should not propagate to children. // However, we must be careful when modifying the behavior of FBXSerializer. @@ -1396,13 +1398,21 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const joint.globalTransform = joint.globalTransform * geometricOffset; } - // accumulate local transforms + // TODO: Remove these lines, just here to make sure we are not breaking the transform computation // QString modelID = fbxModels.contains(it.key()) ? it.key() : _connectionParentMap.value(it.key()); glm::mat4 anotherModelTransform = getGlobalTransform(_connectionParentMap, fbxModels, modelID, hfmModel.applicationName == "mixamo.com", url); - /* if (anotherModelTransform != joint.globalTransform) { - joint.globalTransform = anotherModelTransform; + auto col0 = (glm::epsilonNotEqual(anotherModelTransform[0], joint.globalTransform[0], 0.001f)); + auto col1 = (glm::epsilonNotEqual(anotherModelTransform[1], joint.globalTransform[1], 0.001f)); + auto col2 = (glm::epsilonNotEqual(anotherModelTransform[2], joint.globalTransform[2], 0.001f)); + auto col3 = (glm::epsilonNotEqual(anotherModelTransform[3], joint.globalTransform[3], 0.001f)); + if ( glm::any(col0) + || glm::any(col1) + || glm::any(col2) + || glm::any(col3)) { + anotherModelTransform = getGlobalTransform(_connectionParentMap, fbxModels, modelID, hfmModel.applicationName == "mixamo.com", url); + // joint.globalTransform = anotherModelTransform; } -*/ + hfmModel.joints.push_back(joint); } diff --git a/libraries/hfm/src/hfm/HFM.h b/libraries/hfm/src/hfm/HFM.h index 08410f17f2..96030672f2 100644 --- a/libraries/hfm/src/hfm/HFM.h +++ b/libraries/hfm/src/hfm/HFM.h @@ -120,6 +120,7 @@ public: glm::vec3 geometricScaling; // globalTransform is the transform of the joint with all parent transforms applied, plus the geometric offset + glm::mat4 localTransform; glm::mat4 globalTransform; }; diff --git a/libraries/material-networking/src/material-networking/MaterialCache.h b/libraries/material-networking/src/material-networking/MaterialCache.h index aa103adb1e..31bbd02198 100644 --- a/libraries/material-networking/src/material-networking/MaterialCache.h +++ b/libraries/material-networking/src/material-networking/MaterialCache.h @@ -50,7 +50,7 @@ public: Textures getTextures() { return _textures; } protected: - friend class Geometry; + friend class NetworkModel; Textures _textures; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 1fcfcfcc70..e1df0f95c7 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -203,23 +203,23 @@ QUrl resolveTextureBaseUrl(const QUrl& url, const QUrl& textureBaseUrl) { return textureBaseUrl.isValid() ? textureBaseUrl : url; } -GeometryResource::GeometryResource(const GeometryResource& other) : +ModelResource::ModelResource(const ModelResource& other) : Resource(other), - Geometry(other), + NetworkModel(other), _modelLoader(other._modelLoader), _mappingPair(other._mappingPair), _textureBaseURL(other._textureBaseURL), _combineParts(other._combineParts), _isCacheable(other._isCacheable) { - if (other._geometryResource) { + if (other._modelResource) { _startedLoading = false; } } -void GeometryResource::downloadFinished(const QByteArray& data) { +void ModelResource::downloadFinished(const QByteArray& data) { if (_effectiveBaseURL.fileName().toLower().endsWith(".fst")) { - PROFILE_ASYNC_BEGIN(resource_parse_geometry, "GeometryResource::downloadFinished", _url.toString(), { { "url", _url.toString() } }); + PROFILE_ASYNC_BEGIN(resource_parse_geometry, "ModelResource::downloadFinished", _url.toString(), { { "url", _url.toString() } }); // store parsed contents of FST file _mapping = FSTReader::readMapping(data); @@ -267,19 +267,19 @@ void GeometryResource::downloadFinished(const QByteArray& data) { auto modelCache = DependencyManager::get(); GeometryExtra extra { GeometryMappingPair(base, _mapping), _textureBaseURL, false }; - // Get the raw GeometryResource - _geometryResource = modelCache->getResource(url, QUrl(), &extra, std::hash()(extra)).staticCast(); + // Get the raw ModelResource + _modelResource = modelCache->getResource(url, QUrl(), &extra, std::hash()(extra)).staticCast(); // Avoid caching nested resources - their references will be held by the parent - _geometryResource->_isCacheable = false; + _modelResource->_isCacheable = false; - if (_geometryResource->isLoaded()) { - onGeometryMappingLoaded(!_geometryResource->getURL().isEmpty()); + if (_modelResource->isLoaded()) { + onGeometryMappingLoaded(!_modelResource->getURL().isEmpty()); } else { if (_connection) { disconnect(_connection); } - _connection = connect(_geometryResource.data(), &Resource::finished, this, &GeometryResource::onGeometryMappingLoaded); + _connection = connect(_modelResource.data(), &Resource::finished, this, &ModelResource::onGeometryMappingLoaded); } } } else { @@ -291,32 +291,32 @@ void GeometryResource::downloadFinished(const QByteArray& data) { } } -void GeometryResource::onGeometryMappingLoaded(bool success) { - if (success && _geometryResource) { - _hfmModel = _geometryResource->_hfmModel; - _materialMapping = _geometryResource->_materialMapping; - _meshParts = _geometryResource->_meshParts; - _meshes = _geometryResource->_meshes; - _materials = _geometryResource->_materials; +void ModelResource::onGeometryMappingLoaded(bool success) { + if (success && _modelResource) { + _hfmModel = _modelResource->_hfmModel; + _materialMapping = _modelResource->_materialMapping; + _meshParts = _modelResource->_meshParts; + _meshes = _modelResource->_meshes; + _materials = _modelResource->_materials; // Avoid holding onto extra references - _geometryResource.reset(); + _modelResource.reset(); // Make sure connection will not trigger again disconnect(_connection); // FIXME Should not have to do this } - PROFILE_ASYNC_END(resource_parse_geometry, "GeometryResource::downloadFinished", _url.toString()); + PROFILE_ASYNC_END(resource_parse_geometry, "ModelResource::downloadFinished", _url.toString()); finishedLoading(success); } -void GeometryResource::setExtra(void* extra) { +void ModelResource::setExtra(void* extra) { const GeometryExtra* geometryExtra = static_cast(extra); _mappingPair = geometryExtra ? geometryExtra->mapping : GeometryMappingPair(QUrl(), QVariantHash()); _textureBaseURL = geometryExtra ? resolveTextureBaseUrl(_url, geometryExtra->textureBaseUrl) : QUrl(); _combineParts = geometryExtra ? geometryExtra->combineParts : true; } -void GeometryResource::setGeometryDefinition(HFMModel::Pointer hfmModel, const MaterialMapping& materialMapping) { +void ModelResource::setGeometryDefinition(HFMModel::Pointer hfmModel, const MaterialMapping& materialMapping) { // Assume ownership of the processed HFMModel _hfmModel = hfmModel; _materialMapping = materialMapping; @@ -348,12 +348,12 @@ void GeometryResource::setGeometryDefinition(HFMModel::Pointer hfmModel, const M finishedLoading(true); } -void GeometryResource::deleter() { +void ModelResource::deleter() { resetTextures(); Resource::deleter(); } -void GeometryResource::setTextures() { +void ModelResource::setTextures() { if (_hfmModel) { for (const HFMMaterial& material : _hfmModel->materials) { _materials.push_back(std::make_shared(material, _textureBaseURL)); @@ -361,7 +361,7 @@ void GeometryResource::setTextures() { } } -void GeometryResource::resetTextures() { +void ModelResource::resetTextures() { _materials.clear(); } @@ -377,17 +377,17 @@ ModelCache::ModelCache() { } QSharedPointer ModelCache::createResource(const QUrl& url) { - return QSharedPointer(new GeometryResource(url, _modelLoader), &GeometryResource::deleter); + return QSharedPointer(new ModelResource(url, _modelLoader), &ModelResource::deleter); } QSharedPointer ModelCache::createResourceCopy(const QSharedPointer& resource) { - return QSharedPointer(new GeometryResource(*resource.staticCast()), &GeometryResource::deleter); + return QSharedPointer(new ModelResource(*resource.staticCast()), &ModelResource::deleter); } -GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url, const GeometryMappingPair& mapping, const QUrl& textureBaseUrl) { +ModelResource::Pointer ModelCache::getModelResource(const QUrl& url, const GeometryMappingPair& mapping, const QUrl& textureBaseUrl) { bool combineParts = true; GeometryExtra geometryExtra = { mapping, textureBaseUrl, combineParts }; - GeometryResource::Pointer resource = getResource(url, QUrl(), &geometryExtra, std::hash()(geometryExtra)).staticCast(); + ModelResource::Pointer resource = getResource(url, QUrl(), &geometryExtra, std::hash()(geometryExtra)).staticCast(); if (resource) { if (resource->isLoaded() && resource->shouldSetTextures()) { resource->setTextures(); @@ -396,12 +396,12 @@ GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url, const return resource; } -GeometryResource::Pointer ModelCache::getCollisionGeometryResource(const QUrl& url, +ModelResource::Pointer ModelCache::getCollisionModelResource(const QUrl& url, const GeometryMappingPair& mapping, const QUrl& textureBaseUrl) { bool combineParts = false; GeometryExtra geometryExtra = { mapping, textureBaseUrl, combineParts }; - GeometryResource::Pointer resource = getResource(url, QUrl(), &geometryExtra, std::hash()(geometryExtra)).staticCast(); + ModelResource::Pointer resource = getResource(url, QUrl(), &geometryExtra, std::hash()(geometryExtra)).staticCast(); if (resource) { if (resource->isLoaded() && resource->shouldSetTextures()) { resource->setTextures(); @@ -410,7 +410,7 @@ GeometryResource::Pointer ModelCache::getCollisionGeometryResource(const QUrl& u return resource; } -const QVariantMap Geometry::getTextures() const { +const QVariantMap NetworkModel::getTextures() const { QVariantMap textures; for (const auto& material : _materials) { for (const auto& texture : material->_textures) { @@ -424,22 +424,22 @@ const QVariantMap Geometry::getTextures() const { } // FIXME: The materials should only be copied when modified, but the Model currently caches the original -Geometry::Geometry(const Geometry& geometry) { - _hfmModel = geometry._hfmModel; - _materialMapping = geometry._materialMapping; - _meshes = geometry._meshes; - _meshParts = geometry._meshParts; +NetworkModel::NetworkModel(const NetworkModel& networkModel) { + _hfmModel = networkModel._hfmModel; + _materialMapping = networkModel._materialMapping; + _meshes = networkModel._meshes; + _meshParts = networkModel._meshParts; - _materials.reserve(geometry._materials.size()); - for (const auto& material : geometry._materials) { + _materials.reserve(networkModel._materials.size()); + for (const auto& material : networkModel._materials) { _materials.push_back(std::make_shared(*material)); } - _animGraphOverrideUrl = geometry._animGraphOverrideUrl; - _mapping = geometry._mapping; + _animGraphOverrideUrl = networkModel._animGraphOverrideUrl; + _mapping = networkModel._mapping; } -void Geometry::setTextures(const QVariantMap& textureMap) { +void NetworkModel::setTextures(const QVariantMap& textureMap) { if (_meshes->size() > 0) { for (auto& material : _materials) { // Check if any material textures actually changed @@ -447,7 +447,7 @@ void Geometry::setTextures(const QVariantMap& textureMap) { [&textureMap](const NetworkMaterial::Textures::value_type& it) { return it.second.texture && textureMap.contains(it.second.name); })) { // FIXME: The Model currently caches the materials (waste of space!) - // so they must be copied in the Geometry copy-ctor + // so they must be copied in the NetworkModel copy-ctor // if (material->isOriginal()) { // // Copy the material to avoid mutating the cached version // material = std::make_shared(*material); @@ -461,11 +461,11 @@ void Geometry::setTextures(const QVariantMap& textureMap) { // If we only use cached textures, they should all be loaded areTexturesLoaded(); } else { - qCWarning(modelnetworking) << "Ignoring setTextures(); geometry not ready"; + qCWarning(modelnetworking) << "Ignoring setTextures(); NetworkModel not ready"; } } -bool Geometry::areTexturesLoaded() const { +bool NetworkModel::areTexturesLoaded() const { if (!_areTexturesLoaded) { for (auto& material : _materials) { if (material->isMissingTexture()) { @@ -500,30 +500,35 @@ bool Geometry::areTexturesLoaded() const { return true; } -const std::shared_ptr Geometry::getShapeMaterial(int partID) const { - if ((partID >= 0) && (partID < (int)_meshParts->size())) { +const std::shared_ptr NetworkModel::getShapeMaterial(int partID) const { + /* if ((partID >= 0) && (partID < (int)_meshParts->size())) { int materialID = _meshParts->at(partID)->materialID; if ((materialID >= 0) && (materialID < (int)_materials.size())) { return _materials[materialID]; } + }*/ + + auto materialID = getHFMModel().shapes[partID].material; + if ((materialID >= 0) && (materialID < (int)_materials.size())) { + return _materials[materialID]; } return nullptr; } -void GeometryResourceWatcher::startWatching() { - connect(_resource.data(), &Resource::finished, this, &GeometryResourceWatcher::resourceFinished); - connect(_resource.data(), &Resource::onRefresh, this, &GeometryResourceWatcher::resourceRefreshed); +void ModelResourceWatcher::startWatching() { + connect(_resource.data(), &Resource::finished, this, &ModelResourceWatcher::resourceFinished); + connect(_resource.data(), &Resource::onRefresh, this, &ModelResourceWatcher::resourceRefreshed); if (_resource->isLoaded()) { resourceFinished(!_resource->getURL().isEmpty()); } } -void GeometryResourceWatcher::stopWatching() { - disconnect(_resource.data(), &Resource::finished, this, &GeometryResourceWatcher::resourceFinished); - disconnect(_resource.data(), &Resource::onRefresh, this, &GeometryResourceWatcher::resourceRefreshed); +void ModelResourceWatcher::stopWatching() { + disconnect(_resource.data(), &Resource::finished, this, &ModelResourceWatcher::resourceFinished); + disconnect(_resource.data(), &Resource::onRefresh, this, &ModelResourceWatcher::resourceRefreshed); } -void GeometryResourceWatcher::setResource(GeometryResource::Pointer resource) { +void ModelResourceWatcher::setResource(ModelResource::Pointer resource) { if (_resource) { stopWatching(); } @@ -537,14 +542,14 @@ void GeometryResourceWatcher::setResource(GeometryResource::Pointer resource) { } } -void GeometryResourceWatcher::resourceFinished(bool success) { +void ModelResourceWatcher::resourceFinished(bool success) { if (success) { - _geometryRef = std::make_shared(*_resource); + _networkModelRef = std::make_shared(*_resource); } emit finished(success); } -void GeometryResourceWatcher::resourceRefreshed() { +void ModelResourceWatcher::resourceRefreshed() { // FIXME: Model is not set up to handle a refresh // _instance.reset(); } diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 5b78c18184..9fdae339f7 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -27,14 +27,14 @@ class MeshPart; using GeometryMappingPair = std::pair; Q_DECLARE_METATYPE(GeometryMappingPair) -class Geometry { +class NetworkModel { public: - using Pointer = std::shared_ptr; - using WeakPointer = std::weak_ptr; + using Pointer = std::shared_ptr; + using WeakPointer = std::weak_ptr; - Geometry() = default; - Geometry(const Geometry& geometry); - virtual ~Geometry() = default; + NetworkModel() = default; + NetworkModel(const NetworkModel& geometry); + virtual ~NetworkModel() = default; // Immutable over lifetime using GeometryMeshes = std::vector>; @@ -76,22 +76,22 @@ private: }; /// A geometry loaded from the network. -class GeometryResource : public Resource, public Geometry { +class ModelResource : public Resource, public NetworkModel { Q_OBJECT public: - using Pointer = QSharedPointer; + using Pointer = QSharedPointer; - GeometryResource(const QUrl& url, const ModelLoader& modelLoader) : Resource(url), _modelLoader(modelLoader) {} - GeometryResource(const GeometryResource& other); + ModelResource(const QUrl& url, const ModelLoader& modelLoader) : Resource(url), _modelLoader(modelLoader) {} + ModelResource(const ModelResource& other); - QString getType() const override { return "Geometry"; } + QString getType() const override { return "Model"; } virtual void deleter() override; virtual void downloadFinished(const QByteArray& data) override; void setExtra(void* extra) override; - virtual bool areTexturesLoaded() const override { return isLoaded() && Geometry::areTexturesLoaded(); } + virtual bool areTexturesLoaded() const override { return isLoaded() && NetworkModel::areTexturesLoaded(); } private slots: void onGeometryMappingLoaded(bool success); @@ -115,21 +115,21 @@ private: QUrl _textureBaseURL; bool _combineParts; - GeometryResource::Pointer _geometryResource; + ModelResource::Pointer _modelResource; QMetaObject::Connection _connection; bool _isCacheable{ true }; }; -class GeometryResourceWatcher : public QObject { +class ModelResourceWatcher : public QObject { Q_OBJECT public: - using Pointer = std::shared_ptr; + using Pointer = std::shared_ptr; - GeometryResourceWatcher() = delete; - GeometryResourceWatcher(Geometry::Pointer& geometryPtr) : _geometryRef(geometryPtr) {} + ModelResourceWatcher() = delete; + ModelResourceWatcher(NetworkModel::Pointer& geometryPtr) : _networkModelRef(geometryPtr) {} - void setResource(GeometryResource::Pointer resource); + void setResource(ModelResource::Pointer resource); QUrl getURL() const { return (bool)_resource ? _resource->getURL() : QUrl(); } int getResourceDownloadAttempts() { return _resource ? _resource->getDownloadAttempts() : 0; } @@ -147,8 +147,8 @@ private slots: void resourceRefreshed(); private: - GeometryResource::Pointer _resource; - Geometry::Pointer& _geometryRef; + ModelResource::Pointer _resource; + NetworkModel::Pointer& _networkModelRef; }; /// Stores cached model geometries. @@ -158,18 +158,18 @@ class ModelCache : public ResourceCache, public Dependency { public: - GeometryResource::Pointer getGeometryResource(const QUrl& url, + ModelResource::Pointer getModelResource(const QUrl& url, const GeometryMappingPair& mapping = GeometryMappingPair(QUrl(), QVariantHash()), const QUrl& textureBaseUrl = QUrl()); - GeometryResource::Pointer getCollisionGeometryResource(const QUrl& url, + ModelResource::Pointer getCollisionModelResource(const QUrl& url, const GeometryMappingPair& mapping = GeometryMappingPair(QUrl(), QVariantHash()), const QUrl& textureBaseUrl = QUrl()); protected: - friend class GeometryResource; + friend class ModelResource; virtual QSharedPointer createResource(const QUrl& url) override; QSharedPointer createResourceCopy(const QSharedPointer& resource) override; diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 9cdefa0545..6e8f37d354 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -87,7 +87,7 @@ void CauterizedModel::createRenderItemSet() { for (int partIndex = 0; partIndex < numParts; partIndex++) { auto ptr = std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset); _modelMeshRenderItems << std::static_pointer_cast(ptr); - auto material = getGeometry()->getShapeMaterial(shapeID); + auto material = getNetworkModel()->getShapeMaterial(shapeID); _modelMeshMaterialNames.push_back(material ? material->getName() : ""); _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i }); shapeID++; diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 1a6e5dbadc..fcf0ffaa48 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -202,9 +202,13 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in assert(model && model->isLoaded()); + auto shape = model->getHFMModel().shapes[shapeIndex]; + assert(shape.mesh == meshIndex); + assert(shape.meshPart == partIndex); + bool useDualQuaternionSkinning = model->getUseDualQuaternionSkinning(); - auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex); + auto& modelMesh = model->getNetworkModel()->getMeshes().at(_meshIndex); _meshNumVertices = (int)modelMesh->getNumVertices(); const Model::MeshState& state = model->getMeshState(_meshIndex); @@ -263,7 +267,7 @@ void ModelMeshPartPayload::initCache(const ModelPointer& model) { _hasTangents = !mesh.tangents.isEmpty(); } - auto networkMaterial = model->getGeometry()->getShapeMaterial(_shapeID); + auto networkMaterial = model->getNetworkModel()->getShapeMaterial(_shapeID); if (networkMaterial) { addMaterial(graphics::MaterialLayer(networkMaterial, 0)); } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index aa3708fb1e..f9e980b2ac 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -42,7 +42,7 @@ using namespace std; int nakedModelPointerTypeId = qRegisterMetaType(); -int weakGeometryResourceBridgePointerTypeId = qRegisterMetaType(); +int weakGeometryResourceBridgePointerTypeId = qRegisterMetaType(); int vec3VectorTypeId = qRegisterMetaType>(); int normalTypeVecTypeId = qRegisterMetaType>("QVector"); float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f; @@ -71,7 +71,7 @@ Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) : setSnapModelToRegistrationPoint(true, glm::vec3(0.5f)); - connect(&_renderWatcher, &GeometryResourceWatcher::finished, this, &Model::loadURLFinished); + connect(&_renderWatcher, &ModelResourceWatcher::finished, this, &Model::loadURLFinished); } Model::~Model() { @@ -151,7 +151,7 @@ void Model::setOffset(const glm::vec3& offset) { } void Model::calculateTextureInfo() { - if (!_hasCalculatedTextureInfo && isLoaded() && getGeometry()->areTexturesLoaded() && !_modelMeshRenderItemsMap.isEmpty()) { + if (!_hasCalculatedTextureInfo && isLoaded() && getNetworkModel()->areTexturesLoaded() && !_modelMeshRenderItemsMap.isEmpty()) { size_t textureSize = 0; int textureCount = 0; bool allTexturesLoaded = true; @@ -178,12 +178,12 @@ int Model::getRenderInfoTextureCount() { } bool Model::shouldInvalidatePayloadShapeKey(int meshIndex) { - if (!getGeometry()) { + if (!getNetworkModel()) { return true; } const HFMModel& hfmModel = getHFMModel(); - const auto& networkMeshes = getGeometry()->getMeshes(); + 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()) { @@ -643,8 +643,8 @@ glm::mat4 Model::getWorldToHFMMatrix() const { // TODO: deprecate and remove MeshProxyList Model::getMeshes() const { MeshProxyList result; - const Geometry::Pointer& renderGeometry = getGeometry(); - const Geometry::GeometryMeshes& meshes = renderGeometry->getMeshes(); + const NetworkModel::Pointer& renderGeometry = getNetworkModel(); + const NetworkModel::GeometryMeshes& meshes = renderGeometry->getMeshes(); if (!isLoaded()) { return result; @@ -772,7 +772,7 @@ scriptable::ScriptableModelBase Model::getScriptableModel() { int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { auto& materialName = _modelMeshMaterialNames[shapeID]; - result.appendMaterial(graphics::MaterialLayer(getGeometry()->getShapeMaterial(shapeID), 0), shapeID, materialName); + result.appendMaterial(graphics::MaterialLayer(getNetworkModel()->getShapeMaterial(shapeID), 0), shapeID, materialName); { std::unique_lock lock(_materialMappingMutex); @@ -1196,7 +1196,7 @@ void Model::setURL(const QUrl& url) { invalidCalculatedMeshBoxes(); deleteGeometry(); - auto resource = DependencyManager::get()->getGeometryResource(url); + auto resource = DependencyManager::get()->getModelResource(url); if (resource) { resource->setLoadPriority(this, _loadingPriority); _renderWatcher.setResource(resource); @@ -1487,7 +1487,7 @@ void Model::createRenderItemSet() { int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { _modelMeshRenderItems << std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset); - auto material = getGeometry()->getShapeMaterial(shapeID); + auto material = getNetworkModel()->getShapeMaterial(shapeID); _modelMeshMaterialNames.push_back(material ? material->getName() : ""); _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i }); shapeID++; @@ -1680,7 +1680,7 @@ void Model::removeMaterial(graphics::MaterialPointer material, const std::string AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); } -class CollisionRenderGeometry : public Geometry { +class CollisionRenderGeometry : public NetworkModel { public: CollisionRenderGeometry(graphics::MeshPointer mesh) { _hfmModel = std::make_shared(); @@ -1838,7 +1838,7 @@ void Blender::run() { bool Model::maybeStartBlender() { if (isLoaded()) { - QThreadPool::globalInstance()->start(new Blender(getThisPointer(), getGeometry()->getConstHFMModelPointer(), + QThreadPool::globalInstance()->start(new Blender(getThisPointer(), getNetworkModel()->getConstHFMModelPointer(), ++_blendNumber, _blendshapeCoefficients)); return true; } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 2ea1f87fae..79ddaeb68d 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -178,7 +178,7 @@ public: virtual void updateClusterMatrices(); /// Returns a reference to the shared geometry. - const Geometry::Pointer& getGeometry() const { return _renderGeometry; } + const NetworkModel::Pointer& getNetworkModel() const { return _renderGeometry; } const QVariantMap getTextures() const { assert(isLoaded()); return _renderGeometry->getTextures(); } Q_INVOKABLE virtual void setTextures(const QVariantMap& textures); @@ -391,9 +391,9 @@ protected: /// \return true if joint exists bool getJointPosition(int jointIndex, glm::vec3& position) const; - Geometry::Pointer _renderGeometry; // only ever set by its watcher + NetworkModel::Pointer _renderGeometry; // only ever set by its watcher - GeometryResourceWatcher _renderWatcher; + ModelResourceWatcher _renderWatcher; SpatiallyNestable* _spatiallyNestableOverride; @@ -515,7 +515,7 @@ private: }; Q_DECLARE_METATYPE(ModelPointer) -Q_DECLARE_METATYPE(Geometry::WeakPointer) +Q_DECLARE_METATYPE(NetworkModel::WeakPointer) Q_DECLARE_METATYPE(BlendshapeOffset) /// Handle management of pending models that need blending From 936ac6f120fe5fe6a56e719ac122f48f6ddd2d8d Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 7 Oct 2019 18:03:33 -0700 Subject: [PATCH 04/10] REmoving more repetitions of the meshParts --- .../src/model-networking/ModelCache.cpp | 22 +++---------------- .../src/model-networking/ModelCache.h | 12 ---------- libraries/render-utils/src/Model.cpp | 1 - 3 files changed, 3 insertions(+), 32 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index e1df0f95c7..2376beba30 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -295,7 +295,7 @@ void ModelResource::onGeometryMappingLoaded(bool success) { if (success && _modelResource) { _hfmModel = _modelResource->_hfmModel; _materialMapping = _modelResource->_materialMapping; - _meshParts = _modelResource->_meshParts; + // _meshParts = _modelResource->_meshParts; _meshes = _modelResource->_meshes; _materials = _modelResource->_materials; @@ -329,21 +329,13 @@ void ModelResource::setGeometryDefinition(HFMModel::Pointer hfmModel, const Mate } std::shared_ptr meshes = std::make_shared(); - std::shared_ptr parts = std::make_shared(); int meshID = 0; for (const HFMMesh& mesh : _hfmModel->meshes) { // Copy mesh pointers meshes->emplace_back(mesh._mesh); - int partID = 0; - for (const HFMMeshPart& part : mesh.parts) { - // Construct local parts - parts->push_back(std::make_shared(meshID, partID, (int)materialIDAtlas[part.materialID])); - partID++; - } meshID++; } _meshes = meshes; - _meshParts = parts; finishedLoading(true); } @@ -428,7 +420,6 @@ NetworkModel::NetworkModel(const NetworkModel& networkModel) { _hfmModel = networkModel._hfmModel; _materialMapping = networkModel._materialMapping; _meshes = networkModel._meshes; - _meshParts = networkModel._meshParts; _materials.reserve(networkModel._materials.size()); for (const auto& material : networkModel._materials) { @@ -500,15 +491,8 @@ bool NetworkModel::areTexturesLoaded() const { return true; } -const std::shared_ptr NetworkModel::getShapeMaterial(int partID) const { - /* if ((partID >= 0) && (partID < (int)_meshParts->size())) { - int materialID = _meshParts->at(partID)->materialID; - if ((materialID >= 0) && (materialID < (int)_materials.size())) { - return _materials[materialID]; - } - }*/ - - auto materialID = getHFMModel().shapes[partID].material; +const std::shared_ptr NetworkModel::getShapeMaterial(int shapeID) const { + auto materialID = getHFMModel().shapes[shapeID].material; if ((materialID >= 0) && (materialID < (int)_materials.size())) { return _materials[materialID]; } diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 9fdae339f7..87dbbe975d 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -22,8 +22,6 @@ #include #include "ModelLoader.h" -class MeshPart; - using GeometryMappingPair = std::pair; Q_DECLARE_METATYPE(GeometryMappingPair) @@ -38,7 +36,6 @@ public: // Immutable over lifetime using GeometryMeshes = std::vector>; - using GeometryMeshParts = std::vector>; // Mutable, but must retain structure of vector using NetworkMaterials = std::vector>; @@ -63,7 +60,6 @@ protected: HFMModel::ConstPointer _hfmModel; MaterialMapping _materialMapping; std::shared_ptr _meshes; - std::shared_ptr _meshParts; // Copied to each geometry, mutable throughout lifetime via setTextures NetworkMaterials _materials; @@ -180,12 +176,4 @@ private: ModelLoader _modelLoader; }; -class MeshPart { -public: - MeshPart(int mesh, int part, int material) : meshID { mesh }, partID { part }, materialID { material } {} - int meshID { -1 }; - int partID { -1 }; - int materialID { -1 }; -}; - #endif // hifi_ModelCache_h diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index f9e980b2ac..f39038aa74 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1687,7 +1687,6 @@ public: std::shared_ptr meshes = std::make_shared(); meshes->push_back(mesh); _meshes = meshes; - _meshParts = std::shared_ptr(); } }; From 2626f85f49d1ab7d598857077f7533d5c8f7396e Mon Sep 17 00:00:00 2001 From: dooglifeSF <41022919+dooglifeSF@users.noreply.github.com> Date: Tue, 8 Oct 2019 15:44:06 -0700 Subject: [PATCH 05/10] Handle multiple inputs, bias towards inputZ instead of inputX, and add a deadzone that matches xbox controller analog deadzone --- libraries/animation/src/Rig.cpp | 47 ++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 88b42285cd..7f83fb5218 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -2160,40 +2160,43 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo } } - //TODO: how to handle multiple inputs? Is there a trick to prioritize fwd/bwd with order of operations? - if (params.inputX) { - if (params.inputX > 0.0f) { - // left + //deadzone constant + #define INPUT_DEADZONE_THRESHOLD 0.05f + + if (abs(params.inputZ) > INPUT_DEADZONE_THRESHOLD && abs(params.inputZ) >= abs(params.inputX)) { + if (params.inputZ > INPUT_DEADZONE_THRESHOLD) { + // forward + _animVars.set("isInputForward", true); + _animVars.set("isInputBackward", false); + _animVars.set("isInputRight", false); + _animVars.set("isInputLeft", false); + _animVars.set("isNotInput", false); + } + else { + // backward + _animVars.set("isInputForward", false); + _animVars.set("isInputBackward", true); + _animVars.set("isInputRight", false); + _animVars.set("isInputLeft", false); + _animVars.set("isNotInput", false); + } + } else if (abs(params.inputX) > INPUT_DEADZONE_THRESHOLD && abs(params.inputX) > abs(params.inputZ)) { + if (params.inputX > INPUT_DEADZONE_THRESHOLD) { + // right _animVars.set("isInputForward", false); _animVars.set("isInputBackward", false); _animVars.set("isInputRight", true); _animVars.set("isInputLeft", false); _animVars.set("isNotInput", false); } else { - // right + // left _animVars.set("isInputForward", false); _animVars.set("isInputBackward", false); _animVars.set("isInputRight", false); _animVars.set("isInputLeft", true); _animVars.set("isNotInput", false); } - } else if (params.inputZ) { - if (params.inputZ > 0.0f) { - // forward - _animVars.set("isInputForward", true); - _animVars.set("isInputBackward", false); - _animVars.set("isInputRight", false); - _animVars.set("isInputLeft", false); - _animVars.set("isNotInput", false); - } else { - // backward - _animVars.set("isInputForward", false); - _animVars.set("isInputBackward", true); - _animVars.set("isInputRight", false); - _animVars.set("isInputLeft", false); - _animVars.set("isNotInput", false); - } - } else if (params.inputX == 0.0f && params.inputZ == 0.0f) { + } else if (params.inputX <= INPUT_DEADZONE_THRESHOLD && params.inputZ <= INPUT_DEADZONE_THRESHOLD) { // no WASD input _animVars.set("isInputForward", false); _animVars.set("isInputBackward", false); From cfa7df7d1a27275d47b50424692d87ae5acbe972 Mon Sep 17 00:00:00 2001 From: dooglifeSF <41022919+dooglifeSF@users.noreply.github.com> Date: Tue, 8 Oct 2019 16:14:21 -0700 Subject: [PATCH 06/10] Refactor the if-logic to remove complexity --- libraries/animation/src/Rig.cpp | 52 ++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 7f83fb5218..8d78ff1418 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -2163,25 +2163,31 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo //deadzone constant #define INPUT_DEADZONE_THRESHOLD 0.05f - if (abs(params.inputZ) > INPUT_DEADZONE_THRESHOLD && abs(params.inputZ) >= abs(params.inputX)) { - if (params.inputZ > INPUT_DEADZONE_THRESHOLD) { - // forward - _animVars.set("isInputForward", true); - _animVars.set("isInputBackward", false); - _animVars.set("isInputRight", false); - _animVars.set("isInputLeft", false); - _animVars.set("isNotInput", false); - } - else { - // backward - _animVars.set("isInputForward", false); - _animVars.set("isInputBackward", true); - _animVars.set("isInputRight", false); - _animVars.set("isInputLeft", false); - _animVars.set("isNotInput", false); - } - } else if (abs(params.inputX) > INPUT_DEADZONE_THRESHOLD && abs(params.inputX) > abs(params.inputZ)) { - if (params.inputX > INPUT_DEADZONE_THRESHOLD) { + if (abs(params.inputX) <= INPUT_DEADZONE_THRESHOLD && abs(params.inputZ) <= INPUT_DEADZONE_THRESHOLD) { + // no WASD input + _animVars.set("isInputForward", false); + _animVars.set("isInputBackward", false); + _animVars.set("isInputRight", false); + _animVars.set("isInputLeft", false); + _animVars.set("isNotInput", true); + } else if ( abs(params.inputZ) >= abs(params.inputX) ) { + if (params.inputZ > 0) { + // forward + _animVars.set("isInputForward", true); + _animVars.set("isInputBackward", false); + _animVars.set("isInputRight", false); + _animVars.set("isInputLeft", false); + _animVars.set("isNotInput", false); + } else { + // backward + _animVars.set("isInputForward", false); + _animVars.set("isInputBackward", true); + _animVars.set("isInputRight", false); + _animVars.set("isInputLeft", false); + _animVars.set("isNotInput", false); + } + } else { + if (params.inputX > 0) { // right _animVars.set("isInputForward", false); _animVars.set("isInputBackward", false); @@ -2196,15 +2202,9 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo _animVars.set("isInputLeft", true); _animVars.set("isNotInput", false); } - } else if (params.inputX <= INPUT_DEADZONE_THRESHOLD && params.inputZ <= INPUT_DEADZONE_THRESHOLD) { - // no WASD input - _animVars.set("isInputForward", false); - _animVars.set("isInputBackward", false); - _animVars.set("isInputRight", false); - _animVars.set("isInputLeft", false); - _animVars.set("isNotInput", true); } + _headEnabled = params.primaryControllerFlags[PrimaryControllerType_Head] & (uint8_t)ControllerFlags::Enabled; bool leftHandEnabled = params.primaryControllerFlags[PrimaryControllerType_LeftHand] & (uint8_t)ControllerFlags::Enabled; bool rightHandEnabled = params.primaryControllerFlags[PrimaryControllerType_RightHand] & (uint8_t)ControllerFlags::Enabled; From 1f3993c3080c93931f4e6e2e3d7639e1c2b7fe32 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 8 Oct 2019 18:13:24 -0700 Subject: [PATCH 07/10] getting the transform right for the rigid bodies --- interface/src/avatar/MyAvatar.cpp | 4 +-- libraries/fbx/src/FBXSerializer.cpp | 14 ++++----- .../render-utils/src/CauterizedModel.cpp | 12 ++++++-- .../render-utils/src/MeshPartPayload.cpp | 11 +++++-- libraries/render-utils/src/Model.cpp | 30 +++++++++++++++++-- libraries/render-utils/src/Model.h | 8 +++++ 6 files changed, 62 insertions(+), 17 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index de6ae526b4..a7fd397915 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2496,7 +2496,7 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { if (_fullAvatarModelName.isEmpty()) { // Store the FST file name into preferences - const auto& mapping = _skeletonModel->getGeometry()->getMapping(); + const auto& mapping = _skeletonModel->getNetworkModel()->getMapping(); if (mapping.value("name").isValid()) { _fullAvatarModelName = mapping.value("name").toString(); } @@ -2504,7 +2504,7 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { initHeadBones(); _skeletonModel->setCauterizeBoneSet(_headBoneSet); - _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); + _fstAnimGraphOverrideUrl = _skeletonModel->getNetworkModel()->getAnimGraphOverrideUrl(); initAnimGraph(); initFlowFromFST(); diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index 0299648294..2fa90af9db 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -530,8 +530,8 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const if (object.properties.at(2) == "Mesh") { meshes.insert(getID(object.properties), extractMesh(object, meshIndex, deduplicateIndices)); } else { // object.properties.at(2) == "Shape" - ExtractedBlendshape extracted = { getID(object.properties), extractBlendshape(object) }; - blendshapes.append(extracted); + ExtractedBlendshape blendshape = { getID(object.properties), extractBlendshape(object) }; + blendshapes.append(blendshape); } } else if (object.name == "Model") { QString name = getModelName(object.properties); @@ -705,8 +705,8 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const // add the blendshapes included in the model, if any if (mesh) { - foreach (const ExtractedBlendshape& extracted, blendshapes) { - addBlendshapes(extracted, blendshapeIndices.values(extracted.id.toLatin1()), *mesh); + foreach (const ExtractedBlendshape& blendshape, blendshapes) { + addBlendshapes(blendshape, blendshapeIndices.values(blendshape.id.toLatin1()), *mesh); } } @@ -1229,11 +1229,11 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const } // assign the blendshapes to their corresponding meshes - foreach (const ExtractedBlendshape& extracted, blendshapes) { - QString blendshapeChannelID = _connectionParentMap.value(extracted.id); + foreach (const ExtractedBlendshape& blendshape, blendshapes) { + QString blendshapeChannelID = _connectionParentMap.value(blendshape.id); QString blendshapeID = _connectionParentMap.value(blendshapeChannelID); QString meshID = _connectionParentMap.value(blendshapeID); - addBlendshapes(extracted, blendshapeChannelIndices.values(blendshapeChannelID), meshes[meshID]); + addBlendshapes(blendshape, blendshapeChannelIndices.values(blendshapeChannelID), meshes[meshID]); } // get offset transform from mapping diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 6e8f37d354..87eacc20ec 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -104,9 +104,11 @@ void CauterizedModel::updateClusterMatrices() { if (!_needsUpdateClusterMatrices || !isLoaded()) { return; } + + updateShapeStatesFromRig(); + _needsUpdateClusterMatrices = false; const HFMModel& hfmModel = getHFMModel(); - for (int i = 0; i < (int)_meshStates.size(); i++) { Model::MeshState& state = _meshStates[i]; const HFMMesh& mesh = hfmModel.meshes.at(i); @@ -221,13 +223,14 @@ void CauterizedModel::updateRenderItems() { auto itemID = self->_modelMeshRenderItemIDs[i]; auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; + const auto& shapeState = self->getShapeState(i); const auto& meshState = self->getMeshState(meshIndex); const auto& cauterizedMeshState = self->getCauterizeMeshState(meshIndex); bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); - transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey, + transaction.updateItem(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, enableCauterization](ModelMeshPartPayload& mmppData) { CauterizedMeshPartPayload& data = static_cast(mmppData); if (useDualQuaternionSkinning) { @@ -241,7 +244,7 @@ void CauterizedModel::updateRenderItems() { } Transform renderTransform = modelTransform; - if (useDualQuaternionSkinning) { + /*if (useDualQuaternionSkinning) { if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) { const auto& dq = meshState.clusterDualQuaternions[0]; Transform transform(dq.getRotation(), @@ -253,6 +256,9 @@ void CauterizedModel::updateRenderItems() { if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) { renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0])); } + }*/ + if (meshState.clusterMatrices.size() <= 1) { + renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); } data.updateTransformForSkinnedMesh(renderTransform, modelTransform); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index fcf0ffaa48..8f992ba329 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -221,8 +221,10 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in } updateTransform(transform, offsetTransform); + Transform renderTransform = transform; - if (useDualQuaternionSkinning) { + +/* if (useDualQuaternionSkinning) { if (state.clusterDualQuaternions.size() == 1) { const auto& dq = state.clusterDualQuaternions[0]; Transform transform(dq.getRotation(), @@ -235,6 +237,10 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0])); } } +*/ + + const Model::ShapeState& shapeState = model->getShapeState(shapeIndex); + renderTransform = transform.worldTransform(shapeState._rootFromJointTransform); updateTransformForSkinnedMesh(renderTransform, transform); initCache(model); @@ -320,7 +326,8 @@ void ModelMeshPartPayload::updateClusterBuffer(const std::vector_modelMeshRenderItemIDs[i]; auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; + const auto& shapeState = self->getShapeState(i); const auto& meshState = self->getMeshState(meshIndex); bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); - transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, + transaction.updateItem(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning, invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, cauterized](ModelMeshPartPayload& data) { if (useDualQuaternionSkinning) { data.updateClusterBuffer(meshState.clusterDualQuaternions); @@ -249,7 +250,7 @@ void Model::updateRenderItems() { Transform renderTransform = modelTransform; - if (useDualQuaternionSkinning) { + /*if (useDualQuaternionSkinning) { if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) { const auto& dq = meshState.clusterDualQuaternions[0]; Transform transform(dq.getRotation(), @@ -261,6 +262,9 @@ void Model::updateRenderItems() { if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) { renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0])); } + }*/ + if (meshState.clusterMatrices.size() <= 1) { + renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); } data.updateTransformForSkinnedMesh(renderTransform, modelTransform); @@ -293,6 +297,21 @@ void Model::reset() { } } +void Model::updateShapeStatesFromRig() { + const HFMModel& hfmModel = getHFMModel(); + // TODO: should all Models have a valid _rig? + { // Shapes state: + 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); + } + } + } +} + bool Model::updateGeometry() { bool needFullUpdate = false; @@ -307,6 +326,8 @@ bool Model::updateGeometry() { initJointStates(); assert(_meshStates.empty()); + updateShapeStatesFromRig(); + const HFMModel& hfmModel = getHFMModel(); int i = 0; foreach (const HFMMesh& mesh, hfmModel.meshes) { @@ -1385,6 +1406,8 @@ void Model::updateClusterMatrices() { return; } + updateShapeStatesFromRig(); + _needsUpdateClusterMatrices = false; const HFMModel& hfmModel = getHFMModel(); for (int i = 0; i < (int) _meshStates.size(); i++) { @@ -1418,6 +1441,7 @@ void Model::updateClusterMatrices() { void Model::deleteGeometry() { _deleteGeometryCounter++; + _shapeStates.clear(); _meshStates.clear(); _rig.destroyAnimGraph(); _blendedBlendshapeCoefficients.clear(); @@ -1496,7 +1520,7 @@ void Model::createRenderItemSet() { } bool Model::isRenderable() const { - return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty()); + return (!_shapeStates.empty() && !_meshStates.empty()) || (isLoaded() && _renderGeometry->getMeshes().empty()); } std::set Model::getMeshIDsFromMaterialID(QString parentMaterialName) { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 79ddaeb68d..85661d4b6b 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -343,6 +343,12 @@ public: const MeshState& getMeshState(int index) { return _meshStates.at(index); } + class ShapeState { + public: + glm::mat4 _rootFromJointTransform; + }; + const ShapeState& getShapeState(int index) { return _shapeStates.at(index); } + uint32_t getGeometryCounter() const { return _deleteGeometryCounter; } const QMap& getRenderItems() const { return _modelMeshRenderItemsMap; } BlendShapeOperator getModelBlendshapeOperator() const { return _modelBlendshapeOperator; } @@ -420,6 +426,8 @@ protected: glm::vec3 _registrationPoint = glm::vec3(0.5f); /// the point in model space our center is snapped to std::vector _meshStates; + std::vector _shapeStates; + void updateShapeStatesFromRig(); virtual void initJointStates(); From 2a1258968aa3113206a3a27be7584bddcdf24453 Mon Sep 17 00:00:00 2001 From: dooglifeSF <41022919+dooglifeSF@users.noreply.github.com> Date: Wed, 9 Oct 2019 10:10:45 -0700 Subject: [PATCH 08/10] Change macro to const float, use floats in control flow. --- libraries/animation/src/Rig.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index d84b04c800..432f9387fa 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -2161,7 +2161,7 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo } //deadzone constant - #define INPUT_DEADZONE_THRESHOLD 0.05f + const float INPUT_DEADZONE_THRESHOLD = 0.05f; if (abs(params.inputX) <= INPUT_DEADZONE_THRESHOLD && abs(params.inputZ) <= INPUT_DEADZONE_THRESHOLD) { // no WASD input @@ -2171,7 +2171,7 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo _animVars.set("isInputLeft", false); _animVars.set("isNotInput", true); } else if ( abs(params.inputZ) >= abs(params.inputX) ) { - if (params.inputZ > 0) { + if (params.inputZ > 0.0f) { // forward _animVars.set("isInputForward", true); _animVars.set("isInputBackward", false); @@ -2187,7 +2187,7 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo _animVars.set("isNotInput", false); } } else { - if (params.inputX > 0) { + if (params.inputX > 0.0f) { // right _animVars.set("isInputForward", false); _animVars.set("isInputBackward", false); From 85b681e70e82a1b28986166f735d6c5238b58590 Mon Sep 17 00:00:00 2001 From: dooglifeSF <41022919+dooglifeSF@users.noreply.github.com> Date: Wed, 9 Oct 2019 11:07:14 -0700 Subject: [PATCH 09/10] switch abs() to fabsf() --- libraries/animation/src/Rig.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 432f9387fa..0be05f843e 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -2163,14 +2163,14 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo //deadzone constant const float INPUT_DEADZONE_THRESHOLD = 0.05f; - if (abs(params.inputX) <= INPUT_DEADZONE_THRESHOLD && abs(params.inputZ) <= INPUT_DEADZONE_THRESHOLD) { + if (fabsf(params.inputX) <= INPUT_DEADZONE_THRESHOLD && fabsf(params.inputZ) <= INPUT_DEADZONE_THRESHOLD) { // no WASD input _animVars.set("isInputForward", false); _animVars.set("isInputBackward", false); _animVars.set("isInputRight", false); _animVars.set("isInputLeft", false); _animVars.set("isNotInput", true); - } else if ( abs(params.inputZ) >= abs(params.inputX) ) { + } else if (fabsf(params.inputZ) >= fabsf(params.inputX)) { if (params.inputZ > 0.0f) { // forward _animVars.set("isInputForward", true); From 9905fc076c74e7a79297b39ea7c8d627604cfb51 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 9 Oct 2019 16:44:06 -0700 Subject: [PATCH 10/10] Materials of baked models fbx are loading correctly, still using the name/id of the mateiral in the part struct --- libraries/fbx/src/FBXSerializer.cpp | 35 +++++++++++++++++++----- libraries/fbx/src/FBXSerializer_Mesh.cpp | 8 +++++- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index 2fa90af9db..c35a23ef3a 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -1480,6 +1480,12 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const // meshShapes will be added to hfmModel at the very end std::vector meshShapes; meshShapes.reserve(instanceModelIDs.size() * mesh.parts.size()); + if (instanceModelIDs.size() > 1) { + qCDebug(modelformat) << "Mesh " << meshID << " made of " << mesh.parts.size() << " parts is instanced " << instanceModelIDs.size() << " times!!!"; + } + if (mesh.parts.size() < 1) { + qCDebug(modelformat) << "Mesh " << meshID << " made of " << mesh.parts.size() << " parts !!!!! "; + } 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); @@ -1500,6 +1506,14 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const shape.mesh = meshIndex; shape.meshPart = i; shape.transform = transformIndex; + + auto matName = mesh.parts[i].materialID; + auto materialIt = materialNameToID.find(matName.toStdString()); + if (materialIt != materialNameToID.end()) { + shape.material = materialIt->second; + } else { + qCDebug(modelformat) << "Unknown material ? " << matName; + } shape.transformedExtents.reset(); // compute the shape extents from the transformed vertices @@ -1546,14 +1560,21 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const } // For baked models with FBX_DRACO_MESH_VERSION >= 2, get materials from extracted.materialIDPerMeshPart if (!extracted.materialIDPerMeshPart.empty()) { - for (uint32_t i = 0; i < (uint32_t)extracted.materialIDPerMeshPart.size(); ++i) { - hfm::Shape& shape = partShapes[i]; - const std::string& materialID = extracted.materialIDPerMeshPart[i]; - auto materialIt = materialNameToID.find(materialID); - if (materialIt != materialNameToID.end()) { - shape.material = materialIt->second; + /* if (partShapes.size() == extracted.materialIDPerMeshPart.size()) { + for (uint32_t i = 0; i < (uint32_t)extracted.materialIDPerMeshPart.size(); ++i) { + hfm::Shape& shape = partShapes[i]; + const std::string& materialID = extracted.materialIDPerMeshPart[i]; + auto materialIt = materialNameToID.find(materialID); + if (materialIt != materialNameToID.end()) { + shape.material = materialIt->second; + } } - } + } else { + for (int p = 0; p < mesh.parts.size(); p++) { + qCDebug(modelformat) << "mesh.parts[" << p <<"] is " << mesh.parts[p].materialID; + } + qCDebug(modelformat) << "partShapes is not the same size as materialIDPerMeshPart ?"; + }*/ } // find the clusters with which the mesh is associated diff --git a/libraries/fbx/src/FBXSerializer_Mesh.cpp b/libraries/fbx/src/FBXSerializer_Mesh.cpp index 7c6be5740a..37f2c9ec1b 100644 --- a/libraries/fbx/src/FBXSerializer_Mesh.cpp +++ b/libraries/fbx/src/FBXSerializer_Mesh.cpp @@ -492,9 +492,15 @@ ExtractedMesh FBXSerializer::extractMesh(const FBXNode& object, unsigned int& me int& partIndexPlusOne = materialTextureParts[materialTexture]; if (partIndexPlusOne == 0) { data.extracted.mesh.parts.resize(data.extracted.mesh.parts.size() + 1); + HFMMeshPart& part = data.extracted.mesh.parts.back(); // Figure out if this is the older way of defining the per-part material for baked FBX - if (dracoMeshNodeVersion < 2) { + if (dracoMeshNodeVersion >= 2) { + // Define the materialID now + if (materialID < dracoMaterialList.size()) { + part.materialID = QString(dracoMaterialList[materialID].c_str()); + } + } else { // Define the materialID later, based on the order of first appearance of the materials in the _connectionChildMap data.extracted.partMaterialTextures.append(materialTexture); }