纳金网

标题: Sandy3D应用指南——使用摄像机 [打印本页]

作者: 驰骋的风    时间: 2012-9-25 11:17
标题: Sandy3D应用指南——使用摄像机
这个指南的目标
在这个指南中,我们将学习Camera3D对象的使用,在之前的指南里,我们只是使用摄像机作为整个场景的观察点,但从来没有真正使用过它,就连访问它的属性和方法都没有。

Camera3D 就像是一个静态对象——我们可以对它进行移动、旋转、滚动、倾斜。

知道你可以移动摄像机是很重要的,因为有些时候你会面临着一个两难的局面:我应该移动场景中的物品还是移动摄像机好?

这是我的个人意见:如果你只需要移动一个物品,其它物品留在原来的位置,这时就移动物品。但是如果你想移动所有的物品,就考虑一下只动摄像机。你很快会发现这样做将会更方便和高效。

例如如果你实现了一个3D的迷宫,你可以只画迷宫的墙和通过移动摄像机来探测迷宫。
但我们先不说了先迯一下我们的例子。我决定移动立方体和开始使用其它基本对象:Line3D和T***s.

怎么做?
建立一份Example003.as 文件,代码如下:

下面我们看一下我们从之前的指南中改变了什么?

package {
   import flash.display.Sprite;
   import flash.events.*;
   import flash.ui.*;
   import sandy.core.Scene3D;
   import sandy.core.data.*;
   import sandy.core.scenegraph.*;
   import sandy.materials.*;
   import sandy.materials.attributes.*;
   import sandy.primitive.*;

   public class Example003 extends Sprite {
      private var scene:Scene3D;
      private var camera:Camera3D;

      public function Example003() {
         camera = new Camera3D( 300, 300 );
         //camera.x = 100;
         //camera.y = 100;
         camera.z = -400;
         //camera.lookAt(0,0,0);

         var root:Group = createScene();

         scene = new Scene3D( "scene", this, camera, root );

         addEventListener( Event.ENTER_FRAME, enterFrameHandler );
         stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);

      }

      private function createScene():Group {
         var g:Group = new Group();

         var myXLineine3D = new Line3D( "x-coord", new Vector(-50, 0, 0), new Vector( 50, 0, 0 ));
         var myYLineine3D = new Line3D( "y-coord", new Vector(0, -50, 0), new Vector( 0, 50, 0 ));
         var myZLineine3D = new Line3D( "z-coord", new Vector(0, 0, -50), new Vector( 0, 0, 50 ));

         var t***s:T***s = new T***s( "theT***s", 120, 20);

         var materialAttr:MaterialAttributes = new MaterialAttributes(
                        new LineAttributes( 0.5, 0x2111BB, 0.4 ),
                        new LightAttributes( ***e, 0.1)
                  );

         var material:Material = new ColorMaterial( 0xFFCC33, 1, materialAttr );
         material.lightingEnable = ***e;
         var app:Appearance = new Appearance( material );

         t***s.appearance = app;

         t***s.rotateX = 30;
         t***s.rotateY = 30;

         g.addChild(myXLine);
         g.addChild(myYLine);
         g.addChild(myZLine);
         g.addChild(t***s);

         return g;
      }

      private function enterFrameHandler( event : Event ) : void {
         scene.render();
      }

      private function keyPressed(event:KeyboardEvent):void {
         switch(event.keyCode) {
            case Keyboard.UP:
               camera.tilt +=2;
               break;
            case Keyboard.DOWN:
               camera.tilt -=2;
               break;
            case Keyboard.RIGHT:
               camera.pan -=2;
               break;
            case Keyboard.LEFT:
               camera.pan +=2;
               break;
            case Keyboard.CONTROL:
               camera.roll +=2;
               break;       
            case Keyboard.PAGE_DOWN:
               camera.z -=5;
               break;
            case Keyboard.PAGE_UP:
               camera.z +=5;
               break;       
         }
      }
   }
}


首先我们增加了一些额外的import 语句用于使用一些新的类。    import flash.display.Sprite;

   import flash.events.*;

   import flash.ui.*;

   import sandy.core.Scene3D;

   import sandy.core.data.*;

   import sandy.core.scenegraph.*;

   import sandy.materials.*;

   import sandy.materials.attributes.*;

   import sandy.primitive.*;   import flash.display.Sprite;

   import flash.events.*;

   import flash.ui.*;

   import sandy.core.Scene3D;

   import sandy.core.data.*;

   import sandy.core.scenegraph.*;

   import sandy.materials.*;

   import sandy.materials.attributes.*;

   import sandy.primitive.*;

重定位报像机
如果你查看报像机的代码段,你会发现我增加了三行被注释掉的代码:
camera = new Camera3D( 300, 300 );

//camera.x = 100;

//camera.y = 100;

camera.z = -400;

//camera.lookAt(0,0,0);


   
    //camera.x = 100; // Moves the camera to the right direction
   
   
    //camera.y = 100; // Moves the camera upwards
   
   
    //camera.lookAt(0,0,0); // Set the direction to look at.
   


在第一个swf例子中,我就没使用这些设置(被注释掉了),你可以去掉这些注册看看它的效果。你只要知道你可以通过使用摄像机的x,y,z属性移动摄像机到任意地方。 而且你还可以通用使用camera.lookAt()方法 告诉摄像机哪里是场景的点。

在createScene()方法中,我们增加了代码来创建三条线来作为我们系统的三个主轴。
var myXLineine3D = new Line3D( "x-coord", new Point3D(-50, 0, 0), new Point3D( 50, 0, 0 ));

var myYLineine3D = new Line3D( "y-coord", new Point3D(0, -50, 0), new Point3D( 0, 50, 0 ));

var myZLineine3D = new Line3D( "z-coord", new Point3D(0, 0, -50), new Point3D( 0, 0, 50 ));

这只是简单地用用Point3D类(注意:原文使用的是Vector,经查阅API文档后,发现是使用Point3D类)定义好起点和终点然后画出直线而已。为了让代码更容易读,我没有增加任何外观给它们,所以它们将会以实线来展现。

放置T***s
下一步我们使用一个新的原始形状:T***s
var t***s:T***s = new T***s( "theT***s", 120, 20);

个别人可能还记得几何学(geometry)中的这个物体。构造函数接受三个参数:名称,圆环的半径,圆环截面的半径(它有多粗)。

把物体放置到组里
然后我们把这四个物品(三个坐标线、圆环)放置到根组里。
g.addChild(myXLine);

g.addChild(myYLine);

g.addChild(myZLine);

g.addChild( t***s);

建立事件***
现在我们回到构造造函数里,因为有一个新的事件***放在那里。
addEventListener( Event.ENTER_FRAME, enterFrameHandler );

stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);

第一个事件负责渲染事个场景,另一个负责捕获用户的输入事件:这里是键盘事件(KEY_DOWN事件)。

让我们研究(investigate)一下按键按下时的方法做了什么:
switch(event.keyCode) {

      case Keyboard.UP:

         camera.tilt +=2;

         break;

      case Keyboard.DOWN:

         camera.tilt -=2;

         break;

      case Keyboard.RIGHT:

         camera.pan -=2;

         break;

      case Keyboard.LEFT:

         camera.pan +=2;

         break;

      case Keyboard.CONTROL:

         camera.roll +=2;

         break;

      case Keyboard.PAGE_DOWN:

         camera.z -=5;

         break;

      case Keyboard.PAGE_UP:

         camera.z +=5;

         break;

   }
这个方法根据被按下是按键做出不同的行为。而它做的只是修改了Camera3D对象的一些属性。这个很容易理解,所以我们只需看看结果。



摄像机调焦和调整屏幕尺寸


指南目标
在这个指南里我们有很多用代码渲染3D物品的实际尺寸的需求。我们想我们的摄像机可以为此提供一些帮助...但显然它没有。

前期准备
我们最少要完成了最简单的例子( simplest tutorial. )

视图域,可视点的高度和集距(Field of view, viewport height and focal length)
在Sandy中camera 有表示视图角度的垂直域(vertical field of view angle) 的fov 属性。fov和可视点的高度的关系的图解如下:



在这里我们很容易就可以计算出集距:
var fl:Numer = (viewport.height / 2) / Math.tan (camera.fov / 2 * (Math.PI / 180));
这个平台后面的所有东西看上去都会比“实际”小,而平面前面的东西会显得比实际大。

调整屏幕尺寸
如上文所述,我们怎么在改变屏幕大小时维持对象为1:1的关系呢? 诀窍是捕获Event.RESIZE事件和重置camera的fov属性以维持必要的焦距。下面是实例的代码:

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 planelane3D = 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);
更多分享尽在Web3D纳金网www.narkii.com
作者: 驰骋的风    时间: 2012-9-25 11:51

Sandy3D应用指南——导入外部3D模型2



Sandy3D中文类简介




Sandy3D应用指南——导入外部3D模型




Sandy3D应用指南——使用灯光




Sandy3D应用指南——在3D场景中移动物品




Sandy3D应用指南——使用摄像机





欢迎光临 纳金网 (http://c-www.narkii.com/club/) Powered by Discuz! X2.5