JoeJ wrote:edit: I see that you added a comment to you joint, after get your later, please post again so that I can take a look. Meant time I will on over the custom Power rag doll
You mean the the comment "Dont copy code, there are bugs"?
I have already fixed and posted in the next reply (not sure if the quote below here can capture all the code correctly).
I did some work on my smoothing idea and it seems promising. It may be a improvement anywhere where gramm schmidt is being used. It works by caching this orientation relative to the parent body, and allow it to rotate it only by a maximum acceleration.
JoeJ wrote:Re: Joints stiffness
Post by JoeJ » Tue Jul 14, 2015 6:59 pm
I have fixed all bugs, now it should be a good test.
Animation and linear mode working now.
You can see my joints are less stiff than yours.
But it does not reproduce my problem that angular mode has for my ragdoll.
I will see if it's a matter of complexity, tweaking or bugs...
Joint code:
Code: Select all
struct JoesRagdollJoint
{
NewtonBody* m_body0;
NewtonBody* m_body1; // parent
dMatrix m_localMatrix0;
dMatrix m_localMatrix1;
NewtonJoint* m_joint;
dQuaternion m_target; // relative target rotatation to reach at next timestep
float m_reduceError;
float m_pin_length;
float m_angularFriction;
float m_linearFriction;
float m_stiffness;
bool m_useLienarMotor;
float m_anim_speed;
float m_anim_offset;
float m_anim_time;
JoesRagdollJoint (NewtonBody* child, NewtonBody* parent, const dMatrix &localMatrix0, const dMatrix &localMatrix1, NewtonWorld *world)
{
m_body0 = child;
m_body1 = parent;
m_localMatrix0 = localMatrix0;
m_localMatrix1 = localMatrix1;
m_target = dQuaternion (dVector(1.0f,0,0), 0.0f);
m_joint = NewtonConstraintCreateUserJoint (world, 6, JoesRagdollJoint::Callback, 0, child, parent);
NewtonJointSetUserData (m_joint, (void*) this);
m_reduceError = 0.2f; // amount of error to reduce per timestep (more -> oszillation)
m_pin_length = 10.0f;
m_angularFriction = 300.0f;
m_linearFriction = 100.0f;
m_stiffness = 0.9f;
m_useLienarMotor = false;
m_anim_speed = 0.0f;
m_anim_offset = 0.0f;
m_anim_time = 0.0f;
}
void SubmitConstraints (dFloat timestep, int threadIndex)
{
float invTimestep = 1.0f / timestep;
dMatrix body0Matrix; NewtonBodyGetMatrix(m_body0, &body0Matrix[0][0]);
dMatrix body1Matrix; NewtonBodyGetMatrix(m_body1, &body1Matrix[0][0]);
dMatrix matrix0 = m_localMatrix0 * body0Matrix;
dMatrix matrix1 = m_localMatrix1 * body1Matrix;
if (m_anim_speed != 0.0f) // some animation to illustrate purpose
{
m_anim_time += timestep * m_anim_speed;
float a0 = sin (m_anim_time);
float a1 = m_anim_offset * 3.14f;
dVector axis (sin(a1), 0.0f, cos(a1));
//dVector axis (1,0,0);
m_target = dQuaternion (axis, a0 * 0.5f);
}
// point to point constraint
dVector p0 (matrix0.m_posit);
dVector p1 (matrix1.m_posit);
NewtonUserJointAddLinearRow (m_joint, &p0[0], &p1[0], &matrix1.m_front[0]);
NewtonUserJointAddLinearRow (m_joint, &p0[0], &p1[0], &matrix1.m_up[0]);
NewtonUserJointAddLinearRow (m_joint, &p0[0], &p1[0], &matrix1.m_right[0]);
// measure error
dQuaternion q0 (matrix0);
dQuaternion q1 (matrix1);
dQuaternion qt0 = m_target * q1;
dQuaternion qErr = (q0.DotProduct(qt0) < 0.0f
? dQuaternion (-q0.m_q0, q0.m_q1, q0.m_q2, q0.m_q3)
: dQuaternion ( q0.m_q0, -q0.m_q1, -q0.m_q2, -q0.m_q3)) * qt0;
float errorAngle = 2.0f * acos (max (-1.0f, min (1.0f, qErr.m_q0)));
if (errorAngle < 1.0e-10f)
{
// error is tiny - do we need to make a fixed joint / some damping here?
// To me it seems ok to do nothing.
}
else
{
dVector errorAxis (qErr.m_q1, qErr.m_q2, qErr.m_q3, 0.0f);
errorAxis = errorAxis.Scale(1.0f / dSqrt (errorAxis % errorAxis));
// fix rotation axis
dVector pin = p1 + errorAxis.Scale(m_pin_length);
dMatrix basis (dGrammSchmidt (errorAxis));
NewtonUserJointAddLinearRow (m_joint, (float*)&pin, (float*)&pin, (float*)&basis[1]);
NewtonUserJointAddLinearRow (m_joint, (float*)&pin, (float*)&pin, (float*)&basis[2]);
dVector angVel0, angVel1;
NewtonBodyGetOmega (m_body0, (float*)&angVel0);
NewtonBodyGetOmega (m_body1, (float*)&angVel1);
// motor
if (!m_useLienarMotor) // default angular motor
{
dVector errorAngVel = errorAxis.Scale (errorAngle * invTimestep * m_reduceError) - (angVel0 - angVel1);
NewtonUserJointAddAngularRow (m_joint, 0.0f, &errorAxis[0]);
NewtonUserJointSetRowAcceleration (m_joint, errorAxis % errorAngVel * invTimestep);
NewtonUserJointSetRowMinimumFriction (m_joint, -m_angularFriction);
NewtonUserJointSetRowMaximumFriction (m_joint, m_angularFriction);
NewtonUserJointSetRowStiffness (m_joint, m_stiffness);
}
else // linear motor
{
// construct two pins that remove error if they match
dVector pin0 (p1 + basis[1].Scale(m_pin_length));
dVector pin1 (p1 + ( basis[2].Scale(sin(errorAngle)) + basis[1].Scale(cos(errorAngle)) ).Scale(m_pin_length));
dVector diff = pin1 - pin0;
// calculate velocity at pins
dVector linVel0, linVel1;
NewtonBodyGetVelocity (m_body0, (float*)&linVel0);
NewtonBodyGetVelocity (m_body1, (float*)&linVel1);
dVector com0, com1;
NewtonBodyGetCentreOfMass (m_body0, (float*)&com0);
NewtonBodyGetCentreOfMass (m_body1, (float*)&com1);
com0 = body0Matrix.TransformVector (com0);
com1 = body1Matrix.TransformVector (com1);
dVector v0 (angVel0 * (pin0 - com0) + linVel0);
dVector v1 (angVel1 * (pin1 - com1) + linVel1);
dVector relAcc ( (diff.Scale(m_reduceError * invTimestep) - (v0 - v1)).Scale(invTimestep) );
diff = diff.Scale (1.0f / sqrt(diff % diff));
NewtonUserJointAddLinearRow (m_joint, (float*)&pin0, (float*)&pin1, (float*)&diff);
NewtonUserJointSetRowAcceleration (m_joint, relAcc % diff);
NewtonUserJointSetRowMinimumFriction (m_joint, -m_linearFriction);
NewtonUserJointSetRowMaximumFriction (m_joint, m_linearFriction);
NewtonUserJointSetRowStiffness (m_joint, m_stiffness);
}
}
}
static void Callback (const NewtonJoint* joint, float timestep, int threadIndex)
{
JoesRagdollJoint *custom = (JoesRagdollJoint*) NewtonJointGetUserData(joint);
custom->SubmitConstraints (timestep, threadIndex);
}
};
Setup code:
Code: Select all
void AddJoesPoweredRagDoll (DemoEntityManager* const scene, const dVector& origin, const int jointType = 1, const float animSpeed = 0.0f, const int numSegments = 4)
{
float height = 1.0f;
float width = 4.0f;
dVector size (width, height, width);
NewtonBody* parent = CreateBox (scene, origin + dVector (0.0f, 0.5f, 0.0f, 0.0f), size);
#ifdef _USE_HARD_JOINTS
NewtonSkeletonContainer* const skeleton = NewtonSkeletonContainerCreate (scene->GetNewton(), parent, NULL);
#endif
for (int i=0; i<numSegments; i++)
{
float height = 1.0f;
float width = 0.5f;
dVector size (width, height, width);
NewtonBody* child = CreateBox (scene, origin + dVector (0.0f, 0.5f + height * float(i+1), 0.0f, 0.0f), size);
if (jointType == 0) // Julios
{
dMatrix pinMatrix = dGrammSchmidt (dVector (0.0f, -1.0f, 1.0f, 0.0f));
dMatrix matrix0; NewtonBodyGetMatrix (parent, &matrix0[0][0]);
dMatrix matrix1; NewtonBodyGetMatrix (child, &matrix1[0][0]);
pinMatrix.m_posit = (matrix0.m_posit + matrix1.m_posit).Scale (0.5f);
CustomControlledBallAndSocket* const joint = new CustomControlledBallAndSocket (pinMatrix, child, parent);
}
else
{
dMatrix matrix0 = dGetIdentityMatrix(); matrix0.m_posit = dVector (0.0f, height*-0.5f, 0.0f, 1.0f);
dMatrix matrix1 = dGetIdentityMatrix(); matrix1.m_posit = dVector (0.0f, height*0.5f, 0.0f, 1.0f);
JoesRagdollJoint* joint = new JoesRagdollJoint (child, parent, matrix0, matrix1, scene->GetNewton());
if (jointType == 2) joint->m_useLienarMotor = true;
if (animSpeed != 0.0f) joint->m_anim_speed = animSpeed, joint->m_anim_offset = float(i) / float(numSegments); // animated
}
#ifdef _USE_HARD_JOINTS
NewtonSkeletonContainerAttachBone (skeleton, child, parent);
#endif
parent = child;
}
#ifdef _USE_HARD_JOINTS
NewtonSkeletonContainerFinalize(skeleton);
#endif
}
and this at the bottom:
Code: Select all
AddJoesPoweredRagDoll (scene, dVector (0.0f, 0.0f, -15.0f), 1, 1.5f); // angular + animated
AddJoesPoweredRagDoll (scene, dVector (0.0f, 0.0f, -5.0f), 1); // angular
AddJoesPoweredRagDoll (scene, dVector (0.0f, 0.0f, 5.0f), 2); // linear
AddJoesPoweredRagDoll (scene, dVector (0.0f, 0.0f, 15.0f), 0); // Julio