Apple Engine

Apple, iPhone, iOS, その周辺のことについて

ARKit や SceneKit で使用している simd について - 行列型編 -

今回は 行列型と初期化について。
ARKit や SceneKit で主に使用する float4x4 を説明する。

double4x4 は float4x4 と上限値以外は同じなので 割愛。

float4x4 と double4x4、クオータニオン以外では、以下の行列が用意されており、double や float、行列の数が違うだけで扱いは同じ。

  • simd_float2x2
  • simd_float3x2
  • simd_float4x2
  • simd_float2x3
  • simd_float3x3
  • simd_float4x3
  • simd_float2x4
  • simd_float3x4
  • simd_double2x2
  • simd_double3x2
  • simd_double4x2
  • simd_double2x3
  • simd_double3x3
  • simd_double4x3
  • simd_double2x4
  • simd_double3x4

 

simd_float4x4 (float4x4)

4つの float4 型を持つ型(構造体)で、パラメーターは 4 x 4 なので、総数は16個となる。
以前あった matrix_float4x4 と同等のもの。

こちらは simd_float4x4 で型がつくられており、float4x4 は simd_float4x4 の Type Alias となっている。

 

初期化

対角成分に同じ値を入れる
var f4x4 = simd_float4x4(1)
/*
simd_float4x4([
    [1.0, 0.0, 0.0, 0.0)],
    [0.0, 1.0, 0.0, 0.0)],
    [0.0, 0.0, 1.0, 0.0)],
    [0.0, 0.0, 0.0, 1.0)]
])
*/
index x y z w
0 1 0 0 0
1 0 1 0 0
2 0 0 1 0
3 0 0 0 1

 

対角成分に設定した値を入れる
var f4x4 = simd_float4x4(diagonal: float4(4.0, 3.0, 2.0, 1.0) )
/*
simd_float4x4([
    [4.0, 0.0, 0.0, 0.0)],
    [0.0, 3.0, 0.0, 0.0)],
    [0.0, 0.0, 2.0, 0.0)],
    [0.0, 0.0, 0.0, 1.0)]
])
*/
index x y z w
0 4 0 0 0
1 0 3 0 0
2 0 0 2 0
3 0 0 0 1

 

float4 の配列か、float4 をそのまま渡し初期化する
var f4x4:simd_float4x4

f4x4 = simd_float4x4(
    float4(1.0, 0.0, 0.0, 0.0),
    float4(0.0, 1.0, 0.0, 0.0),
    float4(0.0, 0.0, 1.0, 0.0),
    float4(4.0, 3.0, 2.0, 1.0)
)

f4x4 = simd_float4x4([
    float4(1.0, 0.0, 0.0, 0.0),
    float4(0.0, 1.0, 0.0, 0.0),
    float4(0.0, 0.0, 1.0, 0.0),
    float4(4.0, 3.0, 2.0, 1.0)
])

/*
simd_float4x4([
    [1.0, 0.0, 0.0, 0.0)],
    [0.0, 1.0, 0.0, 0.0)],
    [0.0, 0.0, 1.0, 0.0)],
    [4.0, 3.0, 2.0, 1.0)]
])
*/
index x y z w
0 1 0 0 0
1 0 1 0 0
2 0 0 1 0
3 4 3 2 1

 

列ベクトルの flaot4 を行で初期化する
var f4x4 = simd_float4x4(rows: [
    float4(1.0, 0.0, 0.0, 0.0),
    float4(0.0, 1.0, 0.0, 0.0),
    float4(0.0, 0.0, 1.0, 0.0),
    float4(4.0, 3.0, 2.0, 1.0)
])

/*
simd_float4x4([
    [1.0, 0.0, 0.0, 4.0)],
    [0.0, 1.0, 0.0, 3.0)],
    [0.0, 0.0, 1.0, 2.0)],
    [0.0, 0.0, 0.0, 1.0)]
])
*/
index x y z w
0 1 0 0 4
1 0 1 0 3
2 0 0 1 2
3 0 0 0 1

 

呼び出し

値は通常の多重配列の様に呼び出すことができる。

var f4x4 = simd_float4x4(1)

f4x4[0]    // float4(1.0, 0.0, 0.0, 0.0)
f4x4[0][0] // 1.0

 

演算子

== や != での論理演算、、符号の変更、割り算を除いた四則演算が可能。 掛け算と片方が simd_flaot4x4 以外のものがあるが、左辺右辺が逆でも演算可能。

ただし、行列であるため左辺右辺を逆にすると演算結果が変わる場合があるので注意。

let f4x4 = simd_float4x4(1)
let f4x4_0 = simd_float4x4(1)

f4x4 == f4x4_0 // true

-f4x4
/*
simd_float4x4([
    [-1.0, 0.0, 0.0, 0.0)],
    [0.0, -1.0, 0.0, 0.0)],
    [0.0, 0.0, -1.0, 0.0)],
    [0.0, 0.0, 0.0, -1.0)]
])
*/

var f4x4_1 = simd_float4x4(2)
var f4x4_2 = simd_float4x4(
    float4(1.0, 0.0, 0.0, 0.0),
    float4(0.0, 1.0, 0.0, 0.0),
    float4(0.0, 0.0, 1.0, 0.0),
    float4(4.0, 3.0, 2.0, 1.0)
)

f4x4_1 + f4x4_2
f4x4_1 += f4x4_2
/*
simd_float4x4([
    [3.0, 0.0, 0.0, 0.0)],
    [0.0, 3.0, 0.0, 0.0)],
    [0.0, 0.0, 3.0, 0.0)],
    [4.0, 3.0, 2.0, 3.0)]
])
*/

f4x4_1 - f4x4_2
f4x4_1 -= f4x4_2
/*
simd_float4x4([
    [ 1.0,  0.0,  0.0,  0.0)],
    [ 0.0,  1.0,  0.0,  0.0)],
    [ 0.0,  0.0,  1.0,  0.0)],
    [-4.0, -3.0, -2.0,  1.0)]
])
*/

f4x4_1 * f4x4_2
f4x4_1 *= f4x4_2
/*
simd_float4x4([
    [2.0, 0.0, 0.0, 0.0)],
    [0.0, 2.0, 0.0, 0.0)],
    [0.0, 0.0, 2.0, 0.0)],
    [8.0, 6.0, 4.0, 2.0)]
])
*/

f4x4_2 * 2.0
/*
simd_float4x4([
    [2.0, 0.0, 0.0, 0.0)],
    [0.0, 2.0, 0.0, 0.0)],
    [0.0, 0.0, 2.0, 0.0)],
    [8.0, 6.0, 4.0, 2.0)]
])
*/

f4x4_2 * float4(2.0, 2.0, 2.0, 2.0)
// float4(10.0, 8.0, 6.0, 2.0)


var f4x4_3 = simd_float4x4(
    float4(1.0, 2.0, 3.0, 0.0),
    float4(2.0, 1.0, 2.0, 0.0),
    float4(3.0, 2.0, 1.0, 0.0),
    float4(4.0, 3.0, 2.0, 1.0)
)

f4x4_3 * float2x4(2)
/*
simd_float2x4([
    [2.0, 4.0, 6.0, 0.0)],
    [4.0, 2.0, 4.0, 0.0)]
])
*/

f4x4_3 * float3x4(2)
/*
simd_float3x4([
    [2.0, 4.0, 6.0, 0.0)],
    [4.0, 2.0, 4.0, 0.0)],
    [6.0, 4.0, 2.0, 0.0)]
])
*/

 

その他

転置行列、逆行列、行列式の結果を返すプロパティがある。

var f4x4 = simd_float4x4(
    float4(1.0, 0.0, 0.0, 0.0),
    float4(0.0, 1.0, 0.0, 0.0),
    float4(0.0, 0.0, 1.0, 0.0),
    float4(4.0, 3.0, 2.0, 1.0)
)

f4x4.tranpose
/*
simd_float4x4([
    [1.0, 0.0, 0.0, 4.0)],
    [0.0, 1.0, 0.0, 3.0)],
    [0.0, 0.0, 1.0, 2.0)],
    [0.0, 0.0, 0.0, 1.0)]
])
*/

f4x4.inverse
/*
simd_float4x4([
    [0.99999994, 0.0, 0.0, 0.0)],
    [0.0, 0.99999994, 0.0, 0.0)],
    [0.0, 0.0, 0.99999994, 0.0)],
    [-3.9999998, -2.9999998, -1.9999999, 0.99999994)]
])
*/

f4x4.determinant // 1.0

 

columns を使うと行をタプルで呼び出しができる。

f4x4.columns
/*
[
    float4(1.0, 0.0, 0.0, 0.0),
    float4(0.0, 1.0, 0.0, 0.0),
    float4(0.0, 0.0, 1.0, 0.0),
    float4(4.0, 3.0, 2.0, 1.0)
]
*/

f4x4.columns.3
// float4(4.0, 3.0, 2.0, 1.0)

 

まとめ

float4x4 も Float の値を入れ初期化し、簡単に行列を計算できることがわかったと思われる。

次回は行列で使用できる関数について。