five3Dメモ
http://d.hatena.ne.jp/nitoyon/20080513/p1
player10が使えない場合、手軽にパースをかけたいと思ったときはfive3Dを使う。
http://d.hatena.ne.jp/nitoyon/20080513/p1
player10が使えない場合、手軽にパースをかけたいと思ったときはfive3Dを使う。
http://level0.kayac.com/2009/03/3d_engine.php
勉強になります
http://yamasv.blog92.fc2.com/blog-entry-142.html
以下転載
--
package{
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.utils.*;
import org.papervision3d.core.math.*;
[SWF(width="400", height="400",backgroundColor="0xffffff")]
public class Light3D extends Sprite{
private var m:Matrix3D = new Matrix3D();
private var rm:Matrix3D = new Matrix3D();
private var lastPoint:Point;
private var mouseDown:Boolean = false;
private var objects:Array = [];
public function Light3D(){
var r:Number = 500;
var l:Number = -500;
var t:Number = 500;
var b:Number = -500;
var n:Number = 500;
var f:Number = 1000;
m.n11 = 2*n/(r-l);
m.n13 = (r+l)/(r-l);
m.n22 = 2*n/(t-b);
m.n23 = (t+b)/(t-b);
m.n33 = -(f+n)/(f-n);
m.n34 = -2*n*f/(f-n);
m.n43 = -1;
var triangle:Triangle = new Triangle();
addChild(triangle);
triangle.redraw(m, rm);
triangle.zz = 0;
objects.push(triangle);
var star:Star = new Star();
addChild(star);
star.redraw(m, rm);
star.zz = 50;
objects.push(star);
var rectangle:Rectangle = new Rectangle();
addChild(rectangle);
rectangle.redraw(m, rm);
rectangle.zz = 100;
objects.push(rectangle);
stage.addEventListener(MouseEvent.MOUSE_DOWN, function(e:*):void{
mouseDown = true;
lastPoint = new Point(stage.mouseX, stage.mouseY);
});
stage.addEventListener(MouseEvent.MOUSE_UP, function(e:*):void{
mouseDown = false;
lastPoint = new Point(stage.mouseX, stage.mouseY);
});
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
}
private function onMouseMove(e:*):void{
if(!mouseDown)
return;
var xx:Number = stage.mouseX - lastPoint.x;
var yy:Number = -stage.mouseY + lastPoint.y;
if(yy == 00) return;
var rotAxis:Number3D = new Number3D();
rotAxis.z = 0;
rotAxis.x = yy;
rotAxis.y = -xx;
// calculate the amount of rotation
var rotAngle:Number = Math.sqrt(xx*xx + yy*yy)/200*Math.PI;
if(rotAngle == 0) return;
rotAxis.normalize();
rm = Matrix3D.multiply(Matrix3D.rotationMatrix(rotAxis.x, rotAxis.y, 0, rotAngle), rm);
lastPoint = new Point(stage.mouseX, stage.mouseY);
for each(var o:Base3D in objects){
o.redraw(m, rm);
}
// 本当はZオーダーを考慮して並べ替える
if(rm.n33 < 0){
setChildIndex(objects[0],2);
setChildIndex(objects[1],1);
setChildIndex(objects[2],0);
}else{
setChildIndex(objects[0],0);
setChildIndex(objects[1],1);
setChildIndex(objects[2],2);
}
}
}
}
internal class Base3D extends Sprite{
public var xx:int ;
public var yy:int ;
public var zz:int ;
public function redraw(m:Matrix3D, rm:Matrix3D):void{
}
protected function convertPoint(p:Number3D, m:Matrix3D, rm:Matrix3D):Point{
// apply camera rotation
Matrix3D.multiplyVector(rm,p);
// convert to 2D point
Matrix3D.multiplyVector(m,p);
return new Point(p.x + 200, 200 - p.y);
}
}
import flash.display.Sprite;
import flash.geom.*;
import org.papervision3d.core.math.*;
internal class Triangle extends Base3D {
public function Triangle() {
}
public override function redraw(m:Matrix3D, rm:Matrix3D):void{
graphics.clear();
graphics.lineStyle(1, 0, 1);
graphics.beginFill(0xff0000);
var p:Point = convertPoint(new Number3D(-30,-30,zz), m, rm);
var p2:Point = convertPoint(new Number3D(30,30,zz), m, rm);
var p3:Point = convertPoint(new Number3D(-30,30,zz), m, rm);
graphics.moveTo(p.x, p.y);
graphics.lineTo(p2.x, p2.y);
graphics.lineTo(p3.x, p3.y);
graphics.endFill();
}
}
internal class Rectangle extends Base3D {
public function Rectangle() {
}
public override function redraw(m:Matrix3D, rm:Matrix3D):void{
graphics.clear();
graphics.lineStyle(1, 0, 1);
graphics.beginFill(0xff00);
var p:Point = convertPoint(new Number3D(0,0,zz), m, rm);
var p2:Point = convertPoint(new Number3D(0,150,zz), m, rm);
var p3:Point = convertPoint(new Number3D(150, 150,zz), m, rm);
var p4:Point = convertPoint(new Number3D(150, 0,zz), m, rm);
graphics.moveTo(p.x, p.y);
graphics.lineTo(p2.x, p2.y);
graphics.lineTo(p3.x, p3.y);
graphics.lineTo(p4.x, p4.y);
graphics.endFill();
}
}
internal class Star extends Base3D{
public function Star(){
}
public override function redraw(m:Matrix3D, rm:Matrix3D):void{
graphics.clear();
graphics.lineStyle(1, 0xff, 0.8);
graphics.beginFill(0xff);
var seq:Array=[2,4,1,3,0];
var p0:Point = convertPoint(new Number3D(100, 200, zz), m, rm);
graphics.moveTo(p0.x, p0.y);
for(var j:int = 0 ; j < 5 ; j++){
var rad:Number = seq[j] * Math.PI * 2 / 5;
var p:Point = convertPoint(new Number3D(-Math.sin(rad)*100+100, Math.cos(rad)*100+100, zz), m, rm);
graphics.lineTo(p.x, p.y);
}
graphics.endFill();
}
}
particle、ちっこいつぶつぶを動かすサンプルを見ていると
各つぶ の描画にはsetPixelsとかを使い
各つぶは、displayObjectではなく、単なるデータ(色、位置、大きさ)
しか持たない。
こっちのほうが高速なんだろうな。
3dのパースの式
scale = fl / (fl + z)
焦点距離flを小さくすると、スケールが急激に変化=広角気味
焦点距離flを大きくすると、スケールがゆるやかに変化=望遠気味
--
ここでいうflはpapervisionのcamera.focusに相当?
http://www.ceres.dti.ne.jp/~ykuroda/oyaj/bone/basic3d.html
3dでの座標回転を考えて見ます。
軸は下記のように定義。
x軸:ディスプレイの横方向
y軸:ディスプレイの縦方向
z軸:z軸は奥行きのほうこうです。ディスプレイを突き抜ける方向です。
回転をイメージしてみる。
x軸回転:タイヤを前面から観測
y軸回転:円盤、CDプレイヤーを考えよう
z軸回転:ルーレット盤を上から観測しよう
---
とりあえず3Dの前に、2Dでの回転を考えます。公式は下記です。
(x,y)をangle回転させて(x1,x2)になります。
x1 = cos(angle)*x - sin(angle)*y
y1 = cos(angle)*y + sin(angle)*x
この式はなぜこうなるのか。。合ってるか知らんが考えてみる。
(x1,y1)を極座標で下記のように表す。a0は(x,y)がなす角度。
abs1 = Math.sqrt(x1*x1+y1*y*1)
x1 = abs1 * cos( a0 +angle)
y1 = abs1 * sin( a0 + angle)
これを加法定理で分解。
x1 =abs1 *( cos(a0)*cos(angle) - sin(a0)*sin(angle) );
y1 =abs1 *( sin(a0)*cos(angle) + cos(a0)*sin(sngle) );
で、ここでの話は回転だけであって(たぶん)、変換後の絶対値は変わらない。つまり
abs1=Math.sqrt(x*x+y*y)
であるから
abs1 * cos(a0) = x
abs1 * sin(a0) = y
と考えられる。よって、式をきれいに書き直すと
x1 =x*cos(angle) - y*sin(angle);
y1 =y*cos(angle) + x*sin(sngle) );
できたー!
焦点距離とは何なのか、よくわからないので考察をします。本にはカメラの焦点距離とは厳密には違うと書いてありました。それがナニを意図するのか分かりません。。
具体的に見ていったほうがイメージしやすいかもしれないので、焦点距離fl=30,fl=3000としてものを図示しました。


焦点距離を小さくすると、つまり視点を投射面に近づけると、
zを大きくするとスケールが急激に小さくなります。
焦点距離を大きくすると、つまり視点を投射面から遠ざけると
zを大きくしてもなかなかスケールは小さくなりません。
うーん。よくわからん…。
とりあえずの結論: 焦点距離はスケールを決定付ける定数であり、深く考えない。
今から3dの勉強をして見ます。
パースペクティブ=物体が近いか遠いかを知らせる方法、だそうです。
それのひとつの手法として下記があります。
1.遠ざかるにつれて小さくなる
2.遠ざかるにつれ消失点に収束する
パースペクティブを横から見た図、というのが読んでいる本に載っております。
「視点」「投影面」「オブジェクト」
という順番で図示されています。
視点から投影面までの距離をfl (focal length:焦点距離)
投影面からオブジェクトまでの距離をz
とすると、画面上に表示されるオブジェクトのスケールは下記のように表されるそうです。
scale = fl / (fl + z)
投影面という概念がいまいちよく分かりませんが。zに対するscaleの関係は下記の図のようになります。焦点距離はふつう300くらいを使うそうなので300でいきます。

図があまりにもダサい。。
zが0だとスケール1、300になるとスケールが0.5、zが600になると0.34
みたいな感じになります。距離とスケールの関係は非線形です。なぜこういう式になるかは分かりませんが、おそらく一般的なのでしょう。深く考えずこれを使っていこうと思います。