- Changed xz limit drawing to use same formulas as the limiting in the IK
module -- the previous method could be off pretty far. - Added drawing of transparent surface for it, instead of just the border. - Added "stretch IK", allowing bones not only to rotate, but also scale. The "Stretch" value below the DoF buttons is used to enabled this. - Some code tweaking: slightly simplified computation of transform for IK, renamed chain to tree, removed unused pchan->ik_mat, .. Internal IK module work: - Do damping per DoF also based on stiffness, hopefully makes it converge faster with very stiff joints. - Instead of having two joints types (translational and rotational), now all 6 DoF's can be enabled for one joint. - Added limits for translational joints.
This commit is contained in:
29
intern/iksolver/extern/IK_solver.h
vendored
29
intern/iksolver/extern/IK_solver.h
vendored
@@ -84,14 +84,13 @@ extern "C" {
|
||||
* - free all segments
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* IK_Segment defines a single segment of an IK tree.
|
||||
* - Individual segments are always defined in local coordinates.
|
||||
* - The segment is assumed to be oriented in the local
|
||||
* y-direction.
|
||||
* y-direction.
|
||||
* - start is the start of the segment relative to the end
|
||||
* of the parent segment.
|
||||
* of the parent segment.
|
||||
* - rest_basis is a column major matrix defineding the rest
|
||||
* position (w.r.t. which the limits are defined), must
|
||||
* be a pure rotation
|
||||
@@ -100,15 +99,12 @@ extern "C" {
|
||||
* - length is the length of the bone.
|
||||
*
|
||||
* - basis_change and translation_change respectively define
|
||||
* the change in rotation or translation for rotational joints
|
||||
* and translational joints. basis_change is a column major 3x3
|
||||
* matrix.
|
||||
* the change in rotation or translation. basis_change is a
|
||||
* column major 3x3 matrix.
|
||||
*
|
||||
* For rotational joints the local transformation is then defined as:
|
||||
* start*rest_basis*basis*basis_change*translate(0,length,0)
|
||||
* The local transformation is then defined as:
|
||||
* start * rest_basis * basis * basis_change * translation_change * translate(0,length,0)
|
||||
*
|
||||
* For translational joints:
|
||||
* start*rest_basis*basis*translation_change*translate(0,length,0)
|
||||
*/
|
||||
|
||||
typedef void IK_Segment;
|
||||
@@ -117,13 +113,18 @@ enum IK_SegmentFlag {
|
||||
IK_XDOF = 1,
|
||||
IK_YDOF = 2,
|
||||
IK_ZDOF = 4,
|
||||
IK_TRANSLATIONAL = 8
|
||||
IK_TRANS_XDOF = 8,
|
||||
IK_TRANS_YDOF = 16,
|
||||
IK_TRANS_ZDOF = 32
|
||||
};
|
||||
|
||||
typedef enum IK_SegmentAxis {
|
||||
IK_X,
|
||||
IK_Y,
|
||||
IK_Z
|
||||
IK_X = 0,
|
||||
IK_Y = 1,
|
||||
IK_Z = 2,
|
||||
IK_TRANS_X = 3,
|
||||
IK_TRANS_Y = 4,
|
||||
IK_TRANS_Z = 5
|
||||
} IK_SegmentAxis;
|
||||
|
||||
extern IK_Segment *IK_CreateSegment(int flag);
|
||||
|
||||
@@ -296,11 +296,16 @@ void IK_QJacobian::InvertSDLS()
|
||||
|
||||
MT_Scalar damp = (gamma < max_dtheta)? gamma/max_dtheta: 1.0;
|
||||
|
||||
for (j = 0; j < m_d_theta.size(); j++)
|
||||
for (j = 0; j < m_d_theta.size(); j++) {
|
||||
// slight hack: we do 0.80*, so that if there is some oscillation,
|
||||
// the system can still converge (for joint limits). also, it's
|
||||
// better to go a little to slow than to far
|
||||
m_d_theta[j] += 0.80*damp*m_d_theta_tmp[j];
|
||||
|
||||
MT_Scalar dofdamp = damp/m_weight[j];
|
||||
if (dofdamp > 1.0) dofdamp = 1.0;
|
||||
|
||||
m_d_theta[j] += 0.80*dofdamp*m_d_theta_tmp[j];
|
||||
}
|
||||
|
||||
if (damp < m_min_damp)
|
||||
m_min_damp = damp;
|
||||
|
||||
@@ -158,11 +158,69 @@ static MT_Vector3 MatrixToAxisAngle(const MT_Matrix3x3& R)
|
||||
return delta;
|
||||
}
|
||||
|
||||
static bool EllipseClamp(MT_Scalar& ax, MT_Scalar& az, MT_Scalar *amin, MT_Scalar *amax)
|
||||
{
|
||||
MT_Scalar xlim, zlim, x, z;
|
||||
|
||||
if (ax < 0.0) {
|
||||
x = -ax;
|
||||
xlim = -amin[0];
|
||||
}
|
||||
else {
|
||||
x = ax;
|
||||
xlim = amax[0];
|
||||
}
|
||||
|
||||
if (az < 0.0) {
|
||||
z = -az;
|
||||
zlim = -amin[1];
|
||||
}
|
||||
else {
|
||||
z = az;
|
||||
zlim = amax[1];
|
||||
}
|
||||
|
||||
if (MT_fuzzyZero(xlim) || MT_fuzzyZero(zlim)) {
|
||||
if (x <= xlim && z <= zlim)
|
||||
return false;
|
||||
|
||||
if (x > xlim)
|
||||
x = xlim;
|
||||
if (z > zlim)
|
||||
z = zlim;
|
||||
}
|
||||
else {
|
||||
MT_Scalar invx = 1.0/(xlim*xlim);
|
||||
MT_Scalar invz = 1.0/(zlim*zlim);
|
||||
|
||||
if ((x*x*invx + z*z*invz) <= 1.0)
|
||||
return false;
|
||||
|
||||
if (MT_fuzzyZero(x)) {
|
||||
x = 0.0;
|
||||
z = zlim;
|
||||
}
|
||||
else {
|
||||
MT_Scalar rico = z/x;
|
||||
MT_Scalar old_x = x;
|
||||
x = sqrt(1.0/(invx + invz*rico*rico));
|
||||
if (old_x < 0.0)
|
||||
x = -x;
|
||||
z = rico*x;
|
||||
}
|
||||
}
|
||||
|
||||
ax = (ax < 0.0)? -x: x;
|
||||
az = (az < 0.0)? -z: z;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// IK_QSegment
|
||||
|
||||
IK_QSegment::IK_QSegment(int num_DoF, bool translational)
|
||||
: m_parent(NULL), m_child(NULL), m_sibling(NULL), m_num_DoF(num_DoF),
|
||||
m_translational(translational)
|
||||
: m_parent(NULL), m_child(NULL), m_sibling(NULL), m_composite(NULL),
|
||||
m_num_DoF(num_DoF), m_translational(translational)
|
||||
{
|
||||
m_locked[0] = m_locked[1] = m_locked[2] = false;
|
||||
m_weight[0] = m_weight[1] = m_weight[2] = 1.0;
|
||||
@@ -232,6 +290,11 @@ void IK_QSegment::SetParent(IK_QSegment *parent)
|
||||
m_parent = parent;
|
||||
}
|
||||
|
||||
void IK_QSegment::SetComposite(IK_QSegment *seg)
|
||||
{
|
||||
m_composite = seg;
|
||||
}
|
||||
|
||||
void IK_QSegment::RemoveChild(IK_QSegment *child)
|
||||
{
|
||||
if (m_child == NULL)
|
||||
@@ -297,19 +360,15 @@ void IK_QSphericalSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
|
||||
lmin = sin(MT_radians(lmin)*0.5);
|
||||
lmax = sin(MT_radians(lmax)*0.5);
|
||||
|
||||
// put center of ellispe in the middle between min and max
|
||||
MT_Scalar offset = 0.5*(lmin + lmax);
|
||||
lmax = lmax - offset;
|
||||
|
||||
if (axis == 0) {
|
||||
m_min[0] = -lmax;
|
||||
m_max[0] = -lmin;
|
||||
m_limit_x = true;
|
||||
m_offset_x = offset;
|
||||
m_max_x = lmax;
|
||||
}
|
||||
else if (axis == 2) {
|
||||
m_min[1] = -lmax;
|
||||
m_max[1] = -lmin;
|
||||
m_limit_z = true;
|
||||
m_offset_z = offset;
|
||||
m_max_z = lmax;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -391,62 +450,28 @@ bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3&
|
||||
}
|
||||
|
||||
if (m_limit_x && m_limit_z) {
|
||||
/* check in ellipsoid region */
|
||||
ax = a.x() + m_offset_x;
|
||||
az = a.z() + m_offset_z;
|
||||
|
||||
MT_Scalar invX = 1.0/(m_max_x*m_max_x);
|
||||
MT_Scalar invZ = 1.0/(m_max_z*m_max_z);
|
||||
|
||||
if ((ax*ax*invX + az*az*invZ) > 1.0) {
|
||||
if (EllipseClamp(ax, az, m_min, m_max))
|
||||
clamp[0] = clamp[2] = true;
|
||||
|
||||
if (MT_fuzzyZero(ax)) {
|
||||
ax = 0.0;
|
||||
az = (az > 0)? m_max_z: -m_max_z;
|
||||
}
|
||||
else {
|
||||
MT_Scalar rico = az/ax;
|
||||
MT_Scalar old_ax = ax;
|
||||
ax = sqrt(1.0/(invX + invZ*rico*rico));
|
||||
if (old_ax < 0.0)
|
||||
ax = -ax;
|
||||
az = rico*ax;
|
||||
}
|
||||
}
|
||||
|
||||
ax = ax - m_offset_x;
|
||||
az = az - m_offset_z;
|
||||
}
|
||||
else if (m_limit_x) {
|
||||
ax = a.x() + m_offset_x;
|
||||
|
||||
if (ax < -m_max_x) {
|
||||
ax = -m_max_x;
|
||||
if (ax < m_min[0]) {
|
||||
ax = m_min[0];
|
||||
clamp[0] = true;
|
||||
}
|
||||
else if (ax > m_max_x) {
|
||||
ax = m_max_x;
|
||||
else if (ax > m_max[0]) {
|
||||
ax = m_max[0];
|
||||
clamp[0] = true;
|
||||
}
|
||||
|
||||
ax = ax - m_offset_x;
|
||||
az = a.z();
|
||||
}
|
||||
else if (m_limit_z) {
|
||||
az = a.z() + m_offset_z;
|
||||
|
||||
if (az < -m_max_z) {
|
||||
az = -m_max_z;
|
||||
if (az < m_min[1]) {
|
||||
az = m_min[1];
|
||||
clamp[2] = true;
|
||||
}
|
||||
else if (az > m_max_z) {
|
||||
az = m_max_z;
|
||||
else if (az > m_max[1]) {
|
||||
az = m_max[1];
|
||||
clamp[2] = true;
|
||||
}
|
||||
|
||||
ax = a.x();
|
||||
az = az - m_offset_z;
|
||||
}
|
||||
|
||||
if (clamp[0] == false && clamp[1] == false && clamp[2] == false) {
|
||||
@@ -645,62 +670,31 @@ bool IK_QSwingSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& del
|
||||
clamp[0] = clamp[1] = false;
|
||||
|
||||
if (m_limit_x && m_limit_z) {
|
||||
/* check in ellipsoid region */
|
||||
ax = a.x() + m_offset_x;
|
||||
az = a.z() + m_offset_z;
|
||||
ax = a.x();
|
||||
az = a.z();
|
||||
|
||||
MT_Scalar invX = 1.0/(m_max_x*m_max_x);
|
||||
MT_Scalar invZ = 1.0/(m_max_z*m_max_z);
|
||||
|
||||
if ((ax*ax*invX + az*az*invZ) > 1.0) {
|
||||
if (EllipseClamp(ax, az, m_min, m_max))
|
||||
clamp[0] = clamp[1] = true;
|
||||
|
||||
if (MT_fuzzyZero(ax)) {
|
||||
ax = 0.0;
|
||||
az = (az > 0)? m_max_z: -m_max_z;
|
||||
}
|
||||
else {
|
||||
MT_Scalar rico = az/ax;
|
||||
MT_Scalar old_ax = ax;
|
||||
ax = sqrt(1.0/(invX + invZ*rico*rico));
|
||||
if (old_ax < 0.0)
|
||||
ax = -ax;
|
||||
az = rico*ax;
|
||||
}
|
||||
}
|
||||
|
||||
ax = ax - m_offset_x;
|
||||
az = az - m_offset_z;
|
||||
}
|
||||
else if (m_limit_x) {
|
||||
ax = a.x() + m_offset_x;
|
||||
|
||||
if (ax < -m_max_x) {
|
||||
ax = -m_max_x;
|
||||
if (ax < m_min[0]) {
|
||||
ax = m_min[0];
|
||||
clamp[0] = true;
|
||||
}
|
||||
else if (ax > m_max_x) {
|
||||
ax = m_max_x;
|
||||
else if (ax > m_max[0]) {
|
||||
ax = m_max[0];
|
||||
clamp[0] = true;
|
||||
}
|
||||
|
||||
ax = ax - m_offset_x;
|
||||
az = a.z();
|
||||
}
|
||||
else if (m_limit_z) {
|
||||
az = a.z() + m_offset_z;
|
||||
|
||||
if (az < -m_max_z) {
|
||||
az = -m_max_z;
|
||||
if (az < m_min[1]) {
|
||||
az = m_min[1];
|
||||
clamp[1] = true;
|
||||
}
|
||||
else if (az > m_max_z) {
|
||||
az = m_max_z;
|
||||
else if (az > m_max[1]) {
|
||||
az = m_max[1];
|
||||
clamp[1] = true;
|
||||
}
|
||||
|
||||
ax = a.x();
|
||||
az = az - m_offset_z;
|
||||
}
|
||||
|
||||
if (clamp[0] == false && clamp[1] == false)
|
||||
@@ -740,14 +734,20 @@ void IK_QSwingSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
|
||||
|
||||
// put center of ellispe in the middle between min and max
|
||||
MT_Scalar offset = 0.5*(lmin + lmax);
|
||||
lmax = lmax - offset;
|
||||
//lmax = lmax - offset;
|
||||
|
||||
if (axis == 0) {
|
||||
m_min[0] = -lmax;
|
||||
m_max[0] = -lmin;
|
||||
|
||||
m_limit_x = true;
|
||||
m_offset_x = offset;
|
||||
m_max_x = lmax;
|
||||
}
|
||||
else if (axis == 2) {
|
||||
m_min[1] = -lmax;
|
||||
m_max[1] = -lmin;
|
||||
|
||||
m_limit_z = true;
|
||||
m_offset_z = offset;
|
||||
m_max_z = lmax;
|
||||
@@ -907,6 +907,8 @@ IK_QTranslateSegment::IK_QTranslateSegment(int axis1)
|
||||
m_axis_enabled[axis1] = true;
|
||||
|
||||
m_axis[0] = axis1;
|
||||
|
||||
m_limit[0] = m_limit[1] = m_limit[2] = false;
|
||||
}
|
||||
|
||||
IK_QTranslateSegment::IK_QTranslateSegment(int axis1, int axis2)
|
||||
@@ -918,6 +920,8 @@ IK_QTranslateSegment::IK_QTranslateSegment(int axis1, int axis2)
|
||||
|
||||
m_axis[0] = axis1;
|
||||
m_axis[1] = axis2;
|
||||
|
||||
m_limit[0] = m_limit[1] = m_limit[2] = false;
|
||||
}
|
||||
|
||||
IK_QTranslateSegment::IK_QTranslateSegment()
|
||||
@@ -928,6 +932,8 @@ IK_QTranslateSegment::IK_QTranslateSegment()
|
||||
m_axis[0] = 0;
|
||||
m_axis[1] = 1;
|
||||
m_axis[2] = 2;
|
||||
|
||||
m_limit[0] = m_limit[1] = m_limit[2] = false;
|
||||
}
|
||||
|
||||
MT_Vector3 IK_QTranslateSegment::Axis(int dof) const
|
||||
@@ -935,18 +941,42 @@ MT_Vector3 IK_QTranslateSegment::Axis(int dof) const
|
||||
return m_global_transform.getBasis().getColumn(m_axis[dof]);
|
||||
}
|
||||
|
||||
bool IK_QTranslateSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3&, bool*)
|
||||
bool IK_QTranslateSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp)
|
||||
{
|
||||
int dof_id = m_DoF_id;
|
||||
int dof_id = m_DoF_id, dof = 0, i, clamped = false;
|
||||
|
||||
MT_Vector3 dx;
|
||||
dx.x() = (m_axis_enabled[0])? jacobian.AngleUpdate(dof_id++): 0.0;
|
||||
dx.y() = (m_axis_enabled[1])? jacobian.AngleUpdate(dof_id++): 0.0;
|
||||
dx.z() = (m_axis_enabled[2])? jacobian.AngleUpdate(dof_id++): 0.0;
|
||||
MT_Vector3 dx(0.0, 0.0, 0.0);
|
||||
|
||||
m_new_translation = m_translation + dx;
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (!m_axis_enabled[i]) {
|
||||
m_new_translation[i] = m_translation[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
clamp[dof] = false;
|
||||
|
||||
if (!m_locked[dof]) {
|
||||
m_new_translation[i] = m_translation[i] + jacobian.AngleUpdate(dof_id);
|
||||
|
||||
if (m_limit[i]) {
|
||||
if (m_new_translation[i] > m_max[i]) {
|
||||
delta[dof] = m_max[i] - m_translation[i];
|
||||
m_new_translation[i] = m_max[i];
|
||||
clamped = clamp[dof] = true;
|
||||
}
|
||||
else if (m_new_translation[i] < m_min[i]) {
|
||||
delta[dof] = m_min[i] - m_translation[i];
|
||||
m_new_translation[i] = m_min[i];
|
||||
clamped = clamp[dof] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dof_id++;
|
||||
dof++;
|
||||
}
|
||||
|
||||
return clamped;
|
||||
}
|
||||
|
||||
void IK_QTranslateSegment::UpdateAngleApply()
|
||||
@@ -954,8 +984,28 @@ void IK_QTranslateSegment::UpdateAngleApply()
|
||||
m_translation = m_new_translation;
|
||||
}
|
||||
|
||||
void IK_QTranslateSegment::SetWeight(int axis, MT_Scalar weight)
|
||||
void IK_QTranslateSegment::Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta)
|
||||
{
|
||||
m_weight[axis] = weight;
|
||||
m_locked[dof] = true;
|
||||
jacobian.Lock(m_DoF_id+dof, delta[dof]);
|
||||
}
|
||||
|
||||
void IK_QTranslateSegment::SetWeight(int axis, MT_Scalar weight)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < m_num_DoF; i++)
|
||||
if (m_axis[i] == axis)
|
||||
m_weight[i] = weight;
|
||||
}
|
||||
|
||||
void IK_QTranslateSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
|
||||
{
|
||||
if (lmax < lmin)
|
||||
return;
|
||||
|
||||
m_min[axis]= lmin;
|
||||
m_max[axis]= lmax;
|
||||
m_limit[axis]= true;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,12 @@ public:
|
||||
IK_QSegment *Parent() const
|
||||
{ return m_parent; }
|
||||
|
||||
// for combining two joints into one from the interface
|
||||
void SetComposite(IK_QSegment *seg);
|
||||
|
||||
IK_QSegment *Composite() const
|
||||
{ return m_composite; }
|
||||
|
||||
// number of degrees of freedom
|
||||
int NumberOfDoF() const
|
||||
{ return m_num_DoF; }
|
||||
@@ -171,6 +177,7 @@ protected:
|
||||
IK_QSegment *m_parent;
|
||||
IK_QSegment *m_child;
|
||||
IK_QSegment *m_sibling;
|
||||
IK_QSegment *m_composite;
|
||||
|
||||
// full transform =
|
||||
// start * rest_basis * basis * translation
|
||||
@@ -217,6 +224,7 @@ public:
|
||||
private:
|
||||
MT_Matrix3x3 m_new_basis;
|
||||
bool m_limit_x, m_limit_y, m_limit_z;
|
||||
MT_Scalar m_min[2], m_max[2];
|
||||
MT_Scalar m_min_y, m_max_y, m_max_x, m_max_z, m_offset_x, m_offset_z;
|
||||
MT_Scalar m_locked_ax, m_locked_ay, m_locked_az;
|
||||
};
|
||||
@@ -252,7 +260,7 @@ public:
|
||||
private:
|
||||
int m_axis;
|
||||
MT_Scalar m_angle, m_new_angle;
|
||||
MT_Scalar m_limit;
|
||||
bool m_limit;
|
||||
MT_Scalar m_min, m_max;
|
||||
};
|
||||
|
||||
@@ -275,6 +283,7 @@ public:
|
||||
private:
|
||||
MT_Matrix3x3 m_new_basis;
|
||||
bool m_limit_x, m_limit_z;
|
||||
MT_Scalar m_min[2], m_max[2];
|
||||
MT_Scalar m_max_x, m_max_z, m_offset_x, m_offset_z;
|
||||
};
|
||||
|
||||
@@ -308,7 +317,7 @@ private:
|
||||
class IK_QTranslateSegment : public IK_QSegment
|
||||
{
|
||||
public:
|
||||
// Revolute, 2DOF or 3DOF translational segments
|
||||
// 1DOF, 2DOF or 3DOF translational segments
|
||||
IK_QTranslateSegment(int axis1);
|
||||
IK_QTranslateSegment(int axis1, int axis2);
|
||||
IK_QTranslateSegment();
|
||||
@@ -316,15 +325,17 @@ public:
|
||||
MT_Vector3 Axis(int dof) const;
|
||||
|
||||
bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp);
|
||||
void Lock(int, IK_QJacobian&, MT_Vector3&) {};
|
||||
void Lock(int, IK_QJacobian&, MT_Vector3&);
|
||||
void UpdateAngleApply();
|
||||
|
||||
void SetWeight(int axis, MT_Scalar weight);
|
||||
void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax);
|
||||
|
||||
private:
|
||||
int m_axis[3];
|
||||
bool m_axis_enabled[3];
|
||||
bool m_axis_enabled[3], m_limit[3];
|
||||
MT_Vector3 m_new_translation;
|
||||
MT_Scalar m_min[3], m_max[3];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -82,7 +82,6 @@ void IK_QPositionTask::ComputeJacobian(IK_QJacobian& jacobian)
|
||||
|
||||
jacobian.SetBetas(m_id, m_size, m_weight*d_pos);
|
||||
|
||||
|
||||
// compute derivatives
|
||||
int i;
|
||||
const IK_QSegment *seg;
|
||||
@@ -92,7 +91,7 @@ void IK_QPositionTask::ComputeJacobian(IK_QJacobian& jacobian)
|
||||
|
||||
for (i = 0; i < seg->NumberOfDoF(); i++) {
|
||||
MT_Vector3 axis = seg->Axis(i)*m_weight;
|
||||
|
||||
|
||||
if (seg->Translational())
|
||||
jacobian.SetDerivatives(m_id, seg->DoFId()+i, axis);
|
||||
else {
|
||||
|
||||
@@ -45,7 +45,7 @@ typedef struct {
|
||||
std::list<IK_QTask*> tasks;
|
||||
} IK_QSolver;
|
||||
|
||||
IK_Segment *IK_CreateSegment(int flag)
|
||||
IK_QSegment *CreateSegment(int flag, bool translate)
|
||||
{
|
||||
int ndof = 0;
|
||||
ndof += (flag & IK_XDOF)? 1: 0;
|
||||
@@ -55,7 +55,7 @@ IK_Segment *IK_CreateSegment(int flag)
|
||||
IK_QSegment *seg;
|
||||
|
||||
if (ndof == 0)
|
||||
seg = new IK_QNullSegment();
|
||||
return NULL;
|
||||
else if (ndof == 1) {
|
||||
int axis;
|
||||
|
||||
@@ -63,7 +63,7 @@ IK_Segment *IK_CreateSegment(int flag)
|
||||
else if (flag & IK_YDOF) axis = 1;
|
||||
else axis = 2;
|
||||
|
||||
if (flag & IK_TRANSLATIONAL)
|
||||
if (translate)
|
||||
seg = new IK_QTranslateSegment(axis);
|
||||
else
|
||||
seg = new IK_QRevoluteSegment(axis);
|
||||
@@ -80,7 +80,7 @@ IK_Segment *IK_CreateSegment(int flag)
|
||||
axis2 = 2;
|
||||
}
|
||||
|
||||
if (flag & IK_TRANSLATIONAL)
|
||||
if (translate)
|
||||
seg = new IK_QTranslateSegment(axis1, axis2);
|
||||
else {
|
||||
if (axis1 + axis2 == 2)
|
||||
@@ -90,27 +90,58 @@ IK_Segment *IK_CreateSegment(int flag)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (flag & IK_TRANSLATIONAL)
|
||||
if (translate)
|
||||
seg = new IK_QTranslateSegment();
|
||||
else
|
||||
seg = new IK_QSphericalSegment();
|
||||
}
|
||||
|
||||
return (IK_Segment*)seg;
|
||||
return seg;
|
||||
}
|
||||
|
||||
IK_Segment *IK_CreateSegment(int flag)
|
||||
{
|
||||
IK_QSegment *rot = CreateSegment(flag, false);
|
||||
IK_QSegment *trans = CreateSegment(flag >> 3, true);
|
||||
|
||||
IK_QSegment *seg;
|
||||
|
||||
if (rot == NULL && trans == NULL)
|
||||
seg = new IK_QNullSegment();
|
||||
else if (rot == NULL)
|
||||
seg = trans;
|
||||
else {
|
||||
seg = rot;
|
||||
|
||||
// make it seem from the interface as if the rotation and translation
|
||||
// segment are one
|
||||
if (trans) {
|
||||
seg->SetComposite(trans);
|
||||
trans->SetParent(seg);
|
||||
}
|
||||
}
|
||||
|
||||
return seg;
|
||||
}
|
||||
|
||||
void IK_FreeSegment(IK_Segment *seg)
|
||||
{
|
||||
IK_QSegment *qseg = (IK_QSegment*)seg;
|
||||
|
||||
if (qseg->Composite())
|
||||
delete qseg->Composite();
|
||||
delete qseg;
|
||||
}
|
||||
|
||||
void IK_SetParent(IK_Segment *seg, IK_Segment *parent)
|
||||
{
|
||||
IK_QSegment *qseg = (IK_QSegment*)seg;
|
||||
IK_QSegment *qparent = (IK_QSegment*)parent;
|
||||
|
||||
qseg->SetParent((IK_QSegment*)parent);
|
||||
if (qparent && qparent->Composite())
|
||||
qseg->SetParent(qparent->Composite());
|
||||
else
|
||||
qseg->SetParent(qparent);
|
||||
}
|
||||
|
||||
void IK_SetTransform(IK_Segment *seg, float start[3], float rest[][3], float basis[][3], float length)
|
||||
@@ -127,19 +158,35 @@ void IK_SetTransform(IK_Segment *seg, float start[3], float rest[][3], float bas
|
||||
rest[0][2], rest[1][2], rest[2][2]);
|
||||
MT_Scalar mlength(length);
|
||||
|
||||
qseg->SetTransform(mstart, mrest, mbasis, mlength);
|
||||
if (qseg->Composite()) {
|
||||
MT_Vector3 cstart(0, 0, 0);
|
||||
MT_Matrix3x3 cbasis;
|
||||
cbasis.setIdentity();
|
||||
|
||||
qseg->SetTransform(mstart, mrest, mbasis, 0.0);
|
||||
qseg->Composite()->SetTransform(cstart, cbasis, cbasis, mlength);
|
||||
}
|
||||
else
|
||||
qseg->SetTransform(mstart, mrest, mbasis, mlength);
|
||||
}
|
||||
|
||||
void IK_SetLimit(IK_Segment *seg, IK_SegmentAxis axis, float lmin, float lmax)
|
||||
{
|
||||
IK_QSegment *qseg = (IK_QSegment*)seg;
|
||||
|
||||
if (axis == IK_X)
|
||||
qseg->SetLimit(0, lmin, lmax);
|
||||
else if (axis == IK_Y)
|
||||
qseg->SetLimit(1, lmin, lmax);
|
||||
else if (axis == IK_Z)
|
||||
qseg->SetLimit(2, lmin, lmax);
|
||||
if (axis >= IK_TRANS_X) {
|
||||
if(!qseg->Translational())
|
||||
if(qseg->Composite() && qseg->Composite()->Translational())
|
||||
qseg = qseg->Composite();
|
||||
else
|
||||
return;
|
||||
|
||||
if(axis == IK_TRANS_X) axis = IK_X;
|
||||
else if(axis == IK_TRANS_Y) axis = IK_Y;
|
||||
else axis = IK_Z;
|
||||
}
|
||||
|
||||
qseg->SetLimit(axis, lmin, lmax);
|
||||
}
|
||||
|
||||
void IK_SetStiffness(IK_Segment *seg, IK_SegmentAxis axis, float stiffness)
|
||||
@@ -153,12 +200,20 @@ void IK_SetStiffness(IK_Segment *seg, IK_SegmentAxis axis, float stiffness)
|
||||
IK_QSegment *qseg = (IK_QSegment*)seg;
|
||||
MT_Scalar weight = 1.0-stiffness;
|
||||
|
||||
if (axis == IK_X)
|
||||
qseg->SetWeight(0, weight);
|
||||
else if (axis == IK_Y)
|
||||
qseg->SetWeight(1, weight);
|
||||
else if (axis == IK_Z)
|
||||
qseg->SetWeight(2, weight);
|
||||
|
||||
if (axis >= IK_TRANS_X) {
|
||||
if(!qseg->Translational())
|
||||
if(qseg->Composite() && qseg->Composite()->Translational())
|
||||
qseg = qseg->Composite();
|
||||
else
|
||||
return;
|
||||
|
||||
if(axis == IK_TRANS_X) axis = IK_X;
|
||||
else if(axis == IK_TRANS_Y) axis = IK_Y;
|
||||
else axis = IK_Z;
|
||||
}
|
||||
|
||||
qseg->SetWeight(axis, weight);
|
||||
}
|
||||
|
||||
void IK_GetBasisChange(IK_Segment *seg, float basis_change[][3])
|
||||
@@ -166,6 +221,9 @@ void IK_GetBasisChange(IK_Segment *seg, float basis_change[][3])
|
||||
IK_QSegment *qseg = (IK_QSegment*)seg;
|
||||
const MT_Matrix3x3& change = qseg->BasisChange();
|
||||
|
||||
if (qseg->Translational() && qseg->Composite())
|
||||
qseg = qseg->Composite();
|
||||
|
||||
// convert from moto row major to blender column major
|
||||
basis_change[0][0] = (float)change[0][0];
|
||||
basis_change[1][0] = (float)change[0][1];
|
||||
@@ -181,6 +239,10 @@ void IK_GetBasisChange(IK_Segment *seg, float basis_change[][3])
|
||||
void IK_GetTranslationChange(IK_Segment *seg, float *translation_change)
|
||||
{
|
||||
IK_QSegment *qseg = (IK_QSegment*)seg;
|
||||
|
||||
if (!qseg->Translational() && qseg->Composite())
|
||||
qseg = qseg->Composite();
|
||||
|
||||
const MT_Vector3& change = qseg->TranslationChange();
|
||||
|
||||
translation_change[0] = (float)change[0];
|
||||
@@ -222,9 +284,11 @@ void IK_SolverAddGoal(IK_Solver *solver, IK_Segment *tip, float goal[3], float w
|
||||
IK_QSolver *qsolver = (IK_QSolver*)solver;
|
||||
IK_QSegment *qtip = (IK_QSegment*)tip;
|
||||
|
||||
if (qtip->Composite())
|
||||
qtip = qtip->Composite();
|
||||
|
||||
MT_Vector3 pos(goal);
|
||||
|
||||
// qsolver->tasks.empty()
|
||||
IK_QTask *ee = new IK_QPositionTask(true, qtip, pos);
|
||||
ee->SetWeight(weight);
|
||||
qsolver->tasks.push_back(ee);
|
||||
@@ -238,6 +302,9 @@ void IK_SolverAddGoalOrientation(IK_Solver *solver, IK_Segment *tip, float goal[
|
||||
IK_QSolver *qsolver = (IK_QSolver*)solver;
|
||||
IK_QSegment *qtip = (IK_QSegment*)tip;
|
||||
|
||||
if (qtip->Composite())
|
||||
qtip = qtip->Composite();
|
||||
|
||||
// convert from blender column major to moto row major
|
||||
MT_Matrix3x3 rot(goal[0][0], goal[1][0], goal[2][0],
|
||||
goal[0][1], goal[1][1], goal[2][1],
|
||||
|
||||
@@ -43,27 +43,29 @@ struct bConstraint;
|
||||
struct Object;
|
||||
struct MDeformVert;
|
||||
struct Mesh;
|
||||
struct PoseChain;
|
||||
struct PoseTree;
|
||||
struct ListBase;
|
||||
|
||||
typedef struct PoseTarget
|
||||
{
|
||||
struct PoseTarget *next, *prev;
|
||||
struct bConstraint *con;
|
||||
int tip;
|
||||
|
||||
struct bConstraint *con; /* the constrait of this target */
|
||||
int tip; /* index of tip pchan in PoseTree */
|
||||
} PoseTarget;
|
||||
|
||||
typedef struct PoseChain
|
||||
typedef struct PoseTree
|
||||
{
|
||||
struct PoseChain *next, *prev;
|
||||
struct bPoseChannel **pchanchain;
|
||||
struct ListBase targets;
|
||||
int totchannel;
|
||||
int tree; // true or false
|
||||
float (*basis_change)[3][3];
|
||||
float tolerance;
|
||||
int iterations;
|
||||
} PoseChain;
|
||||
struct PoseTree *next, *prev;
|
||||
|
||||
struct ListBase targets; /* list of targets of the tree */
|
||||
struct bPoseChannel **pchan; /* array of pose channels */
|
||||
int *parent; /* and their parents */
|
||||
int totchannel; /* number of pose channels */
|
||||
float (*basis_change)[3][3]; /* basis change result from solver */
|
||||
float tolerance; /* tolerance from the constraint */
|
||||
int iterations; /* iterations from the constraint */
|
||||
} PoseTree;
|
||||
|
||||
/* Core armature functionality */
|
||||
#ifdef __cplusplus
|
||||
@@ -91,13 +93,14 @@ void where_is_pose (struct Object *ob);
|
||||
/* get_objectspace_bone_matrix has to be removed still */
|
||||
void get_objectspace_bone_matrix (struct Bone* bone, float M_accumulatedMatrix[][4], int root, int posed);
|
||||
void vec_roll_to_mat3(float *vec, float roll, float mat[][3]);
|
||||
void mat3_to_vec_roll(float mat[][3], float *vec, float *roll);
|
||||
|
||||
|
||||
/* Animation functions */
|
||||
|
||||
struct PoseChain *ik_chain_to_posechain (struct Object *ob, struct Bone *bone);
|
||||
void solve_posechain (PoseChain *chain);
|
||||
void free_posechain (PoseChain *chain);
|
||||
struct PoseTree *ik_tree_to_posetree(struct Object *ob, struct Bone *bone);
|
||||
void solve_posetree(PoseTree *tree);
|
||||
void free_posetree(PoseTree *tree);
|
||||
|
||||
/* Gameblender hacks */
|
||||
void GB_init_armature_deform(struct ListBase *defbase, float premat[][4], float postmat[][4]);
|
||||
|
||||
@@ -186,7 +186,6 @@ void IK_FreeSolver(IK_Solver *solver) {};
|
||||
|
||||
void IK_SolverAddGoal(IK_Solver *solver, IK_Segment *tip, float goal[3], float weight) {}
|
||||
void IK_SolverAddGoalOrientation(IK_Solver *solver, IK_Segment *tip, float goal[][3], float weight) {}
|
||||
void IK_SolverAddCenterOfMass(IK_Solver *solver, IK_Segment *root, float goal[3], float weight) {}
|
||||
int IK_Solve(IK_Solver *solver, float tolerance, int max_iterations) { return 0; }
|
||||
|
||||
/* exotic.c */
|
||||
|
||||
@@ -205,7 +205,6 @@ bPoseChannel *verify_pose_channel(bPose* pose, const char* name)
|
||||
/* init vars to prevent mat errors */
|
||||
chan->quat[0] = 1.0F;
|
||||
chan->size[0] = chan->size[1] = chan->size[2] = 1.0F;
|
||||
Mat3One(chan->ik_mat);
|
||||
|
||||
chan->limitmin[0]= chan->limitmin[1]= chan->limitmin[2]= -180.0f;
|
||||
chan->limitmax[0]= chan->limitmax[1]= chan->limitmax[2]= 180.0f;
|
||||
|
||||
@@ -968,16 +968,16 @@ void armature_rebuild_pose(Object *ob, bArmature *arm)
|
||||
|
||||
|
||||
|
||||
/* allocates PoseChain, and links that to root bone/channel */
|
||||
/* allocates PoseTree, and links that to root bone/channel */
|
||||
/* note; if we got this working, it can become static too? */
|
||||
static void initialize_posechain(struct Object *ob, bPoseChannel *pchan_tip)
|
||||
static void initialize_posetree(struct Object *ob, bPoseChannel *pchan_tip)
|
||||
{
|
||||
bPoseChannel *curchan, *pchan_root=NULL, *chanlist[256], **oldchan;
|
||||
PoseChain *chain;
|
||||
PoseTree *tree;
|
||||
PoseTarget *target;
|
||||
bConstraint *con;
|
||||
bKinematicConstraint *data;
|
||||
int a, segcount= 0, size, newsize;
|
||||
int a, segcount= 0, size, newsize, *oldparent, parent;
|
||||
|
||||
/* find IK constraint, and validate it */
|
||||
for(con= pchan_tip->constraints.first; con; con= con->next) {
|
||||
@@ -1009,9 +1009,9 @@ static void initialize_posechain(struct Object *ob, bPoseChannel *pchan_tip)
|
||||
/* setup the chain data */
|
||||
|
||||
/* we make tree-IK, unless all existing targets are in this chain */
|
||||
for(chain= pchan_root->chain.first; chain; chain= chain->next) {
|
||||
for(target= chain->targets.first; target; target= target->next) {
|
||||
curchan= chain->pchanchain[target->tip];
|
||||
for(tree= pchan_root->iktree.first; tree; tree= tree->next) {
|
||||
for(target= tree->targets.first; target; target= target->next) {
|
||||
curchan= tree->pchan[target->tip];
|
||||
if(curchan->flag & POSE_CHAIN)
|
||||
curchan->flag &= ~POSE_CHAIN;
|
||||
else
|
||||
@@ -1025,62 +1025,72 @@ static void initialize_posechain(struct Object *ob, bPoseChannel *pchan_tip)
|
||||
target->con= con;
|
||||
pchan_tip->flag &= ~POSE_CHAIN;
|
||||
|
||||
if(chain==NULL) {
|
||||
/* make new chain */
|
||||
chain= MEM_callocN(sizeof(PoseChain), "posechain");
|
||||
if(tree==NULL) {
|
||||
/* make new tree */
|
||||
tree= MEM_callocN(sizeof(PoseTree), "posetree");
|
||||
|
||||
chain->tolerance= data->tolerance;
|
||||
chain->iterations= data->iterations;
|
||||
chain->totchannel= segcount;
|
||||
tree->tolerance= data->tolerance;
|
||||
tree->iterations= data->iterations;
|
||||
tree->totchannel= segcount;
|
||||
|
||||
chain->pchanchain= MEM_callocN(segcount*sizeof(void *), "channel chain");
|
||||
tree->pchan= MEM_callocN(segcount*sizeof(void*), "ik tree pchan");
|
||||
tree->parent= MEM_callocN(segcount*sizeof(int), "ik tree parent");
|
||||
for(a=0; a<segcount; a++) {
|
||||
chain->pchanchain[a]= chanlist[segcount-a-1];
|
||||
tree->pchan[a]= chanlist[segcount-a-1];
|
||||
tree->parent[a]= a-1;
|
||||
}
|
||||
target->tip= segcount-1;
|
||||
|
||||
/* AND! link the chain to the root */
|
||||
BLI_addtail(&pchan_root->chain, chain);
|
||||
/* AND! link the tree to the root */
|
||||
BLI_addtail(&pchan_root->iktree, tree);
|
||||
}
|
||||
else {
|
||||
chain->tolerance= MIN2(chain->tolerance, data->tolerance);
|
||||
chain->iterations= MAX2(data->iterations, chain->iterations);
|
||||
tree->tolerance= MIN2(tree->tolerance, data->tolerance);
|
||||
tree->iterations= MAX2(data->iterations, tree->iterations);
|
||||
|
||||
/* skip common pose channels and add remaining*/
|
||||
size= MIN2(segcount, chain->totchannel);
|
||||
for(a=0; a<size && chain->pchanchain[a]==chanlist[segcount-a-1]; a++);
|
||||
size= MIN2(segcount, tree->totchannel);
|
||||
for(a=0; a<size && tree->pchan[a]==chanlist[segcount-a-1]; a++);
|
||||
parent= a-1;
|
||||
|
||||
segcount= segcount-a;
|
||||
target->tip= chain->totchannel + segcount - 1;
|
||||
target->tip= tree->totchannel + segcount - 1;
|
||||
|
||||
if (segcount > 0) {
|
||||
/* resize array */
|
||||
newsize= chain->totchannel + segcount;
|
||||
oldchan= chain->pchanchain;
|
||||
newsize= tree->totchannel + segcount;
|
||||
oldchan= tree->pchan;
|
||||
oldparent= tree->parent;
|
||||
|
||||
chain->pchanchain= MEM_callocN(newsize*sizeof(void*), "channel chain");
|
||||
memcpy(chain->pchanchain, oldchan, sizeof(void*)*chain->totchannel);
|
||||
tree->pchan= MEM_callocN(newsize*sizeof(void*), "ik tree pchan");
|
||||
tree->parent= MEM_callocN(newsize*sizeof(int), "ik tree parent");
|
||||
memcpy(tree->pchan, oldchan, sizeof(void*)*tree->totchannel);
|
||||
memcpy(tree->parent, oldparent, sizeof(int)*tree->totchannel);
|
||||
MEM_freeN(oldchan);
|
||||
MEM_freeN(oldparent);
|
||||
|
||||
/* add new pose channels at the end, in reverse order */
|
||||
for(a=0; a<segcount; a++)
|
||||
chain->pchanchain[chain->totchannel+a]= chanlist[segcount-a-1];
|
||||
for(a=0; a<segcount; a++) {
|
||||
tree->pchan[tree->totchannel+a]= chanlist[segcount-a-1];
|
||||
tree->parent[tree->totchannel+a]= tree->totchannel+a-1;
|
||||
}
|
||||
tree->parent[tree->totchannel]= parent;
|
||||
|
||||
chain->totchannel= newsize;
|
||||
tree->totchannel= newsize;
|
||||
}
|
||||
|
||||
/* move chain to end of list, for correct evaluation order */
|
||||
BLI_remlink(&pchan_root->chain, chain);
|
||||
BLI_addtail(&pchan_root->chain, chain);
|
||||
/* move tree to end of list, for correct evaluation order */
|
||||
BLI_remlink(&pchan_root->iktree, tree);
|
||||
BLI_addtail(&pchan_root->iktree, tree);
|
||||
}
|
||||
|
||||
/* add target to the chain */
|
||||
BLI_addtail(&chain->targets, target);
|
||||
/* add target to the tree */
|
||||
BLI_addtail(&tree->targets, target);
|
||||
}
|
||||
|
||||
/* called from within the core where_is_pose loop, all animsystems and constraints
|
||||
were executed & assigned. Now as last we do an IK pass */
|
||||
static void execute_posechain(Object *ob, PoseChain *chain)
|
||||
static void execute_posetree(Object *ob, PoseTree *tree)
|
||||
{
|
||||
float R_parmat[3][3];
|
||||
float iR_parmat[3][3];
|
||||
@@ -1088,24 +1098,24 @@ static void execute_posechain(Object *ob, PoseChain *chain)
|
||||
float goalrot[3][3], goalpos[3];
|
||||
float rootmat[4][4], imat[4][4];
|
||||
float goal[4][4], goalinv[4][4];
|
||||
float size[3], bonesize[3], irest_basis[3][3], full_basis[3][3];
|
||||
float length, basis[3][3], rest_basis[3][3], start[3];
|
||||
int a, b, flag;
|
||||
float size[3], irest_basis[3][3], full_basis[3][3];
|
||||
float length, basis[3][3], rest_basis[3][3], start[3], *ikstretch=NULL;
|
||||
int a, flag, hasstretch=0;
|
||||
bPoseChannel *pchan;
|
||||
IK_Segment *seg, *parent, **ikchain, *iktarget;
|
||||
IK_Segment *seg, *parent, **iktree, *iktarget;
|
||||
IK_Solver *solver;
|
||||
PoseTarget *target;
|
||||
bKinematicConstraint *data;
|
||||
Bone *bone;
|
||||
|
||||
if (chain->totchannel == 0)
|
||||
if (tree->totchannel == 0)
|
||||
return;
|
||||
|
||||
ikchain= MEM_mallocN(sizeof(void*)*chain->totchannel, "ik chain");
|
||||
iktree= MEM_mallocN(sizeof(void*)*tree->totchannel, "ik tree");
|
||||
|
||||
for(a=0; a<chain->totchannel; a++) {
|
||||
pchan= chain->pchanchain[a];
|
||||
bone = pchan->bone;
|
||||
for(a=0; a<tree->totchannel; a++) {
|
||||
pchan= tree->pchan[a];
|
||||
bone= pchan->bone;
|
||||
|
||||
/* set DoF flag */
|
||||
flag= 0;
|
||||
@@ -1116,54 +1126,51 @@ static void execute_posechain(Object *ob, PoseChain *chain)
|
||||
if((pchan->ikflag & BONE_IK_NO_ZDOF) == 0)
|
||||
flag |= IK_ZDOF;
|
||||
|
||||
seg= ikchain[a]= IK_CreateSegment(flag);
|
||||
if(pchan->ikstretch > 0.0) {
|
||||
flag |= IK_TRANS_YDOF;
|
||||
hasstretch = 1;
|
||||
}
|
||||
|
||||
seg= iktree[a]= IK_CreateSegment(flag);
|
||||
|
||||
/* find parent */
|
||||
if(a == 0)
|
||||
parent= NULL;
|
||||
else {
|
||||
for(b=a-1; chain->pchanchain[b]!=pchan->parent; b--);
|
||||
parent= ikchain[b];
|
||||
}
|
||||
else
|
||||
parent= iktree[tree->parent[a]];
|
||||
|
||||
IK_SetParent(seg, parent);
|
||||
|
||||
/* get the matrix that transforms from prevbone into this bone */
|
||||
Mat3CpyMat4(R_bonemat, pchan->pose_mat);
|
||||
|
||||
|
||||
/* gather transformations for this IK segment */
|
||||
|
||||
if(a>0 && pchan->parent) {
|
||||
Mat3CpyMat4(R_parmat, pchan->parent->pose_mat);
|
||||
VECCOPY(start, bone->head); /* bone offset */
|
||||
}
|
||||
else {
|
||||
Mat3One(R_parmat);
|
||||
start[0]= start[1]= start[2]= 0.0f;
|
||||
}
|
||||
else
|
||||
Mat3One (R_parmat);
|
||||
|
||||
Mat3Inv(iR_parmat, R_parmat);
|
||||
|
||||
/* gather transformations for this IK segment */
|
||||
|
||||
/* change length based on bone size */
|
||||
Mat3ToSize(R_bonemat, bonesize);
|
||||
length= bone->length*bonesize[1];
|
||||
length= bone->length*VecLength(R_bonemat[1]);
|
||||
|
||||
/* compute rest basis and its inverse */
|
||||
Mat3CpyMat3(rest_basis, bone->bone_mat);
|
||||
Mat3CpyMat3(irest_basis, bone->bone_mat);
|
||||
Mat3Transp(irest_basis);
|
||||
|
||||
/* compute basis with rest_basis removed */
|
||||
Mat3Inv(irest_basis, rest_basis);
|
||||
Mat3Inv(iR_parmat, R_parmat);
|
||||
Mat3MulMat3(full_basis, iR_parmat, R_bonemat);
|
||||
Mat3MulMat3(basis, irest_basis, full_basis);
|
||||
|
||||
/* basis must be pure rotation, size was extracted for length already */
|
||||
Mat3Ortho(rest_basis);
|
||||
/* basis must be pure rotation */
|
||||
Mat3Ortho(basis);
|
||||
|
||||
/* Bone offset */
|
||||
if(a>0 && pchan->parent) {
|
||||
VECCOPY(start, bone->head);
|
||||
// Mat3MulVecfl(R_parmat, start);
|
||||
}
|
||||
else
|
||||
start[0]= start[1]= start[2]= 0.0f;
|
||||
|
||||
IK_SetTransform(seg, start, rest_basis, basis, length);
|
||||
|
||||
if (pchan->ikflag & BONE_IK_XLIMIT)
|
||||
@@ -1176,21 +1183,27 @@ static void execute_posechain(Object *ob, PoseChain *chain)
|
||||
IK_SetStiffness(seg, IK_X, pchan->stiffness[0]);
|
||||
IK_SetStiffness(seg, IK_Y, pchan->stiffness[1]);
|
||||
IK_SetStiffness(seg, IK_Z, pchan->stiffness[2]);
|
||||
|
||||
if(pchan->ikstretch > 0.0) {
|
||||
float ikstretch = pchan->ikstretch*pchan->ikstretch;
|
||||
IK_SetStiffness(seg, IK_TRANS_Y, MIN2(1.0-ikstretch, 0.99));
|
||||
IK_SetLimit(seg, IK_TRANS_Y, 0.001, 1e10);
|
||||
}
|
||||
}
|
||||
|
||||
solver= IK_CreateSolver(ikchain[0]);
|
||||
solver= IK_CreateSolver(iktree[0]);
|
||||
|
||||
/* set solver goals */
|
||||
|
||||
/* first set the goal inverse transform, assuming the root of chain was done ok! */
|
||||
pchan= chain->pchanchain[0];
|
||||
/* first set the goal inverse transform, assuming the root of tree was done ok! */
|
||||
pchan= tree->pchan[0];
|
||||
Mat4One(rootmat);
|
||||
VECCOPY(rootmat[3], pchan->pose_head);
|
||||
|
||||
Mat4MulMat4 (imat, rootmat, ob->obmat);
|
||||
Mat4Invert (goalinv, imat);
|
||||
|
||||
for(target=chain->targets.first; target; target=target->next) {
|
||||
for(target=tree->targets.first; target; target=target->next) {
|
||||
data= (bKinematicConstraint*)target->con->data;
|
||||
|
||||
/* 1.0=ctime */
|
||||
@@ -1208,7 +1221,7 @@ static void execute_posechain(Object *ob, PoseChain *chain)
|
||||
float fac= target->con->enforce;
|
||||
float mfac= 1.0-fac;
|
||||
|
||||
pchan= chain->pchanchain[target->tip];
|
||||
pchan= tree->pchan[target->tip];
|
||||
|
||||
/* blend position */
|
||||
VECCOPY(vec, pchan->pose_tail);
|
||||
@@ -1226,9 +1239,7 @@ static void execute_posechain(Object *ob, PoseChain *chain)
|
||||
QuatToMat3(q, goalrot);
|
||||
}
|
||||
|
||||
iktarget= ikchain[target->tip];
|
||||
|
||||
/*IK_SolverAddCenterOfMass(solver, ikchain[0], goalpos, data->weight);*/
|
||||
iktarget= iktree[target->tip];
|
||||
|
||||
if(data->weight != 0.0)
|
||||
IK_SolverAddGoal(solver, iktarget, goalpos, data->weight);
|
||||
@@ -1237,26 +1248,57 @@ static void execute_posechain(Object *ob, PoseChain *chain)
|
||||
}
|
||||
|
||||
/* solve */
|
||||
IK_Solve(solver, chain->tolerance, chain->iterations);
|
||||
IK_Solve(solver, tree->tolerance, tree->iterations);
|
||||
IK_FreeSolver(solver);
|
||||
|
||||
/* gather basis changes */
|
||||
chain->basis_change= MEM_mallocN(sizeof(float[3][3])*chain->totchannel, "ik basis change");
|
||||
tree->basis_change= MEM_mallocN(sizeof(float[3][3])*tree->totchannel, "ik basis change");
|
||||
if(hasstretch)
|
||||
ikstretch= MEM_mallocN(sizeof(float)*tree->totchannel, "ik stretch");
|
||||
|
||||
for(a=0; a<chain->totchannel; a++) {
|
||||
IK_GetBasisChange(ikchain[a], chain->basis_change[a]);
|
||||
IK_FreeSegment(ikchain[a]);
|
||||
for(a=0; a<tree->totchannel; a++) {
|
||||
IK_GetBasisChange(iktree[a], tree->basis_change[a]);
|
||||
|
||||
if(hasstretch) {
|
||||
/* have to compensate for scaling received from parent */
|
||||
float parentstretch, stretch;
|
||||
|
||||
pchan= tree->pchan[a];
|
||||
parentstretch= (tree->parent[a] >= 0)? ikstretch[tree->parent[a]]: 1.0;
|
||||
|
||||
if(pchan->ikstretch > 0.0) {
|
||||
float trans[3], length;
|
||||
|
||||
IK_GetTranslationChange(iktree[a], trans);
|
||||
length= pchan->bone->length*VecLength(pchan->pose_mat[1]);
|
||||
|
||||
ikstretch[a]= (length == 0.0)? 1.0: (trans[1]+length)/length;
|
||||
}
|
||||
else
|
||||
ikstretch[a] = 1.0;
|
||||
|
||||
stretch= (parentstretch == 0.0)? 1.0: ikstretch[a]/parentstretch;
|
||||
|
||||
VecMulf(tree->basis_change[a][0], stretch);
|
||||
VecMulf(tree->basis_change[a][1], stretch);
|
||||
VecMulf(tree->basis_change[a][2], stretch);
|
||||
|
||||
}
|
||||
|
||||
IK_FreeSegment(iktree[a]);
|
||||
}
|
||||
|
||||
MEM_freeN(ikchain);
|
||||
MEM_freeN(iktree);
|
||||
if(ikstretch) MEM_freeN(ikstretch);
|
||||
}
|
||||
|
||||
void free_posechain (PoseChain *chain)
|
||||
void free_posetree(PoseTree *tree)
|
||||
{
|
||||
BLI_freelistN(&chain->targets);
|
||||
if(chain->pchanchain) MEM_freeN(chain->pchanchain);
|
||||
if(chain->basis_change) MEM_freeN(chain->basis_change);
|
||||
MEM_freeN(chain);
|
||||
BLI_freelistN(&tree->targets);
|
||||
if(tree->pchan) MEM_freeN(tree->pchan);
|
||||
if(tree->parent) MEM_freeN(tree->parent);
|
||||
if(tree->basis_change) MEM_freeN(tree->basis_change);
|
||||
MEM_freeN(tree);
|
||||
}
|
||||
|
||||
/* ********************** THE POSE SOLVER ******************* */
|
||||
@@ -1451,42 +1493,42 @@ void where_is_pose (Object *ob)
|
||||
else {
|
||||
Mat4Invert(ob->imat, ob->obmat); // imat is needed
|
||||
|
||||
/* 1. construct the PoseChains, clear flags */
|
||||
/* 1. construct the PoseTrees, clear flags */
|
||||
for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
|
||||
pchan->flag &= ~(POSE_DONE|POSE_CHAIN);
|
||||
if(pchan->constflag & PCHAN_HAS_IK) // flag is set on editing constraints
|
||||
initialize_posechain(ob, pchan); // will attach it to root!
|
||||
initialize_posetree(ob, pchan); // will attach it to root!
|
||||
}
|
||||
|
||||
/* 2. the main loop, channels are already hierarchical sorted from root to children */
|
||||
for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
|
||||
|
||||
/* 3. if we find an IK root, we handle it separated */
|
||||
if(pchan->chain.first) {
|
||||
while(pchan->chain.first) {
|
||||
PoseChain *chain= pchan->chain.first;
|
||||
if(pchan->iktree.first) {
|
||||
while(pchan->iktree.first) {
|
||||
PoseTree *tree= pchan->iktree.first;
|
||||
int a;
|
||||
|
||||
/* 4. walk over the chain for regular solving */
|
||||
for(a=0; a<chain->totchannel; a++) {
|
||||
if(!(chain->pchanchain[a]->flag & POSE_DONE)) // successive chains can set the flag
|
||||
where_is_pose_bone(ob, chain->pchanchain[a]);
|
||||
/* 4. walk over the tree for regular solving */
|
||||
for(a=0; a<tree->totchannel; a++) {
|
||||
if(!(tree->pchan[a]->flag & POSE_DONE)) // successive trees can set the flag
|
||||
where_is_pose_bone(ob, tree->pchan[a]);
|
||||
}
|
||||
/* 5. execute the IK solver */
|
||||
execute_posechain(ob, chain);
|
||||
execute_posetree(ob, tree);
|
||||
|
||||
/* 6. apply the differences to the channels,
|
||||
we need to calculate the original differences first */
|
||||
for(a=0; a<chain->totchannel; a++)
|
||||
make_dmats(chain->pchanchain[a]);
|
||||
for(a=0; a<tree->totchannel; a++)
|
||||
make_dmats(tree->pchan[a]);
|
||||
|
||||
for(a=0; a<chain->totchannel; a++)
|
||||
for(a=0; a<tree->totchannel; a++)
|
||||
/* sets POSE_DONE */
|
||||
where_is_ik_bone(chain->pchanchain[a], chain->basis_change[a]);
|
||||
where_is_ik_bone(tree->pchan[a], tree->basis_change[a]);
|
||||
|
||||
/* 7. and free */
|
||||
BLI_remlink(&pchan->chain, chain);
|
||||
free_posechain(chain);
|
||||
BLI_remlink(&pchan->iktree, tree);
|
||||
free_posetree(tree);
|
||||
}
|
||||
}
|
||||
else if(!(pchan->flag & POSE_DONE)) {
|
||||
|
||||
@@ -53,7 +53,7 @@ typedef struct bPoseChannel {
|
||||
struct Bone *bone; /* set on read file or rebuild pose */
|
||||
struct bPoseChannel *parent; /* set on read file or rebuild pose */
|
||||
struct bPoseChannel *child; /* set on read file or rebuild pose, the 'ik' child, for b-bones */
|
||||
struct ListBase chain; /* only while evaluating pose */
|
||||
struct ListBase iktree; /* only while evaluating pose */
|
||||
void *b_bone_mats; /* only while deform, stores precalculated b_bone deform mats */
|
||||
|
||||
float loc[3]; /* written in by actions or transform */
|
||||
@@ -62,13 +62,13 @@ typedef struct bPoseChannel {
|
||||
|
||||
float chan_mat[4][4]; /* matrix result of loc/quat/size , and where we put deform in, see next line */
|
||||
float pose_mat[4][4]; /* constraints accumulate here. in the end, pose_mat = bone->arm_mat * chan_mat */
|
||||
float ik_mat[3][3]; /* for itterative IK */
|
||||
|
||||
float pose_head[3]; /* actually pose_mat[3] */
|
||||
float pose_tail[3]; /* also used for drawing help lines... */
|
||||
|
||||
float limitmin[3], limitmax[3]; /* DOF constraint */
|
||||
float stiffness[3]; /* DOF stiffness */
|
||||
float ikstretch;
|
||||
|
||||
} bPoseChannel;
|
||||
|
||||
|
||||
@@ -1252,7 +1252,7 @@ void do_fontbuts(unsigned short event)
|
||||
Object *ob;
|
||||
ScrArea *sa;
|
||||
char str[80];
|
||||
int i, style;
|
||||
int i, style=0;
|
||||
|
||||
ob= OBACT;
|
||||
|
||||
@@ -2357,8 +2357,8 @@ static void editing_panel_pose_bones(Object *ob, bArmature *arm)
|
||||
uiDefButF(block, NUM, B_ARM_RECALCDATA, "Stiff X:", bx-10, by-80, 114, 19, &pchan->stiffness[0], 0.0, 0.99, 1.0, 0.0, "Resistance to bending for X axis");
|
||||
uiDefButBitS(block, TOG, BONE_IK_XLIMIT, B_ARM_RECALCDATA, "Limit X", bx-10,by-100,114,19, &pchan->ikflag, 0.0, 0.0, 0.0, 0.0, "Limit rotation over X axis");
|
||||
if ((pchan->ikflag & BONE_IK_XLIMIT)) {
|
||||
uiDefButF(block, NUM, B_ARM_RECALCDATA, "Min X:", bx-10, by-120, 114, 19, &pchan->limitmin[0], -180.0f, pchan->limitmax[0], 1000, 1, "Minimum X limit");
|
||||
uiDefButF(block, NUM, B_ARM_RECALCDATA, "Max X:", bx-10, by-140, 114, 19, &pchan->limitmax[0], pchan->limitmin[0], 180.0f, 1000, 1, "Maximum X limit");
|
||||
uiDefButF(block, NUM, B_ARM_RECALCDATA, "Min X:", bx-10, by-120, 114, 19, &pchan->limitmin[0], -180.0, 0.0, 1000, 1, "Minimum X limit");
|
||||
uiDefButF(block, NUM, B_ARM_RECALCDATA, "Max X:", bx-10, by-140, 114, 19, &pchan->limitmax[0], 0.0, 180.0f, 1000, 1, "Maximum X limit");
|
||||
zerolimit = 0;
|
||||
}
|
||||
zerodof = 0;
|
||||
@@ -2368,11 +2368,11 @@ static void editing_panel_pose_bones(Object *ob, bArmature *arm)
|
||||
uiBlockBeginAlign(block);
|
||||
uiDefButBitS(block, TOG, BONE_IK_NO_YDOF, B_ARM_RECALCDATA, "Lock Y Rot", bx+104,by-60,113,19, &pchan->ikflag, 0.0, 0.0, 0.0, 0.0, "Disable Y DoF for IK");
|
||||
if ((pchan->ikflag & BONE_IK_NO_YDOF)==0) {
|
||||
uiDefButF(block, NUM, B_ARM_RECALCDATA, "Stiff Y:", bx+104, by-80, 114, 19, &pchan->stiffness[1], 0.0, 0.99, 1.0, 0.0, "Resistance to bending for Y axis");
|
||||
uiDefButF(block, NUM, B_ARM_RECALCDATA, "Stiff Y:", bx+104, by-80, 114, 19, &pchan->stiffness[1], 0.0, 0.99, 1.0, 0.0, "Resistance to twisting over Y axis");
|
||||
uiDefButBitS(block, TOG, BONE_IK_YLIMIT, B_ARM_RECALCDATA, "Limit Y", bx+104,by-100,113,19, &pchan->ikflag, 0.0, 0.0, 0.0, 0.0, "Limit rotation over Y axis");
|
||||
if ((pchan->ikflag & BONE_IK_YLIMIT)) {
|
||||
uiDefButF(block, NUM, B_ARM_RECALCDATA, "Min Y:", bx+104, by-120, 113, 19, &pchan->limitmin[1], -180.0f, pchan->limitmax[1], 1000, 1, "Minimum Y limit");
|
||||
uiDefButF(block, NUM, B_ARM_RECALCDATA, "Max Y:", bx+104, by-140, 113, 19, &pchan->limitmax[1], pchan->limitmin[1], 180.0f, 1000, 1, "Maximum Y limit");
|
||||
uiDefButF(block, NUM, B_ARM_RECALCDATA, "Min Y:", bx+104, by-120, 113, 19, &pchan->limitmin[1], -180.0, 0.0, 1000, 1, "Minimum Y limit");
|
||||
uiDefButF(block, NUM, B_ARM_RECALCDATA, "Max Y:", bx+104, by-140, 113, 19, &pchan->limitmax[1], 0.0, 180.0, 1000, 1, "Maximum Y limit");
|
||||
zerolimit = 0;
|
||||
}
|
||||
zerodof = 0;
|
||||
@@ -2385,20 +2385,28 @@ static void editing_panel_pose_bones(Object *ob, bArmature *arm)
|
||||
uiDefButF(block, NUM, B_ARM_RECALCDATA, "Stiff Z:", bx+217, by-80, 114, 19, &pchan->stiffness[2], 0.0, 0.99, 1.0, 0.0, "Resistance to bending for Z axis");
|
||||
uiDefButBitS(block, TOG, BONE_IK_ZLIMIT, B_ARM_RECALCDATA, "Limit Z", bx+217,by-100,113,19, &pchan->ikflag, 0.0, 0.0, 0.0, 0.0, "Limit rotation over Z axis");
|
||||
if ((pchan->ikflag & BONE_IK_ZLIMIT)) {
|
||||
uiDefButF(block, NUM, B_ARM_RECALCDATA, "Min Z:", bx+217, by-120, 113, 19, &pchan->limitmin[2], -180.0f, pchan->limitmax[2], 1000, 1, "Minimum Z limit");
|
||||
uiDefButF(block, NUM, B_ARM_RECALCDATA, "Max Z:", bx+217, by-140, 113, 19, &pchan->limitmax[2], pchan->limitmin[2], 180.0f, 1000, 1, "Maximum Z limit");
|
||||
uiDefButF(block, NUM, B_ARM_RECALCDATA, "Min Z:", bx+217, by-120, 113, 19, &pchan->limitmin[2], -180.0, 0.0, 1000, 1, "Minimum Z limit");
|
||||
uiDefButF(block, NUM, B_ARM_RECALCDATA, "Max Z:", bx+217, by-140, 113, 19, &pchan->limitmax[2], 0.0, 180.0, 1000, 1, "Maximum Z limit");
|
||||
zerolimit = 0;
|
||||
}
|
||||
zerodof = 0;
|
||||
}
|
||||
uiBlockEndAlign(block);
|
||||
|
||||
by -= (zerodof)? 82: (zerolimit)? 122: 162;
|
||||
|
||||
uiBlockBeginAlign(block);
|
||||
uiDefButF(block, NUM, B_ARM_RECALCDATA, "Stretch:", bx-10, by, 113, 19, &pchan->ikstretch, 0.0, 1.0, 1.0, 0.0, "Allow scaling of the bone for IK");
|
||||
uiBlockEndAlign(block);
|
||||
|
||||
by -= 20;
|
||||
}
|
||||
else {
|
||||
uiDefBut(block, LABEL, 0, "(DoF options only for IK chains)", bx-10,by-60, 300, 20, 0, 0, 0, 0, 0, "");
|
||||
|
||||
by -= 82;
|
||||
}
|
||||
|
||||
by -= (zerodof)? 82: (zerolimit)? 122: 162;
|
||||
|
||||
if(by < -200) break; // for time being... extreme long panels are very slow
|
||||
}
|
||||
|
||||
@@ -1100,6 +1100,81 @@ static void pchan_draw_IK_root_lines(bPoseChannel *pchan)
|
||||
}
|
||||
}
|
||||
|
||||
static void bgl_sphere_project(float ax, float az)
|
||||
{
|
||||
float dir[3], sine, q3;
|
||||
|
||||
sine= 1.0f-ax*ax-az*az;
|
||||
q3= 2.0*sqrt((sine < 0.0f)? 0.0f: sine);
|
||||
|
||||
dir[0]= -az*q3;
|
||||
dir[1]= 1.0-2.0*sine;
|
||||
dir[2]= ax*q3;
|
||||
|
||||
glVertex3fv(dir);
|
||||
}
|
||||
|
||||
static void draw_dof_ellipse(float ax, float az)
|
||||
{
|
||||
static float staticSine[16] = {
|
||||
0.0, 0.104528463268, 0.207911690818, 0.309016994375,
|
||||
0.406736643076, 0.5, 0.587785252292, 0.669130606359,
|
||||
0.743144825477, 0.809016994375, 0.866025403784,
|
||||
0.913545457643, 0.951056516295, 0.978147600734,
|
||||
0.994521895368, 1.0
|
||||
};
|
||||
|
||||
int i, j, n=16;
|
||||
float x, z, px, pz;
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_BLEND);
|
||||
glDepthMask(0);
|
||||
|
||||
glColor4ub(70, 70, 70, 50);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
pz= 0.0;
|
||||
for(i=1; i<n; i++) {
|
||||
z= staticSine[i];
|
||||
|
||||
px= 0.0;
|
||||
for(j=1; j<n-i+1; j++) {
|
||||
x = staticSine[j];
|
||||
|
||||
if(j == n-i) {
|
||||
glEnd();
|
||||
glBegin(GL_TRIANGLES);
|
||||
bgl_sphere_project(ax*px, az*z);
|
||||
bgl_sphere_project(ax*px, az*pz);
|
||||
bgl_sphere_project(ax*x, az*pz);
|
||||
glEnd();
|
||||
glBegin(GL_QUADS);
|
||||
}
|
||||
else {
|
||||
bgl_sphere_project(ax*x, az*z);
|
||||
bgl_sphere_project(ax*x, az*pz);
|
||||
bgl_sphere_project(ax*px, az*pz);
|
||||
bgl_sphere_project(ax*px, az*z);
|
||||
}
|
||||
|
||||
px= x;
|
||||
}
|
||||
pz= z;
|
||||
}
|
||||
glEnd();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glDepthMask(1);
|
||||
|
||||
glColor3ub(0, 0, 0);
|
||||
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for(i=0; i<n; i++)
|
||||
bgl_sphere_project(staticSine[n-i-1]*ax, staticSine[i]*az);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
static void draw_pose_dofs(Object *ob)
|
||||
{
|
||||
bPoseChannel *pchan;
|
||||
@@ -1111,9 +1186,8 @@ static void draw_pose_dofs(Object *ob)
|
||||
if(bone && !(bone->flag & BONE_HIDDEN_P)) {
|
||||
if(bone->flag & BONE_SELECTED) {
|
||||
if(pose_channel_in_IK_chain(ob, pchan)) {
|
||||
float corner[4][3], vec[4][3], handle1[3], handle2[3];
|
||||
float mat[4][4];
|
||||
float phi=0.0f, theta=0.0f;
|
||||
float corner[4][3], mat[4][4];
|
||||
float phi=0.0f, theta=0.0f, scale;
|
||||
int a, i;
|
||||
|
||||
/* in parent-bone pose, but own restspace */
|
||||
@@ -1125,19 +1199,37 @@ static void draw_pose_dofs(Object *ob)
|
||||
glTranslatef(bone->head[0], bone->head[1], bone->head[2]);
|
||||
Mat4CpyMat3(mat, pchan->bone->bone_mat);
|
||||
glMultMatrixf(mat);
|
||||
|
||||
/* center of the cone */
|
||||
if(pchan->ikflag & BONE_IK_XLIMIT)
|
||||
phi= 0.5*( pchan->limitmin[0]+pchan->limitmax[0]);
|
||||
if(pchan->ikflag & BONE_IK_ZLIMIT)
|
||||
theta= 0.5*(pchan->limitmin[2]+pchan->limitmax[2]);
|
||||
|
||||
/* now move to cone space */
|
||||
glRotatef(phi, 1.0f, 0.0f, 0.0f);
|
||||
glRotatef(theta, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
scale= bone->length*pchan->size[1];
|
||||
glScalef(scale, scale, scale);
|
||||
|
||||
if(pchan->ikflag & BONE_IK_XLIMIT) {
|
||||
if(pchan->ikflag & BONE_IK_ZLIMIT) {
|
||||
float amin[3], amax[3];
|
||||
|
||||
for(i=0; i<3; i++) {
|
||||
amin[i]= sin(pchan->limitmin[i]*M_PI/360.0);
|
||||
amax[i]= sin(pchan->limitmax[i]*M_PI/360.0);
|
||||
}
|
||||
|
||||
glScalef(1.0, -1.0, 1.0);
|
||||
if (amin[0] != 0.0 && amin[2] != 0.0)
|
||||
draw_dof_ellipse(amin[0], amin[2]);
|
||||
if (amin[0] != 0.0 && amax[2] != 0.0)
|
||||
draw_dof_ellipse(amin[0], amax[2]);
|
||||
if (amax[0] != 0.0 && amin[2] != 0.0)
|
||||
draw_dof_ellipse(amax[0], amin[2]);
|
||||
if (amax[0] != 0.0 && amax[2] != 0.0)
|
||||
draw_dof_ellipse(amax[0], amax[2]);
|
||||
glScalef(1.0, -1.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
/* arcs */
|
||||
if(pchan->ikflag & BONE_IK_ZLIMIT) {
|
||||
theta= 0.5*(pchan->limitmin[2]+pchan->limitmax[2]);
|
||||
glRotatef(theta, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
glColor3ub(50, 50, 255); // blue, Z axis limit
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for(a=-16; a<=16; a++) {
|
||||
@@ -1145,14 +1237,20 @@ static void draw_pose_dofs(Object *ob)
|
||||
phi= fac*(M_PI/360.0f)*(pchan->limitmax[2]-pchan->limitmin[2]);
|
||||
|
||||
if(a==-16) i= 0; else i= 1;
|
||||
corner[i][0]= bone->length*sin(phi);
|
||||
corner[i][1]= bone->length*cos(phi);
|
||||
corner[i][0]= sin(phi);
|
||||
corner[i][1]= cos(phi);
|
||||
corner[i][2]= 0.0f;
|
||||
glVertex3fv(corner[i]);
|
||||
}
|
||||
glEnd();
|
||||
|
||||
glRotatef(-theta, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
if(pchan->ikflag & BONE_IK_XLIMIT) {
|
||||
theta= 0.5*( pchan->limitmin[0]+pchan->limitmax[0]);
|
||||
glRotatef(theta, 1.0f, 0.0f, 0.0f);
|
||||
|
||||
glColor3ub(255, 50, 50); // Red, X axis limit
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for(a=-16; a<=16; a++) {
|
||||
@@ -1161,72 +1259,15 @@ static void draw_pose_dofs(Object *ob)
|
||||
|
||||
if(a==-16) i= 2; else i= 3;
|
||||
corner[i][0]= 0.0f;
|
||||
corner[i][1]= bone->length*sin(phi);
|
||||
corner[i][2]= bone->length*cos(phi);
|
||||
corner[i][1]= sin(phi);
|
||||
corner[i][2]= cos(phi);
|
||||
glVertex3fv(corner[i]);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
if(pchan->ikflag & BONE_IK_XLIMIT) {
|
||||
if(pchan->ikflag & BONE_IK_ZLIMIT) {
|
||||
|
||||
/* using corners to draw the influence area */
|
||||
/* we set up beziers for it */
|
||||
|
||||
VecSubf(handle1, corner[2], corner[3]);
|
||||
VecMulf(handle1, 0.27614f); // 0.5 * kappa, 0.5522847498
|
||||
VecSubf(handle2, corner[0], corner[1]);
|
||||
VecMulf(handle2, 0.27614f);
|
||||
|
||||
cpack(0x0);
|
||||
glEnable(GL_MAP1_VERTEX_3);
|
||||
|
||||
/* bezier part */
|
||||
VECCOPY(vec[0], corner[0]); // 0 and 3 are cv's, 1 and 2 handles
|
||||
VecAddf(vec[1], corner[0], handle1);
|
||||
VecAddf(vec[2], corner[2], handle2);
|
||||
VECCOPY(vec[3], corner[2]);
|
||||
glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]);
|
||||
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for(a=0; a<=16; a++) glEvalCoord1f((float)a/16.0);
|
||||
glEnd();
|
||||
|
||||
/* bezier part */
|
||||
VECCOPY(vec[0], corner[2]); // 0 and 3 are cv's, 1 and 2 handles
|
||||
VecSubf(vec[1], corner[2], handle2);
|
||||
VecAddf(vec[2], corner[1], handle1);
|
||||
VECCOPY(vec[3], corner[1]);
|
||||
glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]);
|
||||
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for(a=0; a<=16; a++) glEvalCoord1f((float)a/16.0);
|
||||
glEnd();
|
||||
|
||||
/* bezier part */
|
||||
VECCOPY(vec[0], corner[1]); // 0 and 3 are cv's, 1 and 2 handles
|
||||
VecSubf(vec[1], corner[1], handle1);
|
||||
VecSubf(vec[2], corner[3], handle2);
|
||||
VECCOPY(vec[3], corner[3]);
|
||||
glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]);
|
||||
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for(a=0; a<=16; a++) glEvalCoord1f((float)a/16.0);
|
||||
glEnd();
|
||||
|
||||
/* bezier part */
|
||||
VECCOPY(vec[0], corner[3]); // 0 and 3 are cv's, 1 and 2 handles
|
||||
VecAddf(vec[1], corner[3], handle2);
|
||||
VecSubf(vec[2], corner[0], handle1);
|
||||
VECCOPY(vec[3], corner[0]);
|
||||
glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]);
|
||||
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for(a=0; a<=16; a++) glEvalCoord1f((float)a/16.0);
|
||||
glEnd();
|
||||
}
|
||||
glRotatef(-theta, 1.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
glPopMatrix(); // out of cone, out of bone
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user