2008-01-31 | 21:03
(3x3の)回転行列Mが分かっている時の回転軸ベクトルは
( M.n32 - M.n23, M.n13 - M.n31, M.n21 - M.n12)
回転角は
arccos((Trace(M) - 1 ) / 2)
4x4の同次座標の場合、(n44成分が1なので)回転角は
arccos((Trace(M) - 2 ) / 2)
で求まる。
(PV3DのDisplayObject3D.transformは同次座標)
(Traceは対角成分の和、PV3DのMatrix3Dにもtraceというプロパティがある)
下のキューブはマウスドラッグで回転できます。
回転後に上のやり方で回転軸と回転角を求めています。(黒い線が回転軸)
ESCキーで元の姿勢に戻ります。(検証のためにもとに戻す時は回転軸を使って逆回転させています。)
( M.n32 - M.n23, M.n13 - M.n31, M.n21 - M.n12)
回転角は
arccos((Trace(M) - 1 ) / 2)
4x4の同次座標の場合、(n44成分が1なので)回転角は
arccos((Trace(M) - 2 ) / 2)
で求まる。
(PV3DのDisplayObject3D.transformは同次座標)
(Traceは対角成分の和、PV3DのMatrix3Dにもtraceというプロパティがある)
下のキューブはマウスドラッグで回転できます。
回転後に上のやり方で回転軸と回転角を求めています。(黒い線が回転軸)
ESCキーで元の姿勢に戻ります。(検証のためにもとに戻す時は回転軸を使って逆回転させています。)
package { import flash.display.*; import flash.events.*; import flash.geom.*; import flash.text.*; import org.papervision3d.core.*; import org.papervision3d.core.geom.*; import org.papervision3d.core.math.*; import org.papervision3d.scenes.* ; import org.papervision3d.objects.*; import org.papervision3d.objects.primitives.*; import org.papervision3d.cameras.*; import org.papervision3d.materials.*; import org.papervision3d.materials.utils.*; import org.papervision3d.view.*; import org.papervision3d.render.*; import org.papervision3d.materials.special.LineMaterial ; [SWF(width="600", height="400", frameRate="10", backgroundColor="#ffffff")] public class Mat2axis extends Sprite{ private var renderer:BasicRenderEngine = new BasicRenderEngine(); private var viewport:Viewport3D = new Viewport3D(600, 800, false, true); private var scene:Scene3D = new Scene3D(); private var camera:FreeCamera3D = new FreeCamera3D(); private var mouseDown:Boolean = false; private var mousePos:Point; private var pose:Matrix3D; private var vl:Lines3D = new Lines3D(new LineMaterial(0xff)); private var redCube:Cube; private var lines:Array = null; private var tf:TextField; public function Mat2axis():void { tf = new TextField(); addChild(tf); stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; //viewport.y = 50; addChild(viewport); camera.y = -300; camera.z = -1100; camera.x = 0; camera.focus = 1100; camera.zoom = 1; var redwire:WireframeMaterial = new WireframeMaterial( 0xff0000 ); redCube = new Cube(new MaterialsList({all:redwire}), 100, 200, 300); scene.addChild(redCube); showVector(); renderer.renderScene(scene, camera, viewport); stage.addEventListener(MouseEvent.MOUSE_DOWN, function(e:*):void{ mouseDown = true; mousePos = new Point(stage.mouseX, stage.mouseY); pose = Matrix3D.clone(redCube.transform); }); stage.addEventListener(MouseEvent.MOUSE_MOVE, rotate); stage.addEventListener(MouseEvent.MOUSE_UP, function(e:*):void{ mouseDown = false; }); stage.addEventListener( KeyboardEvent.KEY_DOWN, function(e:*):void{ switch (e.keyCode){ case 27 :// ESC var m:Matrix3D = redCube.transform; // 回転軸ベクトル var rv:Number3D = new Number3D( m.n32 - m.n23, m.n13 - m.n31, m.n21 - m.n12); rv.normalize(); // 回転角 var rad:Number = Math.acos((m.trace - 2 ) / 2); // 逆回転して元の位置に戻す回転行列 var r:Matrix3D = Matrix3D.rotationMatrix(rv.x, rv.y, rv.z, -rad); redCube.transform = Matrix3D.multiply(r, redCube.transform); renderer.renderScene(scene, camera, viewport); showVector(); break; } }); } private function rotate(e:*):void{ if(mouseDown){ var xv:int = stage.mouseX - mousePos.x; var yv:int = stage.mouseY - mousePos.y; // X方向(Y軸周り)に回転する回転行列 var my:Matrix3D = Matrix3D.rotationMatrix(0,1,0, -0.01*xv); // Y方向(X軸周り)に回転する回転行列 var mx:Matrix3D = Matrix3D.rotationMatrix(1,0,0, -0.01*yv); // 回転の合成 var m:Matrix3D = Matrix3D.multiply(mx,my); redCube.transform = Matrix3D.multiply(m, pose); renderer.renderScene(scene, camera, viewport); showVector(); } } private function showVector():void{ var m:Matrix3D = redCube.transform; // 回転軸ベクトル var rv:Number3D = new Number3D( m.n32 - m.n23, m.n13 - m.n31, m.n21 - m.n12); // (正規化する前に)回転軸を描画 if(vl != null) scene.removeChild(vl); vl = new Lines3D(new LineMaterial(0x0)); scene.addChild(vl); vl.addNewLine(1, 0,0,0, rv.x*200, rv.y*200 , rv.z*200); rv.normalize(); // 回転角 var rad:Number = Math.acos((m.trace - 2 ) / 2); tf.text = rad.toString(); if(lines != null){ for each(var l:Lines3D in lines){ scene.removeChild(l); } } lines = []; var xl:Lines3D = new Lines3D(new LineMaterial()); scene.addChild(xl); xl.addNewLine(2, redCube.x,redCube.y,redCube.z, redCube.x + m.n11*100, redCube.y + m.n21*100 , redCube.z + m.n31*100); lines.push(xl); var yl:Lines3D = new Lines3D(new LineMaterial(0xff)); scene.addChild(yl); yl.addNewLine(2, redCube.x,redCube.y,redCube.z, redCube.x + m.n12*100, redCube.y + m.n22*100 , redCube.z + m.n32*100); lines.push(yl); var zl:Lines3D = new Lines3D(new LineMaterial(0xff00)); scene.addChild (zl); zl.addNewLine(2, redCube.x,redCube.y,redCube.z, redCube.x + m.n13*100, redCube.y + m.n23*100 , redCube.z + m.n33*100); lines.push(zl); renderer.renderScene(scene, camera, viewport); } } }
スポンサーサイト