parent
2c8975b1cd
commit
1543c1a6c7
|
@ -154,6 +154,8 @@ void AnimalPoser::resolveChainRotation(const std::vector<QString> &limbBoneNames
|
||||||
float targetMiddleBoneLength = (middleBone.headPosition - middleBone.tailPosition).length();
|
float targetMiddleBoneLength = (middleBone.headPosition - middleBone.tailPosition).length();
|
||||||
float targetLimbLength = targetBeginBoneLength + targetMiddleBoneLength;
|
float targetLimbLength = targetBeginBoneLength + targetMiddleBoneLength;
|
||||||
|
|
||||||
|
//qDebug() << beginBoneName << "targetLimbLength:" << targetLimbLength << "matchLimbLength:" << matchLimbLength;
|
||||||
|
|
||||||
float targetDistanceBetweenBeginAndEndBones = matchDistanceBetweenBeginAndEndBones * (targetLimbLength / matchLimbLength);
|
float targetDistanceBetweenBeginAndEndBones = matchDistanceBetweenBeginAndEndBones * (targetLimbLength / matchLimbLength);
|
||||||
QVector3D targetEndBoneStartPosition = beginBone.headPosition + matchDirectionBetweenBeginAndEndPones * targetDistanceBetweenBeginAndEndBones;
|
QVector3D targetEndBoneStartPosition = beginBone.headPosition + matchDirectionBetweenBeginAndEndPones * targetDistanceBetweenBeginAndEndBones;
|
||||||
|
|
||||||
|
@ -177,12 +179,15 @@ void AnimalPoser::resolveChainRotation(const std::vector<QString> &limbBoneNames
|
||||||
|
|
||||||
auto oldBeginBoneDirection = (beginBone.tailPosition - beginBone.headPosition).normalized();
|
auto oldBeginBoneDirection = (beginBone.tailPosition - beginBone.headPosition).normalized();
|
||||||
auto newBeginBoneDirection = (targetMiddleBoneStartPosition - beginBone.headPosition).normalized();
|
auto newBeginBoneDirection = (targetMiddleBoneStartPosition - beginBone.headPosition).normalized();
|
||||||
|
//qDebug() << beginBoneName << "oldBeginBoneDirection:" << oldBeginBoneDirection << "newBeginBoneDirection:" << newBeginBoneDirection;
|
||||||
auto beginBoneRotation = QQuaternion::rotationTo(oldBeginBoneDirection, newBeginBoneDirection);
|
auto beginBoneRotation = QQuaternion::rotationTo(oldBeginBoneDirection, newBeginBoneDirection);
|
||||||
m_jointNodeTree.updateRotation(beginBoneIndex, beginBoneRotation);
|
m_jointNodeTree.updateRotation(beginBoneIndex, beginBoneRotation);
|
||||||
|
|
||||||
auto oldMiddleBoneDirection = (middleBone.tailPosition - middleBone.headPosition).normalized();
|
auto oldMiddleBoneDirection = (middleBone.tailPosition - middleBone.headPosition).normalized();
|
||||||
auto newMiddleBoneDirection = (targetEndBoneStartPosition - targetMiddleBoneStartPosition).normalized();
|
auto newMiddleBoneDirection = (targetEndBoneStartPosition - targetMiddleBoneStartPosition).normalized();
|
||||||
|
//qDebug() << beginBoneName << "oldMiddleBoneDirection:" << oldMiddleBoneDirection << "newMiddleBoneDirection:" << newMiddleBoneDirection;
|
||||||
oldMiddleBoneDirection = beginBoneRotation.rotatedVector(oldMiddleBoneDirection);
|
oldMiddleBoneDirection = beginBoneRotation.rotatedVector(oldMiddleBoneDirection);
|
||||||
|
//qDebug() << beginBoneName << "oldMiddleBoneDirection:" << oldMiddleBoneDirection << "after rotation";
|
||||||
auto middleBoneRotation = QQuaternion::rotationTo(oldMiddleBoneDirection, newMiddleBoneDirection);
|
auto middleBoneRotation = QQuaternion::rotationTo(oldMiddleBoneDirection, newMiddleBoneDirection);
|
||||||
m_jointNodeTree.updateRotation(middleBoneIndex, middleBoneRotation);
|
m_jointNodeTree.updateRotation(middleBoneIndex, middleBoneRotation);
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ bool AnimalRigger::validate()
|
||||||
{
|
{
|
||||||
if (m_marksMap.empty()) {
|
if (m_marksMap.empty()) {
|
||||||
m_messages.push_back(std::make_pair(QtCriticalMsg,
|
m_messages.push_back(std::make_pair(QtCriticalMsg,
|
||||||
tr("Please tell me where is the neck, limbs and joints by mark the nodes from context menu")));
|
tr("Please mark the neck, limbs and joints from the context menu")));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,6 +207,7 @@ bool AnimalRigger::rig()
|
||||||
resolveBoundingBox(bodyVerticies, xMin, xMax, yMin, yMax, zMin, zMax);
|
resolveBoundingBox(bodyVerticies, xMin, xMax, yMin, yMax, zMin, zMax);
|
||||||
isMainBodyVerticalAligned = fabs(yMax.y() - yMin.y()) > fabs(zMax.z() - zMin.z());
|
isMainBodyVerticalAligned = fabs(yMax.y() - yMin.y()) > fabs(zMax.z() - zMin.z());
|
||||||
}
|
}
|
||||||
|
qDebug() << "isMainBodyVerticalAligned:" << isMainBodyVerticalAligned;
|
||||||
|
|
||||||
// Collect all branchs
|
// Collect all branchs
|
||||||
auto neckIndicies = m_marksMap.find(std::make_pair(BoneMark::Neck, SkeletonSide::None));
|
auto neckIndicies = m_marksMap.find(std::make_pair(BoneMark::Neck, SkeletonSide::None));
|
||||||
|
@ -299,7 +300,7 @@ bool AnimalRigger::rig()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (countOfChains <= 0) {
|
if (countOfChains <= 0) {
|
||||||
qDebug() << "Should not come here, there must be at least one limb";
|
qDebug() << "Should not come here, there must be at least one chain";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,7 +312,7 @@ bool AnimalRigger::rig()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rawSpineNodes.empty()) {
|
if (rawSpineNodes.empty()) {
|
||||||
qDebug() << "Couldn't find limbs to create a spine";
|
qDebug() << "Couldn't find chain to create a spine";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,7 +356,7 @@ bool AnimalRigger::rig()
|
||||||
|
|
||||||
auto remainingSpineVerticies = bodyVerticies;
|
auto remainingSpineVerticies = bodyVerticies;
|
||||||
const std::vector<QColor> twoColorsForSpine = {BoneMarkToColor(BoneMark::Neck), BoneMarkToColor(BoneMark::Tail)};
|
const std::vector<QColor> twoColorsForSpine = {BoneMarkToColor(BoneMark::Neck), BoneMarkToColor(BoneMark::Tail)};
|
||||||
const std::vector<QColor> twoColorsForLimb = {BoneMarkToColor(BoneMark::Joint), BoneMarkToColor(BoneMark::Limb)};
|
const std::vector<QColor> twoColorsForChain = {BoneMarkToColor(BoneMark::Joint), BoneMarkToColor(BoneMark::Limb)};
|
||||||
int spineGenerateOrder = 1;
|
int spineGenerateOrder = 1;
|
||||||
std::map<std::pair<QString, SkeletonSide>, int> chainOrderMapBySide;
|
std::map<std::pair<QString, SkeletonSide>, int> chainOrderMapBySide;
|
||||||
for (int spineNodeIndex = 0; spineNodeIndex < (int)spineNodes.size(); ++spineNodeIndex) {
|
for (int spineNodeIndex = 0; spineNodeIndex < (int)spineNodes.size(); ++spineNodeIndex) {
|
||||||
|
@ -402,11 +403,7 @@ bool AnimalRigger::rig()
|
||||||
tailPosition = spineNodes[spineNodeIndex + 1].position;
|
tailPosition = spineNodes[spineNodeIndex + 1].position;
|
||||||
} else {
|
} else {
|
||||||
spineBoneVertices = remainingSpineVerticies;
|
spineBoneVertices = remainingSpineVerticies;
|
||||||
if (isMainBodyVerticalAligned) {
|
tailPosition = findExtremPointFrom(spineBoneVertices, spineNode.position);
|
||||||
tailPosition = findMaxY(spineBoneVertices);
|
|
||||||
} else {
|
|
||||||
tailPosition = findMaxZ(spineBoneVertices);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector3D spineBoneHeadPosition = averagePosition(spineBoneVertices);
|
QVector3D spineBoneHeadPosition = averagePosition(spineBoneVertices);
|
||||||
|
@ -428,7 +425,7 @@ bool AnimalRigger::rig()
|
||||||
addVerticesToWeights(spineBoneVertices, spineBone.index);
|
addVerticesToWeights(spineBoneVertices, spineBone.index);
|
||||||
boneIndexMap[spineBone.name] = spineBone.index;
|
boneIndexMap[spineBone.name] = spineBone.index;
|
||||||
|
|
||||||
//qDebug() << spineBone.name << "head:" << spineBone.headPosition << "tail:" << spineBone.tailPosition;
|
qDebug() << "Added spine:" << spineBone.name << "head:" << spineBone.headPosition << "tail:" << spineBone.tailPosition;
|
||||||
|
|
||||||
if (1 == spineGenerateOrder) {
|
if (1 == spineGenerateOrder) {
|
||||||
m_resultBones[boneIndexMap[Rigger::rootBoneName]].tailPosition = spineBone.headPosition;
|
m_resultBones[boneIndexMap[Rigger::rootBoneName]].tailPosition = spineBone.headPosition;
|
||||||
|
@ -450,6 +447,7 @@ bool AnimalRigger::rig()
|
||||||
ribBone.index = m_resultBones.size() - 1;
|
ribBone.index = m_resultBones.size() - 1;
|
||||||
ribBone.name = namingConnector(spineName, chainName);
|
ribBone.name = namingConnector(spineName, chainName);
|
||||||
ribBone.headPosition = spineBoneHeadPosition;
|
ribBone.headPosition = spineBoneHeadPosition;
|
||||||
|
qDebug() << "Added connector:" << ribBone.name;
|
||||||
boneIndexMap[ribBone.name] = ribBone.index;
|
boneIndexMap[ribBone.name] = ribBone.index;
|
||||||
if (1 == spineGenerateOrder) {
|
if (1 == spineGenerateOrder) {
|
||||||
m_resultBones[boneIndexMap[Rigger::rootBoneName]].children.push_back(ribBone.index);
|
m_resultBones[boneIndexMap[Rigger::rootBoneName]].children.push_back(ribBone.index);
|
||||||
|
@ -462,12 +460,12 @@ bool AnimalRigger::rig()
|
||||||
m_jointErrorItems.push_back(chainName);
|
m_jointErrorItems.push_back(chainName);
|
||||||
}
|
}
|
||||||
|
|
||||||
//qDebug() << "Limb markIndex:" << limbMarkIndex << " joints:" << jointMarkIndicies.size();
|
qDebug() << "Adding chain:" << chainName << " joints:" << jointMarkIndicies.size();
|
||||||
|
|
||||||
int jointGenerateOrder = 1;
|
int jointGenerateOrder = 1;
|
||||||
|
|
||||||
auto boneColor = [&]() {
|
auto boneColor = [&]() {
|
||||||
return twoColorsForLimb[jointGenerateOrder % 2];
|
return twoColorsForChain[jointGenerateOrder % 2];
|
||||||
};
|
};
|
||||||
auto addToParentBone = [&](QVector3D headPosition, SkeletonSide side, int boneIndex) {
|
auto addToParentBone = [&](QVector3D headPosition, SkeletonSide side, int boneIndex) {
|
||||||
if (1 == jointGenerateOrder) {
|
if (1 == jointGenerateOrder) {
|
||||||
|
@ -507,21 +505,8 @@ bool AnimalRigger::rig()
|
||||||
lastJointBoneVerticies = remainingLimbVertices;
|
lastJointBoneVerticies = remainingLimbVertices;
|
||||||
}
|
}
|
||||||
// Calculate the tail position from remaining verticies
|
// Calculate the tail position from remaining verticies
|
||||||
std::vector<QVector3D> extremCoords(6, jointPositions.back());
|
jointPositions.push_back(findExtremPointFrom(lastJointBoneVerticies, jointPositions.back()));
|
||||||
resolveBoundingBox(lastJointBoneVerticies, extremCoords[0], extremCoords[1], extremCoords[2], extremCoords[3], extremCoords[4], extremCoords[5]);
|
|
||||||
float maxDistance2 = std::numeric_limits<float>::min();
|
|
||||||
QVector3D choosenExtreamCoord = jointPositions.back();
|
|
||||||
for (size_t i = 0; i < 6; ++i) {
|
|
||||||
const auto &position = extremCoords[i];
|
|
||||||
auto length2 = (position - jointPositions.back()).lengthSquared();
|
|
||||||
if (length2 >= maxDistance2) {
|
|
||||||
maxDistance2 = length2;
|
|
||||||
choosenExtreamCoord = position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jointPositions.push_back(choosenExtreamCoord);
|
|
||||||
|
|
||||||
QVector3D lastPosition = spineBoneHeadPosition;
|
|
||||||
for (jointGenerateOrder = 1; jointGenerateOrder <= (int)jointMarkIndicies.size(); ++jointGenerateOrder) {
|
for (jointGenerateOrder = 1; jointGenerateOrder <= (int)jointMarkIndicies.size(); ++jointGenerateOrder) {
|
||||||
int jointMarkIndex = jointMarkIndicies[jointGenerateOrder - 1];
|
int jointMarkIndex = jointMarkIndicies[jointGenerateOrder - 1];
|
||||||
const auto &jointMark = m_marks[jointMarkIndex];
|
const auto &jointMark = m_marks[jointMarkIndex];
|
||||||
|
@ -567,8 +552,6 @@ bool AnimalRigger::rig()
|
||||||
|
|
||||||
boneIndexMap[jointBone.name] = jointBone.index;
|
boneIndexMap[jointBone.name] = jointBone.index;
|
||||||
addToParentBone(jointBone.headPosition, chainMark.boneSide, jointBone.index);
|
addToParentBone(jointBone.headPosition, chainMark.boneSide, jointBone.index);
|
||||||
|
|
||||||
lastPosition = jointPositions[jointGenerateOrder - 1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
++chainGenerateOrder;
|
++chainGenerateOrder;
|
||||||
|
@ -585,6 +568,23 @@ bool AnimalRigger::rig()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVector3D AnimalRigger::findExtremPointFrom(const std::set<int> &verticies, const QVector3D &from)
|
||||||
|
{
|
||||||
|
std::vector<QVector3D> extremCoords(6, from);
|
||||||
|
resolveBoundingBox(verticies, extremCoords[0], extremCoords[1], extremCoords[2], extremCoords[3], extremCoords[4], extremCoords[5]);
|
||||||
|
float maxDistance2 = std::numeric_limits<float>::min();
|
||||||
|
QVector3D choosenExtreamCoord = from;
|
||||||
|
for (size_t i = 0; i < 6; ++i) {
|
||||||
|
const auto &position = extremCoords[i];
|
||||||
|
auto length2 = (position - from).lengthSquared();
|
||||||
|
if (length2 >= maxDistance2) {
|
||||||
|
maxDistance2 = length2;
|
||||||
|
choosenExtreamCoord = position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return choosenExtreamCoord;
|
||||||
|
}
|
||||||
|
|
||||||
QString AnimalRigger::namingChain(const QString &baseName, SkeletonSide side, int orderInSide, int totalInSide, int jointOrder)
|
QString AnimalRigger::namingChain(const QString &baseName, SkeletonSide side, int orderInSide, int totalInSide, int jointOrder)
|
||||||
{
|
{
|
||||||
return namingChainPrefix(baseName, side, orderInSide, totalInSide) + "_Joint" + QString::number(jointOrder);
|
return namingChainPrefix(baseName, side, orderInSide, totalInSide) + "_Joint" + QString::number(jointOrder);
|
||||||
|
|
|
@ -23,6 +23,7 @@ private:
|
||||||
QString namingConnector(const QString &spineName, const QString &chainName);
|
QString namingConnector(const QString &spineName, const QString &chainName);
|
||||||
QString namingChain(const QString &baseName, SkeletonSide side, int orderInSide, int totalInSide, int jointOrder);
|
QString namingChain(const QString &baseName, SkeletonSide side, int orderInSide, int totalInSide, int jointOrder);
|
||||||
QString namingChainPrefix(const QString &baseName, SkeletonSide side, int orderInSide, int totalInSide);
|
QString namingChainPrefix(const QString &baseName, SkeletonSide side, int orderInSide, int totalInSide);
|
||||||
|
QVector3D findExtremPointFrom(const std::set<int> &verticies, const QVector3D &from);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,7 +19,7 @@ QColor BoneMarkToColor(BoneMark mark) \
|
||||||
{ \
|
{ \
|
||||||
switch (mark) { \
|
switch (mark) { \
|
||||||
case BoneMark::Neck: \
|
case BoneMark::Neck: \
|
||||||
return QColor(0x51, 0xba, 0xf2); \
|
return QColor(0xfd, 0x64, 0x61); \
|
||||||
case BoneMark::Limb: \
|
case BoneMark::Limb: \
|
||||||
return QColor(0x29, 0xfd, 0x2f); \
|
return QColor(0x29, 0xfd, 0x2f); \
|
||||||
case BoneMark::Tail: \
|
case BoneMark::Tail: \
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
const float PoseDocument::m_nodeRadius = 0.01;
|
const float PoseDocument::m_nodeRadius = 0.01;
|
||||||
const float PoseDocument::m_groundPlaneHalfThickness = 0.01 / 4;
|
const float PoseDocument::m_groundPlaneHalfThickness = 0.01 / 4;
|
||||||
|
const bool PoseDocument::m_hideRootAndVirtual = true;
|
||||||
|
|
||||||
bool PoseDocument::hasPastableNodesInClipboard() const
|
bool PoseDocument::hasPastableNodesInClipboard() const
|
||||||
{
|
{
|
||||||
|
@ -176,10 +177,13 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
auto &bonesPart = partMap[m_bonesPartId];
|
auto &bonesPart = partMap[m_bonesPartId];
|
||||||
bonesPart.id = m_bonesPartId;
|
bonesPart.id = m_bonesPartId;
|
||||||
|
|
||||||
|
qDebug() << "rigBones size:" << rigBones->size();
|
||||||
|
|
||||||
std::vector<std::pair<int, int>> edgePairs;
|
std::vector<std::pair<int, int>> edgePairs;
|
||||||
for (size_t i = 1; i < rigBones->size(); ++i) {
|
for (size_t i = m_hideRootAndVirtual ? 1 : 0; i < rigBones->size(); ++i) {
|
||||||
const auto &bone = (*rigBones)[i];
|
const auto &bone = (*rigBones)[i];
|
||||||
for (const auto &child: bone.children) {
|
for (const auto &child: bone.children) {
|
||||||
|
qDebug() << "Add pair:" << bone.name << "->" << (*rigBones)[child].name;
|
||||||
edgePairs.push_back({i, child});
|
edgePairs.push_back({i, child});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,7 +193,7 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
auto findFirst = boneIndexToHeadNodeIdMap.find(edgePair.first);
|
auto findFirst = boneIndexToHeadNodeIdMap.find(edgePair.first);
|
||||||
if (findFirst == boneIndexToHeadNodeIdMap.end()) {
|
if (findFirst == boneIndexToHeadNodeIdMap.end()) {
|
||||||
const auto &bone = (*rigBones)[edgePair.first];
|
const auto &bone = (*rigBones)[edgePair.first];
|
||||||
if (!bone.name.startsWith("Virtual_")) {
|
if (!bone.name.startsWith("Virtual_") || !m_hideRootAndVirtual) {
|
||||||
SkeletonNode node;
|
SkeletonNode node;
|
||||||
node.partId = m_bonesPartId;
|
node.partId = m_bonesPartId;
|
||||||
node.id = QUuid::createUuid();
|
node.id = QUuid::createUuid();
|
||||||
|
@ -208,7 +212,7 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
auto findSecond = boneIndexToHeadNodeIdMap.find(edgePair.second);
|
auto findSecond = boneIndexToHeadNodeIdMap.find(edgePair.second);
|
||||||
if (findSecond == boneIndexToHeadNodeIdMap.end()) {
|
if (findSecond == boneIndexToHeadNodeIdMap.end()) {
|
||||||
const auto &bone = (*rigBones)[edgePair.second];
|
const auto &bone = (*rigBones)[edgePair.second];
|
||||||
if (!bone.name.startsWith("Virtual_")) {
|
if (!bone.name.startsWith("Virtual_") || !m_hideRootAndVirtual) {
|
||||||
SkeletonNode node;
|
SkeletonNode node;
|
||||||
node.partId = m_bonesPartId;
|
node.partId = m_bonesPartId;
|
||||||
node.id = QUuid::createUuid();
|
node.id = QUuid::createUuid();
|
||||||
|
@ -239,9 +243,9 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
nodeMap[secondNodeId].edgeIds.push_back(edge.id);
|
nodeMap[secondNodeId].edgeIds.push_back(edge.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 1; i < rigBones->size(); ++i) {
|
for (size_t i = m_hideRootAndVirtual ? 1 : 0; i < rigBones->size(); ++i) {
|
||||||
const auto &bone = (*rigBones)[i];
|
const auto &bone = (*rigBones)[i];
|
||||||
if (bone.name.startsWith("Virtual_"))
|
if (m_hideRootAndVirtual && bone.name.startsWith("Virtual_"))
|
||||||
continue;
|
continue;
|
||||||
if (bone.children.empty()) {
|
if (bone.children.empty()) {
|
||||||
const QUuid &firstNodeId = boneIndexToHeadNodeIdMap[i];
|
const QUuid &firstNodeId = boneIndexToHeadNodeIdMap[i];
|
||||||
|
@ -250,9 +254,9 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
node.partId = m_bonesPartId;
|
node.partId = m_bonesPartId;
|
||||||
node.id = QUuid::createUuid();
|
node.id = QUuid::createUuid();
|
||||||
node.setRadius(m_nodeRadius / 2);
|
node.setRadius(m_nodeRadius / 2);
|
||||||
node.x = bone.tailPosition.x() + 0.5;
|
node.x = fromOutcomeX(bone.tailPosition.x());
|
||||||
node.y = -bone.tailPosition.y() + 0.5;
|
node.y = fromOutcomeY(bone.tailPosition.y());
|
||||||
node.z = -bone.tailPosition.z() + 1;
|
node.z = fromOutcomeZ(bone.tailPosition.z());
|
||||||
nodeMap[node.id] = node;
|
nodeMap[node.id] = node;
|
||||||
newAddedNodeIds.insert(node.id);
|
newAddedNodeIds.insert(node.id);
|
||||||
m_boneNameToIdsMap[bone.name] = {firstNodeId, node.id};
|
m_boneNameToIdsMap[bone.name] = {firstNodeId, node.id};
|
||||||
|
@ -266,6 +270,8 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
newAddedEdgeIds.insert(edge.id);
|
newAddedEdgeIds.insert(edge.id);
|
||||||
nodeMap[firstNodeId].edgeIds.push_back(edge.id);
|
nodeMap[firstNodeId].edgeIds.push_back(edge.id);
|
||||||
nodeMap[node.id].edgeIds.push_back(edge.id);
|
nodeMap[node.id].edgeIds.push_back(edge.id);
|
||||||
|
|
||||||
|
qDebug() << "Add pair:" << bone.name << "->" << "~";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (const auto &child: bone.children) {
|
for (const auto &child: bone.children) {
|
||||||
|
@ -273,6 +279,11 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto findRootNodeId = boneIndexToHeadNodeIdMap.find(0);
|
||||||
|
if (findRootNodeId != boneIndexToHeadNodeIdMap.end()) {
|
||||||
|
nodeMap[findRootNodeId->second].setRadius(m_nodeRadius * 2);
|
||||||
|
}
|
||||||
|
|
||||||
m_groundPartId = QUuid::createUuid();
|
m_groundPartId = QUuid::createUuid();
|
||||||
auto &groundPart = partMap[m_groundPartId];
|
auto &groundPart = partMap[m_groundPartId];
|
||||||
groundPart.id = m_groundPartId;
|
groundPart.id = m_groundPartId;
|
||||||
|
@ -401,11 +412,42 @@ void PoseDocument::toParameters(std::map<QString, std::map<QString, QString>> &p
|
||||||
auto findSecondNode = nodeMap.find(boneNodeIdPair.second);
|
auto findSecondNode = nodeMap.find(boneNodeIdPair.second);
|
||||||
if (findSecondNode == nodeMap.end())
|
if (findSecondNode == nodeMap.end())
|
||||||
continue;
|
continue;
|
||||||
boneParameter["fromX"] = QString::number(findFirstNode->second.x - 0.5);
|
boneParameter["fromX"] = QString::number(toOutcomeX(findFirstNode->second.x));
|
||||||
boneParameter["fromY"] = QString::number(0.5 - findFirstNode->second.y);
|
boneParameter["fromY"] = QString::number(toOutcomeY(findFirstNode->second.y));
|
||||||
boneParameter["fromZ"] = QString::number(1.0 - findFirstNode->second.z);
|
boneParameter["fromZ"] = QString::number(toOutcomeZ(findFirstNode->second.z));
|
||||||
boneParameter["toX"] = QString::number(findSecondNode->second.x - 0.5);
|
boneParameter["toX"] = QString::number(toOutcomeX(findSecondNode->second.x));
|
||||||
boneParameter["toY"] = QString::number(0.5 - findSecondNode->second.y);
|
boneParameter["toY"] = QString::number(toOutcomeY(findSecondNode->second.y));
|
||||||
boneParameter["toZ"] = QString::number(1.0 - findSecondNode->second.z);
|
boneParameter["toZ"] = QString::number(toOutcomeZ(findSecondNode->second.z));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float PoseDocument::fromOutcomeX(float x)
|
||||||
|
{
|
||||||
|
return x + 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
float PoseDocument::toOutcomeX(float x)
|
||||||
|
{
|
||||||
|
return x - 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
float PoseDocument::fromOutcomeY(float y)
|
||||||
|
{
|
||||||
|
return -y + 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
float PoseDocument::toOutcomeY(float y)
|
||||||
|
{
|
||||||
|
return 0.5 - y;
|
||||||
|
}
|
||||||
|
|
||||||
|
float PoseDocument::fromOutcomeZ(float z)
|
||||||
|
{
|
||||||
|
return -z + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float PoseDocument::toOutcomeZ(float z)
|
||||||
|
{
|
||||||
|
return 1.0 - z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ public slots:
|
||||||
public:
|
public:
|
||||||
static const float m_nodeRadius;
|
static const float m_nodeRadius;
|
||||||
static const float m_groundPlaneHalfThickness;
|
static const float m_groundPlaneHalfThickness;
|
||||||
|
static const bool m_hideRootAndVirtual;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<QString, std::pair<QUuid, QUuid>> m_boneNameToIdsMap;
|
std::map<QString, std::pair<QUuid, QUuid>> m_boneNameToIdsMap;
|
||||||
|
@ -61,6 +62,13 @@ private:
|
||||||
std::deque<PoseHistoryItem> m_undoItems;
|
std::deque<PoseHistoryItem> m_undoItems;
|
||||||
std::deque<PoseHistoryItem> m_redoItems;
|
std::deque<PoseHistoryItem> m_redoItems;
|
||||||
std::vector<RiggerBone> m_riggerBones;
|
std::vector<RiggerBone> m_riggerBones;
|
||||||
|
|
||||||
|
static float fromOutcomeX(float x);
|
||||||
|
static float toOutcomeX(float x);
|
||||||
|
static float fromOutcomeY(float y);
|
||||||
|
static float toOutcomeY(float y);
|
||||||
|
static float fromOutcomeZ(float z);
|
||||||
|
static float toOutcomeZ(float z);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -38,9 +38,35 @@ bool Rigger::calculateBodyTriangles(std::set<MeshSplitterTriangle> &bodyTriangle
|
||||||
}
|
}
|
||||||
if (bodyTriangles.empty()) {
|
if (bodyTriangles.empty()) {
|
||||||
m_messages.push_back(std::make_pair(QtCriticalMsg,
|
m_messages.push_back(std::make_pair(QtCriticalMsg,
|
||||||
tr("Calculate body from marks failed")));
|
tr("Calculate body from marks failed, try to move the center anchor around")));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the calculated body is neighboring with all the cutoff makers
|
||||||
|
std::set<int> bodyVertices;
|
||||||
|
addTrianglesToVertices(bodyTriangles, bodyVertices);
|
||||||
|
for (const auto &marksMapIt: m_marksMap) {
|
||||||
|
if (isCutOffSplitter(marksMapIt.first.first)) {
|
||||||
|
for (const auto index: marksMapIt.second) {
|
||||||
|
auto &mark = m_marks[index];
|
||||||
|
std::set<int> markSplitterVertices;
|
||||||
|
addTrianglesToVertices(mark.markTriangles, markSplitterVertices);
|
||||||
|
bool neighboring = false;
|
||||||
|
for (const auto &index: markSplitterVertices) {
|
||||||
|
if (bodyVertices.find(index) != bodyVertices.end()) {
|
||||||
|
neighboring = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!neighboring) {
|
||||||
|
m_messages.push_back(std::make_pair(QtCriticalMsg,
|
||||||
|
tr("The center anchor is not located in the center of the model")));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +84,7 @@ bool Rigger::addMarkGroup(BoneMark boneMark, SkeletonSide boneSide, QVector3D bo
|
||||||
mark.markTriangles = markTriangles;
|
mark.markTriangles = markTriangles;
|
||||||
|
|
||||||
if (isCutOffSplitter(mark.boneMark)) {
|
if (isCutOffSplitter(mark.boneMark)) {
|
||||||
if (!mark.split(m_inputTriangles, m_maxCutOffSplitterExpandRound)) {
|
if (!mark.split(m_verticesPositions, m_inputTriangles, m_maxCutOffSplitterExpandRound)) {
|
||||||
m_cutoffErrorItems.push_back(SkeletonSideToDispName(mark.boneSide) + " " + BoneMarkToDispName(mark.boneMark));
|
m_cutoffErrorItems.push_back(SkeletonSideToDispName(mark.boneSide) + " " + BoneMarkToDispName(mark.boneMark));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
34
src/rigger.h
34
src/rigger.h
|
@ -22,31 +22,49 @@ public:
|
||||||
std::set<MeshSplitterTriangle> markTriangles;
|
std::set<MeshSplitterTriangle> markTriangles;
|
||||||
const std::set<MeshSplitterTriangle> &bigGroup() const
|
const std::set<MeshSplitterTriangle> &bigGroup() const
|
||||||
{
|
{
|
||||||
return m_firstGroup.size() > m_secondGroup.size() ?
|
return m_isFirstBiggerThenSecond ? m_firstGroup : m_secondGroup;
|
||||||
m_firstGroup :
|
|
||||||
m_secondGroup;
|
|
||||||
}
|
}
|
||||||
const std::set<MeshSplitterTriangle> &smallGroup() const
|
const std::set<MeshSplitterTriangle> &smallGroup() const
|
||||||
{
|
{
|
||||||
return m_firstGroup.size() > m_secondGroup.size() ?
|
return m_isFirstBiggerThenSecond ? m_secondGroup : m_firstGroup;
|
||||||
m_secondGroup :
|
|
||||||
m_firstGroup;
|
|
||||||
}
|
}
|
||||||
bool split(const std::set<MeshSplitterTriangle> &input, int expandRound=0)
|
bool split(const std::vector<QVector3D> &verticesPositions, const std::set<MeshSplitterTriangle> &input, int expandRound=0)
|
||||||
{
|
{
|
||||||
int totalRound = 1 + expandRound;
|
int totalRound = 1 + expandRound;
|
||||||
for (int round = 0; round < totalRound; ++round) {
|
for (int round = 0; round < totalRound; ++round) {
|
||||||
m_firstGroup.clear();
|
m_firstGroup.clear();
|
||||||
m_secondGroup.clear();
|
m_secondGroup.clear();
|
||||||
bool splitResult = MeshSplitter::split(input, markTriangles, m_firstGroup, m_secondGroup, round > 0);
|
bool splitResult = MeshSplitter::split(input, markTriangles, m_firstGroup, m_secondGroup, round > 0);
|
||||||
if (splitResult)
|
if (splitResult) {
|
||||||
|
sortByDistanceFromOrigin(verticesPositions);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
std::set<MeshSplitterTriangle> m_firstGroup;
|
std::set<MeshSplitterTriangle> m_firstGroup;
|
||||||
std::set<MeshSplitterTriangle> m_secondGroup;
|
std::set<MeshSplitterTriangle> m_secondGroup;
|
||||||
|
bool m_isFirstBiggerThenSecond = false;
|
||||||
|
|
||||||
|
float minDistance2FromOrigin(const std::vector<QVector3D> &verticesPositions, const std::set<MeshSplitterTriangle> &triangles)
|
||||||
|
{
|
||||||
|
float minDistance2 = std::numeric_limits<float>::max();
|
||||||
|
for (const auto &triangle: triangles) {
|
||||||
|
for (size_t i = 0; i < 3; ++i) {
|
||||||
|
float distance2 = verticesPositions[triangle.indicies[i]].lengthSquared();
|
||||||
|
if (distance2 < minDistance2)
|
||||||
|
minDistance2 = distance2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return minDistance2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sortByDistanceFromOrigin(const std::vector<QVector3D> &verticesPositions)
|
||||||
|
{
|
||||||
|
m_isFirstBiggerThenSecond = minDistance2FromOrigin(verticesPositions, m_firstGroup) <
|
||||||
|
minDistance2FromOrigin(verticesPositions, m_secondGroup);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class RiggerBone
|
class RiggerBone
|
||||||
|
|
Loading…
Reference in New Issue