Monday, March 31, 2014

Havok Physics Engine Tutorial Series: Chain

In this tutorial, I will show you how to create a rigid body chain using the simple distance constraint which is wrapped into the hkpStiffSpringConstraint object in the Havok Physics SDK. This tutorial will be building on top of to the Simple Distance Constraint Tutorial and Picking Tutorial that we did earlier.

Creating a Chain using a Simple Distance Constraint
In the previous tutorial, we saw how we could use a distance constraint to limit a pair of rigid bodies. In this tutorial, I will show you how to use a pair of distance constraints to create a chain of rigid bodies.You can pick any rigid body and move it around using the mouse.  So lets get started.

The AddRigidBodies function
This function is defined as follows
void AddRigidBodies() {
//add the falling box
{
hkVector4 halfExtents(0.5f, 0.5f, 0.125f);
hkpBoxShape* boxShape = new hkpBoxShape(halfExtents);
boxShape->setRadius(0.001f);
hkpRigidBodyCinfo ci;
ci.m_shape = boxShape;
ci.m_motionType = hkpMotion::MOTION_DYNAMIC;
const hkReal boxMass(10.0f);
hkMassProperties massProps;
hkpInertiaTensorComputer::computeShapeVolumeMassProperties(boxShape, boxMass, massProps);
ci.setMassProperties(massProps);
for(int i=0;i<MAX_BOXES;++i) {
if(i==(MAX_BOXES-1))
ci.m_motionType = hkpMotion::MOTION_FIXED;
ci.m_position = hkVector4(0.0f,1.0f+i*1.125f,0.0f);
hkpRigidBody* rigidBody = new hkpRigidBody(ci);
boxes.push_back(static_cast<hkpRigidBody*>(g_pWorld->addEntity(rigidBody)));
}
boxShape->removeReference();
//now add springs between adjacent boxes
hkpStiffSpringConstraintData* spring = new hkpStiffSpringConstraintData();
hkpStiffSpringConstraintData* spring2 = new hkpStiffSpringConstraintData();
for(size_t i=0;i<boxes.size()-1;i++) {
hkTransform b1 = boxes[i]->getTransform();
hkTransform b2 = boxes[i+1]->getTransform();
hkVector4f t1 = b1.getTranslation();
hkVector4f t2 = b2.getTranslation();
t1.add(hkVector4f(-0.5,0.5,0));
t2.add(hkVector4f(-0.5,-0.5,0));
spring->setInWorldSpace(b1,b2, t1, t2);
{
hkpConstraintInstance* constraint = new hkpConstraintInstance(boxes[i], boxes[i+1], spring );
g_pWorld->addConstraint(constraint);
constraint->removeReference();
}
t1.add(hkVector4f(1,0,0));
t2.add(hkVector4f(1,0,0));
spring2->setInWorldSpace(b1,b2, t1, t2);
{
hkpConstraintInstance* constraint = new hkpConstraintInstance(boxes[i], boxes[i+1], spring2 );
g_pWorld->addConstraint(constraint);
constraint->removeReference();
}
}
spring->removeReference();
spring2->removeReference();
}
//create the static box where the smaller box will fall
{
hkVector4 halfExtents(20.0f, 2.0f, 20.f);
hkpBoxShape* boxShape = new hkpBoxShape(halfExtents);
hkpRigidBodyCinfo ci;
ci.m_shape = boxShape;
ci.m_position = hkVector4(0, -2, 0);
ci.m_motionType = hkpMotion::MOTION_FIXED;
boxShape->setRadius(0.001f);
hkpRigidBody* rigidBody = new hkpRigidBody(ci);
boxShape->removeReference();
g_pWorld->addEntity(rigidBody)->removeReference();
}
}
view raw Chain_01 hosted with ❤ by GitHub


Lets have a look at this function piece by piece. The AddRigidBodies function first creates a number of blocks. This is similar to how we created the boxes in the Multiple Bouncing Box Tutorial.
hkVector4 halfExtents(0.5f, 0.5f, 0.125f);
hkpBoxShape* boxShape = new hkpBoxShape(halfExtents);
boxShape->setRadius(0.001f);
hkpRigidBodyCinfo ci;
ci.m_shape = boxShape;
ci.m_motionType = hkpMotion::MOTION_DYNAMIC;
const hkReal boxMass(10.0f);
hkMassProperties massProps;
hkpInertiaTensorComputer::computeShapeVolumeMassProperties(boxShape, boxMass, massProps);
ci.setMassProperties(massProps);
for(int i=0;i<MAX_BOXES;++i) {
if(i==(MAX_BOXES-1))
ci.m_motionType = hkpMotion::MOTION_FIXED;
ci.m_position = hkVector4(0.0f,1.0f+i*1.125f,0.0f);
hkpRigidBody* rigidBody = new hkpRigidBody(ci);
boxes.push_back(static_cast<hkpRigidBody*>(g_pWorld->addEntity(rigidBody)));
}
boxShape->removeReference();
view raw Chain_02 hosted with ❤ by GitHub



Next, we create another loop but this time we create a pair of stiff spring constraints. The constraints are placed in parallel between each pair of boxes. The offsets are calculated based on the size of the box.
//now add springs between adjacent boxes
hkpStiffSpringConstraintData* spring = new hkpStiffSpringConstraintData();
hkpStiffSpringConstraintData* spring2 = new hkpStiffSpringConstraintData();
for(size_t i=0;i<boxes.size()-1;i++) {
hkTransform b1 = boxes[i]->getTransform();
hkTransform b2 = boxes[i+1]->getTransform();
hkVector4f t1 = b1.getTranslation();
hkVector4f t2 = b2.getTranslation();
t1.add(hkVector4f(-0.5,0.5,0));
t2.add(hkVector4f(-0.5,-0.5,0));
spring->setInWorldSpace(b1,b2, t1, t2);
{
hkpConstraintInstance* constraint = new hkpConstraintInstance(boxes[i], boxes[i+1], spring );
g_pWorld->addConstraint(constraint);
constraint->removeReference();
}
t1.add(hkVector4f(1,0,0));
t2.add(hkVector4f(1,0,0));
spring2->setInWorldSpace(b1,b2, t1, t2);
{
hkpConstraintInstance* constraint = new hkpConstraintInstance(boxes[i], boxes[i+1], spring2 );
g_pWorld->addConstraint(constraint);
constraint->removeReference();
}
}
spring->removeReference();
spring2->removeReference();
}
view raw Chain_03 hosted with ❤ by GitHub


Finally, we create the ground rigid body as was seen in earlier tutorials.
//create the static box where the smaller box will fall
{
hkVector4 halfExtents(20.0f, 2.0f, 20.f);
hkpBoxShape* boxShape = new hkpBoxShape(halfExtents);
hkpRigidBodyCinfo ci;
ci.m_shape = boxShape;
ci.m_position = hkVector4(0, -2, 0);
ci.m_motionType = hkpMotion::MOTION_FIXED;
boxShape->setRadius(0.001f);
hkpRigidBody* rigidBody = new hkpRigidBody(ci);
boxShape->removeReference();
g_pWorld->addEntity(rigidBody)->removeReference();
}
view raw Chain_04 hosted with ❤ by GitHub


The picking and rigid body manipulation functions are virtually unchanged. I simply copied the code from the picking tutorial and it worked without a problem.

Output
That's all, after compiling and building the given code, you will see a chain of boxes. The top most box is fixed to ensure that the chain does not fall down. The rest of the boxes can be picked. You can pick the box by left clicking and dragging the mouse to reposition it as shown in the following figure.


You can get the full source code from my github repo https://github.com/mmmovania/HavokPhysicsTutorials

Controls:
Left click to rotate, left click on box to pick and reposition
Middle click to zoom
Right click to pan

What's next:
In the next tutorial, I will see if I can do a simple cloth using the simple distance constraint object.

0 comments:

Popular Posts

Copyright (C) 2011 - Movania Muhammad Mobeen. Awesome Inc. theme. Powered by Blogger.