forked from: forked from: flash on 2010-6-1
forked from forked from: flash on 2010-6-1 (diff: 534)
PaperVison3D サンプル ・BasicViewを使わずに自前で実装 ・クリックしてアクティブ後、以下のようにしてカメラ操作 回転 - ドラッグ 平行移動 - [Space]キーを押しながらドラッグ 拡大 - マウスホイール
ActionScript3 source code
/**
* Copyright saku_K ( http://wonderfl.net/user/saku_K )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/rKaT
*/
// forked from negimochi's forked from: flash on 2010-6-1
/**
* 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 {
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.FlatShadeMaterial;
import org.papervision3d.materials.shadematerials.GouraudMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.objects.primitives.Plane;
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;
import caurina.transitions.Tweener;
import caurina.transitions.properties.CurveModifiers;
internal class BasicViewOrg extends Sprite {
private static const INIT_CAMERA_X:int = 80;
private static const INIT_CAMERA_Y:int = 80;
private static const INIT_CAMERA_Z:int = -80;
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;
private static const RIBBON_WIDTH:int = 10;
private static const RIBBON_LENGTH:int = 300;
private static const EASING:Number = 0.05;
private static const X_MAX_RANGE:Number = 100;
private static const X_MIN_RANGE:Number = -100;
private static const Y_MAX_RANGE:Number = 100;
private static const Y_MIN_RANGE:Number = -100;
private static const Z_MAX_RANGE:Number = 100;
private static const Z_MIN_RANGE:Number = -100;
// 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 satellites:Array;
private var ribbons:Array;
private var container:DisplayObject3D;
public function BasicViewOrg(viewportWidth:Number = 640, viewportHeight:Number = 320, initFlagAxis:Boolean = true) {
CurveModifiers.init();
_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;
satellites = new Array();
ribbons = new Array();
container = new DisplayObject3D();
scene.addChild(container);
//シーンのオブジェクトを生成
createSceneObject();
}
/**
* レンダリング開始
*/
public function startRendering():void
{
addEventListener(Event.ENTER_FRAME, enterFrameHander);
}
//// private /////////////////////////////////////////////////////////////////////////////////////
private function enterFrameHander(evt:Event):void
{
var i:int = 0;
for ( i = 0; i < ribbons.length; i++ ) {
ribbons[i].x += (satellites[i].x - ribbons[i].x) * EASING;
ribbons[i].y += (satellites[i].y - ribbons[i].y) * EASING;
ribbons[i].z += (satellites[i].z - ribbons[i].z) * EASING;
ribbons[i].draw();
}
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);
// リボン作成
var ribbonMaterial:FlatShadeMaterial = new FlatShadeMaterial(light, 0xEF2A82, 0x44031F);
ribbonMaterial.oneSide = false;
var ribbon:Ribbon3D = new Ribbon3D(ribbonMaterial, RIBBON_WIDTH, RIBBON_LENGTH);
container.addChild(ribbon);
ribbon.x = randomNumber(X_MIN_RANGE, X_MAX_RANGE);
ribbon.y = randomNumber(Y_MIN_RANGE, Y_MAX_RANGE);
ribbon.z = randomNumber(Z_MIN_RANGE, Z_MAX_RANGE);
ribbons.push(ribbon);
// サテライト
var satellite:DisplayObject3D = new DisplayObject3D();
satellites.push(satellite);
var yellow:ColorMaterial = new ColorMaterial(0xffff00, 0.0);
yellow.oneSide = false;
var yellowPlane:Plane = new Plane(yellow, 20, 20, 1, 1);
satellite.addChild(yellowPlane);
container.addChild(satellite);
tweenObject(satellite);
// 軸の描画(デバッグ専用)
if (_flagAxis) {
createAxis();
}
}
private function randomNumber(min:Number, max:Number ):Number
{
return Math.random() * (max - min) + min;
}
private function tweenObject(object:*):void
{
Tweener.addTween(object, {
x: randomNumber(X_MIN_RANGE, X_MAX_RANGE),
y: randomNumber(Y_MIN_RANGE, Y_MAX_RANGE),
z: randomNumber(Z_MIN_RANGE, Z_MAX_RANGE),
_bezier:[ {
x: randomNumber(X_MIN_RANGE, X_MAX_RANGE),
y: randomNumber(Y_MIN_RANGE, Y_MAX_RANGE),
z: randomNumber(Z_MIN_RANGE, Z_MAX_RANGE)
}],
time: 4,
onComplete: tweenObject,
onCompleteParams: [object],
transition: "linear"
}
);
}
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;
}
}
// 以下 Ribbon3Dを転載
// SOULWIRE LTD
// © JUSTIN CLARKE WINDLE
// blog.soulwire.co.uk
// Ribbon3d v1.00
// 11/08/2008 20:35
import org.papervision3d.core.geom.renderables.Triangle3D;
import org.papervision3d.core.geom.renderables.Vertex3D;
import org.papervision3d.core.geom.TriangleMesh3D;
import org.papervision3d.core.math.NumberUV;
import org.papervision3d.core.proto.MaterialObject3D;
import org.papervision3d.objects.DisplayObject3D;
internal class Ribbon3D extends DisplayObject3D
{
// ————————————————————————————————————————————————————————————
// MEMBER CLASS / DATATYPE
// ————————————————————————————————————————————————————————————
private var length: Number;
private var planes: Array;
private var v1: Vertex3D;
private var v2: Vertex3D;
private var v3: Vertex3D;
private var v4: Vertex3D;
// ————————————————————————————————————————————————————————————
public var tx: Number;
public var ty: Number;
public var tz: Number;
public var width: Number;
// ————————————————————————————————————————————————————————————
// CONSTRUCTOR
// ————————————————————————————————————————————————————————————
public function Ribbon3D( materialObj:MaterialObject3D = null, thickness:Number = 20, maxSegments:int = 100 )
{
super();
planes = new Array();
tx = ty = tz = 0;
v1 = new Vertex3D( tx + width, ty, tz );
v2 = new Vertex3D( tx - width, ty, tz );
material = materialObj;
length = maxSegments;
width = thickness;
}
// ————————————————————————————————————————————————————————————
// METHODS
// ————————————————————————————————————————————————————————————
private function newPlane():TriangleMesh3D
{
var plane:TriangleMesh3D = new TriangleMesh3D( material, [], [] );
plane.geometry.vertices.push( v1, v2, v3, v4 );
plane.geometry.faces.push( newTriangle( plane, 0 ) );
plane.geometry.faces.push( newTriangle( plane, 1 ) );
plane.geometry.ready = true;
return plane;
}
private function newTriangle( plane:TriangleMesh3D, type:int ):Triangle3D
{
var b:Boolean = Boolean( type );
var vA:Vertex3D = plane.geometry.vertices[ b ? 3 : 0 ];
var vB:Vertex3D = plane.geometry.vertices[ b ? 1 : 2 ];
var vC:Vertex3D = plane.geometry.vertices[ b ? 2 : 1 ];
var nA:NumberUV = new NumberUV( int(b), 1 );
var nB:NumberUV = new NumberUV( int(b), int(!b) );
var nC:NumberUV = new NumberUV( int(!b), int(b) );
return( new Triangle3D( plane, [ vA, vB, vC ], null, [ nA, nB, nC ] ) );
}
// ————————————————————————————————————————————————————————————
public function draw():void
{
v3 = new Vertex3D( tx + width, ty, tz );
v4 = new Vertex3D( tx - width, ty, tz );
var plane:TriangleMesh3D;
if ( numChildren >= length )
{
plane = planes.shift();
plane.geometry.vertices = [ v1, v2, v3, v4 ];
plane.geometry.faces = [ newTriangle( plane, 0 ), newTriangle( plane, 1 ) ];
planes.push( plane );
}
else
{
plane = newPlane();
planes.push( plane );
addChild( plane );
}
v1 = v3;
v2 = v4;
}
public function moveTo( xp:Number = 0, yp:Number = 0, zp:Number = 0 ):void
{
super.x = xp;
super.y = yp;
super.z = zp;
}
// ————————————————————————————————————————————————————————————
// GET / SET
// ————————————————————————————————————————————————————————————
override public function get x():Number { return tx; }
override public function get y():Number { return ty; }
override public function get z():Number { return tz; }
override public function set x(n:Number):void { tx = n; }
override public function set y(n:Number):void { ty = n; }
override public function set z(n:Number):void { tz = n; }
}