mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 09:18:45 +02:00
Merge pull request #14802 from sabrina-shanman/hfm_prep_joints
Case 20887: Move FST joint property handling to the model preparation step
This commit is contained in:
commit
baf72eaae0
21 changed files with 151 additions and 179 deletions
|
@ -10,10 +10,6 @@ joint = jointRoot = Hips
|
||||||
joint = jointLeftHand = LeftHand
|
joint = jointLeftHand = LeftHand
|
||||||
joint = jointRightHand = RightHand
|
joint = jointRightHand = RightHand
|
||||||
joint = jointHead = Head
|
joint = jointHead = Head
|
||||||
freeJoint = LeftArm
|
|
||||||
freeJoint = LeftForeArm
|
|
||||||
freeJoint = RightArm
|
|
||||||
freeJoint = RightForeArm
|
|
||||||
bs = JawOpen = mouth_Open = 1
|
bs = JawOpen = mouth_Open = 1
|
||||||
bs = LipsFunnel = Oo = 1
|
bs = LipsFunnel = Oo = 1
|
||||||
bs = BrowsU_L = brow_Up = 1
|
bs = BrowsU_L = brow_Up = 1
|
||||||
|
|
|
@ -294,13 +294,6 @@ void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename
|
||||||
}
|
}
|
||||||
|
|
||||||
mapping.insert(JOINT_FIELD, joints);
|
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there are no blendshape mappings, and we detect that this is likely a mixamo file,
|
// If there are no blendshape mappings, and we detect that this is likely a mixamo file,
|
||||||
// then we can add the default mixamo to "faceshift" mappings
|
// then we can add the default mixamo to "faceshift" mappings
|
||||||
|
|
|
@ -58,11 +58,6 @@ _hfmModel(hfmModel)
|
||||||
form->addRow("Left Hand Joint:", _leftHandJoint = createJointBox());
|
form->addRow("Left Hand Joint:", _leftHandJoint = createJointBox());
|
||||||
form->addRow("Right Hand Joint:", _rightHandJoint = createJointBox());
|
form->addRow("Right Hand Joint:", _rightHandJoint = createJointBox());
|
||||||
|
|
||||||
form->addRow("Free Joints:", _freeJoints = new QVBoxLayout());
|
|
||||||
QPushButton* newFreeJoint = new QPushButton("New Free Joint");
|
|
||||||
_freeJoints->addWidget(newFreeJoint);
|
|
||||||
connect(newFreeJoint, SIGNAL(clicked(bool)), SLOT(createNewFreeJoint()));
|
|
||||||
|
|
||||||
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok |
|
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok |
|
||||||
QDialogButtonBox::Cancel | QDialogButtonBox::Reset);
|
QDialogButtonBox::Cancel | QDialogButtonBox::Reset);
|
||||||
connect(buttons, SIGNAL(accepted()), SLOT(accept()));
|
connect(buttons, SIGNAL(accepted()), SLOT(accept()));
|
||||||
|
@ -102,11 +97,6 @@ QVariantHash ModelPropertiesDialog::getMapping() const {
|
||||||
insertJointMapping(joints, "jointLeftHand", _leftHandJoint->currentText());
|
insertJointMapping(joints, "jointLeftHand", _leftHandJoint->currentText());
|
||||||
insertJointMapping(joints, "jointRightHand", _rightHandJoint->currentText());
|
insertJointMapping(joints, "jointRightHand", _rightHandJoint->currentText());
|
||||||
|
|
||||||
mapping.remove(FREE_JOINT_FIELD);
|
|
||||||
for (int i = 0; i < _freeJoints->count() - 1; i++) {
|
|
||||||
QComboBox* box = static_cast<QComboBox*>(_freeJoints->itemAt(i)->widget()->layout()->itemAt(0)->widget());
|
|
||||||
mapping.insertMulti(FREE_JOINT_FIELD, box->currentText());
|
|
||||||
}
|
|
||||||
mapping.insert(JOINT_FIELD, joints);
|
mapping.insert(JOINT_FIELD, joints);
|
||||||
|
|
||||||
return mapping;
|
return mapping;
|
||||||
|
@ -133,16 +123,6 @@ void ModelPropertiesDialog::reset() {
|
||||||
setJointText(_headJoint, jointHash.value("jointHead").toString());
|
setJointText(_headJoint, jointHash.value("jointHead").toString());
|
||||||
setJointText(_leftHandJoint, jointHash.value("jointLeftHand").toString());
|
setJointText(_leftHandJoint, jointHash.value("jointLeftHand").toString());
|
||||||
setJointText(_rightHandJoint, jointHash.value("jointRightHand").toString());
|
setJointText(_rightHandJoint, jointHash.value("jointRightHand").toString());
|
||||||
|
|
||||||
while (_freeJoints->count() > 1) {
|
|
||||||
delete _freeJoints->itemAt(0)->widget();
|
|
||||||
}
|
|
||||||
foreach (const QVariant& joint, _originalMapping.values(FREE_JOINT_FIELD)) {
|
|
||||||
QString jointName = joint.toString();
|
|
||||||
if (_hfmModel.jointIndices.contains(jointName)) {
|
|
||||||
createNewFreeJoint(jointName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelPropertiesDialog::chooseTextureDirectory() {
|
void ModelPropertiesDialog::chooseTextureDirectory() {
|
||||||
|
@ -176,20 +156,6 @@ void ModelPropertiesDialog::updatePivotJoint() {
|
||||||
_pivotJoint->setEnabled(!_pivotAboutCenter->isChecked());
|
_pivotJoint->setEnabled(!_pivotAboutCenter->isChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelPropertiesDialog::createNewFreeJoint(const QString& joint) {
|
|
||||||
QWidget* freeJoint = new QWidget();
|
|
||||||
QHBoxLayout* freeJointLayout = new QHBoxLayout();
|
|
||||||
freeJointLayout->setContentsMargins(QMargins());
|
|
||||||
freeJoint->setLayout(freeJointLayout);
|
|
||||||
QComboBox* jointBox = createJointBox(false);
|
|
||||||
jointBox->setCurrentText(joint);
|
|
||||||
freeJointLayout->addWidget(jointBox, 1);
|
|
||||||
QPushButton* deleteJoint = new QPushButton("Delete");
|
|
||||||
freeJointLayout->addWidget(deleteJoint);
|
|
||||||
freeJoint->connect(deleteJoint, SIGNAL(clicked(bool)), SLOT(deleteLater()));
|
|
||||||
_freeJoints->insertWidget(_freeJoints->count() - 1, freeJoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
QComboBox* ModelPropertiesDialog::createJointBox(bool withNone) const {
|
QComboBox* ModelPropertiesDialog::createJointBox(bool withNone) const {
|
||||||
QComboBox* box = new QComboBox();
|
QComboBox* box = new QComboBox();
|
||||||
if (withNone) {
|
if (withNone) {
|
||||||
|
|
|
@ -39,7 +39,6 @@ private slots:
|
||||||
void chooseTextureDirectory();
|
void chooseTextureDirectory();
|
||||||
void chooseScriptDirectory();
|
void chooseScriptDirectory();
|
||||||
void updatePivotJoint();
|
void updatePivotJoint();
|
||||||
void createNewFreeJoint(const QString& joint = QString());
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QComboBox* createJointBox(bool withNone = true) const;
|
QComboBox* createJointBox(bool withNone = true) const;
|
||||||
|
@ -66,7 +65,6 @@ private:
|
||||||
QComboBox* _headJoint = nullptr;
|
QComboBox* _headJoint = nullptr;
|
||||||
QComboBox* _leftHandJoint = nullptr;
|
QComboBox* _leftHandJoint = nullptr;
|
||||||
QComboBox* _rightHandJoint = nullptr;
|
QComboBox* _rightHandJoint = nullptr;
|
||||||
QVBoxLayout* _freeJoints = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ModelPropertiesDialog_h
|
#endif // hifi_ModelPropertiesDialog_h
|
||||||
|
|
|
@ -292,8 +292,6 @@ void AnimSkeleton::dump(bool verbose) const {
|
||||||
qCDebug(animation) << " relDefaultPose =" << getRelativeDefaultPose(i);
|
qCDebug(animation) << " relDefaultPose =" << getRelativeDefaultPose(i);
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
qCDebug(animation) << " hfmJoint =";
|
qCDebug(animation) << " hfmJoint =";
|
||||||
qCDebug(animation) << " isFree =" << _joints[i].isFree;
|
|
||||||
qCDebug(animation) << " freeLineage =" << _joints[i].freeLineage;
|
|
||||||
qCDebug(animation) << " parentIndex =" << _joints[i].parentIndex;
|
qCDebug(animation) << " parentIndex =" << _joints[i].parentIndex;
|
||||||
qCDebug(animation) << " translation =" << _joints[i].translation;
|
qCDebug(animation) << " translation =" << _joints[i].translation;
|
||||||
qCDebug(animation) << " preTransform =" << _joints[i].preTransform;
|
qCDebug(animation) << " preTransform =" << _joints[i].preTransform;
|
||||||
|
|
|
@ -249,14 +249,6 @@ bool SkeletonModel::getRightHandPosition(glm::vec3& position) const {
|
||||||
return getJointPositionInWorldFrame(getRightHandJointIndex(), position);
|
return getJointPositionInWorldFrame(getRightHandJointIndex(), position);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkeletonModel::getLeftShoulderPosition(glm::vec3& position) const {
|
|
||||||
return getJointPositionInWorldFrame(getLastFreeJointIndex(getLeftHandJointIndex()), position);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SkeletonModel::getRightShoulderPosition(glm::vec3& position) const {
|
|
||||||
return getJointPositionInWorldFrame(getLastFreeJointIndex(getRightHandJointIndex()), position);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const {
|
bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const {
|
||||||
return isActive() && getJointPositionInWorldFrame(_rig.indexOfJoint("Head"), headPosition);
|
return isActive() && getJointPositionInWorldFrame(_rig.indexOfJoint("Head"), headPosition);
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,17 +57,9 @@ public:
|
||||||
/// \return true whether or not the position was found
|
/// \return true whether or not the position was found
|
||||||
bool getRightHandPosition(glm::vec3& position) const;
|
bool getRightHandPosition(glm::vec3& position) const;
|
||||||
|
|
||||||
/// Gets the position of the left shoulder.
|
|
||||||
/// \return whether or not the left shoulder joint was found
|
|
||||||
bool getLeftShoulderPosition(glm::vec3& position) const;
|
|
||||||
|
|
||||||
/// Returns the extended length from the left hand to its last free ancestor.
|
/// Returns the extended length from the left hand to its last free ancestor.
|
||||||
float getLeftArmLength() const;
|
float getLeftArmLength() const;
|
||||||
|
|
||||||
/// Gets the position of the right shoulder.
|
|
||||||
/// \return whether or not the right shoulder joint was found
|
|
||||||
bool getRightShoulderPosition(glm::vec3& position) const;
|
|
||||||
|
|
||||||
/// Returns the position of the head joint.
|
/// Returns the position of the head joint.
|
||||||
/// \return whether or not the head was found
|
/// \return whether or not the head was found
|
||||||
bool getHeadPosition(glm::vec3& headPosition) const;
|
bool getHeadPosition(glm::vec3& headPosition) const;
|
||||||
|
|
|
@ -384,43 +384,6 @@ QByteArray fileOnUrl(const QByteArray& filepath, const QString& url) {
|
||||||
return filepath.mid(filepath.lastIndexOf('/') + 1);
|
return filepath.mid(filepath.lastIndexOf('/') + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QString, QString> getJointNameMapping(const QVariantHash& mapping) {
|
|
||||||
static const QString JOINT_NAME_MAPPING_FIELD = "jointMap";
|
|
||||||
QMap<QString, QString> hfmToHifiJointNameMap;
|
|
||||||
if (!mapping.isEmpty() && mapping.contains(JOINT_NAME_MAPPING_FIELD) && mapping[JOINT_NAME_MAPPING_FIELD].type() == QVariant::Hash) {
|
|
||||||
auto jointNames = mapping[JOINT_NAME_MAPPING_FIELD].toHash();
|
|
||||||
for (auto itr = jointNames.begin(); itr != jointNames.end(); itr++) {
|
|
||||||
hfmToHifiJointNameMap.insert(itr.key(), itr.value().toString());
|
|
||||||
qCDebug(modelformat) << "the mapped key " << itr.key() << " has a value of " << hfmToHifiJointNameMap[itr.key()];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hfmToHifiJointNameMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
QMap<QString, glm::quat> getJointRotationOffsets(const QVariantHash& mapping) {
|
|
||||||
QMap<QString, glm::quat> jointRotationOffsets;
|
|
||||||
static const QString JOINT_ROTATION_OFFSET_FIELD = "jointRotationOffset";
|
|
||||||
if (!mapping.isEmpty() && mapping.contains(JOINT_ROTATION_OFFSET_FIELD) && mapping[JOINT_ROTATION_OFFSET_FIELD].type() == QVariant::Hash) {
|
|
||||||
auto offsets = mapping[JOINT_ROTATION_OFFSET_FIELD].toHash();
|
|
||||||
for (auto itr = offsets.begin(); itr != offsets.end(); itr++) {
|
|
||||||
QString jointName = itr.key();
|
|
||||||
QString line = itr.value().toString();
|
|
||||||
auto quatCoords = line.split(',');
|
|
||||||
if (quatCoords.size() == 4) {
|
|
||||||
float quatX = quatCoords[0].mid(1).toFloat();
|
|
||||||
float quatY = quatCoords[1].toFloat();
|
|
||||||
float quatZ = quatCoords[2].toFloat();
|
|
||||||
float quatW = quatCoords[3].mid(0, quatCoords[3].size() - 1).toFloat();
|
|
||||||
if (!isNaN(quatX) && !isNaN(quatY) && !isNaN(quatZ) && !isNaN(quatW)) {
|
|
||||||
glm::quat rotationOffset = glm::quat(quatW, quatX, quatY, quatZ);
|
|
||||||
jointRotationOffsets.insert(jointName, rotationOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return jointRotationOffsets;
|
|
||||||
}
|
|
||||||
|
|
||||||
HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QString& url) {
|
HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QString& url) {
|
||||||
const FBXNode& node = _rootNode;
|
const FBXNode& node = _rootNode;
|
||||||
QMap<QString, ExtractedMesh> meshes;
|
QMap<QString, ExtractedMesh> meshes;
|
||||||
|
@ -444,8 +407,6 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
||||||
|
|
||||||
std::map<QString, HFMLight> lights;
|
std::map<QString, HFMLight> lights;
|
||||||
|
|
||||||
QVariantHash joints = mapping.value("joint").toHash();
|
|
||||||
|
|
||||||
QVariantHash blendshapeMappings = mapping.value("bs").toHash();
|
QVariantHash blendshapeMappings = mapping.value("bs").toHash();
|
||||||
|
|
||||||
QMultiHash<QByteArray, WeightedIndex> blendshapeIndices;
|
QMultiHash<QByteArray, WeightedIndex> blendshapeIndices;
|
||||||
|
@ -473,8 +434,6 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
||||||
HFMModel& hfmModel = *hfmModelPtr;
|
HFMModel& hfmModel = *hfmModelPtr;
|
||||||
|
|
||||||
hfmModel.originalURL = url;
|
hfmModel.originalURL = url;
|
||||||
hfmModel.hfmToHifiJointNameMapping.clear();
|
|
||||||
hfmModel.hfmToHifiJointNameMapping = getJointNameMapping(mapping);
|
|
||||||
|
|
||||||
float unitScaleFactor = 1.0f;
|
float unitScaleFactor = 1.0f;
|
||||||
glm::vec3 ambientColor;
|
glm::vec3 ambientColor;
|
||||||
|
@ -1287,26 +1246,14 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert the models to joints
|
// convert the models to joints
|
||||||
QVariantList freeJoints = mapping.values("freeJoint");
|
|
||||||
hfmModel.hasSkeletonJoints = false;
|
hfmModel.hasSkeletonJoints = false;
|
||||||
|
|
||||||
foreach (const QString& modelID, modelIDs) {
|
foreach (const QString& modelID, modelIDs) {
|
||||||
const FBXModel& fbxModel = fbxModels[modelID];
|
const FBXModel& fbxModel = fbxModels[modelID];
|
||||||
HFMJoint joint;
|
HFMJoint joint;
|
||||||
joint.isFree = freeJoints.contains(fbxModel.name);
|
|
||||||
joint.parentIndex = fbxModel.parentIndex;
|
joint.parentIndex = fbxModel.parentIndex;
|
||||||
|
|
||||||
// get the indices of all ancestors starting with the first free one (if any)
|
|
||||||
int jointIndex = hfmModel.joints.size();
|
int jointIndex = hfmModel.joints.size();
|
||||||
joint.freeLineage.append(jointIndex);
|
|
||||||
int lastFreeIndex = joint.isFree ? 0 : -1;
|
|
||||||
for (int index = joint.parentIndex; index != -1; index = hfmModel.joints.at(index).parentIndex) {
|
|
||||||
if (hfmModel.joints.at(index).isFree) {
|
|
||||||
lastFreeIndex = joint.freeLineage.size();
|
|
||||||
}
|
|
||||||
joint.freeLineage.append(index);
|
|
||||||
}
|
|
||||||
joint.freeLineage.remove(lastFreeIndex + 1, joint.freeLineage.size() - lastFreeIndex - 1);
|
|
||||||
joint.translation = fbxModel.translation; // these are usually in centimeters
|
joint.translation = fbxModel.translation; // these are usually in centimeters
|
||||||
joint.preTransform = fbxModel.preTransform;
|
joint.preTransform = fbxModel.preTransform;
|
||||||
joint.preRotation = fbxModel.preRotation;
|
joint.preRotation = fbxModel.preRotation;
|
||||||
|
@ -1341,14 +1288,10 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
||||||
}
|
}
|
||||||
joint.inverseBindRotation = joint.inverseDefaultRotation;
|
joint.inverseBindRotation = joint.inverseDefaultRotation;
|
||||||
joint.name = fbxModel.name;
|
joint.name = fbxModel.name;
|
||||||
if (hfmModel.hfmToHifiJointNameMapping.contains(hfmModel.hfmToHifiJointNameMapping.key(joint.name))) {
|
|
||||||
joint.name = hfmModel.hfmToHifiJointNameMapping.key(fbxModel.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
joint.bindTransformFoundInCluster = false;
|
joint.bindTransformFoundInCluster = false;
|
||||||
|
|
||||||
hfmModel.joints.append(joint);
|
hfmModel.joints.append(joint);
|
||||||
hfmModel.jointIndices.insert(joint.name, hfmModel.joints.size());
|
|
||||||
|
|
||||||
QString rotationID = localRotations.value(modelID);
|
QString rotationID = localRotations.value(modelID);
|
||||||
AnimationCurve xRotCurve = animationCurves.value(xComponents.value(rotationID));
|
AnimationCurve xRotCurve = animationCurves.value(xComponents.value(rotationID));
|
||||||
|
@ -1704,7 +1647,6 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
||||||
generateBoundryLinesForDop14(joint.shapeInfo.dots, joint.shapeInfo.avgPoint, joint.shapeInfo.debugLines);
|
generateBoundryLinesForDop14(joint.shapeInfo.dots, joint.shapeInfo.avgPoint, joint.shapeInfo.debugLines);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hfmModel.palmDirection = parseVec3(mapping.value("palmDirection", "0, -1, 0").toString());
|
|
||||||
|
|
||||||
// attempt to map any meshes to a named model
|
// attempt to map any meshes to a named model
|
||||||
for (QHash<QString, int>::const_iterator m = meshIDsToMeshIndices.constBegin();
|
for (QHash<QString, int>::const_iterator m = meshIDsToMeshIndices.constBegin();
|
||||||
|
@ -1722,21 +1664,6 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto offsets = getJointRotationOffsets(mapping);
|
|
||||||
hfmModel.jointRotationOffsets.clear();
|
|
||||||
for (auto itr = offsets.begin(); itr != offsets.end(); itr++) {
|
|
||||||
QString jointName = itr.key();
|
|
||||||
glm::quat rotationOffset = itr.value();
|
|
||||||
int jointIndex = hfmModel.getJointIndex(jointName);
|
|
||||||
if (hfmModel.hfmToHifiJointNameMapping.contains(jointName)) {
|
|
||||||
jointIndex = hfmModel.getJointIndex(jointName);
|
|
||||||
}
|
|
||||||
if (jointIndex != -1) {
|
|
||||||
hfmModel.jointRotationOffsets.insert(jointIndex, rotationOffset);
|
|
||||||
}
|
|
||||||
qCDebug(modelformat) << "Joint Rotation Offset added to Rig._jointRotationOffsets : " << " jointName: " << jointName << " jointIndex: " << jointIndex << " rotation offset: " << rotationOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hfmModelPtr;
|
return hfmModelPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,11 +82,6 @@ FST* FST::createFSTFromModel(const QString& fstPath, const QString& modelFilePat
|
||||||
}
|
}
|
||||||
mapping.insert(JOINT_INDEX_FIELD, jointIndices);
|
mapping.insert(JOINT_INDEX_FIELD, jointIndices);
|
||||||
|
|
||||||
mapping.insertMulti(FREE_JOINT_FIELD, "LeftArm");
|
|
||||||
mapping.insertMulti(FREE_JOINT_FIELD, "LeftForeArm");
|
|
||||||
mapping.insertMulti(FREE_JOINT_FIELD, "RightArm");
|
|
||||||
mapping.insertMulti(FREE_JOINT_FIELD, "RightForeArm");
|
|
||||||
|
|
||||||
|
|
||||||
// If there are no blendshape mappings, and we detect that this is likely a mixamo file,
|
// If there are no blendshape mappings, and we detect that this is likely a mixamo file,
|
||||||
// then we can add the default mixamo to "faceshift" mappings
|
// then we can add the default mixamo to "faceshift" mappings
|
||||||
|
|
|
@ -84,7 +84,7 @@ void FSTReader::writeVariant(QBuffer& buffer, QVariantHash::const_iterator& it)
|
||||||
|
|
||||||
QByteArray FSTReader::writeMapping(const QVariantHash& mapping) {
|
QByteArray FSTReader::writeMapping(const QVariantHash& mapping) {
|
||||||
static const QStringList PREFERED_ORDER = QStringList() << NAME_FIELD << TYPE_FIELD << SCALE_FIELD << FILENAME_FIELD
|
static const QStringList PREFERED_ORDER = QStringList() << NAME_FIELD << TYPE_FIELD << SCALE_FIELD << FILENAME_FIELD
|
||||||
<< MARKETPLACE_ID_FIELD << TEXDIR_FIELD << SCRIPT_FIELD << JOINT_FIELD << FREE_JOINT_FIELD
|
<< MARKETPLACE_ID_FIELD << TEXDIR_FIELD << SCRIPT_FIELD << JOINT_FIELD
|
||||||
<< BLENDSHAPE_FIELD << JOINT_INDEX_FIELD;
|
<< BLENDSHAPE_FIELD << JOINT_INDEX_FIELD;
|
||||||
QBuffer buffer;
|
QBuffer buffer;
|
||||||
buffer.open(QIODevice::WriteOnly);
|
buffer.open(QIODevice::WriteOnly);
|
||||||
|
@ -92,7 +92,7 @@ QByteArray FSTReader::writeMapping(const QVariantHash& mapping) {
|
||||||
for (auto key : PREFERED_ORDER) {
|
for (auto key : PREFERED_ORDER) {
|
||||||
auto it = mapping.find(key);
|
auto it = mapping.find(key);
|
||||||
if (it != mapping.constEnd()) {
|
if (it != mapping.constEnd()) {
|
||||||
if (key == FREE_JOINT_FIELD || key == SCRIPT_FIELD) { // writeVariant does not handle strings added using insertMulti.
|
if (key == SCRIPT_FIELD) { // writeVariant does not handle strings added using insertMulti.
|
||||||
for (auto multi : mapping.values(key)) {
|
for (auto multi : mapping.values(key)) {
|
||||||
buffer.write(key.toUtf8());
|
buffer.write(key.toUtf8());
|
||||||
buffer.write(" = ");
|
buffer.write(" = ");
|
||||||
|
|
|
@ -27,7 +27,6 @@ static const QString TRANSLATION_X_FIELD = "tx";
|
||||||
static const QString TRANSLATION_Y_FIELD = "ty";
|
static const QString TRANSLATION_Y_FIELD = "ty";
|
||||||
static const QString TRANSLATION_Z_FIELD = "tz";
|
static const QString TRANSLATION_Z_FIELD = "tz";
|
||||||
static const QString JOINT_FIELD = "joint";
|
static const QString JOINT_FIELD = "joint";
|
||||||
static const QString FREE_JOINT_FIELD = "freeJoint";
|
|
||||||
static const QString BLENDSHAPE_FIELD = "bs";
|
static const QString BLENDSHAPE_FIELD = "bs";
|
||||||
static const QString SCRIPT_FIELD = "script";
|
static const QString SCRIPT_FIELD = "script";
|
||||||
static const QString JOINT_NAME_MAPPING_FIELD = "jointMap";
|
static const QString JOINT_NAME_MAPPING_FIELD = "jointMap";
|
||||||
|
|
|
@ -719,7 +719,6 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const QUrl& url) {
|
||||||
|
|
||||||
//Build default joints
|
//Build default joints
|
||||||
hfmModel.joints.resize(1);
|
hfmModel.joints.resize(1);
|
||||||
hfmModel.joints[0].isFree = false;
|
|
||||||
hfmModel.joints[0].parentIndex = -1;
|
hfmModel.joints[0].parentIndex = -1;
|
||||||
hfmModel.joints[0].distanceToParent = 0;
|
hfmModel.joints[0].distanceToParent = 0;
|
||||||
hfmModel.joints[0].translation = glm::vec3(0, 0, 0);
|
hfmModel.joints[0].translation = glm::vec3(0, 0, 0);
|
||||||
|
@ -1187,8 +1186,6 @@ void GLTFSerializer::hfmDebugDump(const HFMModel& hfmModel) {
|
||||||
qCDebug(modelformat) << " hasSkeletonJoints =" << hfmModel.hasSkeletonJoints;
|
qCDebug(modelformat) << " hasSkeletonJoints =" << hfmModel.hasSkeletonJoints;
|
||||||
qCDebug(modelformat) << " offset =" << hfmModel.offset;
|
qCDebug(modelformat) << " offset =" << hfmModel.offset;
|
||||||
|
|
||||||
qCDebug(modelformat) << " palmDirection = " << hfmModel.palmDirection;
|
|
||||||
|
|
||||||
qCDebug(modelformat) << " neckPivot = " << hfmModel.neckPivot;
|
qCDebug(modelformat) << " neckPivot = " << hfmModel.neckPivot;
|
||||||
|
|
||||||
qCDebug(modelformat) << " bindExtents.size() = " << hfmModel.bindExtents.size();
|
qCDebug(modelformat) << " bindExtents.size() = " << hfmModel.bindExtents.size();
|
||||||
|
@ -1301,8 +1298,6 @@ void GLTFSerializer::hfmDebugDump(const HFMModel& hfmModel) {
|
||||||
qCDebug(modelformat) << " shapeInfo.dots =" << joint.shapeInfo.dots;
|
qCDebug(modelformat) << " shapeInfo.dots =" << joint.shapeInfo.dots;
|
||||||
qCDebug(modelformat) << " shapeInfo.points =" << joint.shapeInfo.points;
|
qCDebug(modelformat) << " shapeInfo.points =" << joint.shapeInfo.points;
|
||||||
|
|
||||||
qCDebug(modelformat) << " isFree =" << joint.isFree;
|
|
||||||
qCDebug(modelformat) << " freeLineage" << joint.freeLineage;
|
|
||||||
qCDebug(modelformat) << " parentIndex" << joint.parentIndex;
|
qCDebug(modelformat) << " parentIndex" << joint.parentIndex;
|
||||||
qCDebug(modelformat) << " distanceToParent" << joint.distanceToParent;
|
qCDebug(modelformat) << " distanceToParent" << joint.distanceToParent;
|
||||||
qCDebug(modelformat) << " translation" << joint.translation;
|
qCDebug(modelformat) << " translation" << joint.translation;
|
||||||
|
|
|
@ -687,7 +687,6 @@ HFMModel::Pointer OBJSerializer::read(const QByteArray& data, const QVariantHash
|
||||||
mesh.meshIndex = 0;
|
mesh.meshIndex = 0;
|
||||||
|
|
||||||
hfmModel.joints.resize(1);
|
hfmModel.joints.resize(1);
|
||||||
hfmModel.joints[0].isFree = false;
|
|
||||||
hfmModel.joints[0].parentIndex = -1;
|
hfmModel.joints[0].parentIndex = -1;
|
||||||
hfmModel.joints[0].distanceToParent = 0;
|
hfmModel.joints[0].distanceToParent = 0;
|
||||||
hfmModel.joints[0].translation = glm::vec3(0, 0, 0);
|
hfmModel.joints[0].translation = glm::vec3(0, 0, 0);
|
||||||
|
@ -1048,8 +1047,7 @@ void hfmDebugDump(const HFMModel& hfmModel) {
|
||||||
qCDebug(modelformat) << " joints.count() =" << hfmModel.joints.count();
|
qCDebug(modelformat) << " joints.count() =" << hfmModel.joints.count();
|
||||||
|
|
||||||
foreach (HFMJoint joint, hfmModel.joints) {
|
foreach (HFMJoint joint, hfmModel.joints) {
|
||||||
qCDebug(modelformat) << " isFree =" << joint.isFree;
|
|
||||||
qCDebug(modelformat) << " freeLineage" << joint.freeLineage;
|
|
||||||
qCDebug(modelformat) << " parentIndex" << joint.parentIndex;
|
qCDebug(modelformat) << " parentIndex" << joint.parentIndex;
|
||||||
qCDebug(modelformat) << " distanceToParent" << joint.distanceToParent;
|
qCDebug(modelformat) << " distanceToParent" << joint.distanceToParent;
|
||||||
qCDebug(modelformat) << " translation" << joint.translation;
|
qCDebug(modelformat) << " translation" << joint.translation;
|
||||||
|
|
|
@ -75,8 +75,6 @@ struct JointShapeInfo {
|
||||||
class Joint {
|
class Joint {
|
||||||
public:
|
public:
|
||||||
JointShapeInfo shapeInfo;
|
JointShapeInfo shapeInfo;
|
||||||
QVector<int> freeLineage;
|
|
||||||
bool isFree;
|
|
||||||
int parentIndex;
|
int parentIndex;
|
||||||
float distanceToParent;
|
float distanceToParent;
|
||||||
|
|
||||||
|
@ -291,8 +289,6 @@ public:
|
||||||
|
|
||||||
glm::mat4 offset; // This includes offset, rotation, and scale as specified by the FST file
|
glm::mat4 offset; // This includes offset, rotation, and scale as specified by the FST file
|
||||||
|
|
||||||
glm::vec3 palmDirection;
|
|
||||||
|
|
||||||
glm::vec3 neckPivot;
|
glm::vec3 neckPivot;
|
||||||
|
|
||||||
Extents bindExtents;
|
Extents bindExtents;
|
||||||
|
@ -319,7 +315,6 @@ public:
|
||||||
QList<QString> blendshapeChannelNames;
|
QList<QString> blendshapeChannelNames;
|
||||||
|
|
||||||
QMap<int, glm::quat> jointRotationOffsets;
|
QMap<int, glm::quat> jointRotationOffsets;
|
||||||
QMap<QString, QString> hfmToHifiJointNameMapping;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,13 +19,14 @@
|
||||||
#include "CalculateMeshTangentsTask.h"
|
#include "CalculateMeshTangentsTask.h"
|
||||||
#include "CalculateBlendshapeNormalsTask.h"
|
#include "CalculateBlendshapeNormalsTask.h"
|
||||||
#include "CalculateBlendshapeTangentsTask.h"
|
#include "CalculateBlendshapeTangentsTask.h"
|
||||||
|
#include "PrepareJointsTask.h"
|
||||||
|
|
||||||
namespace baker {
|
namespace baker {
|
||||||
|
|
||||||
class GetModelPartsTask {
|
class GetModelPartsTask {
|
||||||
public:
|
public:
|
||||||
using Input = hfm::Model::Pointer;
|
using Input = hfm::Model::Pointer;
|
||||||
using Output = VaryingSet5<std::vector<hfm::Mesh>, hifi::URL, baker::MeshIndicesToModelNames, baker::BlendshapesPerMesh, QHash<QString, hfm::Material>>;
|
using Output = VaryingSet6<std::vector<hfm::Mesh>, hifi::URL, baker::MeshIndicesToModelNames, baker::BlendshapesPerMesh, QHash<QString, hfm::Material>, std::vector<hfm::Joint>>;
|
||||||
using JobModel = Job::ModelIO<GetModelPartsTask, Input, Output>;
|
using JobModel = Job::ModelIO<GetModelPartsTask, Input, Output>;
|
||||||
|
|
||||||
void run(const BakeContextPointer& context, const Input& input, Output& output) {
|
void run(const BakeContextPointer& context, const Input& input, Output& output) {
|
||||||
|
@ -39,6 +40,7 @@ namespace baker {
|
||||||
blendshapesPerMesh.push_back(hfmModelIn->meshes[i].blendshapes.toStdVector());
|
blendshapesPerMesh.push_back(hfmModelIn->meshes[i].blendshapes.toStdVector());
|
||||||
}
|
}
|
||||||
output.edit4() = hfmModelIn->materials;
|
output.edit4() = hfmModelIn->materials;
|
||||||
|
output.edit5() = hfmModelIn->joints.toStdVector();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,23 +101,29 @@ namespace baker {
|
||||||
|
|
||||||
class BuildModelTask {
|
class BuildModelTask {
|
||||||
public:
|
public:
|
||||||
using Input = VaryingSet2<hfm::Model::Pointer, std::vector<hfm::Mesh>>;
|
using Input = VaryingSet5<hfm::Model::Pointer, std::vector<hfm::Mesh>, std::vector<hfm::Joint>, QMap<int, glm::quat> /*jointRotationOffsets*/, QHash<QString, int> /*jointIndices*/>;
|
||||||
using Output = hfm::Model::Pointer;
|
using Output = hfm::Model::Pointer;
|
||||||
using JobModel = Job::ModelIO<BuildModelTask, Input, Output>;
|
using JobModel = Job::ModelIO<BuildModelTask, Input, Output>;
|
||||||
|
|
||||||
void run(const BakeContextPointer& context, const Input& input, Output& output) {
|
void run(const BakeContextPointer& context, const Input& input, Output& output) {
|
||||||
auto hfmModelOut = input.get0();
|
auto hfmModelOut = input.get0();
|
||||||
hfmModelOut->meshes = QVector<hfm::Mesh>::fromStdVector(input.get1());
|
hfmModelOut->meshes = QVector<hfm::Mesh>::fromStdVector(input.get1());
|
||||||
|
hfmModelOut->joints = QVector<hfm::Joint>::fromStdVector(input.get2());
|
||||||
|
hfmModelOut->jointRotationOffsets = input.get3();
|
||||||
|
hfmModelOut->jointIndices = input.get4();
|
||||||
output = hfmModelOut;
|
output = hfmModelOut;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class BakerEngineBuilder {
|
class BakerEngineBuilder {
|
||||||
public:
|
public:
|
||||||
using Input = hfm::Model::Pointer;
|
using Input = VaryingSet2<hfm::Model::Pointer, QVariantHash>;
|
||||||
using Output = hfm::Model::Pointer;
|
using Output = hfm::Model::Pointer;
|
||||||
using JobModel = Task::ModelIO<BakerEngineBuilder, Input, Output>;
|
using JobModel = Task::ModelIO<BakerEngineBuilder, Input, Output>;
|
||||||
void build(JobModel& model, const Varying& hfmModelIn, Varying& hfmModelOut) {
|
void build(JobModel& model, const Varying& input, Varying& hfmModelOut) {
|
||||||
|
const auto& hfmModelIn = input.getN<Input>(0);
|
||||||
|
const auto& mapping = input.getN<Input>(1);
|
||||||
|
|
||||||
// Split up the inputs from hfm::Model
|
// Split up the inputs from hfm::Model
|
||||||
const auto modelPartsIn = model.addJob<GetModelPartsTask>("GetModelParts", hfmModelIn);
|
const auto modelPartsIn = model.addJob<GetModelPartsTask>("GetModelParts", hfmModelIn);
|
||||||
const auto meshesIn = modelPartsIn.getN<GetModelPartsTask::Output>(0);
|
const auto meshesIn = modelPartsIn.getN<GetModelPartsTask::Output>(0);
|
||||||
|
@ -123,6 +131,7 @@ namespace baker {
|
||||||
const auto meshIndicesToModelNames = modelPartsIn.getN<GetModelPartsTask::Output>(2);
|
const auto meshIndicesToModelNames = modelPartsIn.getN<GetModelPartsTask::Output>(2);
|
||||||
const auto blendshapesPerMeshIn = modelPartsIn.getN<GetModelPartsTask::Output>(3);
|
const auto blendshapesPerMeshIn = modelPartsIn.getN<GetModelPartsTask::Output>(3);
|
||||||
const auto materials = modelPartsIn.getN<GetModelPartsTask::Output>(4);
|
const auto materials = modelPartsIn.getN<GetModelPartsTask::Output>(4);
|
||||||
|
const auto jointsIn = modelPartsIn.getN<GetModelPartsTask::Output>(5);
|
||||||
|
|
||||||
// Calculate normals and tangents for meshes and blendshapes if they do not exist
|
// Calculate normals and tangents for meshes and blendshapes if they do not exist
|
||||||
// Note: Normals are never calculated here for OBJ models. OBJ files optionally define normals on a per-face basis, so for consistency normals are calculated beforehand in OBJSerializer.
|
// Note: Normals are never calculated here for OBJ models. OBJ files optionally define normals on a per-face basis, so for consistency normals are calculated beforehand in OBJSerializer.
|
||||||
|
@ -138,19 +147,27 @@ namespace baker {
|
||||||
const auto buildGraphicsMeshInputs = BuildGraphicsMeshTask::Input(meshesIn, url, meshIndicesToModelNames, normalsPerMesh, tangentsPerMesh).asVarying();
|
const auto buildGraphicsMeshInputs = BuildGraphicsMeshTask::Input(meshesIn, url, meshIndicesToModelNames, normalsPerMesh, tangentsPerMesh).asVarying();
|
||||||
const auto graphicsMeshes = model.addJob<BuildGraphicsMeshTask>("BuildGraphicsMesh", buildGraphicsMeshInputs);
|
const auto graphicsMeshes = model.addJob<BuildGraphicsMeshTask>("BuildGraphicsMesh", buildGraphicsMeshInputs);
|
||||||
|
|
||||||
|
// Prepare joint information
|
||||||
|
const auto prepareJointsInputs = PrepareJointsTask::Input(jointsIn, mapping).asVarying();
|
||||||
|
const auto jointInfoOut = model.addJob<PrepareJointsTask>("PrepareJoints", prepareJointsInputs);
|
||||||
|
const auto jointsOut = jointInfoOut.getN<PrepareJointsTask::Output>(0);
|
||||||
|
const auto jointRotationOffsets = jointInfoOut.getN<PrepareJointsTask::Output>(1);
|
||||||
|
const auto jointIndices = jointInfoOut.getN<PrepareJointsTask::Output>(2);
|
||||||
|
|
||||||
// Combine the outputs into a new hfm::Model
|
// Combine the outputs into a new hfm::Model
|
||||||
const auto buildBlendshapesInputs = BuildBlendshapesTask::Input(blendshapesPerMeshIn, normalsPerBlendshapePerMesh, tangentsPerBlendshapePerMesh).asVarying();
|
const auto buildBlendshapesInputs = BuildBlendshapesTask::Input(blendshapesPerMeshIn, normalsPerBlendshapePerMesh, tangentsPerBlendshapePerMesh).asVarying();
|
||||||
const auto blendshapesPerMeshOut = model.addJob<BuildBlendshapesTask>("BuildBlendshapes", buildBlendshapesInputs);
|
const auto blendshapesPerMeshOut = model.addJob<BuildBlendshapesTask>("BuildBlendshapes", buildBlendshapesInputs);
|
||||||
const auto buildMeshesInputs = BuildMeshesTask::Input(meshesIn, graphicsMeshes, normalsPerMesh, tangentsPerMesh, blendshapesPerMeshOut).asVarying();
|
const auto buildMeshesInputs = BuildMeshesTask::Input(meshesIn, graphicsMeshes, normalsPerMesh, tangentsPerMesh, blendshapesPerMeshOut).asVarying();
|
||||||
const auto meshesOut = model.addJob<BuildMeshesTask>("BuildMeshes", buildMeshesInputs);
|
const auto meshesOut = model.addJob<BuildMeshesTask>("BuildMeshes", buildMeshesInputs);
|
||||||
const auto buildModelInputs = BuildModelTask::Input(hfmModelIn, meshesOut).asVarying();
|
const auto buildModelInputs = BuildModelTask::Input(hfmModelIn, meshesOut, jointsOut, jointRotationOffsets, jointIndices).asVarying();
|
||||||
hfmModelOut = model.addJob<BuildModelTask>("BuildModel", buildModelInputs);
|
hfmModelOut = model.addJob<BuildModelTask>("BuildModel", buildModelInputs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Baker::Baker(const hfm::Model::Pointer& hfmModel) :
|
Baker::Baker(const hfm::Model::Pointer& hfmModel, const QVariantHash& mapping) :
|
||||||
_engine(std::make_shared<Engine>(BakerEngineBuilder::JobModel::create("Baker"), std::make_shared<BakeContext>())) {
|
_engine(std::make_shared<Engine>(BakerEngineBuilder::JobModel::create("Baker"), std::make_shared<BakeContext>())) {
|
||||||
_engine->feedInput<BakerEngineBuilder::Input>(hfmModel);
|
_engine->feedInput<BakerEngineBuilder::Input>(0, hfmModel);
|
||||||
|
_engine->feedInput<BakerEngineBuilder::Input>(1, mapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Baker::run() {
|
void Baker::run() {
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#ifndef hifi_baker_Baker_h
|
#ifndef hifi_baker_Baker_h
|
||||||
#define hifi_baker_Baker_h
|
#define hifi_baker_Baker_h
|
||||||
|
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
#include <hfm/HFM.h>
|
#include <hfm/HFM.h>
|
||||||
|
|
||||||
#include "Engine.h"
|
#include "Engine.h"
|
||||||
|
@ -19,7 +21,7 @@
|
||||||
namespace baker {
|
namespace baker {
|
||||||
class Baker {
|
class Baker {
|
||||||
public:
|
public:
|
||||||
Baker(const hfm::Model::Pointer& hfmModel);
|
Baker(const hfm::Model::Pointer& hfmModel, const QVariantHash& mapping);
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
|
|
86
libraries/model-baker/src/model-baker/PrepareJointsTask.cpp
Normal file
86
libraries/model-baker/src/model-baker/PrepareJointsTask.cpp
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
//
|
||||||
|
// PrepareJointsTask.cpp
|
||||||
|
// model-baker/src/model-baker
|
||||||
|
//
|
||||||
|
// Created by Sabrina Shanman on 2019/01/25.
|
||||||
|
// Copyright 2019 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "PrepareJointsTask.h"
|
||||||
|
|
||||||
|
#include "ModelBakerLogging.h"
|
||||||
|
|
||||||
|
QMap<QString, QString> getJointNameMapping(const QVariantHash& mapping) {
|
||||||
|
static const QString JOINT_NAME_MAPPING_FIELD = "jointMap";
|
||||||
|
QMap<QString, QString> hfmToHifiJointNameMap;
|
||||||
|
if (!mapping.isEmpty() && mapping.contains(JOINT_NAME_MAPPING_FIELD) && mapping[JOINT_NAME_MAPPING_FIELD].type() == QVariant::Hash) {
|
||||||
|
auto jointNames = mapping[JOINT_NAME_MAPPING_FIELD].toHash();
|
||||||
|
for (auto itr = jointNames.begin(); itr != jointNames.end(); itr++) {
|
||||||
|
hfmToHifiJointNameMap.insert(itr.key(), itr.value().toString());
|
||||||
|
qCDebug(model_baker) << "the mapped key " << itr.key() << " has a value of " << hfmToHifiJointNameMap[itr.key()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hfmToHifiJointNameMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, glm::quat> getJointRotationOffsets(const QVariantHash& mapping) {
|
||||||
|
QMap<QString, glm::quat> jointRotationOffsets;
|
||||||
|
static const QString JOINT_ROTATION_OFFSET_FIELD = "jointRotationOffset";
|
||||||
|
if (!mapping.isEmpty() && mapping.contains(JOINT_ROTATION_OFFSET_FIELD) && mapping[JOINT_ROTATION_OFFSET_FIELD].type() == QVariant::Hash) {
|
||||||
|
auto offsets = mapping[JOINT_ROTATION_OFFSET_FIELD].toHash();
|
||||||
|
for (auto itr = offsets.begin(); itr != offsets.end(); itr++) {
|
||||||
|
QString jointName = itr.key();
|
||||||
|
QString line = itr.value().toString();
|
||||||
|
auto quatCoords = line.split(',');
|
||||||
|
if (quatCoords.size() == 4) {
|
||||||
|
float quatX = quatCoords[0].mid(1).toFloat();
|
||||||
|
float quatY = quatCoords[1].toFloat();
|
||||||
|
float quatZ = quatCoords[2].toFloat();
|
||||||
|
float quatW = quatCoords[3].mid(0, quatCoords[3].size() - 1).toFloat();
|
||||||
|
if (!isNaN(quatX) && !isNaN(quatY) && !isNaN(quatZ) && !isNaN(quatW)) {
|
||||||
|
glm::quat rotationOffset = glm::quat(quatW, quatX, quatY, quatZ);
|
||||||
|
jointRotationOffsets.insert(jointName, rotationOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return jointRotationOffsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrepareJointsTask::run(const baker::BakeContextPointer& context, const Input& input, Output& output) {
|
||||||
|
const auto& jointsIn = input.get0();
|
||||||
|
const auto& mapping = input.get1();
|
||||||
|
auto& jointsOut = output.edit0();
|
||||||
|
auto& jointRotationOffsets = output.edit1();
|
||||||
|
auto& jointIndices = output.edit2();
|
||||||
|
|
||||||
|
// Get joint renames
|
||||||
|
auto jointNameMapping = getJointNameMapping(mapping);
|
||||||
|
// Apply joint metadata from FST file mappings
|
||||||
|
for (const auto& jointIn : jointsIn) {
|
||||||
|
jointsOut.push_back(jointIn);
|
||||||
|
auto& jointOut = jointsOut.back();
|
||||||
|
|
||||||
|
auto jointNameMapKey = jointNameMapping.key(jointIn.name);
|
||||||
|
if (jointNameMapping.contains(jointNameMapKey)) {
|
||||||
|
jointOut.name = jointNameMapKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
jointIndices.insert(jointOut.name, (int)jointsOut.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get joint rotation offsets from FST file mappings
|
||||||
|
auto offsets = getJointRotationOffsets(mapping);
|
||||||
|
for (auto itr = offsets.begin(); itr != offsets.end(); itr++) {
|
||||||
|
QString jointName = itr.key();
|
||||||
|
int jointIndex = jointIndices.value(jointName) - 1;
|
||||||
|
if (jointIndex != -1) {
|
||||||
|
glm::quat rotationOffset = itr.value();
|
||||||
|
jointRotationOffsets.insert(jointIndex, rotationOffset);
|
||||||
|
qCDebug(model_baker) << "Joint Rotation Offset added to Rig._jointRotationOffsets : " << " jointName: " << jointName << " jointIndex: " << jointIndex << " rotation offset: " << rotationOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
libraries/model-baker/src/model-baker/PrepareJointsTask.h
Normal file
30
libraries/model-baker/src/model-baker/PrepareJointsTask.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// PrepareJointsTask.h
|
||||||
|
// model-baker/src/model-baker
|
||||||
|
//
|
||||||
|
// Created by Sabrina Shanman on 2019/01/25.
|
||||||
|
// Copyright 2019 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_PrepareJointsTask_h
|
||||||
|
#define hifi_PrepareJointsTask_h
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
|
#include <hfm/HFM.h>
|
||||||
|
|
||||||
|
#include "Engine.h"
|
||||||
|
|
||||||
|
class PrepareJointsTask {
|
||||||
|
public:
|
||||||
|
using Input = baker::VaryingSet2<std::vector<hfm::Joint>, QVariantHash /*mapping*/>;
|
||||||
|
using Output = baker::VaryingSet3<std::vector<hfm::Joint>, QMap<int, glm::quat> /*jointRotationOffsets*/, QHash<QString, int> /*jointIndices*/>;
|
||||||
|
using JobModel = baker::Job::ModelIO<PrepareJointsTask, Input, Output>;
|
||||||
|
|
||||||
|
void run(const baker::BakeContextPointer& context, const Input& input, Output& output);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_PrepareJointsTask_h
|
|
@ -233,7 +233,7 @@ void GeometryReader::run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
QMetaObject::invokeMethod(resource.data(), "setGeometryDefinition",
|
QMetaObject::invokeMethod(resource.data(), "setGeometryDefinition",
|
||||||
Q_ARG(HFMModel::Pointer, hfmModel));
|
Q_ARG(HFMModel::Pointer, hfmModel), Q_ARG(QVariantHash, _mapping));
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
auto resource = _resource.toStrongRef();
|
auto resource = _resource.toStrongRef();
|
||||||
if (resource) {
|
if (resource) {
|
||||||
|
@ -261,7 +261,7 @@ public:
|
||||||
virtual void downloadFinished(const QByteArray& data) override;
|
virtual void downloadFinished(const QByteArray& data) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Q_INVOKABLE void setGeometryDefinition(HFMModel::Pointer hfmModel);
|
Q_INVOKABLE void setGeometryDefinition(HFMModel::Pointer hfmModel, QVariantHash mapping);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ModelLoader _modelLoader;
|
ModelLoader _modelLoader;
|
||||||
|
@ -277,9 +277,9 @@ void GeometryDefinitionResource::downloadFinished(const QByteArray& data) {
|
||||||
QThreadPool::globalInstance()->start(new GeometryReader(_modelLoader, _self, _effectiveBaseURL, _mapping, data, _combineParts, _request->getWebMediaType()));
|
QThreadPool::globalInstance()->start(new GeometryReader(_modelLoader, _self, _effectiveBaseURL, _mapping, data, _combineParts, _request->getWebMediaType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeometryDefinitionResource::setGeometryDefinition(HFMModel::Pointer hfmModel) {
|
void GeometryDefinitionResource::setGeometryDefinition(HFMModel::Pointer hfmModel, QVariantHash mapping) {
|
||||||
// Do processing on the model
|
// Do processing on the model
|
||||||
baker::Baker modelBaker(hfmModel);
|
baker::Baker modelBaker(hfmModel, mapping);
|
||||||
modelBaker.run();
|
modelBaker.run();
|
||||||
|
|
||||||
// Assume ownership of the processed HFMModel
|
// Assume ownership of the processed HFMModel
|
||||||
|
|
|
@ -1116,10 +1116,6 @@ int Model::getParentJointIndex(int jointIndex) const {
|
||||||
return (isActive() && jointIndex != -1) ? getHFMModel().joints.at(jointIndex).parentIndex : -1;
|
return (isActive() && jointIndex != -1) ? getHFMModel().joints.at(jointIndex).parentIndex : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Model::getLastFreeJointIndex(int jointIndex) const {
|
|
||||||
return (isActive() && jointIndex != -1) ? getHFMModel().joints.at(jointIndex).freeLineage.last() : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Model::setTextures(const QVariantMap& textures) {
|
void Model::setTextures(const QVariantMap& textures) {
|
||||||
if (isLoaded()) {
|
if (isLoaded()) {
|
||||||
_needsFixupInScene = true;
|
_needsFixupInScene = true;
|
||||||
|
|
|
@ -379,9 +379,6 @@ protected:
|
||||||
/// Clear the joint states
|
/// Clear the joint states
|
||||||
void clearJointState(int index);
|
void clearJointState(int index);
|
||||||
|
|
||||||
/// Returns the index of the last free ancestor of the indexed joint, or -1 if not found.
|
|
||||||
int getLastFreeJointIndex(int jointIndex) const;
|
|
||||||
|
|
||||||
/// \param jointIndex index of joint in model structure
|
/// \param jointIndex index of joint in model structure
|
||||||
/// \param position[out] position of joint in model-frame
|
/// \param position[out] position of joint in model-frame
|
||||||
/// \return true if joint exists
|
/// \return true if joint exists
|
||||||
|
|
Loading…
Reference in a new issue