Thursday, June 28, 2012

Setting the Camera in Gladius

‹prev | My Chain | next›

I really need to begin investigating the latest version of Gladius. But first, I would like to tackle two problems. One is switching between cameras and the other is targeting a moving object. I think the latter is the harder problem, but since I already started the former last night, I continue now.

I found last night that I could find all Gladius entities with a camera via:
space.findAllWith("Camera");
Furthermore, I was able to remove a camera from an entity with:
var camera = camera_entity.removeComponent("Camera");
Removing a camera from an entity had the desirable side-effect of disabling the camera. Without doing so, multiple cameras would all display at the same time, in the same space. This makes for confusing viewing:



I also found that I could reactivate a camera by adding it back to it original "entity":
camera_entity.addComponent(camera);
Tonight, I would like to take a page from CubicVR.js by adding a setCamera() method to the Space class. I am not ready to add this directly to the Gladius source, so I opt instead for some JavaScript monkey-patching. I have a space object on which I am doing the bulk of the work in my game. So I grab that object's prototype so that I can add setCamera() to it:
    var spacePrototype = Object.getPrototypeOf(space);

    spacePrototype.setCamera = function(camera_name) {
    }
I start this method by disabling all active cameras:
    spacePrototype.setCamera = function(camera_name) {
      this._deactivateAllCameras();
    }
As mentioned, deactivating cameras is as simple as removing the component from its Gladius "entity". So that I can reactivate it later, when I remove each camera, I store it in a private _inactive_cameras instance variable:
    spacePrototype._deactivateAllCameras = function() {
      if (typeof(this._inactive_cameras) == "undefined") {
        this._inactive_cameras = {};
      }

      var all_cameras = this.findAllWith("Camera");
      for (var i=0; i<all_cameras.length; i++) {
        var name = all_cameras[i].name;
        this._inactive_cameras[name] = all_cameras[i].removeComponent("Camera");
      }
    };
In there, I use Space's findAllWith() method just like I did last night. Since I am working on the Space prototype, I am free to refer to the object as this.

With all cameras inactive, I need to activate one of them back in setCamera():
    spacePrototype.setCamera = function(camera_name) {
      this._deactivateAllCameras();

      this.
        findNamed(camera_name).
        addComponent(this._inactive_cameras[camera_name]);

      delete this._inactive_cameras[camera_name];
    };
With that, I can activate one camera with:
space.setCamera("camera2");
Resulting in a single camera view:


And, if I want all of the functionality from the CubicVR.js example, I can switch between cameras ever 240 clock ticks:
    var task = new engine.FunctionTask( function() {
      if (space.clock.time % 240 == 0) {
        space.setCamera(space.camera.name == "camera1" ? "camera2" : "camera1");
      }
      // move the planets ...
    }

That will suffice for now (until Gladius supports this more directly). Up tomorrow, I see if I can get a moving camera to target a moving object.


Day #431

1 comment:

  1. Hey Chris,

    The current situation with cameras is that they are all associated with a single canvas element. Going forward, I want to change the API so that you can associate individual cameras with their own render outputs, either viewports on the canvas element or a texture. This will let you run multiple cameras concurrently in a way that doesn't superimpose the rendered output.

    A

    ReplyDelete