Working with Matrices - juniverse1103/ARKitStudy GitHub Wiki

Working with Matrices

연립방정식을 ν’€κ³ , 곡간 λ‚΄μ˜ 점을 λ³€ν˜•μ‹œν‚€μ„Έμš”


Overview

ν–‰λ ¬(matrix)은 ν–‰(row)κ³Ό μ—΄(column)둜 이루어진 2차원 λ°°μ—΄μž…λ‹ˆλ‹€. simd λΌμ΄λΈŒλŸ¬λ¦¬λŠ” μ΅œλŒ€ 4개의 ν–‰κ³Ό 4개의 μ—΄μ˜ 16개의 μ›μ†Œλ₯Ό ν¬ν•¨ν•˜λŠ” 행렬듀에 λŒ€ν•œ 지원을 μ œκ³΅ν•©λ‹ˆλ‹€. 이 λΌμ΄λΈŒλŸ¬λ¦¬λŠ” 컬럼(μ—΄) 메이저 넀이밍 μ»¨λ²€μ…˜(Column major naming convention)을 μ‚¬μš©ν•©λ‹ˆλ‹€;

예λ₯Ό λ“€μ–΄, simd_doublel4x2 λŠ” 4개의 컬럼(μ—΄)κ³Ό 2개의 둜우(ν–‰)을 ν¬ν•¨ν•˜λŠ” 맀트릭슀(ν–‰λ ¬)μž…λ‹ˆλ‹€.

simd λΌμ΄λΈŒλŸ¬λ¦¬λŠ” 적절히 크기가 μ‘°μ •λœ λ²‘ν„°λ“€λ‘œλΆ€ν„° ν–‰λ ¬μ˜ ν–‰ λ˜λŠ” 열을 μƒμ„±ν• μˆ˜ μžˆλŠ” μ˜΅μ…˜μ„ ν¬ν•¨ν•˜λŠ” μƒμ„±μž(initializer)λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, λ‹€μŒμ˜ μ½”λ“œλŠ” λ„€ 개의 μ›μ†Œλ₯Ό κ°€μ§€λŠ” 두 벑터λ₯Ό μ‚¬μš©ν•˜μ—¬ 2 x 4 ν–‰λ ¬κ³Ό 4 x2 행렬을 μƒμ„±ν•©λ‹ˆλ‹€:

let x = simd_double4(x: 10, y: 20, z: 30, w: 40)
let y = simd_double4(x:  1, y: 2, z: 3, w: 4)

/* 
A matrix of two columns and four rows:

	10 1
	20 2
	30 3
	40 4

*/
let a = simd_double2x4([x,y])

/* 
A matrix of four columns and two rows"

	10 20 30 40
	1  2  3  4

*/
let b = simd_double4x2(row:[x,y])

λ‹€μŒμ˜ μ˜ˆμ‹œλ“€μ€ ν–‰λ ¬μ˜ 보편적인 μ‚¬μš©λ²•μ„ λ³΄μ—¬μ€λ‹ˆλ‹€.

Solve Simultaneous Equations

AX = B ν˜•νƒœμ˜ 연립방정식을 ν’€κΈ° μœ„ν•΄ 행렬을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€; 예λ₯Ό λ“€μ–΄, λ‹€μŒκ³Ό 같은 λ°©μ •μ‹μ—μ„œ x와 yλ₯Ό μ°ΎλŠ”λ° μ‚¬μš©ν•©λ‹ˆλ‹€:

2x + 4y = 2
-4x + 2y = 14

λ¨Όμ € μ’Œλ³€μ˜ κ³„μˆ˜λ₯Ό ν¬ν•¨ν•˜λŠ” 2x2 행렬을 μƒμ„±ν•©λ‹ˆλ‹€.

let a = simd_2x2(rows: [simd_double2(2,4), simd_double2(-4,2)])

그리고 μš°λ³€μ˜ 값을 ν¬ν•¨ν•˜λŠ” 벑터λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€.

let b = simd_double2(2,14)

x와 y의 값을 κ΅¬ν•˜κΈ° μœ„ν•΄μ„œ, a ν–‰λ ¬μ˜ μ—­ν–‰λ ¬κ³Ό 벑터 bλ₯Ό κ³±ν•΄μ€λ‹ˆλ‹€:

let x = simd_mul(a.inverse, b)

κ²°κ³Ό x λŠ” λ‘κ°œμ˜ μ›μ†Œλ₯Ό κ°€μ§€λŠ” 벑터 (x,y) = (-2.6,1.8) μž…λ‹ˆλ‹€.

Transform Vectors with Matrix Multiplication

행렬은 2Dλ‚˜ 3D 곡간 내에 μžˆλŠ” 점듀을 λ³€ν˜•(이동(translate), νšŒμ „(rotate), 배율(scale))μ‹œν‚€κΈ° μœ„ν•œ νŽΈλ¦¬ν•œ 방법을 μ œκ³΅ν•©λ‹ˆλ‹€.

λ‹€μŒμ˜ μ΄λ―Έμ§€λŠ” 점 Aκ°€ B둜 μ΄λ™λœ 것, C둜 νšŒμ „λœ 것, 그리고 D둜 배율된 것을 λ³΄μ—¬μ€λ‹ˆλ‹€.

2D μ’Œν‘œλ“€μ„ 3개의 μ›μ†Œλ₯Ό κ°€μ§€λŠ” λ²‘ν„°λ‘œ λ‚˜νƒ€λ‚΄λŠ” κ²ƒμœΌλ‘œ, ν–‰λ ¬ 곱을 톡해 점듀을 λ³€ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 일반적으둜, κ³΅κ°„μ—μ„œμ˜ μœ„μΉ˜λ₯Ό λ‚˜νƒ€λ‚΄λŠ” λ²‘ν„°μ˜ 3번째 μ›μ†ŒμΈ zλŠ” 1으둜 κ³ μ •λ©λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄, μœ„ κ·Έλ¦Όμ—μ„œ 점 Aλ₯Ό λ‚˜νƒ€λ‚΄λŠ” λ²‘ν„°λŠ”simd_float3둜 λ‹€μŒ μ½”λ“œμ™€ 같이 μ •μ˜λ©λ‹ˆλ‹€.

let positionVector = simd_float3(x: 3, y: 2, z: 1)

2차원 μ’Œν‘œκ³„μ— λŒ€ν•œ λ³€ν™˜ 행렬은 3x3 ν–‰λ ¬λ‘œ λ‚˜νƒ€λ‚΄μ–΄μ§‘λ‹ˆλ‹€.

Translate

이동 λ³€ν™˜ 행렬은 λ‹€μŒκ³Ό 같은 ν˜•νƒœλ₯Ό κ°€μ§‘λ‹ˆλ‹€:

1 0 0

0 1 0

tx ty 1

simd λΌμ΄λΈŒλŸ¬λ¦¬λŠ” ν•­λ“± ν–‰λ ¬(λŒ€κ°μ„ μ„ 따라 1이 있고, λ‚˜λ¨Έμ§€ 뢀뢄에 0이 μ‘΄μž¬ν•˜λŠ”)에 λŒ€ν•œ μƒμˆ˜λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€. 3x3 Float ν•­λ“± 행렬은 matrix_identity_float3x3 μž…λ‹ˆλ‹€.

λ‹€μŒμ˜ ν•¨μˆ˜λŠ” ν•­λ“± ν–‰λ ¬μ˜ μ›μ†Œλ₯Ό μ„€μ •ν•˜λŠ” κ²ƒμœΌλ‘œ νŠΉμ •ν•œ tx와 ty값에 따라 simd_float3x3 행렬을 λ°˜ν™˜ν•©λ‹ˆλ‹€.

func makeTranslationMatrix(tx: Float, ty: Float) -> simd_float3x3{
    var matrix = matrix_identity_float3x3
    
    matrix[0,2] = tx
    matrix[1,2] = ty
    
    return matrix
}

μœ„μΉ˜λ²‘ν„°μ˜ 이동을 μ μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” 각 μŒμ„ μ„œλ‘œ κ³±ν•©λ‹ˆλ‹€.

let translationMatrix = makeTranslationMatrix(tx: 1, ty: 3)
let translatedVector = positionVector * translationMatrix

translatedVector의 κ²°κ³ΌλŠ” μœ„ 그림에 λ‚˜νƒ€λ‚œ 점 B와 같이 (x: 4.0, y: 5.0, z: 1.0) 의 값을 κ°€μ§‘λ‹ˆλ‹€.

Rotate

νšŒμ „ λ³€ν™˜ 행렬은 λ‹€μŒκ³Ό 같은 ν˜•νƒœλ₯Ό κ°€μ§‘λ‹ˆλ‹€.

cos(angle) sin(angle) 0

-sin(angle) cos(angle) 0

0 0 1

λ‹€μŒ ν•¨μˆ˜λŠ” νŠΉμ •λœ λΌλ””μ•ˆμ˜ νšŒμ „κ°λ„μ— 따라 simd_float3x3행렬을 λ°˜ν™˜ν•©λ‹ˆλ‹€.

func makeRotationMatrix(angle: Float) -> simd_float3x3{
    let rows = [
        simd_float3(cos(angle), sin(angle), 0),
        simd_float3(-sin(angle), cos(angle), 0),
        simd_float3(0,			 0, 		 1)
    ]
    return float3x3(rows: rows)
}

이전에 μ΄λ™λœ 벑터에 νšŒμ „ λ³€ν™˜μ„ μ μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ”, 두 μŒμ„ μ„œλ‘œ κ³±ν•˜λ©΄ λœλ‹€.

let rotationMatrix = makeRotationMatrix(angle: GLKMatehDegreesToRadians(30))
let rotatedVector = translatedVector * rotationMatrix

rotatedVector의 결과값은 (x: 0.964102, y: 6.33013, z: 1.0)으둜 μœ„ 그림에 λ‚˜νƒ€λ‚œ 점 C와 κ°™λ‹€.

Scale

배율 λ³€ν™˜ 행렬은 λ‹€μŒκ³Ό 같은 ν˜•νƒœλ₯Ό κ°€μ§‘λ‹ˆλ‹€.

xScale 0 0

0 yscale 0

0 0 1

λ‹€μŒ ν•¨μˆ˜λŠ” νŠΉμ •ν•œ x와 y λ°°μœ¨κ°’μ— 따라 simd_float3x3행렬을 λ°˜ν™˜ν•©λ‹ˆλ‹€.

func makeScaleMatrix(xScale: Float, yScale: Float)->sim_float3x3{
    let rows = [
        simd_float3(xScale, 	0, 0),
        simd_float3(	 0, yScale, 0),
        simd_float3(	 0, 	0, 1)
    ]
    
    return float3x3(rows: rows)
}

이전에 νšŒμ „λœ 벑터에 λŒ€ν•˜μ—¬ 배율 λ³€ν™˜μ„ μ μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” 두 μŒμ„ μ„œλ‘œ κ³±ν•˜λ©΄ λœλ‹€.

let scaleMatrix = makeScaleMatrix(xScale: 8, yScale: 1.25)
let scaledVector = rotateVector * scaleMatrix

scaledVector의 결과값은 (x: 7.71282, y: 7.91266, z: 1.0) 으둜 μœ„ 그림에 λ‚˜νƒ€λ‚œ 점 2와 κ°™λ‹€.

이 μ„Έκ°€μ§€μ˜ λ³€ν™˜ 행렬은 μ „λΆ€ κ³±ν•΄μ§ˆ 수 있으며, 이와 κ³±ν•΄μ§„ μœ„μΉ˜λ²‘ν„° μ—­μ‹œ 같은 κ²°κ³Όλ₯Ό κ°€μ§„λ‹€:

let transformMatrix = translationMatrix * rotationMatrix * scaleMatrix
let transformedVector = positionVector * transformMatrix