flash on 2010-6-1

by negimochi
PaperVison3D サンプル
* ・BasicViewを使わずに自前で実装
* ・クリックしてアクティブ後、以下のようにしてカメラ操作
*   回転 - ドラッグ
*   平行移動 - [Space]キーを押しながらドラッグ
*   拡大 - マウスホイール
♥0 | Line 279 | Modified 2010-06-03 07:03:21 | MIT License
play

ActionScript3 source code

/**
 * Copyright negimochi ( http://wonderfl.net/user/negimochi )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/e08v
 */

/**
 * PaperVison3D サンプル
 * ・BasicViewを使わずに自前で実装
 * ・クリックしてアクティブ後、以下のようにしてカメラ操作
 *   回転 - ドラッグ
 *   平行移動 - [Space]キーを押しながらドラッグ
 *   拡大 - マウスホイール
 */
package
{
	import flash.display.Sprite;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.ui.Keyboard;
	import flash.geom.Point;
	import flash.geom.Vector3D;
	import org.papervision3d.core.math.Matrix3D;
	import org.papervision3d.objects.DisplayObject3D;
	
	public class TestFlash extends Sprite
	{
		private var pvLayer:Sprite;
		
		private static const ZOOM_SPEED:Number = 1.0;
		private static const MOVE_SPEED:Number = 0.1;
		private static const ROTATE_SPEED:Number = 0.1;
		
		private var pv3d:BasicViewOrg;
		
		private var cameraLookAtTarget:DisplayObject3D;
		private var cameraFollowTarget:DisplayObject3D;
		
		private var mousePoint:Point;
		private var cameraRotX:Number;
		private var cameraRotY:Number;
		
		private var initCameraPos:Vector3D;
		
		private var isSpaceDown:Boolean;
		
		public function TestFlash() 
		{
			// ベースレイヤー
			this.tabEnabled = false;
			this.graphics.beginFill(0xFFFFFF, 1.0);
			this.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
			this.graphics.endFill();
			
			pv3d = new BasicViewOrg( stage.stageWidth, stage.stageHeight, true );
			pv3d.x = 0;
			pv3d.y = 0;
			
			// レイヤーにビューポートを貼り付け
			this.addChild( pv3d );
			
			pv3d.startRendering();
			
			mousePoint = new Point(0, 0);
			initCameraPos = new Vector3D( 
				pv3d.camera.x - pv3d.camera.target.x,
				pv3d.camera.y - pv3d.camera.target.y,
				pv3d.camera.z - pv3d.camera.target.z,
				0
			);
			cameraRotY = Math.atan2( initCameraPos.x, -initCameraPos.z );
			cameraRotX = Math.atan2( initCameraPos.x, initCameraPos.y );
			
			this.stage.addEventListener( MouseEvent.MOUSE_DOWN, cameraMouseDownHandler );
			this.stage.addEventListener( MouseEvent.MOUSE_UP, cameraMouseUpHandler );
			this.stage.addEventListener( MouseEvent.MOUSE_WHEEL, cameraMouseWheelHandler );
			this.stage.addEventListener( KeyboardEvent.KEY_DOWN, keyboardDownHandler );
			this.stage.addEventListener( KeyboardEvent.KEY_UP, keyboardUpHandler );
			
			isSpaceDown = false;
		}
			
		private function keyboardDownHandler(evt:KeyboardEvent):void
		{
			switch( evt.keyCode ) 
			{
				case Keyboard.SPACE : // [Space]
					isSpaceDown = true;
					break;
					
				default: 
			}
		}
		
		private function keyboardUpHandler(evt:KeyboardEvent):void 
		{
			isSpaceDown = false;
		}

		private function cameraMouseWheelHandler(evt:MouseEvent):void 
		{
			pv3d.camera.zoom += evt.delta * ZOOM_SPEED;
			if ( pv3d.camera.zoom < 1.0 ) pv3d.camera.zoom = 1.0;
		}
		
		private function cameraMouseDownHandler(evt:MouseEvent):void 
		{
			mousePoint.x = evt.stageX;
			mousePoint.y = evt.stageY;
			this.stage.addEventListener(MouseEvent.MOUSE_MOVE, cameraMouseMoveHandler);
		}
		
		private function cameraMouseMoveHandler(evt:MouseEvent):void
		{
			var dx:Number = mousePoint.x - evt.stageX;
			var dy:Number = evt.stageY - mousePoint.y;
			
			if (isSpaceDown) {
				// カメラ -> カメラ視点のベクトル(スクリーンの法線ベクトルの算出)
				var nx:Number = pv3d.camera.target.x - pv3d.camera.x;
				var ny:Number = pv3d.camera.target.y - pv3d.camera.y;
				var nz:Number = pv3d.camera.target.z - pv3d.camera.z;
				var vectorLength:Number = Math.sqrt(nx * nx + ny * ny + nz * nz);
				// 単位ベクトル化
				nx /= vectorLength;
				ny /= vectorLength;
				nz /= vectorLength;
				
				// スクリーンのX方向を表すベクトル
				var ux:Number = nz;
				var uy:Number = 0;
				var uz:Number = -nx;
				vectorLength = Math.sqrt(ux * ux + uy * uy + uz * uz);
				// 単位ベクトル化
				ux /= vectorLength;
				uy /= vectorLength;
				uz /= vectorLength;
				
				// スクリーンのY方向を表すベクトル
				var vx:Number = -nx * ny;
				var vy:Number = nx * nx + nz * nz;
				var vz:Number = -nz * ny;
				vectorLength = Math.sqrt(vx * vx + vy * vy + vz * vz);
				// 単位ベクトル化
				vx /= vectorLength;
				vy /= vectorLength;
				vz /= vectorLength;
				
				// カメラとカメラ視点の更新
				pv3d.camera.x += ux * dx + vx * dy;
				pv3d.camera.y += uy * dx + vy * dy;
				pv3d.camera.z += uz * dx + vz * dy;
				pv3d.camera.target.x += ux * dx + vx * dy;
				pv3d.camera.target.y += uy * dx + vy * dy;
				pv3d.camera.target.z += uz * dx + vz * dy;
			}
			else {
				// X軸の回転角を算出
				cameraRotX = cameraRotX - dy * ROTATE_SPEED;
				if(-89 >= cameraRotX) {
					cameraRotX = -89;
				}
				else if(89 <= cameraRotX) {
					cameraRotX = 89;
				}
				// Y軸の回転角を算出
				cameraRotY = cameraRotY - dx * ROTATE_SPEED;
				
				// 行列演算
				var oldPoint:Matrix3D = new Matrix3D(
									   [initCameraPos.x, initCameraPos.y, initCameraPos.z, 1,
										0, 0, 0, 0,
										0, 0, 0, 0]);
				var rotateX:Matrix3D = Matrix3D.rotationX( cameraRotX * Math.PI / 180 );
				var rotateY:Matrix3D = Matrix3D.rotationY( cameraRotY * Math.PI / 180 );
				var newPoint:Matrix3D = Matrix3D.multiply( Matrix3D.multiply(oldPoint, rotateX), rotateY );
				
				pv3d.camera.x = newPoint.n11 + pv3d.camera.target.x;
				pv3d.camera.y = newPoint.n12 + pv3d.camera.target.y;
				pv3d.camera.z = newPoint.n13 + pv3d.camera.target.z;
			}
			
			// マウス位置の更新
			mousePoint.x = evt.stageX;
			mousePoint.y = evt.stageY;
		}
		
		private function cameraMouseUpHandler(evt:MouseEvent):void {
			trace("cameraMouseUpHandler");
			mousePoint.x = evt.stageX;
			mousePoint.x = evt.stageY;
			this.stage.removeEventListener(MouseEvent.MOUSE_MOVE, cameraMouseMoveHandler);
		}
	}
	
}

import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.events.Event;
import org.papervision3d.materials.shadematerials.GouraudMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.render.BasicRenderEngine;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.layer.ViewportLayer;
import org.papervision3d.view.Viewport3D;
import org.papervision3d.view.BasicView;
import org.papervision3d.lights.PointLight3D;
import org.papervision3d.cameras.Camera3D;
import org.papervision3d.core.geom.Lines3D;
import org.papervision3d.core.geom.renderables.Vertex3D; 
import org.papervision3d.materials.special.LineMaterial;
import org.papervision3d.core.proto.MaterialObject3D;
import org.papervision3d.objects.primitives.Sphere;

internal class BasicViewOrg extends Sprite {
	private static const INIT_CAMERA_X:int = 0;
	private static const INIT_CAMERA_Y:int = 100;
	private static const INIT_CAMERA_Z:int = -400;
	private static const INIT_CAMERA_ZOOM:int = 10;
	private static const INIT_CAMERA_FOCUS:int = 20;
	
	private static const INIT_TARGET_X:int = 0;
	private static const INIT_TARGET_Y:int = 0;
	private static const INIT_TARGET_Z:int = 0;
	
	private static const INIT_LIGHT_X:int = 500;
	private static const INIT_LIGHT_Y:int = 500;
	private static const INIT_LIGHT_Z:int = -200;
	
	// 3D基本要素
	private var scene:Scene3D;
	private var _camera:Camera3D;
	private var viewport:Viewport3D;	
	private var renderer:BasicRenderEngine;
	
	// ライト
	private var light:PointLight3D;
	
	// 軸
	private var axisXMaterial:LineMaterial; // X軸マテリアル
	private var axisYMaterial:LineMaterial; // Y軸マテリアル
	private var axisZMaterial:LineMaterial; // Z軸マテリアル
	private var axisXLine:Lines3D;          // X軸コンテナ
	private var axisYLine:Lines3D;          // Y軸コンテナ
	private var axisZLine:Lines3D;          // Z軸コンテナ
	
	// ベースライン
	private var _flagAxis:Boolean;
	
	private var container:DisplayObject3D;
	
	public function BasicViewOrg(viewportWidth:Number = 640, viewportHeight:Number = 320, initFlagAxis:Boolean = true) {
		_flagAxis = initFlagAxis;
		
		// シーン設定
		renderer = new BasicRenderEngine();
		scene = new Scene3D();
		
		// ビューポートの設定
		viewport = new Viewport3D(viewportWidth, viewportHeight, false, true, true, true);
		viewport.x = 0;
		viewport.y = 0;
		viewport.opaqueBackground = 0xcccccc;
		this.addChild( viewport );
		
		// カメラ設定
		var cameraTarget:DisplayObject3D = new DisplayObject3D();
		cameraTarget.x = INIT_TARGET_X;
		cameraTarget.y = INIT_TARGET_Y;
		cameraTarget.z = INIT_TARGET_Z;
		
		_camera = new Camera3D();
		_camera.target = cameraTarget;
		_camera.x = INIT_CAMERA_X;
		_camera.y = INIT_CAMERA_Y;
		_camera.z = INIT_CAMERA_Z;
		_camera.zoom = INIT_CAMERA_ZOOM;
		_camera.focus = INIT_CAMERA_FOCUS;
					
		//シーンのオブジェクトを生成
		createSceneObject();
	}
	
	/**
	 * レンダリング開始
	 */
	public function startRendering():void
	{
		addEventListener(Event.ENTER_FRAME, enterFrameHander);
	}
	
	//// private /////////////////////////////////////////////////////////////////////////////////////
	private function enterFrameHander(evt:Event):void
	{
		renderer.renderScene(scene, _camera, viewport);
	}
	
	private function createSceneObject():void {
		// ライトの設定
		light = new PointLight3D(false);
		light.x = INIT_LIGHT_X;
		light.y = INIT_LIGHT_Y;
		light.z = INIT_LIGHT_Z;
		scene.addChild(light);
		
		// 軸の描画(デバッグ専用)
		if (_flagAxis) {
			createAxis();
		}
	}
			
	private function createAxis():void {
		axisXMaterial = new LineMaterial(0xFF0000, 0.5); // X軸マテリアル
		axisYMaterial = new LineMaterial(0x00FF00, 0.5); // Y軸マテリアル
		axisZMaterial = new LineMaterial(0x0000FF, 0.5); // Z軸マテリアル
		
		axisXMaterial.interactive = true;
		axisYMaterial.interactive = true;
		axisZMaterial.interactive = true;
		
		axisXLine = new Lines3D(axisXMaterial);           // コンテナ
		axisYLine = new Lines3D(axisYMaterial);           // コンテナ
		axisZLine = new Lines3D(axisZMaterial);           // コンテナ
		
		axisXLine.addNewLine(1, 0, 0, 0, 
								50, 0, 0);
		
		axisYLine.addNewLine(1, 0, 0, 0, 
								0, 50, 0);
		
		axisZLine.addNewLine(1, 0, 0, 0, 
								0, 0, 50);
		
		scene.addChild(axisXLine);
		scene.addChild(axisYLine);
		scene.addChild(axisZLine);
	}
	
	private function deleteAxis():void {
		// materialのインタラクティブを切ってからremove
		if(axisXMaterial != null) {
			axisXMaterial.interactive = false;
			axisXMaterial.destroy();
			axisXMaterial = null;
		}
		if(axisYMaterial != null) {
			axisYMaterial.interactive = false;
			axisYMaterial.destroy();
			axisYMaterial = null;
		}
		if(axisZMaterial != null) {
			axisZMaterial.interactive = false;
			axisZMaterial.destroy();
			axisZMaterial = null;
		}
		scene.removeChild(axisXLine);
		scene.removeChild(axisYLine);
		scene.removeChild(axisZLine);
	}
	
	//// setter ////////////////////////////////////////////////////////////////
	/**
	 * _flagAxis
	 * @param setFlag
	 */
	public function set flagAxis(setFlag:Boolean):void 
	{
		if (_flagAxis && !setFlag) {
			_flagAxis = setFlag;
			deleteAxis();
		}
		else if (!_flagAxis && setFlag) {
			_flagAxis = setFlag;
			createAxis();
		}
	}
	
	//// getter ////////////////////////////////////////////////////////////////
	/**
	 * _camera
	 */
	public function get camera():Camera3D
	{
		return _camera;
	}
	
}

Forked