Tuesday, January 22, 2013

Abusing the Three.js clone method

‹prev | My Chain | next›

Last night I was able to get two Three.js renderers displaying on the same screen. The approach was highly manual—recreating the objects, cameras and positions from the first scene in the second. Tonight, I hope to automate some of that.

I am still working on the animating the phases of the Moon—both from above the Solar System and from the Earth:


When I first tackled simultaneous rendering of multiple cameras, I found that the clone() method was not working well for me. Now that I no longer have multiple things going wrong, I look a little closer at clone(). First off, it is not a public method so I probably should not be using it. It is defined in Object3D, but does not appear in the documentation. Secondly, the API is a bit weird (unsurprising in that it is only meant for internal use).

By default, clone() creates Object3D objects, not new instances of whatever is being cloned. This gets position an similar items, so it presumably is used for cloning size, orientation, and position of things, but not much else. In other words, it is of little use to me in this case. Just to be clear, this is a private method so I have no cause to complain.

Anyhow, to verify that I have an approximate grasp on what is going on here, I clone the light from the main scene into the overlay scene. Instead of relying on the vanilla clone() which is going to return an Object3D instead of the desired DirectionalLight, I supply clone() with an argument—an instance of DirectionalLight:
  var directionalLight = directionalLight.clone(new THREE.DirectionalLight());
  scene2.add( directionalLight );
This does the trick, except that the colors of the Moon are not copied in this approach:


(the Moon is a dull grey instead of white)

This is to be expected since clone() only knows to copy Object3D properties.

So it seems that, if I want what I consider a clone, then I need to do a little prototype hacking:
  THREE.DirectionalLight.prototype.clone = function(){
     var copy = THREE.Object3D.prototype.clone.call(this, new THREE.DirectionalLight());
     copy.color = this.color;
     copy.intensity = this.intensity;
     return copy;
  };
  
  scene2.add(directionalLight.clone());
With this updated clone() in place, I now get the nice, bright Moon that I expected:


I would have to do something similar to get the planet and Moon meshes to clone. I am not sure if that is worth the effort at this point. I do not really need a general purpose solution, especially with all of the other outstanding work needed in 3D Game Programming for Kids. Still, stubborness may win out, in which case I could be back at this tomorrow.


Day #638

1 comment:

  1. I am creating a game with various enemies and I was thinking of using clone to clone a texture that I am using as a sprite map. If you use the same texture for multiple meshes and then try to shift the texture to a new sprite -- all the enemies change sprites. I was thinking cloning the texture might solve the issue and reduce texture swaps. Does that make any sense?

    ReplyDelete