Wednesday, August 15, 2012

I Can Damp Physijs

‹prev | My Chain | next›

I am struggling with damping motion with the Physijs physics engine for Three.js. I have tried a variety of arguments to the setDamping() method, so far to no avail. Depending on how I hit obstacles, my avatar can go into a very long spin:



Mikael Eliasson was kind enough to point me to the GitHub issue that introduced the damping arguments. So it seems that I need to supply two float values to the setDamping() method—one for the linear damping and the other for the rotational damping (hopefully this means that my avatar will stop spinning uncontrollably).

I specify a linear damping of 0.8, which should stop positional motion relatively quickly. I also specify a rotational damping of 1.0, which should stop spins almost immediately. The code:
  a_frame = new Physijs.BoxMesh(
    new THREE.CubeGeometry(250, 250, 250),
    new THREE.Material()
  );
  a_frame.position.y = 125;
  a_frame.setDamping(0.8, 1.0);
Unfortunately, this also proves to have no effect. If I set the velocity in the X-direction:
a_frame.setLinearVelocity({x: 500, y: 0, z: 0});
Then not only does the motion continue for a long time, it never stops.

But...

I eventually realize that, if I manually specify the damping in the JavaScript console and then set the velocity:
a_frame.setDamping(0.8, 1.0);
a_frame.setLinearVelocity({x: 500, y: 0, z: 0});
Then I get my desired behavior. My avatar spurts to the right, but only very briefly before the 0.8 linear damping slows my avatar to a halt.

It only takes a little bit of experimentation to find that setDamping() only has an effect if invoked after the object in question has been added to the scene:
  a_frame = new Physijs.BoxMesh(
    new THREE.CubeGeometry(250, 250, 250),
    new THREE.Material()
  );
  a_frame.position.y = 125;
  a_frame.add(avatar);

  scene.add(a_frame);
  a_frame.setDamping(0.8, 1.0);
In retrospect, I probably should have suspected something like this from my investigation of the Physijs source code. I had thought the method definition more or less a dead-end:
 // Physijs.Mesh.setDamping
 Physijs.Mesh.prototype.setDamping = function ( linear, angular ) {
  if ( this.world ) {
   this.world.execute( 'setDamping', { id: this._physijs.id, linear: linear, angular: angular } );
  }
 };
On the face of it, this seemed to me little more than handing off to the equivalent ammo.js call. Since ammo.js is generated code, I was unable to make heads or tails of it.

The key to the Physijs method, however, is not the subsequent handling of the damping. Rather, it is the conditional that only applies damping if a world (scene) has been defined.

I suppose that, to a certain extent, this makes sense. After all, it would be the world that might exert some friction on an object to stop its motion. But, of course, this was not obvious (at least to me). At any rate, there are a number of Physijs methods that need a world/scene:
  • applyImpulse()
  • applyCentralForce()
  • applyForce()
  • setAngularVelocity()
  • setLinearVelocity()
  • setAngularFactor()
  • setLinearFactor()
  • setDamping()
  • setCcdMotionThreshold()
  • setCcdSweptSphereRadius()
In the end, even a damping of 1.0 is not sufficient to prevent rotation-after-collision entirely. It is probably good enough, though I may explore it a bit more tomorrow. For now, I am thrilled to finally have Physijs damping working.


Day #479

No comments:

Post a Comment