クォータニオン練習
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.filters.BlurFilter;
import flash.filters.ColorMatrixFilter;
[SWF(width="465", height="465", backgroundColor="0x0", frameRate="90")]
public class TestQuaternion extends Sprite
{
private const L:uint = 465;
private const N:uint = 10000;
private const cameraZ:Number = -3.0;
private const X0:Number = L / 2;
private const Y0:Number = L / 2;
private var particles:Array = [];
private var dat:BitmapData;
private var bm:Bitmap;
private var qx:Quaternion = new Quaternion(0,1,0,0);
private var qy:Quaternion = new Quaternion(0,0,1,0);
private var qz:Quaternion = new Quaternion(0,0,0,1);
private var lastX:Number;
private var lastY:Number;
public function TestQuaternion() {
dat = new BitmapData(L, L, false, 0);
bm = new Bitmap(dat);
for (var i:int = 0; i < N; i++)
{
particles[i] = new Particle();
}
addChild(bm);
filters = [new BlurFilter(2,2)];
lastX = mouseX;
lastY = mouseY;
addEventListener(Event.ENTER_FRAME, loop);
}
private function loop(e:Event):void {
update();
}
private function update():void {
var dx:Number = mouseX - lastX;
var dy:Number = mouseY - lastY;
var dr:Number = Math.sqrt(dx * dx + dy * dy) / L;
if(dr != 0){
qx = qx.rotateV(dr, dy, -dx, 0);
qy = qy.rotateV(dr, dy, -dx, 0);
qz = qz.rotateV(dr, dy, -dx, 0);
}
lastX = mouseX;
lastY = mouseY;
dat.lock();
dat.draw(this);
var p:Particle;
var _x:Number;
var _y:Number;
var _z:Number;
var $x:Number;
var $y:Number;
var $z:Number;
for each(p in particles) {
_x = p.x * qx.x + p.y * qy.x + p.z * qz.x;
_y = p.x * qx.y + p.y * qy.y + p.z * qz.y;
_z = p.x * qx.z + p.y * qy.z + p.z * qz.z;
$z = (_z - cameraZ) / L;
$x = X0 + _x / $z;
$y = Y0 + _y / $z;
dat.setPixel($x, $y, p.color);
}
dat.unlock();
}
}
}
internal class Quaternion
{
public var w:Number;
public var x:Number;
public var y:Number;
public var z:Number;
public function Quaternion(w:Number = 0, x:Number = 0, y:Number = 0, z:Number = 0) {
this.w = w;
this.x = x;
this.y = y;
this.z = z;
}
public static function multiple(q1:Quaternion, q2:Quaternion):Quaternion {
return new Quaternion(
q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z,
q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y,
q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x,
q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w
);
}
public function rotateX(r:Number):Quaternion {
var cos :Number = Math.cos(r);
var sin :Number = Math.sin(r);
return multiple(
multiple(
new Quaternion(cos, sin, 0, 0),
this
),
new Quaternion (cos, -sin, 0,0)
);
}
public function rotateY(r:Number):Quaternion {
var cos :Number = Math.cos(r);
var sin :Number = Math.sin(r);
return multiple(
multiple(
new Quaternion(cos, 0, sin, 0),
this
),
new Quaternion (cos, 0, -sin,0)
);
}
public function rotateZ(r:Number):Quaternion {
var cos :Number = Math.cos(r);
var sin :Number = Math.sin(r);
return multiple(
multiple(
new Quaternion(cos, 0, 0, sin),
this
),
new Quaternion (cos, 0,0, -sin)
);
}
public function rotateV(r:Number, x:Number, y:Number, z:Number):Quaternion {
var cos :Number = Math.cos(r);
var sin :Number = Math.sin(r)/Math.sqrt(x * x + y * y + z * z);
x *= sin;
y *= sin;
z *= sin;
return multiple(
multiple(
new Quaternion(cos, x, y, z),
this
),
new Quaternion (cos, -x, -y, -z)
);
}
}
internal class Particle {
public var x:Number;
public var y:Number;
public var z:Number;
private var vx:Number;
private var vy:Number;
private var vz:Number;
public var color:uint;
public function Particle() {
var r:Number = Math.random();
var phi:Number = Math.PI * Math.random();
var theta:Number = 2 * Math.PI * Math.random();
x = r * Math.sin(phi)*Math.cos(theta);
y = r * Math.sin(phi)*Math.sin(theta);
z = r * Math.cos(phi);
vx = 0;
vy = 0;
vz = 0;
color = Math.random ()* 0xffffff;
}
public function update():void {
}
}