Papervision3D の FreeCamera3D で視点移動

Papervision3D でテクスチャぐるぐる PlaneWorld サンプル その2 by Flex SDK でうまく視点移動できなかった問題を解決できたっぽい。

Papervision3D には視野を司るカメラオブジェクトというのがあって、3Dオブジェクトの世界を描画するには SceneObject3D#renderCamera(camera:CameraObject3D) を使う。
引数の CameraObject3D がカメラオブジェクト。

APIリファレンスを見ると、

The CameraObject3D class is the base class for all the cameras that can be placed in a scene.
A camera defines the view from which a scene will be rendered. Different camera settings would present a scene from different points of view.
3D cameras simulate still-image, motion picture, or video cameras of the real world. When rendering, the scene is drawn as if you were looking through the camera lens.

とある。CameraObject3D はすべてのカメラオブジェクトの一番基本となるクラスらしい。

で、実際にはそこらのサンプルコードを見た感じでは CameraObject3D のサブクラスである Camera3D と FreeCamera3D がよく使われている。

Papervision3D の API リファレンスには、

The Camera3D class creates a camera that views the area around a target object.
The FreeCamera3D class creates a camera that views the area in the direction the camera is aimed.

とある。

Camera3D は目標対象のオブジェクトを見つめている感じのカメラ。カメラをぐるぐる回しても、視界にはいつも目標のオブジェクトが映っている。映画マトリックスのあの有名なグルグルシーンみたいに。

FreeCamera3D はカメラは見ている方向を映す。目標対象は無い。自由に動かせるイメージ。

参考: [PV3D] Camera3DとFreeCamera3D (C-dashi._blog)

動くサンプル

方向キーとShiftキーを組み合わせて前後左右上昇下降な移動が可能。

画像は XB-LIM さん作の Pledge of BAHAMUT { FF3 ULTIMANIAc DATABASE } - ドラゴンクエストの世界地図 を利用しています。

The map image by XB-LIM (Pledge of BAHAMUT { FF3 ULTIMANIAc DATABASE } - The World maps of Dragon Quest)

ソースコード(MovingCamera.as)


package {
  import flash.display.*;
  import flash.events.*;
  import flash.text.*;
 
  import org.papervision3d.scenes.*;
  import org.papervision3d.objects.*;
  import org.papervision3d.cameras.*;
  import org.papervision3d.materials.*;
 
  [SWF(width="400", height="400", backgroundColor="#000000", frameRate="30")]
 
  public class MovingCamera extends Sprite {
 
    private var container : Sprite;
    private var scene     : Scene3D;
    private var camera    : FreeCamera3D;
    private var rootNode  : DisplayObject3D;
 
    // 画像ファイルのパス
    private var imageFilePath:String = "movingcamera.png";
 
    // カメラ移動速度
    private var cameraSpeed : Number = 5;
 
    public function MovingCamera():void {
 
      // リサイズに対応(swfをブラウザで直接ひらいているときとか)
      stage.addEventListener(Event.RESIZE, onStageResize);
 
      // キーボード操作
      stage.addEventListener(KeyboardEvent.KEY_DOWN, keydown);
 
      // 表示用の Sprite オブジェクトを生成
      container = new Sprite();
      container.x = 400 / 2; // at center : swf width  = 400
      //container.y = 400 / 2; // at center : swf height = 400
      container.y = 500;
 
      addChild(container);
 
      // シーンオブジェクトを作る
      scene = new MovieScene3D(container);
 
      // カメラオブジェクトを作る
      camera = new FreeCamera3D();
      camera.x =  0;
      camera.y =  0;
      camera.z =  0;
      camera.focus = 100;
      camera.zoom = 10;
      camera.sort = true;
      camera.rotationX = 60;
 
      // ルートノードを作る
      rootNode = new DisplayObject3D();
      scene.addChild(rootNode);
 
      // 平面世界オブジェクトを作る
      rootNode.addChild(createWorld());
 
      scene.renderCamera(camera);
    }
 
    private function createWorld():DisplayObject3D{
 
      var material:BitmapFileMaterial = new BitmapFileMaterial(imageFilePath);
      material.doubleSided = true;
      material.lineColor = 0x00FF00;
      material.lineAlpha = 1;
 
      var planeSize:int = 400;
      var segment:int = 30;
 
      var p:Plane = new Plane(material, planeSize, planeSize, segment, segment);
      p.x =  0;
      p.y =  0;
      p.z =  0;
      return p;
    }
 
    private function keydown(event:KeyboardEvent):void {
 
      if(event.shiftKey){
        switch(event.keyCode) { // 37← 38↑ 39→ 40↓
          case 37: // 左移動
            camera.x = camera.x - (cameraSpeed * sin(camera.rotationZ + 90));
            camera.y = camera.y + (cameraSpeed * cos(camera.rotationZ + 90));
            break;
          case 38:
            camera.z -= cameraSpeed; // 上昇
            break;
          case 39: // 右移動
            camera.x = camera.x - (cameraSpeed * sin(camera.rotationZ + 270));
            camera.y = camera.y + (cameraSpeed * cos(camera.rotationZ + 270));
            break;
          case 40:
            camera.z += cameraSpeed; // 下降
            break;
        }
      }else{
        switch(event.keyCode) { // 37← 38↑ 39→ 40↓
          case 37: // 右回転
            camera.rotationZ += 1;
            break;
          case 38: // 前進
            camera.x = camera.x - (cameraSpeed * sin(camera.rotationZ));
            camera.y = camera.y + (cameraSpeed * cos(camera.rotationZ));
            break;
          case 39: // 左回転
            camera.rotationZ -= 1;
            break;
          case 40: // 後退
            camera.x = camera.x + (cameraSpeed * sin(camera.rotationZ));
            camera.y = camera.y - (cameraSpeed * cos(camera.rotationZ));
            break;
        }
      }
 
      scene.renderCamera(camera);
    }
 
    private static function sin(degrees:Number):Number{
      return Math.sin(toRadians(degrees));
    }
 
    private static function cos(degrees:Number):Number{
      return Math.cos(toRadians(degrees));
    }
 
    private static function toRadians(degrees:Number):Number{
      return degrees * (Math.PI / 180);
    }
 
     private function onStageResize(event:Event):void {
      container.x = stage.stageWidth  / 2;
      container.y = stage.stageHeight / 2;
    }
    
  }
}

# FreeCamera3D を使わなくても
# 透明で動く目標物を作って、
# それを Camera3D で追いかければ
# けっこう自由に視点移動できるんじゃないだろうか。
# とか思った。

tags: zlashdot Flash Flash Flex Papervision3D

Posted by NI-Lab. (@nilab)