Monday, August 27, 2012

Frame of Reference with Physijs Objects

‹prev | My Chain | next›

After cleaning up my Three.js / Physijs rafting game last night, I ended up with more questions than answers. Although I was able to fill in some of the gaps between river segments with last night's work, some gaps were not as filled as others:


I think that part of my problem at least is that I cannot take advantage of my old friend fame-of-reference. Instead of creating a simple frame of reference for a river segment's frame of reference, rotating it, then adding Physijs objects to that frame of reference, I am forced to perform some pretty hairy calculations for each river segment:
function riverSegment(scene, rotation, offset) {
  if (!offset) offset = {x: 0, z: 0};

  var length = 1500
    , sin = Math.sin(rotation)
    , cos = Math.cos(rotation)
    , z_frame = 0.5 * length * sin
    , z_offset = z_frame + offset.z
    , x_frame = 0.5 * length * cos
    , x_offset = x_frame + offset.x
    , new_x = 2 * x_frame + offset.x
    , new_z = 2 * z_frame + offset.z;

  // ...
}
But am I forced to do that?

Now that I think about it, as long as I have Physijs objects everywhere and as long as I add all of them to the the parent object before adding them to the scene, I ought to be able to get myself a frame of reference:
function riverSegment(rotation, offset) {
  if (!offset) offset = {x: 0, z: 0};

  var length = 1500
    , half = length / 2;

  var segment = new Physijs.PlaneMesh(
    new THREE.PlaneGeometry(10, 10),
    new THREE.Material()
  );
  segment.rotation.y = rotation;
  segment.position.x = offset.x;
  segment.position.z = offset.z;
  // ...
}
That segment is effectively a frame of reference. I shift it to the end of the previous segement's X-Z position. Then I rotate it however the river is supposed to be rotated:
  offset = riverSegment(Math.PI/8);
  offset = riverSegment(0, offset);
  offset = riverSegment(0,          offset);
  offset = riverSegment(-Math.PI/8, offset);
  // ...
Since the segment is a PlaneMesh, it will not physically interact with my raft. Since the Material is a top-level Three.Material, it has no visible substance (a subclass is required for it to be visible).

The frame of reference is already rotated, so I can add the water to it and shift it by half its length:
  // ...
  var water = new Physijs.PlaneMesh(
    new THREE.PlaneGeometry(length, 500),
    new THREE.MeshBasicMaterial({color: 0x483D8B})
  );
  water.position.x = half;
  segment.add(water);
  //
Then I add the riverbanks to the water as I have been doing:
 //...
  water.add(bank(-250));
  water.add(bank(250));
  // ...
I can add the joint / river end as I have been doing and add the segment to the scene:
  // ...
  scene.add(segment);
  river_segments.push(water);
  // ...
Again, since everything from the segment frame of reference down to the riverbanks is a Physijs object and since the parent frame of reference is not added to the scene until all objects are added to the frame of reference, Physijs is able to handle the correct physics for everything.

Last up, I still need a little but of trigonometry, but it is much, much simpler than what I had been doing:
  // ...
  return {
    x: Math.cos(rotation) * 1500 + offset.x,
    z: -Math.sin(rotation) * 1500 + offset.z
  };
I still feel as though I need some clean-up. Especially if this is going to be a game that kids will have to write / type in. Still, this is a big improvement over last night.



Day #491

No comments:

Post a Comment