This example, showing multiple car models only one of which tracks the camera, demonstrates two key ideas. First, the use of the lookAt
function, which is so useful for practical animation. Secondly, the wrapping of a Three model up as one's own JavaScript object. This is a key idea that keeps code managable in complex applications. Let's discuss object creation first.
function VWBug(scene,loc,loader) {
var that = this;
this.onScene = function(scn) {
that.mesh = scn.getObjectByName("Bug");
that.mesh.material.shininess = 5;
that.mesh.position.copy(loc);
fixMatrix(that.mesh);
scene.add(that.mesh);
};
loader.load( "models/vwbug/vwbug-scene.json", this.onScene );
}
The VWBug
function is an object constructor. You can tell by the fact that it assigns a value to a name starting with this
. This value is an onScene
function similar to those we've seen before.
It may seem a bit silly to have an object with only one method (function). However, it solves a specific function that we've encountered before, namely the problem of needing a separate onScene
function for each model we load.
Note that instead of using this
in onScene
we use that
...which is itself set equal to this
. What's going on here?
The issue is that onScene
is not getting invoked by us, but rather by the Three engine. For some reason, Three has chosen to invoke onScene
with this
set equal to the window. JavaScript grants control of what this
points to to the caller of a method. Usually this control is not used, with the exception of this case and mouse and keyboard event handlers. To work around this issue, we define our own variable (that
) which is set to point to our VWBug
object.
It is now straightforward to use this constructor to load many VWBug models and set each one in a unique location while keeping tabs on their meshes for later animation.
var loader = new THREE.JSONLoader( );
var bug1 = new VWBug(scene,new THREE.Vector3(-5,0,0),loader);
var bug2 = new VWBug(scene,new THREE.Vector3(0,0,0),loader);
var bug3 = new VWBug(scene,new THREE.Vector3(5,0,0),loader);
The animation is all done via these two lines of code from the rendering function.
if (bug2.mesh)
bug2.mesh.lookAt(camera.position);
Ideally, the animation of a model should be done by a method of the model. Note that we only try to animate bug2
if its mesh exists. This test will generally fail the first few frames while the models are being loaded. If there is a mesh to animate, the lookAt
function makes it trivial to point the model at the camera's position, provided the model faces in the +Z direction in its own coordinate system.