mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
More work on avatar customization.
This commit is contained in:
parent
c8877c31fe
commit
6caa928e64
4 changed files with 95 additions and 30 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1006,9 +1006,25 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
}
|
||||
}
|
||||
QMultiHash<QString, WeightedIndex> 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())));
|
||||
|
|
|
@ -174,6 +174,8 @@ public:
|
|||
class FBXGeometry {
|
||||
public:
|
||||
|
||||
QString applicationName; ///< the name of the application that generated the model
|
||||
|
||||
QVector<FBXJoint> joints;
|
||||
QHash<QString, int> jointIndices; ///< 1-based, so as to more easily detect missing indices
|
||||
|
||||
|
|
Loading…
Reference in a new issue