2021-12-24 21:11:44 +08:00
|
|
|
|
//
|
2020-10-18 00:27:23 +08:00
|
|
|
|
// Created by liangshuochen on 12/06/2017.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#include "Constraint.h"
|
|
|
|
|
#include "Armature.h"
|
|
|
|
|
#include "Bone.h"
|
|
|
|
|
|
|
|
|
|
DRAGONBONES_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
|
|
Matrix Constraint::_helpMatrix;
|
|
|
|
|
Transform Constraint::_helpTransform;
|
|
|
|
|
Point Constraint::_helpPoint;
|
|
|
|
|
|
|
|
|
|
void Constraint::_onClear()
|
|
|
|
|
{
|
|
|
|
|
_constraintData = nullptr;
|
2021-12-25 10:04:45 +08:00
|
|
|
|
_armature = nullptr;
|
|
|
|
|
_target = nullptr;
|
|
|
|
|
_root = nullptr;
|
|
|
|
|
_bone = nullptr;
|
2020-10-18 00:27:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IKConstraint::_onClear()
|
|
|
|
|
{
|
|
|
|
|
Constraint::_onClear();
|
|
|
|
|
|
|
|
|
|
_scaleEnabled = false;
|
|
|
|
|
_bendPositive = false;
|
2021-12-25 10:04:45 +08:00
|
|
|
|
_weight = 1.0f;
|
2020-10-18 00:27:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IKConstraint::_computeA()
|
|
|
|
|
{
|
2021-12-25 10:04:45 +08:00
|
|
|
|
const auto& ikGlobal = _target->global;
|
|
|
|
|
auto& global = _root->global;
|
2020-10-18 00:27:23 +08:00
|
|
|
|
auto& globalTransformMatrix = _root->globalTransformMatrix;
|
|
|
|
|
|
|
|
|
|
auto radian = std::atan2(ikGlobal.y - global.y, ikGlobal.x - global.x);
|
|
|
|
|
if (global.scaleX < 0.0f)
|
|
|
|
|
{
|
|
|
|
|
radian += Transform::PI;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
global.rotation += Transform::normalizeRadian(radian - global.rotation) * _weight;
|
|
|
|
|
global.toMatrix(globalTransformMatrix);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IKConstraint::_computeB()
|
|
|
|
|
{
|
2021-12-25 10:04:45 +08:00
|
|
|
|
const auto boneLength = _bone->_boneData->length;
|
|
|
|
|
const auto parent = _root;
|
|
|
|
|
const auto& ikGlobal = _target->global;
|
|
|
|
|
auto& parentGlobal = parent->global;
|
|
|
|
|
auto& global = _bone->global;
|
2020-10-18 00:27:23 +08:00
|
|
|
|
auto& globalTransformMatrix = _bone->globalTransformMatrix;
|
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
|
const auto x = globalTransformMatrix.a * boneLength;
|
|
|
|
|
const auto y = globalTransformMatrix.b * boneLength;
|
|
|
|
|
const auto lLL = x * x + y * y;
|
|
|
|
|
const auto lL = sqrt(lLL);
|
|
|
|
|
auto dX = global.x - parentGlobal.x;
|
|
|
|
|
auto dY = global.y - parentGlobal.y;
|
|
|
|
|
const auto lPP = dX * dX + dY * dY;
|
|
|
|
|
const auto lP = sqrt(lPP);
|
|
|
|
|
const auto rawRadian = global.rotation;
|
2020-10-18 00:27:23 +08:00
|
|
|
|
const auto rawParentRadian = parentGlobal.rotation;
|
2021-12-25 10:04:45 +08:00
|
|
|
|
const auto rawRadianA = std::atan2(dY, dX);
|
2020-10-18 00:27:23 +08:00
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
|
dX = ikGlobal.x - parentGlobal.x;
|
|
|
|
|
dY = ikGlobal.y - parentGlobal.y;
|
2020-10-18 00:27:23 +08:00
|
|
|
|
const auto lTT = dX * dX + dY * dY;
|
2021-12-25 10:04:45 +08:00
|
|
|
|
const auto lT = sqrt(lTT);
|
2020-10-18 00:27:23 +08:00
|
|
|
|
|
|
|
|
|
auto radianA = 0.0f;
|
2021-12-25 10:04:45 +08:00
|
|
|
|
if (lL + lP <= lT || lT + lL <= lP || lT + lP <= lL)
|
2020-10-18 00:27:23 +08:00
|
|
|
|
{
|
|
|
|
|
radianA = std::atan2(ikGlobal.y - parentGlobal.y, ikGlobal.x - parentGlobal.x);
|
2021-12-25 10:04:45 +08:00
|
|
|
|
if (lL + lP <= lT)
|
|
|
|
|
{}
|
|
|
|
|
else if (lP < lL)
|
2020-10-18 00:27:23 +08:00
|
|
|
|
{
|
|
|
|
|
radianA += Transform::PI;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-25 10:04:45 +08:00
|
|
|
|
else
|
2020-10-18 00:27:23 +08:00
|
|
|
|
{
|
2021-12-25 10:04:45 +08:00
|
|
|
|
const auto h = (lPP - lLL + lTT) / (2.0f * lTT);
|
|
|
|
|
const auto r = sqrt(lPP - h * h * lTT) / lT;
|
2020-10-18 00:27:23 +08:00
|
|
|
|
const auto hX = parentGlobal.x + (dX * h);
|
|
|
|
|
const auto hY = parentGlobal.y + (dY * h);
|
|
|
|
|
const auto rX = -dY * r;
|
|
|
|
|
const auto rY = dX * r;
|
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
|
auto isPPR = false;
|
2020-10-18 00:27:23 +08:00
|
|
|
|
const auto parentParent = parent->getParent();
|
|
|
|
|
if (parentParent != nullptr)
|
|
|
|
|
{
|
|
|
|
|
auto parentParentMatrix = parentParent->globalTransformMatrix;
|
|
|
|
|
isPPR = parentParentMatrix.a * parentParentMatrix.d - parentParentMatrix.b * parentParentMatrix.c < 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
|
if (isPPR != _bendPositive)
|
2020-10-18 00:27:23 +08:00
|
|
|
|
{
|
|
|
|
|
global.x = hX - rX;
|
|
|
|
|
global.y = hY - rY;
|
|
|
|
|
}
|
2021-12-25 10:04:45 +08:00
|
|
|
|
else
|
2020-10-18 00:27:23 +08:00
|
|
|
|
{
|
|
|
|
|
global.x = hX + rX;
|
|
|
|
|
global.y = hY + rY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
radianA = std::atan2(global.y - parentGlobal.y, global.x - parentGlobal.x);
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
|
const auto dR = Transform::normalizeRadian(radianA - rawRadianA);
|
2020-10-18 00:27:23 +08:00
|
|
|
|
parentGlobal.rotation = rawParentRadian + dR * _weight;
|
|
|
|
|
parentGlobal.toMatrix(parent->globalTransformMatrix);
|
|
|
|
|
//
|
|
|
|
|
const auto currentRadianA = rawRadianA + dR * _weight;
|
2021-12-25 10:04:45 +08:00
|
|
|
|
global.x = parentGlobal.x + cos(currentRadianA) * lP;
|
|
|
|
|
global.y = parentGlobal.y + sin(currentRadianA) * lP;
|
2020-10-18 00:27:23 +08:00
|
|
|
|
//
|
|
|
|
|
auto radianB = std::atan2(ikGlobal.y - global.y, ikGlobal.x - global.x);
|
2021-12-25 10:04:45 +08:00
|
|
|
|
if (global.scaleX < 0.0f)
|
|
|
|
|
{
|
2020-10-18 00:27:23 +08:00
|
|
|
|
radianB += Transform::PI;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
|
global.rotation = parentGlobal.rotation + rawRadian - rawParentRadian +
|
|
|
|
|
Transform::normalizeRadian(radianB - dR - rawRadian) * _weight;
|
2020-10-18 00:27:23 +08:00
|
|
|
|
global.toMatrix(globalTransformMatrix);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IKConstraint::init(ConstraintData* constraintData, Armature* armature)
|
|
|
|
|
{
|
|
|
|
|
if (_constraintData != nullptr)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_constraintData = constraintData;
|
2021-12-25 10:04:45 +08:00
|
|
|
|
_armature = armature;
|
|
|
|
|
_target = _armature->getBone(_constraintData->target->name);
|
|
|
|
|
_root = _armature->getBone(_constraintData->root->name);
|
|
|
|
|
_bone = _constraintData->bone != nullptr ? _armature->getBone(_constraintData->bone->name) : nullptr;
|
2020-10-18 00:27:23 +08:00
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
const auto ikConstraintData = static_cast<IKConstraintData*>(_constraintData);
|
2021-12-25 10:04:45 +08:00
|
|
|
|
_bendPositive = ikConstraintData->bendPositive;
|
|
|
|
|
_scaleEnabled = ikConstraintData->scaleEnabled;
|
|
|
|
|
_weight = ikConstraintData->weight;
|
2020-10-18 00:27:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_root->_hasConstraint = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IKConstraint::update()
|
|
|
|
|
{
|
|
|
|
|
_root->updateByConstraint();
|
|
|
|
|
|
|
|
|
|
if (_bone != nullptr)
|
|
|
|
|
{
|
|
|
|
|
_bone->updateByConstraint();
|
|
|
|
|
_computeB();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_computeA();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IKConstraint::invalidUpdate()
|
|
|
|
|
{
|
|
|
|
|
_root->invalidUpdate();
|
|
|
|
|
|
|
|
|
|
if (_bone != nullptr)
|
|
|
|
|
{
|
|
|
|
|
_bone->invalidUpdate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DRAGONBONES_NAMESPACE_END
|