追尾カメラ
/**
* Copyright uwi ( http://wonderfl.net/user/uwi )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/5wVZ
*/
package {
import org.papervision3d.view.BasicView;
import flash.text.TextField;
import flash.events.Event;
import flash.events.MouseEvent;
import net.hires.debug.Stats;
import org.papervision3d.objects.primitives.*;
import org.papervision3d.objects.*;
import org.papervision3d.core.math.*;
import org.papervision3d.core.proto.*;
import org.papervision3d.materials.*;
import org.papervision3d.materials.special.*;
import org.papervision3d.objects.special.*;
import com.bit101.components.*;
[SWF(backgroundColor="0x000000", frameRate="60")]
public class PV3D extends BasicView {
private var _tf : TextField;
private var _pp : PaperPlane;
private var _XX : Number;
private var _YY : Number;
private var _ZZ : Number;
private var _t : Number;
private var _next : DisplayObject3D;
private var _ppup : Number3D;
private var _prevDir : Number3D = null;
private var _cameras : Array;
public function PV3D() {
super(0, 0, true, false);
graphics.beginFill(0x000000);
graphics.drawRect(0, 0, 465, 465);
graphics.endFill();
scene.addChild(new ParticleField(new ParticleMaterial(0xffff99, 0.8, 0), 3000, 2, 1300, 1300, 1300));
var wm : MaterialObject3D = new WireframeMaterial(0xffffff, 0.5);
wm.oneSide = false;
_pp = new PaperPlane(wm);
scene.addChild(_pp);
_XX = 1 + Math.random();
_YY = 1 + Math.random();
_ZZ = 1 + Math.random();
_t = Math.random() * 100;
_next = new DisplayObject3D();
// カメラ
_cameras = [];
var tc : TrackingCamera = new TrackingCamera(_pp, new Number3D(0, 1, 0));
tc.x = 0; tc.y = 0; tc.z = 0;
_cameras.push(tc);
var rc : RidingCamera = new RidingCamera(_pp, new Number3D(0, 1, 0));
_cameras.push(rc);
var sc : SphereCamera = new SphereCamera(new Number3D(0, 0, 0), 1000, new Number3D(0, 0, 1), new Number3D(0, 1, 0));
_cameras.push(sc);
_ppup = null;
_tf = new TextField();
addChild(_tf);
_tf.textColor = 0xffffff;
_tf.width = 100;
_tf.height = 465;
// addChild(new Stats());
_modeCamera = -1;
changeMode();
startRendering();
var btn : PushButton = new PushButton(this, 365, 0, "change", function(e : MouseEvent) : void { changeMode(); });
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
}
private var _modeCamera : int;
private function changeMode() : void
{
_modeCamera = (_modeCamera + 1) % _cameras.length;
_camera = _cameras[_modeCamera];
_tf.text = ["TrackingCamera", "RidingCamera", "SphereCamera"][_modeCamera];
}
private var _prevX : Number = 0;
private var _prevY : Number = 0;
private function onMouseMove(e : MouseEvent) : void
{
if(!(_camera is SphereCamera))return;
if(e.buttonDown){
// ボタンをおしている状態のときのみカメラを移動
if(_prevX != 0 && _prevY != 0){
var sc : SphereCamera = SphereCamera(_camera);
// 直前との差分だけ移動
sc.move((stage.mouseX - _prevX) * 0.005, (stage.mouseY - _prevY) * 0.005);
}
_prevX = stage.mouseX;
_prevY = stage.mouseY;
}else{
_prevX = 0;
_prevY = 0;
}
}
override protected function onRenderTick(e : Event = null) : void
{
_pp.x = 500 * Math.cos(_XX * _t);
_pp.y = 500 * Math.cos(_YY * _t);
_pp.z = 500 * Math.cos(_ZZ * _t);
_next.x = 500 * Math.cos(_XX * (_t + 0.01));
_next.y = 500 * Math.cos(_YY * (_t + 0.01));
_next.z = 500 * Math.cos(_ZZ * (_t + 0.01));
var curDir : Number3D = Number3D.sub(_next.position, _pp.position);
curDir.normalize();
if(_ppup == null){
var x : Number3D = Number3D.cross(new Number3D(0, 1, 0), curDir);
x.normalize();
_ppup = Number3D.cross(x, curDir);
}
if(_prevDir != null){
// 飛行機ヨー用
var X : Number3D = Number3D.cross(_prevDir, _ppup);
var dx : Number = Number3D.dot(curDir, X) / X.moduloSquared;
var n : Number3D = Number3D.cross(_prevDir, curDir);
// if(n.moduloSquared > 0.00000001){
if(n.moduloSquared != 0){
n.normalize();
var angle : Number = Math.acos(Number3D.dot(_prevDir, curDir));
_ppup = QCamera3D.applyQuaternion([_ppup], n, angle)[0];
}
var airup : Number3D = QCamera3D.applyQuaternion([_ppup], curDir, dx*10)[0];
_pp.lookAt(_next, airup);
}else{
_pp.lookAt(_next, _ppup);
}
_prevDir = curDir;
TrackingCamera(_cameras[0]).track();
// 3frameほど調整しないといけない
if(ttt < 3){
RidingCamera(_cameras[1])._up = _ppup.clone();
ttt++;
}
RidingCamera(_cameras[1]).move(60, 230);
_t += 0.01;
super.onRenderTick(e);
}
private var ttt : uint = 0;
private function tr(...o : Array) : void
{
_tf.appendText(o + "\n");
_tf.scrollV = _tf.maxScrollV;
}
}
}
import org.papervision3d.core.math.*;
import org.papervision3d.objects.*;
import org.papervision3d.cameras.*;
// ジンバルロックを解消した以外はCamera3Dと同じ
class QCamera3D extends Camera3D
{
public var _up : Number3D; // カメラの上の向きの単位ベクトル
protected var _front : Number3D;
private var _prevDir : Number3D;
private var _ltarg : DisplayObject3D;
public function QCamera3D(up : Number3D, front : Number3D = null)
{
super();
_up = null;
_ltarg = new DisplayObject3D();
init(up, front);
}
// prevDirからcurDirへ向ける回転を_upにかけるだけ。カメラ自体に操作はしない
public function rotate(curDir : Number3D) : void
{
if(_prevDir != null){
var n : Number3D = Number3D.cross(_prevDir, curDir);
// if(n.moduloSquared > 0.00000001){
if(n.moduloSquared != 0){
n.normalize();
var angle : Number = Math.acos(Number3D.dot(_prevDir, curDir));
if(_front != null){
var a : Array = applyQuaternion([_front, _up], n, angle);
_front = a[0];
_up = a[1];
}else{
_up = applyQuaternion([_up], n, angle)[0];
}
}
_prevDir.copyFrom(curDir);
}else{
_prevDir = curDir.clone();
}
}
// カメラの右方向へx[rad], 上方向へy[rad]回転させる
public function rotateXY(x : Number, y : Number) : void
{
if(_front == null)return;
// X方向の移動
_front = applyQuaternion([_front], _up, -x)[0];
// Y方向の移動
var right : Number3D = Number3D.cross(_up, _front);
right.normalize();
var ret : Array = applyQuaternion([_front, _up], right, y);
_front = ret[0];
_up = ret[1];
}
public function head() : void
{
if(_front != null){
// まわりくどい
var ltpos : Number3D = this.position.clone();
ltpos.plusEq(_front);
_ltarg.position = ltpos;
this.lookAt(_ltarg, _up);
}
}
public function init(up : Number3D = null, front : Number3D = null) : void
{
if(up != null){
_up = up.clone();
_up.normalize();
}
if(front != null){
_front = front.clone();
_front.normalize();
}else{
_front = null;
}
_prevDir = null;
}
// axisを軸にangle回転させる変換を、srcsの要素それぞれに適用する
public static function applyQuaternion(srcs : Array, axis : Number3D, angle : Number) : Array
{
var q : Quaternion = Quaternion.createFromAxisAngle(
axis.x / axis.modulo,
axis.y / axis.modulo,
axis.z / axis.modulo,
angle
);
var qc : Quaternion = Quaternion.conjugate(q);
var ret : Array = [];
for each(var src : Number3D in srcs){
var qSrc : Quaternion = new Quaternion(src.x, src.y, src.z, 0);
var qDst : Quaternion = Quaternion.multiply(qc, qSrc);
qDst.mult(q);
ret.push(new Number3D(qDst.x, qDst.y, qDst.z));
}
return ret;
}
}
// 球面上を動き、球の中心を見るカメラ
class SphereCamera extends QCamera3D
{
private var _O : DisplayObject3D; // 球の中心
private var _R : Number; // 球の半径
public function SphereCamera(O : Number3D, R : Number, front : Number3D, up : Number3D) : void
{
super(up, front);
_O = new DisplayObject3D();
_O.x = O.x;
_O.y = O.y;
_O.z = O.z;
_R = R;
move();
}
public function move(x : Number = 0, y : Number = 0) : void
{
rotateXY(x, y);
this.x = _front.x * -_R + _O.x;
this.y = _front.y * -_R + _O.y;
this.z = _front.z * -_R + _O.z;
this.lookAt(_O, _up);
}
}
// 固定視点から継続的にターゲッティングするカメラ
class TrackingCamera extends QCamera3D
{
private var _targ : DisplayObject3D;
public function TrackingCamera(targ : DisplayObject3D, up : Number3D)
{
super(up);
_targ = targ;
}
public function track() : void
{
var curDir : Number3D = Number3D.sub(_targ.position, this.position);
curDir.normalize();
rotate(curDir);
this.lookAt(_targ, _up);
}
}
// ゲットライド!
class RidingCamera extends QCamera3D
{
private var _ride : DisplayObject3D;
private var _prevPos : Number3D;
public function RidingCamera(ride : DisplayObject3D, up : Number3D, front : Number3D = null)
{
super(up, front);
_ride = ride;
_prevPos = _ride.position.clone();
}
public function move(up : Number = 0, back : Number = 0) : void
{
var curDir : Number3D = Number3D.sub(_ride.position, _prevPos);
curDir.normalize();
if(_front == null){
_front = curDir.clone();
}
rotate(curDir);
var curPos : Number3D = _ride.position.clone();
var temp : Number3D;
temp = _up.clone();
temp.multiplyEq(up);
curPos.plusEq(temp);
temp = _front.clone();
temp.multiplyEq(-back);
curPos.plusEq(temp);
this.position = curPos;
head();
_prevPos.copyFrom(_ride.position);
}
}