기본 호출 방식

사용자가 matrix 를 브라우저 페이지내에 로드 하였다면 아무때나 matrix를 실행할 수 있습니다. matrix는 matrix 계산을 위한 MatrixCalc 와 Transform 계산을 위한 MatrixTransform 두개의 기능의 기능을 가지고 있습니다.

@@include( 'codeTop.html' ) var matrix = MatrixCalc.multiply(m1, m2); var transform = MatrixTranform.translate([x, y, z]); @@include( 'codeBtm.html' )
Matrix Multiply(곱셈)

MatrixCalc은 N x N 형태의 행렬만 계산이 가능합니다. 밑에 있는 예제에서 배열을 수정해서 결과를 다시 확인할 수 있습니다.

@@include( 'codeTop.html' ) var matrix = MatrixCalc.multiply(m1, m2); @@include( 'codeBtm.html' )

Matrix가 1차 배열 형태의 경우

1, 2, 3, 4,
1, 2, 3, 4,
1, 2, 3, 4,
1, 2, 3, 4

X

4, 3, 2, 1,
4, 3, 2, 1,
4, 3, 2, 1,
4, 3, 2, 1

=

Matrix가 2차 배열 형태의 경우

[ 1, 2, 3, 4 ],
[ 1, 2, 3, 4 ],
[ 1, 2, 3, 4 ],
[ 1, 2, 3, 4 ]

X

[ 4, 3, 2, 1 ],
[ 4, 3, 2, 1 ],
[ 4, 3, 2, 1 ],
[ 4, 3, 2, 1 ]

=

Matrix Inverse (역행렬)

Matrix의 역행렬을 계산 합니다.
3 x 3 과 4 x 4 행렬만 계산이 가능합니다. 위 multiply 과 동일하게 1차 및 2차 배열 두 형태 모두 계산이 가능합니다.
역행렬이 기존 행렬과 동일하게 나오는 경우는 행렬 공식에서 inverseM = 1/det(M) * adj(M) 에서 det(M) = 0 인 경우는 역행렬이 성립할 수 없으므로 기존 행렬 값을 반환 합니다.
참고 : https://en.wikipedia.org/wiki/Invertible_matrix

@@include( 'codeTop.html' ) var matrix = MatrixCalc.inverse(m); @@include( 'codeBtm.html' )

Multiply과 동일하게 1차 2차 배열 입력이 가능합니다.
예제는 1차 배열만 다루었고 실제 값은 복잡하여 소수점 1번째 이상 값만 표현 한 것 입니다.

1, 2, 3, 4,
4, 5, 6, 4,
1, 2, 4, 4,
9, 7, 3, 4

=

Transform

Matrix를 이용한 transform 연산을 합니다.
Matrix transform을 css에 적용 시 킬 경우 3D transform 인 matrix3d(n, n, ....) 을 사용 하셔야 정상적으로 적용 됩니다. matrix3d 는 ie10 이상에 적용이 가능합니다. 2D transform 인 matrix(n, n, ....)에 적용을 위해서는 따로 변형이 필요합니다.
참고 : http://www.w3schools.com/css/css3_3dtransforms.asp

@@include( 'codeTop.html' ) var translate = MatrixTransform.translate([x, y, z]); var rotate = MatrixTransform.rotate([angleX, angleY, angleZ]); .... @@include( 'codeBtm.html' )
Translate

Matrix를 사용한 translate 좌표를 반환 합니다. 2D와 3D 개별 계산이 가능합니다.

@@include( 'codeTop.html' ) // 기본적으로 좌표의 수의 따라 2D와 3D를 구분 합니다. // 2D var translate = MatrixTransform.translate([x, y]); var translate = MatrixTransform.translate([x, y], matrix); //이전 값 + 입력 값 //3D var translate = MatrixTransform.translate([x, y, z]); var translate = MatrixTransform.translate([x, y, z], matrix); //이전 값 + 입력 값 // 좌표의 수가 아닌 직접 2D, 3D를 계산하는 함수를 호출 할 수도 있습니다. // 사용방법과 기능은 동일 합니다. var translate2D = MatrixTransform.translate2D([x, y]); //2D var translate3D = MatrixTransform.translate3D([x, y, z]); //3D @@include( 'codeBtm.html' )
  • X axis : 0
  • Y axis : 0
  • Z axis : 0
Rotate

사용법은 위 Translate와 동일 합니다. 각도는 Degree가 기본이며 Radian으로 사용 하시려면 변경 하신 후 사용 하셔야 합니다.

@@include( 'codeTop.html' ) // 기본적으로 입력 값의 수의 따라 2D와 3D를 구분 합니다. // 2D var rotate = MatrixTransform.rotate(angle); var rotate = MatrixTransform.rotate(angle, matrix); //이전 값 + 입력 값 //3D var rotate = MatrixTransform.rotate([angle, angle, angle]); var rotate = MatrixTransform.rotate([angle, angle, angle], matrix); //이전 값 + 입력 값 // 좌표의 수가 아닌 직접 2D, 3D를 계산하는 함수를 호출 할 수도 있습니다. // 사용방법과 기능은 동일 합니다. var rotate2D = MatrixTransform.rotate2D(angle); //2D var rotate3D = MatrixTransform.rotate3D([angle, angle, angle]); //3D //degree -> radian var radian = degree * Math.PI/180; //radian -> degree var degree = radian * 180/Math.PI; @@include( 'codeBtm.html' )
  • X axis : 0
  • Y axis : 0
  • Z axis : 0
Axis each rotate

X, Y, Z 각도를 각각 따로 입력 할 수 있습니다. 3D Matrix만 계산 가능하며 반환 값 역시 3D Matrix 입니다.

@@include( 'codeTop.html' ) var rotateX = MatrixTransform.rotateX(angle); var rotateY = MatrixTransform.rotateY(angle); var rotateZ = MatrixTransform.rotateZ(angle); // 위와 rotate와 동일하게 이전 값 입력도 가능합니다. var ratateX = MatrixTransform.rotateX(angle, matrix);//이전 값 + 입력 값 @@include( 'codeBtm.html' )
Scale

사용법은 Rotate와 동일하나 Rotate 처럼 개별 계산은 제공되지 않습니다. z scale은 값을 넣지 않아도 되며 기본 1로 설정되어 있습니다.

@@include( 'codeTop.html' ) //2D var scale = MatrixTransform.scale(scale); var scale = MatrixTransform.scale(scale, matrix); //이전 값 + 입력 값 //3D var scale = MatrixTransform.scale([scale, scale, scale]); or var scale = MatrixTransform.scale([scale, scale]); var scale = MatrixTransform.scale([scale, scale, scale], matrix); //이전 값 + 입력 값 or var scale = MatrixTransform.scale([scale, scale], matrix); //이전 값 + 입력 값 // 좌표의 수가 아닌 직접 2D, 3D를 계산하는 함수를 호출 할 수도 있습니다. // 사용방법과 기능은 동일 합니다. var scale2D = MatrixTransform.scale2D(scale); //2D var scale3D = MatrixTransform.scale3D([scale, scale, scale]); //3D @@include( 'codeBtm.html' )
  • X axis : 1
  • Y axis : 1
  • Z axis : 1
CSS Example

밑 예제 코드의 정육면체 배치는 직접 구현해 주세요.

<div class="target" style="width:100px; height:100px;">
	<div></div>
	<div></div>
	<div></div>
	<div></div>
	<div></div>
	<div></div>
</div>	
@@include( 'codeTop.html' ) var multiTarget = document.querySelector('.multiply .target'); var targetMatrix; targetMatrix = MatrixTransform.rotate([anglex, angley, anglez]); targetMatrix = MatrixTransform.translate([x, y, z], targetMatrix); multiTarget.style.transform = "matrix3d(" + targetMatrix + ")"; @@include( 'codeBtm.html' )
  • X angle : 30
  • Y angle : 30
  • Z angle : 30
  • X axis : 0
  • Y axis : 0
  • Z axis : 0
CSS Example2

Transform을 적용하는 순서에 따라 위 Multiply 과 결과가 다르게 나오게 됩니다. 비교해 보세요

<div class="target" style="width:100px; height:100px;">
	<div></div>
	<div></div>
	<div></div>
	<div></div>
	<div></div>
	<div></div>
</div>	
@@include( 'codeTop.html' ) var multiTarget = document.querySelector('.multiply .target'); var targetMatrix; // rotate와 translate 를 곱하는 순서가 위와 다릅니다. targetMatrix = MatrixTransform.translate([x, y, z]); targetMatrix = MatrixTransform.rotate([anglex, angley, anglez], targetMatrix); multiTarget.style.transform = "matrix3d(" + targetMatrix + ")"; @@include( 'codeBtm.html' )
  • X angle : 30
  • Y angle : 30
  • Z angle : 30
  • X axis : 0
  • Y axis : 0
  • Z axis : 0
Look at

대상을 카메라로 보는 것과 동일같은 효과룰 줄 수 있습니다. lookAt을 사용 하기 위해서는 벡터와 같은 수학적 지식이 약간 필요합니다. 우선 MatrixTransform.looAt() 코드롤 보시기 바랍니다. 코드 안에 Vector는 matrixcalc.js에 포함되어 있습니다.

lookAt : function(camera, target, up){
        up = up ? up : [0,1,0];
        var z = Vector.normalize(Vector.subtract(camera, target))
        ,   x = Vector.cross(up, z)
        ,   y = Vector.cross(z, x)
        ;
        return [
            x[0], x[1], x[2], 0, // X축 
            y[0], y[1], y[2], 0, // Y축
            z[0], z[1], z[2], 0, // Z축
            camera[0], camera[1], camera[2], 1 //camera 위치
        ];
    }
우선 Camera( 사람의 시선 )의 위치 x, y, z, 대상의 위치 x, y, z 가 필요합니다. 3D는 2D 처럼 평면이 아닌 구 형태입니다. 그래서 정규화 된 벡터를 단의로 사용하게 됩니다.
Z은 대상과 카메라의 거리를 의미 합니다. 즉 camera 위치에서 대상의 위치를 빼서 -Z 방향으로 카메라가 대상과 얼마나 떨어져 있는지 알 수 있습니다. 그 결과를 벡터 단위로 정규화 시키면 구 안에서의 Z를 구할 수 있습니다. X을 구하기 위해서는 벡터의 외적을 이용 합니다. 즉 Z * Y = X 를 이용해서 X의 값을 알 수 있습니다. 그래서 Y를 Z와 수직을 이루는 값 up = [0,1,0]로 설정을 하면 X의 값을 구할 수 있습니다. Y도 X와 동일하게 벡터의 외적을 이용하는데 Y와 수직을 이루는 Z와 X를 곱하면 Y의 값을 구할 수 있고 이를 matrix에 추가해 줍니다.
더 자세한 설명은 https://webglfundamentals.org/webgl/lessons/webgl-3d-camera.html 에서 참고 하시기 바랍니다.

밑에 lookAt을 이용한 예제 입니다. 위 cube 예제들은 6개의 element를 cube 모양으로 만들고 부모 element에 matrix를 적용하여 cube가 움직이게 했지만 이번 예제 에서는 부모 element를 조정 하지 않고 6개의 element에 matrix를 적용하였습니다.
위와 같은 방법으로 element를 조작하여도 같은 효과가 나오지만 이 예제를 통해 matrix의 다양한 적용 방법을 확인해 보시기 바랍니다.

/* HTML */
<ul class="target">
	<li> 1 </li>
	<li> 2 </li>
	<li> 3 </li>
	<li> 4 </li>
	<li> 5 </li>
	<li> 6 </li>
</ul>

<style>
	.target { position:absolute; top:50%; left:50%; width:100px; height:100px; transform:translate(-50%, -50%); perspective:2000px; transform-style:preserve-3d; }
	.target > li {position:absolute; top:0px; left:0px; width:100%; height:100%; background:red; color:#fff; border:2px solid #fff; font-size:30px;}
</style>

<script>
	var targets = document.querySelector('.target');
	var radius = 100; // Element를 원형으로 배치 하기 위한 지름 크기
	var cameraData = {
			x:0, y:0, z:radius*2, // 대상과 카메라의 거리를 반지름에 2배로 설정 
			anglex : 0,
			angley : 0,
			anglez : 0
		};
	var targetData = {
			x:0, y:0, z:0,
			anglex : 30,
			angley : 30,
			anglez : 30
		};

	draw();

	function draw(){
		var targetMatrix, cameraMatrix, viewMatrix;
		//lookat( 카메라 위치, 대상의 위치, x를 구하긴 위한 벡터 : 생략 가능한 argument로 생략 시 [0,1,0]로 설정한다.  )
		// 위치를 음수로 변경 하는 이유는 lookat 이후 cameraMatrix의 역행렬을 계산 시 값이 +로 변경하기 위해서 이다.
		cameraMatrix = MatrixTransform.lookAt([-cameraData.x,-cameraData.y,-cameraData.z*1.5 ], [0,0,0], [0,1,0]);
		cameraMatrix = MatrixTransform.rotate([cameraData.anglex,cameraData.angley,cameraData.anglez], cameraMatrix);

		//cameraMatrix의 역행렬을 구하면 기준이 대상이 아닌 카메라로 변경 된다.
		cameraMatrix = MatrixCalc.inverse(cameraMatrix);
		
		// 각 Element를 배치하고 CameraMatrix와 곱함
		// forEachChild 는 gaesigner common.js에 있습니다.
		targets.forEachChild(function(index){
			angle = index*Math.PI*2 / targets.children.length;
			// Element를 각도에 맞게 배치
			targetMatrix = MatrixTransform.rotateY(angle*180/Math.PI);

			// Element의 위치 및 각도 수정
			targetMatrix = MatrixTransform.translate([Math.sin(angle)*radius, 0, Math.cos(angle)*radius], targetMatrix);
			targetMatrix = MatrixTransform.rotate([targetData.anglex, targetData.angley, targetData.anglez], targetMatrix);
			targetMatrix = MatrixTransform.translate([targetData.x, targetData.y, targetData.z], targetMatrix);
			
			// 위치가 설정된 Element와 cameraMatrix를 곱하여 위치 및 모양 적용
			viewMatrix = MatrixCalc.multiply(targetMatrix, cameraMatrix);

			this.style.transform = "matrix3d(" + viewMatrix + ")";
		});
	}
</script>

Camera

  • X angle : 0
  • Y angle : 0
  • Z angle : 0
  • X position : 0
  • Y position : 0
  • Z position : 200

Target

  • X angle : 30
  • Y angle : 30
  • Z angle : 30
  • X axis : 0
  • Y axis : 0
  • Z axis : 0
1
2
3
4
5
6