[Flash 3D].03 3D 공간 돌아다니기(1.Vector) 생활수단/Flash2008/06/20 14:51
3D 공간 돌아다니기(1.Vector)
가장 먼저 3D 공간 안에서 이동시 사용하는 기본 단위인 Vector 에 대해 알아보겠습니다.
쉽게 표현하자면 이제까지 플래쉬에서 사용하던 이동 좌표인 x, y 를 모아 놓은것이 Point 라는 Class 라면
Vector 는 각각의 축인 x, y, z 의 값을 가지고 있는 비슷한 것이라고 생각하기 쉽습니다.
하지만 벡터라는 이름이 뜻하는 것이 Point 와는 다르게 방향과 크기(멀리 떨어진 정도) 전부를 표현하는 것 입니다.
따라서 Vector 는 x, y, z 의 좌표점 이외에 추가적으로 으로 w 라는 값을 가지고 있습니다.
x, y, z 의 좌표값이 방향을 지시하는 값이라면 w 는 그 방향으로 얼마만큼의 이동을 하는지를 나타내는 크기값이 되는것 입니다.
이러한 크기를 가지고 있는 Vector 클래스를 이용하면 다른 회전이나 행렬 계산시에 보다 효과적으로 사용할 수 있습니다.
이런 벡터는 3D 에서 종종 화살표 모양의 그림으로 많이 표현됩니다.
[그림 예정]
벡터는 이러한 특성을 이용하여 기하학적인 공간이나 물리학 적인 정의들을 수치화 하기 편하다는
장점이 있습니다. 이런 특징 때문에 3D 에서도 많이 사용되는 것입니다.
수치화 하는 방법들로는 각각의 쓰임새 별로 여러 함수 들이 존재 합니다.
가장 기본적인 것으로는 하나 이상의 벡터들 끼리의 덧셈과 뺄셈을 하는 것 입니다.
이는 각각의 벡터를 방향과 힘으로 비교 했을때 여기저기 분산되어 있는 벡터들의 힘이
결국 최종적으로 어느 방향으로 얼마만큼의 힘이 되는지를 알아내는 것이 될 수 있습니다.
다음 벡터의 내적이라는 것이 있습니다.
이는 아래와 같은 공식이 적용됩니다.
두 벡터 A와 B 가 있을때 A = (a_1, a_2, a_3), B = (b_1, b_2, b_3) 의 내적의 정의는
a_1 b_1 + a_2 b_2 + a_3 b_3
위와 같이 표현됩니다.
이는 다시말해 내적은 벡터의 곱이라 생각하시면 됩니다.
다만, 그 값은 스칼라, 즉 크기만 가지고 있는 것입니다.
즉, 방향을 같게 만들어 준 후, 그 두개의 크기를 곱한것이 벡터의 내적입니다.
이는 다른 식으로 표현해 |a||b| cos x 이렇게 표현하는것도 가능합니다.![]()
(그림 : Wiki 백과 참조 [http://en.wikipedia.org/wiki/Dot_product] )
이를 통해 두 벡터의 내적이 결과 값이 0 이라면 이 두 벡터는 서로 수직 관계라는 것을 유추 할 수도 있고
두 벡터 사이의 각도를 알아 내는 데에도 많이 사용됩니다.
다음으로 벡터의 외적입니다.
A={a1,a2,a3} B={b1,b2,b3} 일때
A,B벡터의 외적은 A X B = { a2b3-a3b2 , a3b1-a1b3, a1b2-a2b1 } 가 됩니다.
이는 결과값에 해당하는 축의 값을 구하기 위해 서로 다른 축들과 계산하여 나타내는 것 입니다.
따라서 두벡터의 외적의 결과값은 두 벡터에 서로 수직하는 벡터값이 나오게 됩니다.
그리고 이는 곧 두벡터가 만드는 평행사변형의 넓이가 됩니다.
공간평면의 넓이를 계산하는데에도 외적이 사용될 수 있습니다.
3D 에서는 이러한 외적으로 임의의 평면에 수직하는 법선 벡터를 찾는데 쓰이며 이는
조명 효과 결과값 계산등 다양하게 쓰입니다.
이것 외에도 3D 공간상에서 회전을 할때 사원수의 값으로 쓰이기도 합니다.
이처럼 Vector 는 기하학 적인 공간을 수치적으로 표현하는데 있어 기본 단위이자 유용한 도구 입니다.
작성 도구는 FlashDevelop3 beta7, Flex3SDK 가 될 예정이며 모두 공개되어 있습니다.
완성된 결과물은 Flash Player 10 에서 확인 가능하므로 해당 player 도 설치 하셔야 합니다.
위의 모든 과정은 http://cafe.naver.com/uiaa/7 이곳에 자세한 설명이 올라와 있으니 참고 바랍니다.
[Flash 3D 예제 1]
package
{
import flash.display.*;
import flash.geom.*;
/**
* ...
* @author MomO
*/
public class Util3D
{
public function Util3D() {}
public static function angleBetween( v1:Vector3D, v2:Vector3D ):Number
{
if ( v1.length == 0 || v2.length == 0 )
{
return NaN;
}
v1.normalize();
v2.normalize();
var dot:Number = v1.dotProduct(v2);
trace( dot );
var theta:Number = Math.acos(dot / (v1.length * v2.length));
return theta;
}
public static function getRotateXwithVector3D( vector:Vector3D ):Number
{
var v1:Vector3D = new Vector3D( 0, vector.y, vector.z );
if ( v1.length == 0 )return 0;
v1.normalize();
var dot:Number = v1.dotProduct(Vector3D.ZAXIS);
var theta:Number = Math.acos(dot / v1.length );
return theta * 180 / Math.PI;
}
public static function getRotateYwithVector3D( vector:Vector3D ):Number
{
var v1:Vector3D = new Vector3D( vector.x, 0, vector.z );
if ( v1.length == 0 )return 0;
v1.normalize();
var dot:Number = v1.dotProduct(Vector3D.XAXIS);
var theta:Number = Math.acos(dot / v1.length );
return -theta * 180 / Math.PI;
}
public static function getRotateZwithVector3D( vector:Vector3D ):Number
{
var v1:Vector3D = new Vector3D( vector.x, vector.y, 0 );
if ( v1.length == 0 )return 0;
v1.normalize();
var dot:Number = v1.dotProduct(Vector3D.XAXIS);
var theta:Number = Math.acos(dot / v1.length );
return theta * 180 / Math.PI;
}
}
}
package
{
import flash.display.*;
import flash.geom.*;
public class Main extends Sprite
{
public var xAxis:Sprite = new Sprite();
public var yAxis:Sprite = new Sprite();
public var zAxis:Sprite = new Sprite();
public var vectorXAxis:Vector3D = new Vector3D( 200, 0, 0 );
public var vectorYAxis:Vector3D = new Vector3D( 0, 200, 0 );
public var vectorZAxis:Vector3D = new Vector3D( 0, 0, 200 );
public function Main():void
{
addChild( xAxis );
addChild( yAxis );
addChild( zAxis );
drawVector( xAxis, vectorXAxis, 0xFF0000 );
drawVector( yAxis, vectorYAxis, 0x00FF00 );
drawVector( zAxis, vectorZAxis, 0x0000FF );
xAxis.x = yAxis.x = zAxis.x = 100;
xAxis.y = yAxis.y = zAxis.y = 100;
}
public function drawVector( sprite:Sprite, vector:Vector3D, color:uint = 0xFF0000 ):void
{
sprite.graphics.clear();
sprite.graphics.lineStyle( 5, color, 1 );
sprite.graphics.drawCircle( 0, 0, 5 );
sprite.graphics.lineTo( vector.length, 0 );
sprite.graphics.lineTo( vector.length-10, -5 );
sprite.graphics.lineTo( vector.length-10, 5 );
sprite.graphics.lineTo( vector.length, 0 );
sprite.z = 0;
var vectorR:Vector3D = new Vector3D();
vectorR.y = Util3D.getRotateYwithVector3D( vector );
vectorR.z = Util3D.getRotateZwithVector3D( vector );
sprite.rotationY = vectorR.y;
sprite.rotationZ = vectorR.z;
}
}
}
Util3D.as 와 Main.as 파일로 나눠 저장 한 후 Test 하면 아래와 같은 화면이 나옵니다.
Util3D 는 벡터의 내적 등을 이용해 회전 각도를 알아내는 함수들이 있고
Main 은 이를 이용해 graphics 사용하여 그린 객체를 Vector 성분에 맞게 회전시킨 것입니다.
위의 코드와 관련하여 좀더 상세한 Vector 예제는 다음회부터 진행 될 예정 입니다.

