RigidBodyPhysics Example: Ball with Rope
From H3D.org
This simple application demonstrates the use of RigidBodyPhysics engine. A ball and a haptics device are attached to both ends of a elastic rope. As you move around, the ball will float according to the constraint made by the rope.
Alternatively, you can download the example here.
Contents |
Development
General developement flow:
- Create a ball (RigidBody object), attached to a SpringEffect
- Implement force to push the ball towards haptics device
- Implement damping
- Add rope
Create force to the haptics device
Because we'll work with the haptics device, we need to explicitly declare it and assign a name
<DeviceInfo> <AnyDevice DEF='device'> <Shape containerField='stylus'> <Appearance> <Material/> </Appearance> <Sphere radius='0.0025'/> </Shape> </AnyDevice> </DeviceInfo>
The above code also attach the haptics device pointer with a small sphere.
We then proceed to create the ball and its RigidBody's equivalence. After that, add a SpringEffect node and attach its position to the ball's position
In case you don't know, SpringEffect node gives a force to the haptics device based on the distance between it and a fixed point.
<SpringEffect DEF='spr' position='0 0 0' springConstant='40' startDistance='0.1' escapeDistance='1' deviceIndex='0'/>
<ROUTE fromNode="rbbox" fromField="position" toNode="spr" toField="position" />
From the code above, when the haptics device enters the radius of 0.1m within the desired position, SpringEffect (SE) is activated. It will add a force of springConstant * distance to the haptics device towards SpringEffect's position (which is also the ball's position)
Moving the ball
We add a force to the ball to make it move towards the haptics device. Note: According to dynamics physics, these 2 forces are equal but of opposite direction, so make sure the 2 constant are the same.
<ROUTE fromNode='device' fromField='weightedProxyPosition' toNode='PY' toField='devicemove' />
class DeviceMove(SFVec3f): def __init__(self, const): SFVec3f.__init__(self) self.const = const def update(self, event): global device devpos, = self.getRoutesIn() ballpos = rbball.position.getValue() # get pos of haptics device devpos = device.weightedProxyPosition.getValue() deltapos = ballpos - devpos return -self.const*deltapos devicemove = DeviceMove(SpringDemo.INVERT_CONSTANT)
Damping factor
RigidBodyPhysics sometimes doesn't really follow dynamics law. So if we stop here, the ball will keep oscillating with greater and greater amplitude. That's why we need some force to dampen this movement. That is achieved by adding a force of opposite direction to the ball movement and propotional to its velocity.
<ROUTE fromNode="rbbox" fromField="linearVelocity" toNode="PY" toField="dampspring" />
class DampSpring(SFVec3f): def __init__(self, const): SFVec3f.__init__(self) self.const = const def update(self, event): v = event.getValue() return - self.const * v dampspring = DampSpring(SpringDemo.DAMP_CONST)
Combine force
There are now 2 forces (2 SFVec3f objects) coming to the RigidBody object. However RigidBody.forces is of type MFVec3f. The code below will take care of that:
class SumForces( TypedField( MFVec3f, (SFVec3f, SFVec3f) ) ): def update( self, event ): routes = getRoutesIn( self ) ans = [] for r in routes: if isinstance( r, SFVec3f ): ans.append(r.getValue()) return ans sumforces = SumForces() sumforces.route(rbball.forces) devicemove.route(sumforces) dampspring.route(sumforces)
Creating the rope
We use a LineSet and attach 2 end-points to it.
<Shape> <LineSet vertexCount='2'> <Coordinate DEF='coorline' point='0 0 0 0 0 0' /> </LineSet> <Appearance> <Material emissiveColor='0 0 1' /> </Appearance> </Shape> <ROUTE fromNode="rbbox" fromField="position" toNode="PY" toField="drawline" /> <ROUTE fromNode="device" fromField="weightedProxyPosition" toNode="PY" toField="drawline" />
class DrawLine(TypedField(MFVec3f, (SFVec3f, SFVec3f))): def update(self, event): arr = self.getRoutesIn() ans = [] for f in arr: ans.append(f.getValue()) return ans drawline = DrawLine() drawline.route(coorline.point)
Hula
You're done. Simple huh? Any issue please post on the forum.


