Yesterday I updated the FrustumCamera3D class of Papervision3D. Time for a short tutorial on this camera!
The main difference between this camera and the other 2 cameras (Camera3D and FreeCamera3D) is that this camera uses a ‘real’ projection matrix, analogue to OpenGL. The FrustumCamera3D has 2 types of projection matrices: perspective and orthographic.
Checkout the example belonging to this tutorial (well: the code below IS the tutorial
.
package { import flash.display.Sprite; import flash.events.*; import flash.geom.Point; import flash.text.TextField; import flash.text.TextFormat; import org.papervision3d.Papervision3D; import org.papervision3d.cameras.*; import org.papervision3d.core.math.*; import org.papervision3d.core.proto.*; import org.papervision3d.materials.*; import org.papervision3d.materials.utils.*; import org.papervision3d.objects.*; import org.papervision3d.objects.primitives.*; import org.papervision3d.render.*; import org.papervision3d.scenes.*; import org.papervision3d.view.*; /** * @author timknip */ public class TutoFrustumCamera3D extends Sprite { /** The PV3D scene to render */ public var scene : Scene3D; /** This PV3D camera */ public var camera : FrustumCamera3D; /** The PV3D renderer */ public var renderer : BasicRenderEngine; /** The PV3D viewport */ public var viewport : Viewport3D; /** Show info */ public var status : TextField; /** * Constructor. */ public function TutoFrustumCamera3D() : void { init(); } /** * Init. */ private function init() : void { // add a textfield initStatusLine(); // used by orbiting / zooming _lastMouse = new Point(); // create a viewport viewport = new Viewport3D(800, 600); // add addChild(viewport); // create a frustum camera with FOV=60, near=10, far=10000 camera = new FrustumCamera3D(viewport, 60, 10, 10000); // create a renderer renderer = new BasicRenderEngine(); // create the scene scene = new Scene3D(); // init the scene initScene(); // mouse listeners stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler); stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler); stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler); // key listener stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler); // render on each frame addEventListener(Event.ENTER_FRAME, render); showInfo(); } /** * Init the scene. */ private function initScene() : void { var materials : MaterialsList = new MaterialsList(); materials.addMaterial(new WireframeMaterial(0xff0000), "front"); materials.addMaterial(new WireframeMaterial(0x0000ff), "back"); materials.addMaterial(new WireframeMaterial(0xffff00), "left"); materials.addMaterial(new WireframeMaterial(0x00ffff), "right"); materials.addMaterial(new WireframeMaterial(0x00ff00), "top"); materials.addMaterial(new WireframeMaterial(0xff00ff), "bottom"); var cube : Cube = new Cube(materials); scene.addChild(cube); } /** * Add a textfield. */ private function initStatusLine() : void { status = new TextField(); addChild(status); status.x = status.y = 5; status.width = 500; status.height = 200; status.multiline = true; status.selectable = false; status.defaultTextFormat = new TextFormat("Arial", 12, 0xffff00); status.text = ""; } /** * Render! */ private function render( event : Event = null ) : void { // orbit the camera camera.orbit(_camTarget, _camPitch, _camYaw, _camDist); // render renderer.renderScene(scene, camera, viewport); } /** * Show some info; */ private function showInfo() : void { var msg : String = "usage:\ndrag to rotate, drag-shift to zoom\n"; msg += "- o: toggle ortho / perspective mode\n"; msg += "- v: increase / decrease(+shift) FOV\n"; msg += "- f: increase / decrease(+shift) camera far-plane\n"; msg += "- n: increase / decrease(+shift) camera near-plane\n\n"; msg += "camera\n- projection mode: " + (camera.ortho?"ortho":"perspective") + "\n"; msg += "- fov: " + camera.fov + " near: " + camera.near + " far: " + camera.far + "\n"; status.text = msg; } /** * * @param event */ private function keyUpHandler( event : KeyboardEvent ) : void { switch(event.keyCode) { case 70: // f if(!camera.ortho) { if(event.shiftKey) camera.far -= 10; else camera.far += 10; } break; case 78: // n if(!camera.ortho) { if(event.shiftKey) camera.near -= 10; else camera.near += 10; } break; case 79: // o camera.ortho = !camera.ortho; break; case 86: // v if(!camera.ortho) { if(event.shiftKey) camera.fov -= 5; else camera.fov += 5; } break; default: break; } showInfo(); } /** * * @param event */ private function mouseDownHandler( event : MouseEvent ) : void { _lastMouse.x = event.stageX; _lastMouse.y = event.stageY; if(event.shiftKey) _zooming = true; else _orbiting = true; } /** * * @param event */ private function mouseMoveHandler( event : MouseEvent ) : void { var dx:Number = _lastMouse.x - event.stageX; var dy:Number = _lastMouse.y - event.stageY; if(_orbiting) { _camYaw += dx * (Math.PI/180); _camPitch -= dy * (Math.PI/180); _camPitch = _camPitch < 0.001 ? 0.001 : _camPitch; _camPitch = _camPitch > Math.PI/2 ? Math.PI/2 : _camPitch; _lastMouse.x = event.stageX; _lastMouse.y = event.stageY; } else if(!camera.ortho && _zooming) { if(_camDist - dy > 10) _camDist -= dy; } else if(camera.ortho && _zooming) { // this is the essential bit to zoom the camera in ortho-mode! camera.orthoScale += (dy * 0.0005); } render(); event.updateAfterEvent(); } /** * * @param event */ private function mouseUpHandler( event : MouseEvent ) : void { _orbiting = _zooming = false; } /** Are we orbiting the camera? */ private var _orbiting : Boolean = false; /** Are we zooming the camera? */ private var _zooming : Boolean = false; /** A Point to keep track of mouse coords */ private var _lastMouse : Point; /** Camera Yaw */ private var _camYaw : Number = -Math.PI/2; /** Camera Pitch */ private var _camPitch : Number = Math.PI/2; /** Camera distance */ private var _camDist : Number = 2000; /** Camera target */ private var _camTarget : DisplayObject3D = DisplayObject3D.ZERO; } }



February 14th, 2008 at 12:59 pm
Thanks for the tutorial.
Still , I can’t get the difference between a frustrum cameras and a FreeCamera3D/Camera3D…
February 14th, 2008 at 5:51 pm
Well, a FrustumCamera uses a Frustum – http://en.wikipedia.org/wiki/Viewing_frustum – to cull objects outside the frustum.
FreeCamera3D and Camera3D don’t use a frustum.
February 17th, 2008 at 5:25 pm
Lian, all I was interested in with the Frustum camera is that it makes it easier to match your PV3D scene to your 3d/compositing programs. The new camera uses a FOV property instead of zoom/focus which are tough to get the right numbers for.
April 8th, 2008 at 8:25 am
Great thanks for this example.
It’s the only source where i’ve found that when we’re orbiting FrustumCamera3D, yaw and pitch should be in radians,
in contrast to FreeCamera3D.
The possibility to orbit a camera around an object is very nice!