Thursday, July 19, 2012

Camera Controls in Three.js

‹prev | My Chain | next›

From yesterday, I have a walking avatar working in Three.js:


Today, I hope to add saunter to the walk. OK, maybe not saunter, but I would like to get the avatar a little more animated by getting the arms to move in rhythm with the legs.

Before worrying about frames of reference and the rotation of the arms, I try this the dumb way. That is, I add a name to the arm objects just as I did the leg objects yesterday:
  var right_arm = limb(material);
  right_arm.name = 'right_arm';
  right_arm.position.x = 150;
  right_arm.position.z = -50;
  right_arm.rotation.z = -Math.PI/3;
Using the name, I can make use of Three.js' getChildByName() to find the arms for later manipulation:
  avatar_left_arm = avatar.getChildByName("left_arm", true);
  avatar_right_arm = avatar.getChildByName("right_arm", true);
  avatar_left_leg = avatar.getChildByName("left_leg", true);
  avatar_right_leg = avatar.getChildByName("right_leg", true);
Lastly, in the render() function that animates my avatar, I add the same exact x-axis rotation to the arms that I did the legs:
var w = 500;
function render() {
  var t_float = clock.getElapsedTime()
    , t = t_float * 1000
    , amplitude = (w/2 - Math.abs((t % (2*w)) - w))/w;

  avatar_left_arm.rotation.x  =    amplitude*(Math.PI/8);
  avatar_right_arm.rotation.x = -1*amplitude*(Math.PI/8);
  avatar_left_leg.rotation.x  =    amplitude*(Math.PI/8);
  avatar_right_leg.rotation.x = -1*amplitude*(Math.PI/8);

  renderer.render(scene, camera);
}
After reloading the page... it actually seems to work:


I am not quite convinced that this is doing what I expect—it may just be a trick of perspective. To find out for certain, I am going to rotate the camera around. I could just hard-code the camera to a different position, refresh the page and look. I think it a better use of my time to figure out how to animate that.

At first I think about doing this manually myself, but stumble across FirstPersonControls. There is no actual documentation, but the code is quite readable. It seems that I need to supply a Camera object, which I have in the standard Three.js init() function:
function init() {
  scene = new THREE.Scene();

  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
  camera.position.z = 1000;
  scene.add(camera);

  controls = new THREE.FirstPersonControls(camera);
  // ...
}
Then, in the usual Three.js render() function, I update the controls:
function render() {
  // ...
  controls.update(clock.getDelta());
}
(I added the clock yesterday)

With that, I get a completely blank page. After some experimentation, I find that, if I start right on top of the avatar and I tune the controls:
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
//  camera.position.z = 1000;
  scene.add(camera);

  controls = new THREE.FirstPersonControls(camera);
  controls.movementSpeed = 1000;
  controls.lookSpeed = 0.125;
  controls.lookVertical = true;
Then I can eventually navigate back to see that my orientation is wrong. I am now underneath my avatar looking up:


It probably should not surprise me, but the FirstPersonControls start moving forward and I have to stop the motion in order to reverse and re-orient so that I can see things.

It turns out that I want the FlyControls, no the first person controls. I am still unclear why the first person controls seemingly ignored my z-axis orientation, but when I uncomment that setting and enable some reasonable FlyControls settings:
function init() {
  scene = new THREE.Scene();

  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
  camera.position.z = 1000;
  scene.add(camera);

  controls = new THREE.FlyControls(camera);
  controls.movementSpeed = 1000;
  controls.rollSpeed = 1.0;
  // ...
}
Then I can again see the avatar when I start. More importantly, I can use the controls to see that I have a seriously messed up avatar when viewed from anywhere other than straight on:


The controls are nice, but the mouse movement on my trackpad causes wild gyration of the camera. To disable, I find the dragToLook property in the source. Setting it to true seems to disable it:
  controls = new THREE.FlyControls(camera);
  controls.movementSpeed = 1000;
  controls.rollSpeed = 1.0;
  controls.dragToLook = true;
With that setting, I would expect that I could click and drag the page to repeat the wild gyrations, but this has no effect. I am not going to worry (for now) about that since I have no use for the behavior.

Satisfied that I have decent camera control, I call it a night. I am going to revisit the way that I build the avatar tomorrow and hopefully ensure that the arm motion is also satisfactory.


Day #452

1 comment: