Erain 3D
-->

Author: Makc
Date: July 22nd 2008
version: 3.0.2

Focusing the camera and handling screen resize

Objective of the tutorial

We had a lot of demand for code to render 3D stuff in its “actual” size, hence this tutorial. And we thought our camera page would provide some help in this… apparently it did not.

Pre-requisites

You should at least complete our simplest tutorial.

Field of view, viewport height and focal length

In Sandy, camera has fov property, which stands for vertical field of view angle. The realtionship between vertical field of view angle and viewport height is illustrated below:

From here, it is fairly easy to calculate focal length:

var fl:Numer = (viewport.height / 2) / Math.tan (camera.fov / 2 * (Math.PI / 180));

Everything behind the plane with wz = fl (a.k.a. focal plane) will appear smaller than it “actually” is, and everything in front of it will appear larger, in pixels.

Handling screen resize

Given the above, how does one maintain 1:1 scale for some plane when the screen is resized? The trick is to catch Event.RESIZE and reset camera.fov to maintain necessary focal length. Here goes example code and FLA to do this:

import flash.display.*;
import flash.events.*;
 
import sandy.core.Scene3D;
import sandy.core.scenegraph.*;
import sandy.primitive.*;
import sandy.materials.*;
 
// make texture, assuming class Texture extends BitmapData
var tex:BitmapData = new Texture (0, 0);
 
// set stage to no-scale mode
stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT;
 
// some standard Sandy stuff
var scene:Scene3D = new Scene3D ("myScene", this, new Camera3D (100, 100), new Group ("myRoot"));
var plane:Plane3D = new Plane3D ("myPlane", tex.height, tex.width);
plane.appearance = new Appearance (new BitmapMaterial (tex));
 
// add plane to scene and render it to fill its view matrix
scene.root.addChild (plane); scene.render ();
 
// finally, make resize handler
function onResize (e:Event):void
{
	// get new stage dimensions
	var w:Number = stage.stageWidth;
	var h:Number = stage.stageHeight;
	// update the viewport
	scene.camera.viewport.width = w;
	scene.camera.viewport.height = h;
	// get plane distance to camera
	var d:Number = plane.getPosition ("camera").getNorm ();
	// focus camera on wz = d for 1:1 scale
	scene.camera.fov = 2 * Math.atan2 (h / 2, d) * (180 / Math.PI);
	// re-render the scene
	scene.render();
}
 
stage.addEventListener (Event.RESIZE, onResize); onResize (null);

fov.zip

Hope it helps.