From 6caa928e6445accbbd0d138934d62fffe2c53aef Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 1 May 2014 16:12:20 -0700 Subject: [PATCH] More work on avatar customization. --- interface/src/ModelUploader.cpp | 99 ++++++++++++++++++++++++--------- interface/src/ModelUploader.h | 3 +- libraries/fbx/src/FBXReader.cpp | 21 ++++++- libraries/fbx/src/FBXReader.h | 2 + 4 files changed, 95 insertions(+), 30 deletions(-) diff --git a/interface/src/ModelUploader.cpp b/interface/src/ModelUploader.cpp index 309ac5dcd6..09715fde04 100644 --- a/interface/src/ModelUploader.cpp +++ b/interface/src/ModelUploader.cpp @@ -148,6 +148,43 @@ bool ModelUploader::zip() { mapping.insert(TEXDIR_FIELD, "."); } + // mixamo/autodesk defaults + if (!mapping.contains(SCALE_FIELD)) { + mapping.insert(SCALE_FIELD, 10.0); + } + QVariantHash joints = mapping.value(JOINT_FIELD).toHash(); + if (!joints.contains("jointEyeLeft")) { + joints.insert("jointEyeLeft", "LeftEye"); + } + if (!joints.contains("jointEyeRight")) { + joints.insert("jointEyeRight", "RightEye"); + } + if (!joints.contains("jointNeck")) { + joints.insert("jointNeck", "Neck"); + } + if (!joints.contains("jointRoot")) { + joints.insert("jointRoot", "Hips"); + } + if (!joints.contains("jointLean")) { + joints.insert("jointLean", "Spine"); + } + if (!joints.contains("jointHead")) { + joints.insert("jointHead", geometry.applicationName == "mixamo.com" ? "HeadTop_End" : "HeadEnd"); + } + if (!joints.contains("jointLeftHand")) { + joints.insert("jointLeftHand", "LeftHand"); + } + if (!joints.contains("jointRightHand")) { + joints.insert("jointRightHand", "RightHand"); + } + mapping.insert(JOINT_FIELD, joints); + if (!mapping.contains(FREE_JOINT_FIELD)) { + mapping.insertMulti(FREE_JOINT_FIELD, "LeftArm"); + mapping.insertMulti(FREE_JOINT_FIELD, "LeftForeArm"); + mapping.insertMulti(FREE_JOINT_FIELD, "RightArm"); + mapping.insertMulti(FREE_JOINT_FIELD, "RightForeArm"); + } + // open the dialog to configure the rest ModelPropertiesDialog properties(_isHead, mapping, basePath, geometry); if (properties.exec() == QDialog::Rejected) { @@ -475,10 +512,8 @@ ModelPropertiesDialog::ModelPropertiesDialog(bool isHead, const QVariantHash& or _scale->setMaximum(FLT_MAX); _scale->setSingleStep(0.01); - if (isHead) { - form->addRow("Left Eye Joint:", _leftEyeJoint = createJointBox()); - form->addRow("Right Eye Joint:", _rightEyeJoint = createJointBox()); - } + form->addRow("Left Eye Joint:", _leftEyeJoint = createJointBox()); + form->addRow("Right Eye Joint:", _rightEyeJoint = createJointBox()); form->addRow("Neck Joint:", _neckJoint = createJointBox()); if (!isHead) { form->addRow("Root Joint:", _rootJoint = createJointBox()); @@ -519,17 +554,15 @@ QVariantHash ModelPropertiesDialog::getMapping() const { mapping.insert(JOINT_INDEX_FIELD, jointIndices); QVariantHash joints = mapping.value(JOINT_FIELD).toHash(); - if (_isHead) { - joints.insert("jointEyeLeft", _leftEyeJoint->currentText()); - joints.insert("jointEyeRight", _rightEyeJoint->currentText()); - } - joints.insert("jointNeck", _neckJoint->currentText()); + insertJointMapping(joints, "jointEyeLeft", _leftEyeJoint->currentText()); + insertJointMapping(joints, "jointEyeRight", _rightEyeJoint->currentText()); + insertJointMapping(joints, "jointNeck", _neckJoint->currentText()); if (!_isHead) { - joints.insert("jointRoot", _rootJoint->currentText()); - joints.insert("jointLean", _leanJoint->currentText()); - joints.insert("jointHead", _headJoint->currentText()); - joints.insert("jointLeftHand", _leftHandJoint->currentText()); - joints.insert("jointRightHand", _rightHandJoint->currentText()); + insertJointMapping(joints, "jointRoot", _rootJoint->currentText()); + insertJointMapping(joints, "jointLean", _leanJoint->currentText()); + insertJointMapping(joints, "jointHead", _headJoint->currentText()); + insertJointMapping(joints, "jointLeftHand", _leftHandJoint->currentText()); + insertJointMapping(joints, "jointRightHand", _rightHandJoint->currentText()); mapping.remove(FREE_JOINT_FIELD); for (int i = 0; i < _freeJoints->count() - 1; i++) { @@ -542,23 +575,25 @@ QVariantHash ModelPropertiesDialog::getMapping() const { return mapping; } +static void setJointText(QComboBox* box, const QString& text) { + box->setCurrentIndex(qMax(box->findText(text), 0)); +} + void ModelPropertiesDialog::reset() { _name->setText(_originalMapping.value(NAME_FIELD).toString()); _textureDirectory->setText(_originalMapping.value(TEXDIR_FIELD).toString()); _scale->setValue(_originalMapping.value(SCALE_FIELD, 1.0).toDouble()); QVariantHash jointHash = _originalMapping.value(JOINT_FIELD).toHash(); - if (_isHead) { - _leftEyeJoint->setCurrentText(jointHash.value("jointEyeLeft").toString()); - _rightEyeJoint->setCurrentText(jointHash.value("jointEyeRight").toString()); - } - _neckJoint->setCurrentText(jointHash.value("jointNeck").toString()); + setJointText(_leftEyeJoint, jointHash.value("jointEyeLeft").toString()); + setJointText(_rightEyeJoint, jointHash.value("jointEyeRight").toString()); + setJointText(_neckJoint, jointHash.value("jointNeck").toString()); if (!_isHead) { - _rootJoint->setCurrentText(jointHash.value("jointRoot").toString()); - _leanJoint->setCurrentText(jointHash.value("jointLean").toString()); - _headJoint->setCurrentText(jointHash.value("jointHead").toString()); - _leftHandJoint->setCurrentText(jointHash.value("jointLeftHand").toString()); - _rightHandJoint->setCurrentText(jointHash.value("jointRightHand").toString()); + setJointText(_rootJoint, jointHash.value("jointRoot").toString()); + setJointText(_leanJoint, jointHash.value("jointLean").toString()); + setJointText(_headJoint, jointHash.value("jointHead").toString()); + setJointText(_leftHandJoint, jointHash.value("jointLeftHand").toString()); + setJointText(_rightHandJoint, jointHash.value("jointRightHand").toString()); while (_freeJoints->count() > 1) { delete _freeJoints->itemAt(0)->widget(); @@ -587,7 +622,7 @@ void ModelPropertiesDialog::createNewFreeJoint(const QString& joint) { QHBoxLayout* freeJointLayout = new QHBoxLayout(); freeJointLayout->setContentsMargins(QMargins()); freeJoint->setLayout(freeJointLayout); - QComboBox* jointBox = createJointBox(); + QComboBox* jointBox = createJointBox(false); jointBox->setCurrentText(joint); freeJointLayout->addWidget(jointBox, 1); QPushButton* deleteJoint = new QPushButton("Delete"); @@ -596,10 +631,22 @@ void ModelPropertiesDialog::createNewFreeJoint(const QString& joint) { _freeJoints->insertWidget(_freeJoints->count() - 1, freeJoint); } -QComboBox* ModelPropertiesDialog::createJointBox() const { +QComboBox* ModelPropertiesDialog::createJointBox(bool withNone) const { QComboBox* box = new QComboBox(); + if (withNone) { + box->addItem("(none)"); + } foreach (const FBXJoint& joint, _geometry.joints) { box->addItem(joint.name); } return box; } + +void ModelPropertiesDialog::insertJointMapping(QVariantHash& joints, const QString& joint, const QString& name) const { + if (_geometry.jointIndices.contains(name)) { + joints.insert(joint, name); + } else { + joints.remove(joint); + } +} + diff --git a/interface/src/ModelUploader.h b/interface/src/ModelUploader.h index a30729d6e2..6526a3d83e 100644 --- a/interface/src/ModelUploader.h +++ b/interface/src/ModelUploader.h @@ -84,7 +84,8 @@ private slots: void createNewFreeJoint(const QString& joint = QString()); private: - QComboBox* createJointBox() const; + QComboBox* createJointBox(bool withNone = true) const; + void insertJointMapping(QVariantHash& joints, const QString& joint, const QString& name) const; bool _isHead; QVariantHash _originalMapping; diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 628296c9f6..cf7153259e 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1006,9 +1006,25 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } } QMultiHash blendshapeChannelIndices; - + + FBXGeometry geometry; foreach (const FBXNode& child, node.children) { - if (child.name == "Objects") { + if (child.name == "FBXHeaderExtension") { + foreach (const FBXNode& object, child.children) { + if (object.name == "SceneInfo") { + foreach (const FBXNode& subobject, object.children) { + if (subobject.name == "Properties70") { + foreach (const FBXNode& subsubobject, subobject.children) { + if (subsubobject.name == "P" && subsubobject.properties.size() >= 5 && + subsubobject.properties.at(0) == "Original|ApplicationName") { + geometry.applicationName = subsubobject.properties.at(4).toString(); + } + } + } + } + } + } + } else if (child.name == "Objects") { foreach (const FBXNode& object, child.children) { if (object.name == "Geometry") { if (object.properties.at(2) == "Mesh") { @@ -1317,7 +1333,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } // get offset transform from mapping - FBXGeometry geometry; float offsetScale = mapping.value("scale", 1.0f).toFloat(); glm::quat offsetRotation = glm::quat(glm::radians(glm::vec3(mapping.value("rx").toFloat(), mapping.value("ry").toFloat(), mapping.value("rz").toFloat()))); diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index f43131e41a..ea8b8f517d 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -174,6 +174,8 @@ public: class FBXGeometry { public: + QString applicationName; ///< the name of the application that generated the model + QVector joints; QHash jointIndices; ///< 1-based, so as to more easily detect missing indices