topical media & game development

talk show tell print

graphic-o3d-samples-o3djs-camera.js / js



  /*
   * Copyright 2009, Google Inc.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are
   * met:
   *
   *     * Redistributions of source code must retain the above copyright
   * notice, this list of conditions and the following disclaimer.
   *     * Redistributions in binary form must reproduce the above
   * copyright notice, this list of conditions and the following disclaimer
   * in the documentation and/or other materials provided with the
   * distribution.
   *     * Neither the name of Google Inc. nor the names of its
   * contributors may be used to endorse or promote products derived from
   * this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  
@fileoverview This file contains various camera utility functions for o3d. It puts them in the "camera" module on the o3djs object. Note: This library is only a sample. It is not meant to be some official library. It is provided only as example code.

  
  
  o3djs.provide('o3djs.camera');
  
  o3djs.require('o3djs.util');
  o3djs.require('o3djs.math');
  
  
A Module for camera utilites. @namespace

  
  o3djs.camera = o3djs.camera || {};
  
  
Class to hold Camera information. @constructor
parameter: {!o3djs.math.Matrix4} view The 4-by-4 view matrix.
parameter: {number} zNear near z plane.
parameter: {number} zFar far z plane.
parameter: {!o3djs.math.Vector3} opt_eye The eye position.
parameter: {!o3djs.math.Vector3} opt_target The target position.
parameter: {!o3djs.math.Vector3} opt_up The up vector.

  
  o3djs.camera.CameraInfo = function(view,
                                     zNear,
                                     zFar,
                                     opt_eye,
                                     opt_target,
                                     opt_up) {
    
View Matrix. @type {!o3djs.math.Matrix4}

  
    this.view = view;
  
    
Projection Matrix. @type {!o3djs.math.Matrix4}

  
    this.projection = o3djs.math.matrix4.identity();
  
    
Projection is orthographic. @type {boolean}

  
    this.orthographic = false;
  
    
Near z plane. @type {number}

  
    this.zNear = zNear;
  
    
Far z plane. @type {number}

  
    this.zFar = zFar;
  
    
Field of view in radians. @type {number}

  
    this.fieldOfViewRadians = o3djs.math.degToRad(30);
  
    
Eye position. @type {(!o3djs.math.Vector3|undefined)}

  
    this.eye = opt_eye;
  
    
Target position. @type {(!o3djs.math.Vector3|undefined)}

  
    this.target = opt_target;
  
    
Up Vector. @type {(!o3djs.math.Vector3|undefined)}

  
    this.up = opt_up;
  
    
horizontal magnification for an orthographic view. @type {(number|undefined)}

  
    this.magX = undefined;
  
    
vertical magnification for an orthographic view. @type {(number|undefined)}

  
    this.magY = undefined;
  };
  
  
Sets the CameraInfo to an orthographic camera.
parameter: {number} magX horizontal magnification.
parameter: {number} magY vertical magnification.

  
  o3djs.camera.CameraInfo.prototype.setAsOrthographic = function(
      magX, magY) {
    this.orthographic = true
    this.magX = magX;
    this.magY = magY;
  };
  
  
Sets the CameraInfo to an orthographic camera.
parameter: {number} fieldOfView Field of view in radians.

  
  o3djs.camera.CameraInfo.prototype.setAsPerspective = function(
      fieldOfView) {
    this.orthographic = false;
    this.fieldOfViewRadians = fieldOfView;
  };
  
  
Computes a projection matrix for this CameraInfo using the areaWidth and areaHeight passed in.
parameter: {number} areaWidth width of client area.
parameter: {number} areaHeight heigh of client area.
returns: {!o3djs.math.Matrix4} The computed projection matrix.

  
  o3djs.camera.CameraInfo.prototype.computeProjection = function(
      areaWidth,
      areaHeight) {
    if (this.orthographic) {
      // TODO: figure out if there is a way to make this take the areaWidth
      //     and areaHeight into account. As it is, magX and magY from the
      //     collada file are relative to the aspect ratio of Maya's render
      //     settings which are not available here.
      // var magX = areaWidth * 0.5 / this.magX;
      // var magY = areaHeight * 0.5 / this.magY;
      var magX = this.magX;
      var magY = this.magY;
      this.projection = o3djs.math.matrix4.orthographic(
          -magX, magX, -magY, magY, this.zNear, this.zFar);
    } else {
      this.projection = o3djs.math.matrix4.perspective(
          this.fieldOfViewRadians,  // field of view.
          areaWidth / areaHeight,   // Aspect ratio.
          this.zNear,               // Near plane.
          this.zFar);               // Far plane.
    }
    return this.projection;
  };
  
  
Searches for all nodes with a "o3d.tags" ParamString that contains the word "camera" assuming comma separated words.
parameter: {!o3d.Transform} treeRoot Root of tree to search for cameras.
returns: {!Array.Transform>} Array of camera transforms.

  
  o3djs.camera.findCameras = function(treeRoot) {
    return o3djs.util.getTransformsInTreeByTags(treeRoot, 'camera');
  };
  
  
Creates a object with view and projection matrices using paramters found on the camera 'o3d.projection_near_z', 'o3d.projection_far_z', and 'o3d.perspective_fov_y' as well as the areaWidth and areaHeight passed in.
parameter: {!o3d.Transform} camera Transform with camera information on it.
parameter: {number} areaWidth width of client area.
parameter: {number} areaHeight height of client area.
returns: {!o3djs.camera.CameraInfo} A CameraInfo object.

  
  o3djs.camera.getViewAndProjectionFromCamera = function(camera,
                                                         areaWidth,
                                                         areaHeight) {
    var fieldOfView = 30;
    var zNear = 1;
    var zFar = 5000;
    var eye = undefined;
    var target = undefined;
    var up = undefined;
    var view;
    var math = o3djs.math;
    var cameraInfo;
  
    // Check if any LookAt elements were found for the camera and use their
    // values to compute a view matrix.
    var eyeParam = camera.getParam('collada.eyePosition');
    var targetParam = camera.getParam('collada.targetPosition');
    var upParam = camera.getParam('collada.upVector');
    if (eyeParam != null && targetParam != null && upParam != null) {
      eye = eyeParam.value;
      target = targetParam.value;
      up = upParam.value;
      view = math.matrix4.lookAt(eye, target, up);
    } else {
      // Set it to the orientation of the camera.
      view = math.inverse(camera.getUpdatedWorldMatrix());
    }
  
    var projectionType = camera.getParam('collada.projectionType');
    if (projectionType) {
      zNear = camera.getParam('collada.projectionNearZ').value;
      zFar = camera.getParam('collada.projectionFarZ').value;
  
      if (projectionType.value == 'orthographic') {
        var magX = camera.getParam('collada.projectionMagX').value;
        var magY = camera.getParam('collada.projectionMagY').value;
  
        cameraInfo = new o3djs.camera.CameraInfo(view, zNear, zFar);
        cameraInfo.setAsOrthographic(magX, magY);
      } else if (projectionType.value == 'perspective') {
        fieldOfView = camera.getParam('collada.perspectiveFovY').value;
      }
    }
  
    if (!cameraInfo) {
      cameraInfo = new o3djs.camera.CameraInfo(view, zNear, zFar,
                                                    eye, target, up);
      cameraInfo.setAsPerspective(math.degToRad(fieldOfView));
    }
  
    cameraInfo.computeProjection(areaWidth, areaHeight);
    return cameraInfo;
  };
  
  
Get CameraInfo that represents a view of the bounding box that encompasses a tree of transforms.
parameter: {!o3d.Transform} treeRoot Root of sub tree to get extents from.
parameter: {number} clientWidth width of client area.
parameter: {number} clientHeight height of client area.
returns: {!o3djs.camera.CameraInfo} A CameraInfo object.

  
  o3djs.camera.getCameraFitToScene = function(treeRoot,
                                              clientWidth,
                                              clientHeight) {
    var math = o3djs.math;
    var box = o3djs.util.getBoundingBoxOfTree(treeRoot);
    var target = math.lerp(box.minExtent, box.maxExtent, 0.5);
    var boxDimensions = math.sub(box.maxExtent, box.minExtent);
    var diag = o3djs.math.distance(box.minExtent, box.maxExtent);
    var eye = math.add(target, [boxDimensions[0] * 0.3,
                                boxDimensions[1] * 0.7,
                                diag * 1.5]);
    var nearPlane = diag / 1000;
    var farPlane = diag * 10;
  
    var up = [0, 1, 0];
    var cameraInfo = new o3djs.camera.CameraInfo(
        math.matrix4.lookAt(eye, target, up),
        nearPlane,
        farPlane);
  
    cameraInfo.setAsPerspective(math.degToRad(45));
    cameraInfo.computeProjection(clientWidth, clientHeight);
    return cameraInfo;
  };
  
  
Calls findCameras and takes the first camera. Then calls o3djs.camera.getViewAndProjectionFromCamera. If no camera is found it sets up some defaults.
parameter: {!o3d.Transform} treeRoot Root of tree to search for cameras.
parameter: {number} areaWidth Width of client area.
parameter: {number} areaHeight Height of client area.
returns: {!o3djs.camera.CameraInfo} A CameraInfo object.

  
  o3djs.camera.getViewAndProjectionFromCameras = function(treeRoot,
                                                          areaWidth,
                                                          areaHeight) {
    var cameras = o3djs.camera.findCameras(treeRoot);
  
    if (cameras.length > 0) {
      return o3djs.camera.getViewAndProjectionFromCamera(cameras[0],
                                                         areaWidth,
                                                         areaHeight);
    } else {
      // There was no camera in the file so make up a hopefully resonable default.
      return o3djs.camera.getCameraFitToScene(treeRoot,
                                              areaWidth,
                                              areaHeight);
    }
  };
  
  
Calls findCameras and creates an array of CameraInfos for each camera found.
parameter: {!o3d.Transform} treeRoot Root of tree to search for cameras.
parameter: {number} areaWidth Width of client area.
parameter: {number} areaHeight Height of client area.
returns: {!Array.} A CameraInfo object.

  
  o3djs.camera.getCameraInfos = function(treeRoot, areaWidth, areaHeight) {
    var cameras = o3djs.camera.findCameras(treeRoot);
    var cameraInfos = [];
  
    for (var cc = 0; cc < cameras.length; ++cc) {
      cameraInfos.push(o3djs.camera.getViewAndProjectionFromCamera(
          cameras[cc], areaWidth, areaHeight));
    }
    return cameraInfos;
  };
  
  
Sets the view and projection of a DrawContext to view the bounding box that encompasses the tree of transforms passed. This function is here to help debug a program by providing an easy way to attempt to get your content in front of the camera.
parameter: {!o3d.Transform} treeRoot Root of sub tree to get extents from.
parameter: {number} clientWidth width of client area.
parameter: {number} clientHeight height of client area.
parameter: {!o3d.DrawContext} drawContext DrawContext to set view and projection on.

  
  o3djs.camera.fitContextToScene = function(treeRoot,
                                            clientWidth,
                                            clientHeight,
                                            drawContext) {
    var cameraInfo = o3djs.camera.getCameraFitToScene(treeRoot,
                                                      clientWidth,
                                                      clientHeight);
    drawContext.view = cameraInfo.view;
    drawContext.projection = cameraInfo.projection;
  };
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.