Saturday, August 25, 2012

Physijs River Current

‹prev | My Chain | next›

Up today, would like to get the river in my Three.js / Physijs rafting simulation to push the raft. Last night, I tried to accomplish this with Physijs events, but was thwarted in my efforts. Having considered it some, I believe that an events-based approach would not be an appropriate solution, even had I been successful.

So tonight, I give another approach a shot: Three.js rays. The idea here is that on every animation() step, I ask if a ray from the raft pointing straight down impacts a river segment. It should always do so (because the river banks should bound the raft) and I should then be able to query the segment for its rotation so that I can apply a force in the appropriate direction.

I collect the active river segments in a river_segments array. Then, in the animate() function, I call to a function that will use those segments to see where the raft is:
function animate() {
  requestAnimationFrame(animate);
  applyRiverCurrent();
  scene.simulate(); // run physics
  render();
}
In applyRiverCurrent(), I create a ray from the raft down. Then I check to see which active river segment that ray passes through:
function applyRiverCurrent() {
  var ray = new THREE.Ray(
    raft.position,
    new THREE.Vector3(0, -1, 0)
  );
  var intersects = ray.intersectObjects(river_segments);

  console.log(intersects);

  // raft.applyCentralForce(new THREE.Vector3(1e8 * c, 0, 1e8 * s));
}
Once I verify that I am, in fact, seeing the correct river segments in the console.log() output, I apply a force in the appropriate direction:
function applyRiverCurrent() {
  var ray = new THREE.Ray(
    raft.position,
    new THREE.Vector3(0, -1, 0)
  );

  var intersects = ray.intersectObjects(river_segments);
  if (!intersects[0]) return;

  var current_segment = intersects[0].object;
  if (!current_segment) return;

  var angle = -current_segment.rotation.y
    , cos = Math.cos(angle)
    , sine = Math.sin(angle);

  raft.applyCentralForce(
    new THREE.Vector3(1e6 * cos, 0, 1e6 * sine)
  );
}
And oooh! I think that does the trick. When I first start off on my journey, the river current pushes me straight down the river, even though the first segment is rotated:


Momentum carries me into the bank of the second river segment, but it is a Physijs bank, so I bounce off. At this point, the downward current also kicks in, carrying me further downstream.

There is still room for clean-up here. Applying current seems a bit CPU intensive, so I might modulo the application of the river current to some number of clock cycles. Still, it works and it feels like a pretty decent approach, which makes this a good stopping point for today.


Day #489

No comments:

Post a Comment