Joint Controler(描画test)
3Dオブジェクトの位置移動と回転を制御できるコントローラー描画テスト
リングパーツが長すぎて描画に破綻をきたすためalphaで誤魔化してます。
/**
* Copyright Kay ( http://wonderfl.net/user/Kay )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/3OE2
*/
// 3Dオブジェクトの位置移動と回転を制御できるコントローラー描画テスト
// リングパーツが長すぎて描画に破綻をきたすためalphaで誤魔化してます。
package {
import flash.display.*;
import flash.geom.*;
import flash.events.*;
[SWF(width=465,height=465,frameRate=30, backgroundColor=0x666666)]
public class Main extends Sprite {
private const SW:Number = stage.stageWidth;
private const SH:Number = stage.stageHeight;
public var proj:PerspectiveProjection = new PerspectiveProjection();
public function Main():void {
var container:Sprite = new Sprite();
addChild(container);
container.x=SW/2;
container.y=SH/2;
var numJoint:uint=3;
var dist:Number=150;
var shift:Number = dist*(numJoint-1)/2;
for (var v:int = 0; v < numJoint; v++) {
var nY:Number=dist*v-shift;
for (var h:int = 0; h < numJoint; h++) {
var nX:Number=dist*h-shift;
var jointControler:JointControler = new JointControler();
container.addChild(jointControler);
jointControler.mtx.prepend(proj.toMatrix3D());
jointControler.mtx.prependTranslation(nX, nY, proj.focalLength);
jointControler.xRender();
jointControler.addEventListener(Event.ENTER_FRAME, xRotate);
}
}
}
public function xRotate(e:Event):void {
// Box空間ではなくBox座標を回転させる
e.target.rMtx.appendRotation(2,Vector3D.X_AXIS);
e.target.rMtx.appendRotation(3,Vector3D.Y_AXIS);
e.target.rMtx.appendRotation(4,Vector3D.Z_AXIS);
e.target.xRender();
}
}
}
import flash.display.*;
import flash.geom.*;
import flash.events.*;
class JointControler extends Sprite {
private var vertices3D:Vector.<Number> = new Vector.<Number>();
private var vertices2D:Vector.<Number> = new Vector.<Number>();
private var vertices3Db:Vector.<Number> = new Vector.<Number>();
private var indices:Vector.<int> = new Vector.<int>();
private var uvt:Vector.<Number> = new Vector.<Number>();
private var tempVerts:Vector.<Number>;
private var staticVerts:Vector.<Number>;
public var mtx:Matrix3D = new Matrix3D();
public var rMtx:Matrix3D = new Matrix3D();
private var ringParts:Array;
public function JointControler(radius:Number=50, innerRadius:Number=30, ballRadius:Number=25):void {
// curveToで描くための座標群を取得
var arcPoints:Array = new Array();
var arcInfo:Object = getArcValues(radius, Math.PI*2);
var innerArcInfo:Object = getArcValues(innerRadius, Math.PI*2);
var ballPoints:Array = new Array();
var ballArcInfo:Object = getArcValues(ballRadius, Math.PI*2);
for (var i:int = 0; i <= arcInfo.divideNum; i++) {
// Outer Control Point
arcPoints.push(new Point(arcInfo.distance*Math.cos(arcInfo.dividedRadian*(i-0.5)),
arcInfo.distance*Math.sin(arcInfo.dividedRadian*(i-0.5))));
// Outer Anchor Point
arcPoints.push(new Point(radius*Math.cos(arcInfo.dividedRadian*i),
radius*Math.sin(arcInfo.dividedRadian*i)));
// Inner Control Point
arcPoints.push(new Point(innerArcInfo.distance*Math.cos(innerArcInfo.dividedRadian*(i-0.5)),
innerArcInfo.distance*Math.sin(innerArcInfo.dividedRadian*(i-0.5))));
// Inner Anchor Point
arcPoints.push(new Point(innerRadius*Math.cos(innerArcInfo.dividedRadian*i),
innerRadius*Math.sin(innerArcInfo.dividedRadian*i)));
// Ball Control Point
ballPoints.push(new Point(ballArcInfo.distance*Math.cos(ballArcInfo.dividedRadian*(i-0.5)),
ballArcInfo.distance*Math.sin(ballArcInfo.dividedRadian*(i-0.5))));
// Ball Anchor Point
ballPoints.push(new Point(ballRadius*Math.cos(ballArcInfo.dividedRadian*i),
ballRadius*Math.sin(ballArcInfo.dividedRadian*i)));
}
var numPoint:int = arcPoints.length; // 36(=8*2(outer&inner)*2(anchor&control))
// Z回転軸(Ballにも利用)
for (i = 0; i < numPoint; i++) {
vertices3D.push(arcPoints[i].x,arcPoints[i].y,0);
}
// Y回転軸
for (i = 0; i < numPoint; i++) {
vertices3D.push(arcPoints[i].x,0,arcPoints[i].y);
}
// X回転軸
for (i = 0; i < numPoint; i++) {
vertices3D.push(0,arcPoints[i].x,arcPoints[i].y);
}
// 移動用ボール
numPoint = ballPoints.length;
for (i = 0; i < numPoint; i++) {
vertices3Db.push(ballPoints[i].x,ballPoints[i].y,0);
}
}
public function xRender():void {
// 回転させた座標に透視投影を反映してた後に2D化する
tempVerts = new Vector.<Number>();
rMtx.transformVectors(vertices3D, tempVerts);
Utils3D.projectVectors(mtx,tempVerts,vertices2D,uvt);
// ボール用は回転させずに透視投影のみ反映する
staticVerts = new Vector.<Number>();
Utils3D.projectVectors(mtx,vertices3Db,staticVerts,uvt);
// 初期化
while (numChildren > 0) removeChildAt(0);
ringParts = new Array();
drawRing(0x33ffff,0); // Z軸
drawRing(0xffff33,1); // Y軸
drawRing(0xff33ff,2); // X軸
drawBall(0xff0000); // 移動用ボール
// ソートして配置
ringParts.sortOn("nZ", Array.NUMERIC);
for (var i:int = 0; i <13; i++) {
addChild(ringParts[i]);
}
}
// 中心に球もどきを配置
private function drawBall(color:int):void {
var ball:QuarterRing = new QuarterRing();
ball.graphics.beginFill(color);
ball.graphics.moveTo(staticVerts[2],staticVerts[3]);
for (var i:int = 0; i < 9; i++) {
ball.graphics.curveTo(staticVerts[(i*4)+0],staticVerts[(i*4)+1],staticVerts[(i*4)+2],staticVerts[(i*4)+3]);
}
ball.graphics.endFill();
ball.nZ = 0;
ball.alpha = 0.75;
ringParts.push(ball);
}
// 4枚のパーツに分けて描画する
private function drawRing(color:int, num:int):void {
for (var i:int = 0; i < 4; i++) {
var ringPart:QuarterRing = new QuarterRing();
drawRingPart(ringPart,color,num*72,i*2+1);
ringPart.nZ = tempVerts[num*108+27*i+17]; // 17,26
ringParts.push(ringPart);
}
}
public function drawRingPart(obj:Object,color:int,num:int,offset:int):void {
obj.graphics.lineStyle(0,0x666666);
obj.graphics.beginFill(color);
// Outer
obj.graphics.moveTo(vertices2D[(offset-1)*8+num+2],vertices2D[(offset-1)*8+num+3]);
for (var i:int = offset; i <= offset+1; i++) {
var base:int = i*8;
obj.graphics.curveTo(vertices2D[i*8+num+0],vertices2D[i*8+num+1],vertices2D[i*8+num+2],vertices2D[i*8+num+3]);
}
// Inner(逆から)
obj.graphics.lineTo(vertices2D[(offset+1)*8+num+6],vertices2D[(offset+1)*8+num+7]);
for (i = offset+1; i >= offset; i--) {
obj.graphics.curveTo(vertices2D[i*8+num+4],vertices2D[i*8+num+5],vertices2D[i*8+num-2],vertices2D[i*8+num-1]);
}
obj.graphics.lineTo(vertices2D[(offset-1)*8+num+2],vertices2D[(offset-1)*8+num+3]);
obj.graphics.endFill();
}
//----------------------------------------------------------------------
// 以下LineClassより
/*
* 円弧を描くのに必要な材料をオブジェクトとして返す
* @return divideNum: 分割数
* @return dividedRadian: 分割された角度
* @return distance: 中心点からコントロールポイントまでの距離
*/
public static function getArcValues(nRadius:Number, nRadian:Number):Object {
// 分割数を得る(45°未満:1)
var divideNum:int = 1;
while (Math.abs(nRadian)/divideNum > Math.PI/4) divideNum++;
// 分割された角度
var dividedRadian:Number = nRadian/divideNum;
// コントロールポイントまでの距離を得る
var distance:Number = getControlRadius(nRadius,Math.abs(dividedRadian));
return {divideNum:divideNum, dividedRadian:dividedRadian, distance:distance};
}
// 角度からコントロールポイントの半径を取得
public static function getControlRadius(nRadius:Number, nRadian:Number):Number {
var rHalf:Number = nRadian/2;
var nHeight:Number = nRadius * Math.atan(rHalf);
var radius:Number = Math.sqrt(Math.pow(nHeight,2)+Math.pow(nRadius,2));
return radius;
}
// 数値を+-limitの範囲に収束
public function getRangeValue(num:Number, limit:Number):Number {
while(num > limit) num -= limit*2;
while(num < -limit) num += limit*2;
return num;
}
// angleをradianに変換
private function angle2radian(angle:Number=0):Number {
var radian:Number= angle * (Math.PI / 180);
return radian;
}
}
/*
* ソート情報(nZ)記録用
*/
class QuarterRing extends Shape {
public var nZ:Number;
public function QuaterRing():void {
}
}