# stabilizing a hkpConstraintChainInstance

## stabilizing a hkpConstraintChainInstance

hi all..

I've built a scenario where i have two "ropes" consisting of constrain chain instances suspended between a fixed rigid body and a movable rigid body, where the latter is pulled by a stiff spring. The intent is to tauten the ropes initially, then remove the constraint at a later time. I've tried playing around with the solver Tau/damping, and rope mass and inertia but it still oscillates unless i slacken the rope. Does anyone know how to get consistently taut ropes?

I'm working with the following code.. to run, place it in DemosPhysicsApiConstraintsBallAndSocketRopeBallAndSocketRopeDemo.cpp .

thanks.. probably an overly turgid example :>(
VanDelayyyy

Time flies like an arrow.
Fruit flies like a banana.
Haiku by G. Marx...

// Example showing rope instability when stretched to (what i think is) full length.
// There are three cubes aligned, in order, along the positive x-axis:
//
// F -------------- M ------------ C
// < ropes > < constraint >
//
// F: fixedCube - anchors two strands of rope. Fixed!
// M: movableCube - constrains the other end of the ropes. Movable!
// markerCube - just a non-colliding marker at the point where the rope is stable.
// C: companionCube - stresses the rope via a stiff spring constraint on the movable cube
//

#include
#include "BallAndSocketRopeDemo.h"
#include
#include
#include
#include
#include
#include
#include
#include

// for debugging
#include
#include "stdio.h"

struct BallAndSocketRopeVariant
{
const char* m_name;
int m_numBodies;
const char* m_details;
};

static const BallAndSocketRopeVariant g_variants[] =
{
{ "Length 10" , 10, "" } // actually numRopeLinks is used
};

void dbgout(char *fmt, ...)
{
char dst[2048];
va_list args;
va_start(args, fmt);
vsprintf_s(dst, sizeof(dst), fmt, args);
strcat_s(dst, sizeof(dst), "
");
OutputDebugStringA(dst);
}

static hkpRigidBody*
createCubeBody(
hkpWorld *world,
hkReal rigidBodyMass,
const hkVector4 &rigidBodyPosition,
const hkVector4 &rigidBodySize,
hkEnum motionType,
bool collidable,
hkReal damping = 0.0f)
{
hkpRigidBodyCinfo info;
hkpBoxShape* rigidBodyShape = new hkpBoxShape(rigidBodySize, 0);

hkpMassProperties massProperties;
hkpInertiaTensorComputer::computeBoxVolumeMassProperties(rigidBodySize, rigidBodyMass, massProperties);
info.m_inertiaTensor = massProperties.m_inertiaTensor;
info.m_mass = rigidBodyMass;
info.m_position = rigidBodyPosition;
info.m_shape = rigidBodyShape;
info.m_motionType = motionType;
if(damping > 0.0f)
{
info.m_angularDamping = damping;
}
if(!collidable)
{
info.m_collisionResponse = hkpMaterial::RESPONSE_NONE; // TBD - may not be correct
}
hkpRigidBody *body = new hkpRigidBody(info);
return body;
}

static void
createRope(
hkpWorld *world,
hkpRigidBody *startBody,
const hkVector4& startBodyPivotPoint,
hkpRigidBody*endBody,
const hkVector4& endBodyPivotPoint,
{
hkpConstraintChainInstance* chainConstraint;
{
hkpShape* capsuleShape = new hkpCapsuleShape( hkVector4(elemHalfSize, 0.0f, 0.0f), hkVector4(-elemHalfSize, 0.0f, 0.0f), linkCapsuleRadius );

hkpRigidBodyCinfo info;
info.m_linearDamping = 0.0f;
info.m_angularDamping = 0.3f;
info.m_friction = 0.0f;
info.m_motionType = hkpMotion::MOTION_SPHERE_INERTIA;
info.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo(1, 1);
{
hkArray beamEndRopeEntities;
beamEndRopeEntities.pushBack(startBody);
hkVector4 startPos = startBody->getPosition();
hkVector4 endPos = endBody->getPosition();
hkVector4 posInc = endPos;
posInc.sub4(startPos);
for (int b = 1; b < numRopeLinks-1; b++)
{
info.m_position = startPos;
hkVector4 incr = posInc;
incr.mul4((hkSimdRealParameter)b);
dbgout("(%f, %f, %f)", info.m_position(0), info.m_position(1), info.m_position(2));

hkReal mass;
hkReal inertiaMultiplier;
info.m_shape = capsuleShape;
mass = 1.0f;
inertiaMultiplier = 100.0f; // slight wobble which goes away after a few seconds
//inertiaMultiplier = 50.0f; // original value.. still get persistent slight wobble near ends
hkpInertiaTensorComputer::setShapeVolumeMassProperties(info.m_shape, inertiaMultiplier * mass, info);
info.m_mass = mass;
{
hkpRigidBody* body = new hkpRigidBody(info);
beamEndRopeEntities.pushBack(body);
}
}

beamEndRopeEntities.pushBack(endBody);

{
{
hkpBallSocketChainData* chainData = new hkpBallSocketChainData();
chainConstraint = new hkpConstraintChainInstance( chainData );

for (int e = 1; e < beamEndRopeEntities.getSize(); e++)
{
if(1 == e)
{
chainData->addConstraintInfoInBodySpace( startBodyPivotPoint, hkVector4( -elemHalfSize, 0.0f, 0.0f) );
&n
bsp; }
else if((beamEndRopeEntities.getSize()-1) == e)
{
chainData->addConstraintInfoInBodySpace( hkVector4(elemHalfSize, 0.0f, 0.0f), endBodyPivotPoint );
}
else
{
chainData->addConstraintInfoInBodySpace( hkVector4(elemHalfSize, 0.0f, 0.0f), hkVector4( -elemHalfSize, 0.0f, 0.0f) );
}
}
chainData->removeReference();
}

chainConstraint->removeReference();
}
for (int i = 1; i < beamEndRopeEntities.getSize()-1; i++)
{
beamEndRopeEntities[i]->removeReference();
}
}
capsuleShape->removeReference();
}
}

BallAndSocketRopeDemo::BallAndSocketRopeDemo(hkDemoEnvironment* env)
: hkDefaultPhysicsDemo(env, DEMO_FLAGS_NO_SERIALIZE)
{
const BallAndSocketRopeVariant& variant = g_variants[env->m_variantId];
{
hkpWorldCinfo info;
info.m_gravity.set(0.0f, 0.0f, -9.81f);
m_world = new hkpWorld( info );
m_world->lock();
m_world->m_wantDeactivation = false;

m_debugViewerNames.pushBack( hkpConstraintViewer::getN
ame() );

setupGraphics();

{
hkpGroupFilter* filter = new hkpGroupFilter();
m_world->setCollisionFilter( filter );
filter->removeReference();
}

}

hkpAgentRegisterUtil::registerAllAgents( m_world->getCollisionDispatcher() );

hkpRigidBody* groundBody;
hkReal groundHalfHeight = 0.1f;
{
hkpRigidBodyCinfo info;
info.m_motionType = hkpMotion::MOTION_FIXED;
info.m_shape = new hkpBoxShape( hkVector4(100.0f, 100.0f, groundHalfHeight) );
info.m_position(2) = - 0.1f;

groundBody = new hkpRigidBody(info);
info.m_shape->removeReference();

groundBody->removeReference();

HK_SET_OBJECT_COLOR( hkUlong(groundBody->getCollidable()), 0xff339933);
}

hkReal cubeHalfSize = 1.0f;

hkReal fixedCubeMass = 1000.0f;
hkVector4 fixedCubePos(0.0f, 0.0f, cubeHalfSize);
hkVector4 cubeSize(cubeHalfSize, cubeHalfSize, cubeHalfSize);
hkpRigidBody *fixedCube = createCubeBody(m_world, fixedCubeMass, fixedCubePos, cubeSize, hkpMotion::MOTION_FIXED, false);

// **************************************************************************************************************
// **************************************************************************************************************
// I think each capsule in the rope contributes the length between the
// two points to the overall length of the rope (the radius doesn't seem to matter) which means that a
// rope with 100 links and a capsule halfsize of .075 (as we have here) should be taut if stretched over 15
// units. Unfortunately, if i stretch over 14 units there is persistent jitter even without introducing any
// additional constraints and fixing the movable cube in place.
// **************************************************************************************************************

hkReal ropeLen = 14.0f; // a little wobble near blocks which settles down using higher rope inertia setting.
//hkReal ropeLen = 14.1f; // very slight persistent jitter near blocks
//hkReal ropeLen = 14.5f; // slight persistent jitter near blocks
//hkReal ropeLen = 14.9f; // significant persistent jitter
hkVector4 movableCubePos(ropeLen, 0.0f, cubeHalfSize);
&n
bsp; hkpRigidBody *movableCube = createCubeBody(m_world, fixedCubeMass, movableCubePos, cubeSize, hkpMotion::MOTION_BOX_INERTIA, true);

// add a marker cube at point where rope is stable
hkVector4 markerCubePos(14.0f, 0.0f, cubeHalfSize);
createCubeBody(m_world, fixedCubeMass, markerCubePos, cubeSize, hkpMotion::MOTION_FIXED, false);

hkReal lenTocompanionCube = 20.0f;
hkVector4 companionCubePos(ropeLen + lenTocompanionCube, 0.0f, cubeHalfSize);
hkReal companionCubeMass = 1000.0f;
//hkReal companionCubeMass = 10000.0f; // doesn't care at slack length
hkpRigidBody *companionCube = createCubeBody(m_world, companionCubeMass, companionCubePos, cubeSize, hkpMotion::MOTION_FIXED, false);

createRope(
m_world,
fixedCube,
hkVector4(0.0f, cubeHalfSize, 0.0f),
movableCube,
hkVector4(0.0f, cubeHalfSize, 0.0f),

createRope(
m_world,
fixedCube,
hkVector4(0.0f, -cubeHalfSize, 0.0f),
movableCube,
hkVector4(0.0f, -cubeHalfSize, 0.0f),

// **************************************************************************************************************
// **************************************************************************************************************
// pull the movable cube towards the companion cube and tighten the rope.. but it jitters persistently.
// **************************************************************************************************************

{
hkpStiffSpringConstraintData* stiffSpringConstraint = new hkpStiffSpringConstraintData();
hkVector4 movableCubePivotPoint(cubeHalfSize, 0.0f, 0.0f);
hkVector4 companionCubePivotPoint(-cubeHalfSize, 0.0f, 0.0f);
hkReal constraintLen = (lenTocompanionCube - 2.0f * cubeHalfSize) - 1.0f; // taut.. persistent jitter
//hkReal constraintLen = lenTocompanionCube - 2.0f * topHalfSize; // ok.. this doesn't shift the movable cube
//hkReal constraintLen = (lenTocompanionCube - 2.0f * topHalfSize) + 1.0f; // ok.. lots of slack
stiffSpringConstraint->setInBodySpace(companionCubePivotPoint, movableCubePivotPoint, constraintLen)
;
}

hkpSolverInfo *solverInfo = m_world->getSolverInfo();
solverInfo->setTauAndDamping(1.0f/2.0f, 0.6f);

m_world->unlock();

{
hkVector4 from(movableCubePos);
hkVector4 to (movableCubePos);
hkVector4 up (0.0f, 0.0f, 1.0f);
setupDefaultCameras( env, from, to, up, 0.1f, 500.0f );
}
}

BallAndSocketRopeDemo::~BallAndSocketRopeDemo()
{
}

hkDemo::Result BallAndSocketRopeDemo::stepDemo()
{
return hkDefaultPhysicsDemo::stepDemo();
}

////////////////////////////////////////////////////////////////////////////////

#if defined(HK_COMPILER_MWERKS)
# pragma force_active on
# pragma fullpath_file on
#endif

static const char helpString[] =
"This shows the low stretch of the new chain constraints";

HK_DECLARE_DEMO_VARIANT_USING_STRUCT( BallAndSocketRopeDemo, PRIME, BallAndSocketRopeVariant, g_variants, helpString );

5 posts / 0 nouveau(x)
Reportez-vous à notre Notice d'optimisation pour plus d'informations sur les choix et l'optimisation des performances dans les produits logiciels Intel.

Hey David,

I haven't had a chance to look through your code in much detail but at first glance I notice that you're setting your cubes' masses to 1000kg each. Have you tried running this with smaller masses? Very large masses can put very large forces into the system which can cause instability as you describe.

Daniel

Played with it a bit more and noticed that the cubes were potentially colliding with the rope capsules in the chain. Fixed this by setting the cube collision filter info to match the rope capsules, but it didn't resolve the jitter.

If the fixed cube is allowed to move and is similarly constrained by another companion cube to create a symmetric arrangement

C1 ------------- M1 ----------------------- M2 ------------- C2
< constraint > < ropes > < constraint >

the ropes/movable cubes jitter persistently even if the movable cubes are constrained such that they are 14.0 units apart.

I tried reducing the mass from 1000 to 100 and 10, but there is significantly more jitter of both cubes and ropes. If the cubes are kept at 1000 they don't seem to be moving rapidly.. just get persistent jitter along the entire rope length.

Page 158 of TFM mentions that
hkConstraintChainData has m_tau, m_damping, and m_cfm settings. They
also recommend an inertia increase for the jittering bodies. I've already tried this and it helped a bit. Guess i can play around with these a bit more..

The latest trial, with constraints on both side of the movable blocks, is below.

// Example showing rope instability when stretched to (what i think is) full length.
// There are five cubes aligned, in order, along the positive x-axis:
//
// C ------------ M -------------- M ------------ C
// < constraint > < ropes > < constraint >
//
// M: movableCube - constrains the ropes. Movable!
// markerCube - just a non-colliding marker at the point where the rope is stable.
// C: companionCube - stresses the rope via a stiff spring constraint on a movable cube
//

#include
#include "BallAndSocketRopeDemo.h"
#include
#include
#include
#include
#include
#include
#include
#include

// for debugging
#include
#include "stdio.h"

struct BallAndSocketRopeVariant
{
const char* m_name;
int m_numBodies;
const char* m_details;
};

static const BallAndSocketRopeVariant g_variants[] =
{
{ "Length 10" , 10, "" } // actually numRopeLinks is used
};

void dbgout(char *fmt, ...)
{
char dst[2048];
va_list args;
va_start(args, fmt);
vsprintf_s(dst, sizeof(dst), fmt, args);
strcat_s(dst, sizeof(dst), "
");
OutputDebugStringA(dst);
}

static hkpRigidBody*
createCubeBody(
hkpWorld *world,
hkReal rigidBodyMass,
const hkVector4 &rigidBodyPosition,
const hkVector4 &rigidBodySize,
hkEnum motionType,
bool collidable,
hkReal damping = 0.0f)
{
hkpRigidBodyCinfo info;
hkpBoxShape* rigidBodyShape = new hkpBoxShape(rigidBodySize, 0);

hkpMassProperties massProperties;
hkpInertiaTensorComputer::compute
BoxVolumeMassProperties(rigidBodySize, rigidBodyMass, massProperties);
info.m_inertiaTensor = massProperties.m_inertiaTensor;
info.m_mass = rigidBodyMass;
info.m_position = rigidBodyPosition;
info.m_shape = rigidBodyShape;
info.m_motionType = motionType;
if(damping > 0.0f)
{
info.m_angularDamping = damping;
}
info.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo(1, 1);
if(!collidable)
{
info.m_collisionResponse = hkpMaterial::RESPONSE_NONE; // TBD - may not be correct
}
hkpRigidBody *body = new hkpRigidBody(info);
return body;
}

static void
createRope(
hkpWorld *world,
hkpRigidBody *startBody,
const hkVector4& startBodyPivotPoint,
hkpRigidBody*endBody,
const hkVector4& endBodyPivotPoint,
{
hkpConstraintChainInstance* chainConstraint;
{
hkpShape* capsuleShape = new hkpCapsuleShape( hkVector4(elemHalfSize, 0.0f, 0.0f), hkVector4(-elemHalfSize, 0.0f, 0.0f), linkCapsuleRadius );

hkpRigidBodyCinfo info;
info.m_linearDamping = 0.0f;
info.m_angularDamping = 0.3f;
info.m_friction = 0.0f;
info.m_motionType = hkpMotion::MOTION_SPHERE_INERTIA;
info.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo(1, 1);
{
hkArray beamEndRopeEntities;
beamEndRopeEntities.pushBack(startBody);
hkVector4 startPos = startBody->getPosition();
hkVector4 endPos = endBody->getPosition();
hkVector4 posInc = endPos;
posInc.sub4(startPos);
for (int b = 1; b < numRopeLinks-1; b++)
{
info.m_position = startPos;
hkVector4 incr = posInc;
incr.mul4((hkSimdRealParameter)b);
&nb
dbgout("(%f, %f, %f)", info.m_position(0), info.m_position(1), info.m_position(2));

hkReal mass;
hkReal inertiaMultiplier;
info.m_shape = capsuleShape;
mass = 1.0f;
inertiaMultiplier = 100.0f; // slight wobble which goes away after a few seconds
//inertiaMultiplier = 50.0f; // original value.. still get persistent slight wobble near ends
hkpInertiaTensorComputer::setShapeVolumeMassProperties(info.m_shape, inertiaMultiplier * mass, info);
info.m_mass = mass;
{
hkpRigidBody* body = new hkpRigidBody(info);
beamEndRopeEntities.pushBack(body);
}
}

beamEndRopeEntities.pushBack(endBody);

{
{
hkpBallSocketChainData* chainData = new hkpBallSocketChainData();
chainConstraint = new hkpConstraintChainInstance( chainData );

for (int e = 1; e < beamEndRopeEntities.getSize(); e++)
{
if(1 == e)
{
chainData->addConstraintInfoInBodySpace( startBodyPivotPoint, hkVector4( -elemHalfSize, 0.0f, 0.0f) );

}
else if((beamEndRopeEntities.getSize()-1) == e)
{
chainData->addConstraintInfoInBodySpace( hkVector4(elemHalfSize, 0.0f, 0.0f), endBodyPivotPoint );
}
else
{
chainData->addConstraintInfoInBodySpace( hkVector4(elemHalfSize, 0.0f, 0.0f), hkVector4( -elemHalfSize, 0.0f, 0.0f) );
}
}
chainData->removeReference();
}

chainConstraint->removeReference();
}
for (int i = 1; i < beamEndRopeEntities.getSize()-1; i++)
{
beamEndRopeEntities[i]->removeReference();
}
}
capsuleShape->removeReference();
}
}

BallAndSocketRopeDemo::BallAndSocketRopeDemo(hkDemoEnvironment* env)
: hkDefaultPhysicsDemo(env, DEMO_FLAGS_NO_SERIALIZE)
{
const BallAndSocketRopeVariant& variant = g_variants[env->m_variantId];
{
hkpWorldCinfo info;
info.m_gravity.set(0.0f, 0.0f, -9.81f);
m_world = new hkpWorld( info );
m_world->lock();
m_world->m_wantDeactivation = false;

m_debugViewerNames.pushBack( hkpConstraintViewer::getName() );

setupGraphics();

&n
bsp; {
hkpGroupFilter* filter = new hkpGroupFilter();
m_world->setCollisionFilter( filter );
filter->removeReference();
}

}

hkpAgentRegisterUtil::registerAllAgents( m_world->getCollisionDispatcher() );

hkpRigidBody* groundBody;
hkReal groundHalfHeight = 0.1f;
{
hkpRigidBodyCinfo info;
info.m_motionType = hkpMotion::MOTION_FIXED;
info.m_shape = new hkpBoxShape( hkVector4(100.0f, 100.0f, groundHalfHeight) );
info.m_position(2) = - 0.1f;

groundBody = new hkpRigidBody(info);
info.m_shape->removeReference();

groundBody->removeReference();

HK_SET_OBJECT_COLOR( hkUlong(groundBody->getCollidable()), 0xff339933);
}

hkReal cubeHalfSize = 1.0f;

hkReal cubeMass = 1000.0f;
hkVector4 movableCube1Pos(0.0f, 0.0f, cubeHalfSize);
hkVector4 cubeSize(cubeHalfSize, cubeHalfSize, cubeHalfSize);
hkpRigidBody *movableCube1 = createCubeBody(m_world, cubeMass, movableCube1Pos, cubeSize, hkpMotion::MOTION_BOX_INERTIA, true);

// **************************************************************************************************************
// **************************************************************************************************************
// I think each capsule in the rope contributes the length between the
// two points to the overall length of the rope (the radius doesn't seem to matter) which means that a
// rope with 100 links and a capsule halfsize of .075 (as we have here) should be taut if stretched over 15
// units. Unfortunately, if i stretch over 14 units there is persistent jitter even without introducing any
// additional constraints and fixing the movable cube in place.
// **************************************************************************************************************

hkReal ropeLen = 14.0f; // a little wobble near blocks which settles down using higher rope inertia setting.
//hkReal ropeLen = 14.1f; // very slight persistent jitter near blocks
//hkReal ropeLen = 14.5f; // slight persistent jitter near blocks
//hkReal ropeLen = 14.9f; // significant persistent jitter
hkVector4 movableCubePos(ropeLen, 0.0f, cubeHalfSize);
hkpRigidBody *movableCube2 = createCubeBody(m_world, cubeMass, movableCubePos, cubeSize, hkpMotion::MO
TION_BOX_INERTIA, true);

// add marker cubes at point where rope is stable
hkVector4 marker2CubePos(14.0f, 0.0f, cubeHalfSize);
createCubeBody(m_world, cubeMass, marker2CubePos, cubeSize, hkpMotion::MOTION_FIXED, false);
hkVector4 marker1CubePos(-14.0f, 0.0f, cubeHalfSize);
createCubeBody(m_world, cubeMass, marker1CubePos, cubeSize, hkpMotion::MOTION_FIXED, false);

hkReal lenTocompanionCube = 20.0f;
hkReal companionCubeMass = 1000.0f;

hkVector4 companionCube2Pos(ropeLen + lenTocompanionCube, 0.0f, cubeHalfSize);
hkpRigidBody *companionCube2 = createCubeBody(m_world, companionCubeMass, companionCube2Pos, cubeSize, hkpMotion::MOTION_FIXED, false);

hkVector4 companionCube1Pos(-(ropeLen + lenTocompanionCube), 0.0f, cubeHalfSize);
hkpRigidBody *companionCube1 = createCubeBody(m_world, companionCubeMass, companionCube1Pos, cubeSize, hkpMotion::MOTION_FIXED, false);

createRope(
m_world,
movableCube1,
hkVector4(0.0f, cubeHalfSize, 0.0f),
movableCube2,
hkVector4(0.0f, cubeHalfSize, 0.0f),

createRope(
m_world,
movableCube1,
hkVector4(0.0f, -cubeHalfSize, 0.0f),
movableCube2,
hkVector4(0.0f, -cubeHalfSize, 0.0f),

// **************************************************************************************************************
// **************************************************************************************************************
// pull the movable cube towards the companion cube and tighten the rope.. but it jitters persistently.
// **************************************************************************************************************

{
hkpStiffSpringConstraintData* stiffSpringConstraint = new hkpStiffSpringConstraintData();
hkVector4 movableCubePivotPoint(cubeHalfSize, 0.0f, 0.0f);
hkVector4 companionCubePivotPoint(-cubeHalfSize, 0.0f, 0.0f);
hkReal constraintLen = (lenTocompanionCube - 2.0f * cubeHalfSize); // taut.. persistent jitter
//hkReal constraintLen = lenTocompanionCube - 2.0f * topHalfSize; // ok.. this doesn't shift the movable cube
&nb
sp; //hkReal constraintLen = (lenTocompanionCube - 2.0f * topHalfSize) + 1.0f; // ok.. lots of slack
stiffSpringConstraint->setInBodySpace(companionCubePivotPoint, movableCubePivotPoint, constraintLen);
}

{
hkpStiffSpringConstraintData* stiffSpringConstraint = new hkpStiffSpringConstraintData();
hkVector4 movableCubePivotPoint(-cubeHalfSize, 0.0f, 0.0f);
hkVector4 companionCubePivotPoint(cubeHalfSize, 0.0f, 0.0f);
hkReal constraintLen = (lenTocompanionCube - 2.0f * cubeHalfSize); // taut.. persistent jitter
//hkReal constraintLen = lenTocompanionCube - 2.0f * topHalfSize; // ok.. this doesn't shift the movable cube
//hkReal constraintLen = (lenTocompanionCube - 2.0f * topHalfSize) + 1.0f; // ok.. lots of slack
stiffSpringConstraint->setInBodySpace(companionCubePivotPoint, movableCubePivotPoint, constraintLen);
}

hkpSolverInfo *solverInfo = m_world->getSolverInfo();
solverInfo->setTauAndDamping(1.0f/2.0f, 0.6f);

m_world->unlock();

{
hkVector4 from(movableCubePos);
hkVector4 to (movableCubePos);
hkVector4 up (0.0f, 0.0f, 1.0f);
setupDefaultCameras( env, from, to, up, 0.1f, 500.0f );
}
}

BallAndSocketRopeDemo::~BallAndSocketRopeDemo()
{
}

hkDemo::Result BallAndSocketRopeDemo::stepDemo()
{
return hkDefaultPhysicsDemo::stepDemo();
}

////////////////////////////////////////////////////////////////////////////////

#if defined(HK_COMPILER_MWERKS)
# pragma force_active on
# pragma fullpath_file on
#endif

static const char helpString[] =
"This shows the low stretch of the new chain constraints";

HK_DECLARE_DEMO_VARIANT_USING_STRUCT( BallAndSocketRopeDemo, PRIME, BallAndSocketRopeVariant, g_variants, helpString );

Got it to settle using some very empirical settings for the chain data m_tau and m_cfg.. the Constraint Force Mixing Parameter was particularly important (whatever that means :>). If the weight of the blocks is dropped to 100, persistent jitter occurs. Increasing the weight to 100000 reduces jitter - i think because in this case the blocks become much harder for the rope capsules to shift. It's all very black box to me right now.

I post the code below in case anyone else may be able to use/improve it.. thanks for your help daniel!

// There are five cubes aligned, in order, along the positive x-axis:
//
// C ------------ M -------------- M ------------ C
// < constraint > < ropes > < constraint >
//
// M: movableCube - constrains the ropes. Movable!
// markerCube - just a non-colliding marker at the point where the rope is stable.
// C: companionCube - stresses the rope via a stiff spring constraint on a movable cube
//

#include
#include "BallAndSocketRopeDemo.h"
#include
#include
#include
#include
#include
#include
#include
#include

// for debugging
#include
#include "stdio.h"

struct BallAndSocketRopeVariant
{
const char* m_name;
int m_numBodies;
const char* m_details;
};

static const BallAndSocketRopeVariant g_variants[] =
{
{ "Length 10" , 10, "" } // actually numRopeLinks is used
};

void dbgout(char *fmt, ...)
{
char dst[2048];
va_list args;
va_start(args, fmt);
vsprintf_s(dst, sizeof(dst), fmt, args);
strcat_s(dst, sizeof(dst), "
");
OutputDebugStringA(dst);
}

static hkpRigidBody*
createCubeBody(
hkpWorld *world,
hkReal rigidBodyMass,
const hkVector4 &rigidBodyPosition,
const hkVector4 &rigidBodySize,
hkEnum motionType,
bool collidable,
hkReal damping = 0.0f)
{
hkpRigidBodyCinfo info;
hkpBoxShape* ri
gidBodyShape = new hkpBoxShape(rigidBodySize, 0);

hkpMassProperties massProperties;
hkpInertiaTensorComputer::computeBoxVolumeMassProperties(rigidBodySize, rigidBodyMass, massProperties);
info.m_inertiaTensor = massProperties.m_inertiaTensor;
info.m_mass = rigidBodyMass;
info.m_position = rigidBodyPosition;
info.m_shape = rigidBodyShape;
info.m_motionType = motionType;
if(damping > 0.0f)
{
info.m_angularDamping = damping;
}
info.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo(1, 1);
if(!collidable)
{
info.m_collisionResponse = hkpMaterial::RESPONSE_NONE; // TBD - may not be correct
}
hkpRigidBody *body = new hkpRigidBody(info);
return body;
}

static void
createRope(
hkpWorld *world,
hkpRigidBody *startBody,
const hkVector4& startBodyPivotPoint,
hkpRigidBody*endBody,
const hkVector4& endBodyPivotPoint,
{
hkpConstraintChainInstance* chainConstraint;
{
hkpShape* capsuleShape = new hkpCapsuleShape( hkVector4(elemHalfSize, 0.0f, 0.0f), hkVector4(-elemHalfSize, 0.0f, 0.0f), linkCapsuleRadius );

hkpRigidBodyCinfo info;
info.m_linearDamping = 0.0f;
info.m_angularDamping = 0.3f;
info.m_friction = 0.0f;
info.m_motionType = hkpMotion::MOTION_SPHERE_INERTIA;
info.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo(1, 1);
{
hkArray beamEndRopeEntities;
beamEndRopeEntities.pushBack(startBody);
hkVector4 startPos = startBody->getPosition();
hkVector4 endPos = endBody->getPosition();
hkVector4 posInc = endPos;
posInc.sub4(startPos);
for (int b = 1; b <
{
info.m_position = startPos;
hkVector4 incr = posInc;
incr.mul4((hkSimdRealParameter)b);
dbgout("(%f, %f, %f)", info.m_position(0), info.m_position(1), info.m_position(2));

hkReal mass;
hkReal inertiaMultiplier;
info.m_shape = capsuleShape;
mass = 1.0f;
inertiaMultiplier = 100.0f; // slight wobble which goes away after a few seconds
//inertiaMultiplier = 50.0f; // original value.. still get persistent slight wobble near ends
hkpInertiaTensorComputer::setShapeVolumeMassProperties(info.m_shape, inertiaMultiplier * mass, info);
info.m_mass = mass;
{
hkpRigidBody* body = new hkpRigidBody(info);
beamEndRopeEntities.pushBack(body);
}
}

beamEndRopeEntities.pushBack(endBody);

{
{
hkpBallSocketChainData* chainData = new hkpBallSocketChainData();
chainConstraint = new hkpConstraintChainInstance( chainData );

// **************************************************************************************************************
// **************************************************************************************************************
// the parameters below were key to getting the rope to settle. Very empir
ical.
// **************************************************************************************************************
chainData->m_cfm = 0.0005f; // this has a strong effect
chainData->m_tau = 0.2f;

for (int e = 1; e < beamEndRopeEntities.getSize(); e++)
{
if(1 == e)
{
chainData->addConstraintInfoInBodySpace( startBodyPivotPoint, hkVector4( -elemHalfSize, 0.0f, 0.0f) );
}
else if((beamEndRopeEntities.getSize()-1) == e)
{
chainData->addConstraintInfoInBodySpace( hkVector4(elemHalfSize, 0.0f, 0.0f), endBodyPivotPoint );
}
else
{
chainData->addConstraintInfoInBodySpace( hkVector4(elemHalfSize, 0.0f, 0.0f), hkVector4( -elemHalfSize, 0.0f, 0.0f) );
}
}
chainData->removeReference();
}

chainConstraint->remove
Reference();
}
for (int i = 1; i < beamEndRopeEntities.getSize()-1; i++)
{
beamEndRopeEntities[i]->removeReference();
}
}
capsuleShape->removeReference();
}
}

BallAndSocketRopeDemo::BallAndSocketRopeDemo(hkDemoEnvironment* env)
: hkDefaultPhysicsDemo(env, DEMO_FLAGS_NO_SERIALIZE)
{
const BallAndSocketRopeVariant& variant = g_variants[env->m_variantId];
{
hkpWorldCinfo info;
info.m_gravity.set(0.0f, 0.0f, -9.81f);
m_world = new hkpWorld( info );
m_world->lock();
m_world->m_wantDeactivation = false;

m_debugViewerNames.pushBack( hkpConstraintViewer::getName() );

setupGraphics();

{
hkpGroupFilter* filter = new hkpGroupFilter();
m_world->setCollisionFilter( filter );
filter->removeReference();
}

}

hkpAgentRegisterUtil::registerAllAgents( m_world->getCollisionDispatcher() );

hkpRigidBody* groundBody;
hkReal groundHalfHeight = 0.1f;
{
hkpRigidBodyCinfo info;
info.m_motionType = hkpMotion::MOTION_FIXED;
info.m_shape = new hkpBoxShape( hkVector4(100.0f, 100.0f, groundHalfHeight) );
info.m_position(2) = - 0.1f;

groundBody = new hkpRigidBody(info);
info.m_shape->removeReference();

groundBody->removeReference();

HK_SET_OBJECT_COLOR( hkUlong(groundBody->getCollidable()), 0xff339933);
}

hkReal cubeHalfSize = 1.0f;

hkReal cubeMass = 1000.0f; // don't set too low i.e. 100 or will get persistent jitter
hkVector4 movableCube1Pos(0.0f, 0.0f, cubeHalfSize);
hkVector4 cubeSize(cubeHalfSize, cubeHalfSize, cubeHalfSize);
//hkpRigidBody *movableCube1 = createCubeBody(m_world, cubeMass, movableCube1Pos, cubeSize, hkpMotion::MOTION_FIXED, true);
hkpRigidBody *movableCube1 = createCubeBody(m_world, cubeMass, movableC
ube1Pos, cubeSize, hkpMotion::MOTION_BOX_INERTIA, true);

// **************************************************************************************************************
// **************************************************************************************************************
// I think each capsule in the rope contributes the length between the
// two points to the overall length of the rope (the radius doesn't seem to matter) which means that a
// rope with 100 links and a capsule halfsize of .075 (as we have here) should be taut if stretched over 15
// units. Unfortunately, if i stretch over 14 units there is persistent jitter even without introducing any
// additional constraints and fixing the movable cube in place.
// **************************************************************************************************************

hkReal ropeLen = 14.0f; // a little wobble near blocks which settles down using higher rope inertia setting.
//hkReal ropeLen = 14.1f; // very slight persistent jitter near blocks
//hkReal ropeLen = 14.5f; // slight persistent jitter near blocks
//hkReal ropeLen = 14.9f; // significant persistent jitter
hkVector4 movableCube2Pos(ropeLen, 0.0f, cubeHalfSize);
//hkpRigidBody *movableCube2 = createCubeBody(m_world, cubeMass, movableCube2Pos, cubeSize, hkpMotion::MOTION_FIXED, true);
hkpRigidBody *movableCube2 = createCubeBody(m_world, cubeMass, movableCube2Pos, cubeSize, hkpMotion::MOTION_BOX_INERTIA, true);

// add marker cubes at point where rope is stable
hkVector4 marker2CubePos(14.0f, 0.0f, cubeHalfSize);
createCubeBody(m_world, cubeMass, marker2CubePos, cubeSize, hkpMotion::MOTION_FIXED, false);
hkVector4 marker1CubePos(0.0f, 0.0f, cubeHalfSize);
createCubeBody(m_world, cubeMass, marker1CubePos, cubeSize, hkpMotion::MOTION_FIXED, false);

hkReal lenTocompanionCube = 20.0f;
hkReal companionCubeMass = 1000.0f;

hkVector4 companionCube2Pos(ropeLen + lenTocompanionCube, 0.0f, cubeHalfSize);
hkpRigidBody *companionCube2 = createCubeBody(m_world, companionCubeMass, companionCube2Pos, cubeSize, hkpMotion::MOTION_FIXED, false);

hkVector4 companionCube1Pos(-lenTocompanionCube, 0.0f, cubeHalfSize);
hkpRigidBody *companionCube1 = createCubeBody(m_world, companionCubeMass, companionCube1Pos, cubeSize, hkpMotion::MOTION_FIXED, false);

createRope(
m_world,
movableCube1,
hkVector4(0.0f, cubeHalfSize, 0.0f),
movableCube2,
hkVector4(0.0f, cubeHalfSize, 0.0f),
&nbsp

createRope(
m_world,
movableCube1,
hkVector4(0.0f, -cubeHalfSize, 0.0f),
movableCube2,
hkVector4(0.0f, -cubeHalfSize, 0.0f),

// **************************************************************************************************************
// **************************************************************************************************************
// pull the movable cube towards the companion cube and tighten the rope.. but it jitters persistently.
// **************************************************************************************************************

{
hkpStiffSpringConstraintData* stiffSpringConstraint = new hkpStiffSpringConstraintData();
hkVector4 movableCubePivotPoint(cubeHalfSize, 0.0f, 0.0f);
hkVector4 companionCubePivotPoint(-cubeHalfSize, 0.0f, 0.0f);
hkReal constraintLen = (lenTocompanionCube - 2.0f * cubeHalfSize)-0.5f; // taut.. persistent jitter
//hkReal constraintLen = lenTocompanionCube - 2.0f * topHalfSize; // ok.. this doesn't shift the movable cube
//hkReal constraintLen = (lenTocompanionCube - 2.0f * topHalfSize) + 1.0f; // ok.. lots of slack
stiffSpringConstraint->setInBodySpace(companionCubePivotPoint, movableCubePivotPoint, constraintLen);
}

{
hkpStiffSpringConstraintData* stiffSpringConstraint = new hkpStiffSpringConstraintData();
hkVector4 movableCubePivotPoint(-cubeHalfSize, 0.0f, 0.0f);
hkVector4 companionCubePivotPoint(cubeHalfSize, 0.0f, 0.0f);
hkReal constraintLen = (lenTocompanionCube - 2.0f * cubeHalfSize)-0.5f; // taut.. persistent jitter
//hkReal constraintLen = lenTocompanionCube - 2.0f * topHalfSize; // ok.. this doesn't shift the movable cube
//hkReal constraintLen = (lenTocompanionCube - 2.0f * topHalfSize) + 1.0f; // ok.. lots of slack
stiffSpringConstraint->setInBodySpace(companionCubePivotPoint, movableCubePivotPoint, constraintLen);
}

hkpSolverInfo *solverInfo = m_world->g
etSolverInfo();
solverInfo->setTauAndDamping(1.0f/2.0f, 0.6f);

m_world->unlock();

{
hkVector4 from(movableCube2Pos);
hkVector4 to (movableCube2Pos);
hkVector4 up (0.0f, 0.0f, 1.0f);
setupDefaultCameras( env, from, to, up, 0.1f, 500.0f );
}
}

BallAndSocketRopeDemo::~BallAndSocketRopeDemo()
{
}

hkDemo::Result BallAndSocketRopeDemo::stepDemo()
{
return hkDefaultPhysicsDemo::stepDemo();
}

////////////////////////////////////////////////////////////////////////////////

#if defined(HK_COMPILER_MWERKS)
# pragma force_active on
# pragma fullpath_file on
#endif

static const char helpString[] =
"This shows the low stretch of the new chain constraints";

HK_DECLARE_DEMO_VARIANT_USING_STRUCT( BallAndSocketRopeDemo, PRIME, BallAndSocketRopeVariant, g_variants, helpString );