Fix pose setting: Height above ground level.
Root bone will have heightAboveGroundLevel parameter to indicate the distance between ground and foot. It's a relative value, comparing with the distance of the first spine head position and foot.master
parent
205a9f512f
commit
9231ce9162
|
@ -9,27 +9,8 @@ AnimalPoser::AnimalPoser(const std::vector<RiggerBone> &bones) :
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimalPoser::resolveTranslation()
|
void AnimalPoser::resolveTransform()
|
||||||
{
|
{
|
||||||
for (const auto &item: parameters()) {
|
|
||||||
int boneIndex = findBoneIndex(item.first);
|
|
||||||
if (-1 == boneIndex) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto findTranslateXResult = item.second.find("translateX");
|
|
||||||
auto findTranslateYResult = item.second.find("translateY");
|
|
||||||
auto findTranslateZResult = item.second.find("translateZ");
|
|
||||||
if (findTranslateXResult != item.second.end() ||
|
|
||||||
findTranslateYResult != item.second.end() ||
|
|
||||||
findTranslateZResult != item.second.end()) {
|
|
||||||
float x = valueOfKeyInMapOrEmpty(item.second, "translateX").toFloat();
|
|
||||||
float y = valueOfKeyInMapOrEmpty(item.second, "translateY").toFloat();
|
|
||||||
float z = valueOfKeyInMapOrEmpty(item.second, "translateZ").toFloat();
|
|
||||||
QVector3D translation = {x, y, z};
|
|
||||||
m_jointNodeTree.addTranslation(boneIndex, translation);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QRegularExpression reJoints("^([a-zA-Z]+\\d*)_Joint\\d+$");
|
QRegularExpression reJoints("^([a-zA-Z]+\\d*)_Joint\\d+$");
|
||||||
QRegularExpression reSpine("^([a-zA-Z]+)\\d*$");
|
QRegularExpression reSpine("^([a-zA-Z]+)\\d*$");
|
||||||
std::map<QString, std::vector<QString>> chains;
|
std::map<QString, std::vector<QString>> chains;
|
||||||
|
@ -56,12 +37,63 @@ void AnimalPoser::resolveTranslation()
|
||||||
std::sort(chain.second.begin(), chain.second.end(), [](const QString &first, const QString &second) {
|
std::sort(chain.second.begin(), chain.second.end(), [](const QString &first, const QString &second) {
|
||||||
return first < second;
|
return first < second;
|
||||||
});
|
});
|
||||||
//qDebug() << "Chain:";
|
|
||||||
//for (const auto &chainJoint: chain.second) {
|
|
||||||
// qDebug() << chainJoint;
|
|
||||||
//}
|
|
||||||
resolveChainRotation(chain.second);
|
resolveChainRotation(chain.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int firstSpineBoneIndex = findBoneIndex(Rigger::firstSpineBoneName);
|
||||||
|
if (-1 == firstSpineBoneIndex) {
|
||||||
|
qDebug() << "Find first spine bone failed:" << Rigger::firstSpineBoneName;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &firstSpineBone = bones()[firstSpineBoneIndex];
|
||||||
|
|
||||||
|
float mostBottomYBeforeTransform = std::numeric_limits<float>::max();
|
||||||
|
for (const auto &bone: bones()) {
|
||||||
|
if (bone.tailPosition.y() < mostBottomYBeforeTransform)
|
||||||
|
mostBottomYBeforeTransform = bone.tailPosition.y();
|
||||||
|
}
|
||||||
|
|
||||||
|
float legHeightBeforeTransform = std::abs(mostBottomYBeforeTransform - firstSpineBone.headPosition.y());
|
||||||
|
auto transformedJointNodeTree = m_jointNodeTree;
|
||||||
|
transformedJointNodeTree.recalculateTransformMatrices();
|
||||||
|
float mostBottomYAfterTransform = std::numeric_limits<float>::max();
|
||||||
|
QVector3D firstSpineBonePositionAfterTransform = firstSpineBone.headPosition;
|
||||||
|
for (int i = 0; i < (int)transformedJointNodeTree.nodes().size(); ++i) {
|
||||||
|
const auto &bone = bones()[i];
|
||||||
|
const auto &jointNode = transformedJointNodeTree.nodes()[i];
|
||||||
|
QVector3D newPosition = jointNode.transformMatrix * bone.tailPosition;
|
||||||
|
if (0 == i) {
|
||||||
|
// Root bone's tail position is the first spine bone's head position
|
||||||
|
firstSpineBonePositionAfterTransform = newPosition;
|
||||||
|
}
|
||||||
|
if (newPosition.y() < mostBottomYAfterTransform)
|
||||||
|
mostBottomYAfterTransform = newPosition.y();
|
||||||
|
}
|
||||||
|
float legHeightAfterTransform = std::abs(mostBottomYAfterTransform - firstSpineBonePositionAfterTransform.y());
|
||||||
|
float translateY = legHeightAfterTransform - legHeightBeforeTransform;
|
||||||
|
|
||||||
|
//qDebug() << "Leg height changed, translateY:" << translateY << "legHeightBeforeTransform:" << legHeightBeforeTransform << "legHeightAfterTransform:" << legHeightAfterTransform << "firstSpineBonePositionAfterTransform:" << firstSpineBonePositionAfterTransform << "firstSpineBone.headPosition:" << firstSpineBone.headPosition;
|
||||||
|
|
||||||
|
const auto &findRootParameters = parameters().find(Rigger::rootBoneName);
|
||||||
|
if (findRootParameters != parameters().end()) {
|
||||||
|
auto findHeightAboveGroundLevel = findRootParameters->second.find("heightAboveGroundLevel");
|
||||||
|
if (findHeightAboveGroundLevel != findRootParameters->second.end()) {
|
||||||
|
float heightAboveGroundLevel = findHeightAboveGroundLevel->second.toFloat();
|
||||||
|
float myHeightAboveGroundLevel = heightAboveGroundLevel * legHeightAfterTransform;
|
||||||
|
translateY += myHeightAboveGroundLevel;
|
||||||
|
//qDebug() << "heightAboveGroundLevel:" << heightAboveGroundLevel << "myHeightAboveGroundLevel:" << myHeightAboveGroundLevel << "legHeightBeforeTransform:" << legHeightBeforeTransform << "applied translateY:" << translateY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!qFuzzyIsNull(translateY)) {
|
||||||
|
int rootBoneIndex = findBoneIndex(Rigger::rootBoneName);
|
||||||
|
if (-1 == rootBoneIndex) {
|
||||||
|
qDebug() << "Find root bone failed:" << Rigger::rootBoneName;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_jointNodeTree.addTranslation(rootBoneIndex, QVector3D(0, translateY, 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, QVector3D> AnimalPoser::findQVector3DFromMap(const std::map<QString, QString> &map, const QString &xName, const QString &yName, const QString &zName)
|
std::pair<bool, QVector3D> AnimalPoser::findQVector3DFromMap(const std::map<QString, QString> &map, const QString &xName, const QString &yName, const QString &zName)
|
||||||
|
@ -231,7 +263,7 @@ void AnimalPoser::resolveChainRotation(const std::vector<QString> &limbBoneNames
|
||||||
|
|
||||||
void AnimalPoser::commit()
|
void AnimalPoser::commit()
|
||||||
{
|
{
|
||||||
resolveTranslation();
|
resolveTransform();
|
||||||
|
|
||||||
Poser::commit();
|
Poser::commit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ public:
|
||||||
void commit() override;
|
void commit() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void resolveTranslation();
|
void resolveTransform();
|
||||||
void resolveChainRotation(const std::vector<QString> &limbBoneNames);
|
void resolveChainRotation(const std::vector<QString> &limbBoneNames);
|
||||||
std::pair<bool, QVector3D> findQVector3DFromMap(const std::map<QString, QString> &map, const QString &xName, const QString &yName, const QString &zName);
|
std::pair<bool, QVector3D> findQVector3DFromMap(const std::map<QString, QString> &map, const QString &xName, const QString &yName, const QString &zName);
|
||||||
std::pair<bool, std::pair<QVector3D, QVector3D>> findBonePositionsFromParameters(const std::map<QString, QString> &map);
|
std::pair<bool, std::pair<QVector3D, QVector3D>> findBonePositionsFromParameters(const std::map<QString, QString> &map);
|
||||||
|
|
|
@ -595,6 +595,8 @@ QString AnimalRigger::namingChain(const QString &baseName, SkeletonSide side, in
|
||||||
|
|
||||||
QString AnimalRigger::namingSpine(int spineOrder)
|
QString AnimalRigger::namingSpine(int spineOrder)
|
||||||
{
|
{
|
||||||
|
if (1 == spineOrder)
|
||||||
|
return Rigger::firstSpineBoneName;
|
||||||
return "Spine" + QString::number(spineOrder);
|
return "Spine" + QString::number(spineOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,10 +19,10 @@ protected:
|
||||||
BoneMark translateBoneMark(BoneMark boneMark) override;
|
BoneMark translateBoneMark(BoneMark boneMark) override;
|
||||||
private:
|
private:
|
||||||
bool collectJontsForChain(int markIndex, std::vector<int> &jointMarkIndicies);
|
bool collectJontsForChain(int markIndex, std::vector<int> &jointMarkIndicies);
|
||||||
QString namingSpine(int spineOrder);
|
static QString namingSpine(int spineOrder);
|
||||||
QString namingConnector(const QString &spineName, const QString &chainName);
|
static QString namingConnector(const QString &spineName, const QString &chainName);
|
||||||
QString namingChain(const QString &baseName, SkeletonSide side, int orderInSide, int totalInSide, int jointOrder);
|
static QString namingChain(const QString &baseName, SkeletonSide side, int orderInSide, int totalInSide, int jointOrder);
|
||||||
QString namingChainPrefix(const QString &baseName, SkeletonSide side, int orderInSide, int totalInSide);
|
static QString namingChainPrefix(const QString &baseName, SkeletonSide side, int orderInSide, int totalInSide);
|
||||||
QVector3D findExtremPointFrom(const std::set<int> &verticies, const QVector3D &from);
|
QVector3D findExtremPointFrom(const std::set<int> &verticies, const QVector3D &from);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ void JointNodeTree::reset()
|
||||||
{
|
{
|
||||||
for (auto &node: m_boneNodes) {
|
for (auto &node: m_boneNodes) {
|
||||||
node.rotation = QQuaternion();
|
node.rotation = QQuaternion();
|
||||||
|
node.translation = node.bindTranslation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +78,7 @@ JointNodeTree::JointNodeTree(const std::vector<RiggerBone> *resultRigBones)
|
||||||
} else {
|
} else {
|
||||||
node.translation = node.position;
|
node.translation = node.position;
|
||||||
}
|
}
|
||||||
|
node.bindTranslation = node.translation;
|
||||||
QMatrix4x4 translateMatrix;
|
QMatrix4x4 translateMatrix;
|
||||||
translateMatrix.translate(node.translation);
|
translateMatrix.translate(node.translation);
|
||||||
node.transformMatrix = parentTransformMatrix * translateMatrix;
|
node.transformMatrix = parentTransformMatrix * translateMatrix;
|
||||||
|
|
|
@ -10,6 +10,7 @@ struct JointNode
|
||||||
int parentIndex;
|
int parentIndex;
|
||||||
QString name;
|
QString name;
|
||||||
QVector3D position;
|
QVector3D position;
|
||||||
|
QVector3D bindTranslation;
|
||||||
QVector3D translation;
|
QVector3D translation;
|
||||||
QQuaternion rotation;
|
QQuaternion rotation;
|
||||||
QMatrix4x4 transformMatrix;
|
QMatrix4x4 transformMatrix;
|
||||||
|
|
|
@ -159,7 +159,7 @@ void PoseDocument::fromParameters(const std::vector<RiggerBone> *rigBones,
|
||||||
if (&m_riggerBones != rigBones)
|
if (&m_riggerBones != rigBones)
|
||||||
m_riggerBones = *rigBones;
|
m_riggerBones = *rigBones;
|
||||||
|
|
||||||
QVector3D rootTranslation;
|
float heightAboveGroundLevel = 0;
|
||||||
std::vector<RiggerBone> bones = *rigBones;
|
std::vector<RiggerBone> bones = *rigBones;
|
||||||
for (auto &bone: bones) {
|
for (auto &bone: bones) {
|
||||||
const auto findParameterResult = parameters.find(bone.name);
|
const auto findParameterResult = parameters.find(bone.name);
|
||||||
|
@ -205,25 +205,17 @@ void PoseDocument::fromParameters(const std::vector<RiggerBone> *rigBones,
|
||||||
if (findRoot != parameters.end()) {
|
if (findRoot != parameters.end()) {
|
||||||
const auto &map = findRoot->second;
|
const auto &map = findRoot->second;
|
||||||
{
|
{
|
||||||
auto findXResult = map.find("translateX");
|
auto findHeightAboveGroundLevel = map.find("heightAboveGroundLevel");
|
||||||
auto findYResult = map.find("translateY");
|
if (findHeightAboveGroundLevel != map.end()) {
|
||||||
auto findZResult = map.find("translateZ");
|
heightAboveGroundLevel = valueOfKeyInMapOrEmpty(map, "heightAboveGroundLevel").toFloat();
|
||||||
if (findXResult != map.end() ||
|
|
||||||
findYResult != map.end() ||
|
|
||||||
findZResult != map.end()) {
|
|
||||||
rootTranslation = {
|
|
||||||
valueOfKeyInMapOrEmpty(map, "translateX").toFloat(),
|
|
||||||
valueOfKeyInMapOrEmpty(map, "translateY").toFloat(),
|
|
||||||
valueOfKeyInMapOrEmpty(map, "translateZ").toFloat()
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRigBones(&bones, rootTranslation);
|
updateRigBones(&bones, heightAboveGroundLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const QVector3D &rootTranslation)
|
void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const float heightAboveGroundLevel)
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
|
@ -349,7 +341,10 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
auto &groundPart = partMap[m_groundPartId];
|
auto &groundPart = partMap[m_groundPartId];
|
||||||
groundPart.id = m_groundPartId;
|
groundPart.id = m_groundPartId;
|
||||||
|
|
||||||
float groundY = findGroundY() + rootTranslation.y();
|
float footBottomY = findFootBottomY();
|
||||||
|
float legHeight = findLegHeight();
|
||||||
|
float myHeightAboveGroundLevel = heightAboveGroundLevel * legHeight;
|
||||||
|
float groundNodeY = footBottomY + m_groundPlaneHalfThickness + myHeightAboveGroundLevel;
|
||||||
|
|
||||||
std::pair<QUuid, QUuid> groundNodesPair;
|
std::pair<QUuid, QUuid> groundNodesPair;
|
||||||
{
|
{
|
||||||
|
@ -358,7 +353,7 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
node.id = QUuid::createUuid();
|
node.id = QUuid::createUuid();
|
||||||
node.setRadius(m_groundPlaneHalfThickness);
|
node.setRadius(m_groundPlaneHalfThickness);
|
||||||
node.x = -100;
|
node.x = -100;
|
||||||
node.y = groundY + m_groundPlaneHalfThickness;
|
node.y = groundNodeY;
|
||||||
node.z = -100;
|
node.z = -100;
|
||||||
nodeMap[node.id] = node;
|
nodeMap[node.id] = node;
|
||||||
newAddedNodeIds.insert(node.id);
|
newAddedNodeIds.insert(node.id);
|
||||||
|
@ -371,7 +366,7 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
node.id = QUuid::createUuid();
|
node.id = QUuid::createUuid();
|
||||||
node.setRadius(m_groundPlaneHalfThickness);
|
node.setRadius(m_groundPlaneHalfThickness);
|
||||||
node.x = 100;
|
node.x = 100;
|
||||||
node.y = groundY + m_groundPlaneHalfThickness;
|
node.y = groundNodeY;
|
||||||
node.z = 100;
|
node.z = 100;
|
||||||
nodeMap[node.id] = node;
|
nodeMap[node.id] = node;
|
||||||
newAddedNodeIds.insert(node.id);
|
newAddedNodeIds.insert(node.id);
|
||||||
|
@ -432,7 +427,7 @@ void PoseDocument::setNodeOrigin(QUuid nodeId, float x, float y, float z)
|
||||||
emit parametersChanged();
|
emit parametersChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
float PoseDocument::findGroundY() const
|
float PoseDocument::findFootBottomY() const
|
||||||
{
|
{
|
||||||
auto maxY = std::numeric_limits<float>::lowest();
|
auto maxY = std::numeric_limits<float>::lowest();
|
||||||
for (const auto &nodeIt: nodeMap) {
|
for (const auto &nodeIt: nodeMap) {
|
||||||
|
@ -445,9 +440,31 @@ float PoseDocument::findGroundY() const
|
||||||
return maxY;
|
return maxY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float PoseDocument::findLegHeight() const
|
||||||
|
{
|
||||||
|
float firstSpineY = findFirstSpineY();
|
||||||
|
float footBottomY = findFootBottomY();
|
||||||
|
return std::abs(footBottomY - firstSpineY);
|
||||||
|
}
|
||||||
|
|
||||||
|
float PoseDocument::findFirstSpineY() const
|
||||||
|
{
|
||||||
|
const auto &findFirstSpine = m_boneNameToIdsMap.find(Rigger::firstSpineBoneName);
|
||||||
|
if (findFirstSpine == m_boneNameToIdsMap.end()) {
|
||||||
|
qDebug() << "Find first spine bone failed:" << Rigger::firstSpineBoneName;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const SkeletonNode *firstSpineNode = findNode(findFirstSpine->second.first);
|
||||||
|
if (nullptr == firstSpineNode) {
|
||||||
|
qDebug() << "Find first spine node failed";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return firstSpineNode->y;
|
||||||
|
}
|
||||||
|
|
||||||
void PoseDocument::toParameters(std::map<QString, std::map<QString, QString>> ¶meters, const std::set<QUuid> &limitNodeIds) const
|
void PoseDocument::toParameters(std::map<QString, std::map<QString, QString>> ¶meters, const std::set<QUuid> &limitNodeIds) const
|
||||||
{
|
{
|
||||||
float translateY = 0;
|
float heightAboveGroundLevel = 0;
|
||||||
auto findGroundEdge = edgeMap.find(m_groundEdgeId);
|
auto findGroundEdge = edgeMap.find(m_groundEdgeId);
|
||||||
if (findGroundEdge != edgeMap.end()) {
|
if (findGroundEdge != edgeMap.end()) {
|
||||||
const auto &nodeIds = findGroundEdge->second.nodeIds;
|
const auto &nodeIds = findGroundEdge->second.nodeIds;
|
||||||
|
@ -456,15 +473,19 @@ void PoseDocument::toParameters(std::map<QString, std::map<QString, QString>> &p
|
||||||
auto findSecondNode = nodeMap.find(nodeIds[1]);
|
auto findSecondNode = nodeMap.find(nodeIds[1]);
|
||||||
if (findFirstNode != nodeMap.end() && findSecondNode != nodeMap.end()) {
|
if (findFirstNode != nodeMap.end() && findSecondNode != nodeMap.end()) {
|
||||||
if (limitNodeIds.empty() || limitNodeIds.find(findFirstNode->first) != limitNodeIds.end() ||
|
if (limitNodeIds.empty() || limitNodeIds.find(findFirstNode->first) != limitNodeIds.end() ||
|
||||||
limitNodeIds.find(findSecondNode->first) != limitNodeIds.end())
|
limitNodeIds.find(findSecondNode->first) != limitNodeIds.end()) {
|
||||||
translateY = (findFirstNode->second.y + findSecondNode->second.y) / 2 -
|
float myHeightAboveGroundLevel = (findFirstNode->second.y + findSecondNode->second.y) / 2 -
|
||||||
(findGroundY() + m_groundPlaneHalfThickness);
|
(findFootBottomY() + m_groundPlaneHalfThickness);
|
||||||
|
float legHeight = findLegHeight();
|
||||||
|
if (legHeight > 0)
|
||||||
|
heightAboveGroundLevel = myHeightAboveGroundLevel / legHeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!qFuzzyIsNull(translateY)) {
|
if (!qFuzzyIsNull(heightAboveGroundLevel)) {
|
||||||
auto &boneParameter = parameters[Rigger::rootBoneName];
|
auto &boneParameter = parameters[Rigger::rootBoneName];
|
||||||
boneParameter["translateY"] = QString::number(translateY);
|
boneParameter["heightAboveGroundLevel"] = QString::number(heightAboveGroundLevel);
|
||||||
}
|
}
|
||||||
for (const auto &item: m_boneNameToIdsMap) {
|
for (const auto &item: m_boneNameToIdsMap) {
|
||||||
const auto &boneNodeIdPair = item.second;
|
const auto &boneNodeIdPair = item.second;
|
||||||
|
|
|
@ -32,7 +32,7 @@ public:
|
||||||
void copyNodes(std::set<QUuid> nodeIdSet) const override;
|
void copyNodes(std::set<QUuid> nodeIdSet) const override;
|
||||||
|
|
||||||
void updateTurnaround(const QImage &image);
|
void updateTurnaround(const QImage &image);
|
||||||
void updateRigBones(const std::vector<RiggerBone> *rigBones, const QVector3D &rootTranslation=QVector3D(0, 0, 0));
|
void updateRigBones(const std::vector<RiggerBone> *rigBones, const float heightAboveGroundLevel=0.0);
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
void toParameters(std::map<QString, std::map<QString, QString>> ¶meters, const std::set<QUuid> &limitNodeIds=std::set<QUuid>()) const;
|
void toParameters(std::map<QString, std::map<QString, QString>> ¶meters, const std::set<QUuid> &limitNodeIds=std::set<QUuid>()) const;
|
||||||
|
@ -48,7 +48,6 @@ public slots:
|
||||||
|
|
||||||
void moveNodeBy(QUuid nodeId, float x, float y, float z);
|
void moveNodeBy(QUuid nodeId, float x, float y, float z);
|
||||||
void setNodeOrigin(QUuid nodeId, float x, float y, float z);
|
void setNodeOrigin(QUuid nodeId, float x, float y, float z);
|
||||||
float findGroundY() const;
|
|
||||||
void switchChainSide(const std::set<QUuid> nodeIds);
|
void switchChainSide(const std::set<QUuid> nodeIds);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -59,6 +58,9 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString findBoneNameByNodeId(const QUuid &nodeId);
|
QString findBoneNameByNodeId(const QUuid &nodeId);
|
||||||
|
float findFootBottomY() const;
|
||||||
|
float findFirstSpineY() const;
|
||||||
|
float findLegHeight() const;
|
||||||
|
|
||||||
std::map<QString, std::pair<QUuid, QUuid>> m_boneNameToIdsMap;
|
std::map<QString, std::pair<QUuid, QUuid>> m_boneNameToIdsMap;
|
||||||
QUuid m_groundPartId;
|
QUuid m_groundPartId;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
size_t Rigger::m_maxCutOffSplitterExpandRound = 3;
|
size_t Rigger::m_maxCutOffSplitterExpandRound = 3;
|
||||||
QString Rigger::rootBoneName = "Body";
|
QString Rigger::rootBoneName = "Body";
|
||||||
|
QString Rigger::firstSpineBoneName = "Spine1";
|
||||||
|
|
||||||
Rigger::Rigger(const std::vector<QVector3D> &verticesPositions,
|
Rigger::Rigger(const std::vector<QVector3D> &verticesPositions,
|
||||||
const std::set<MeshSplitterTriangle> &inputTriangles) :
|
const std::set<MeshSplitterTriangle> &inputTriangles) :
|
||||||
|
|
|
@ -131,6 +131,7 @@ public:
|
||||||
const std::map<int, RiggerVertexWeights> &resultWeights();
|
const std::map<int, RiggerVertexWeights> &resultWeights();
|
||||||
virtual bool rig() = 0;
|
virtual bool rig() = 0;
|
||||||
static QString rootBoneName;
|
static QString rootBoneName;
|
||||||
|
static QString firstSpineBoneName;
|
||||||
protected:
|
protected:
|
||||||
virtual bool validate() = 0;
|
virtual bool validate() = 0;
|
||||||
virtual bool isCutOffSplitter(BoneMark boneMark) = 0;
|
virtual bool isCutOffSplitter(BoneMark boneMark) = 0;
|
||||||
|
|
Loading…
Reference in New Issue