Apple Engine

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

ARKit や SceneKit で使用している simd について - 型の初期化と演算子編 -

前回に引き続き simd の説明で、今回は simd 型の初期化と演算子に付いて。
行列型に関して他の記事で紹介する。

今回は ARKit や SceneKit で主に使用する以下のものの説明。
double は float と上限値以外は同じなので割愛。

  • float3
  • float4

 

直接使用することはないが simd_bool という Bool 型の Type Alias がある。

 

また、今回使用しない以下のものに関しても使い方は float とさほど変わりはない。

  • simd_short
  • simd_ushort
  • simd_int
  • simd_uint
  • simd_long
  • simd_ulong

 

float3 (simd_float3)

3つの Float 型を持つ型(構造体)
C / Objective-C の vector_float3 と C++ の simd::float3 と同等のもの。
simd_float3 は float3 の Type Alias。

 

初期化

パラメーターが3つあるため x, y, z で Float 値の読み書きが可能。
float3()、float3.init() で初期化した際には x, y, z には 0 が入り、パラメーターが1つの場合は同じ値が3つはいる。

配列での代入も可能で、数字での添字でも読み書きが可能。

var f3:float3
f3 = float3()                       // float3(0.0, 0.0, 0.0)
f3 = float3(1.0)                    // float3(1.0, 1.0, 1.0)
f3 = float3(1.0, 2.0, 3.0)          // float3(1.0, 2.0, 3.0)
f3 = float3(x: 1.0, y: 2.0, z: 3.0) // 上と同じ
f3 = float3([1.0, 2.0, 3.0])        // 上と同じ

f3.x // 1.0
f3.y // 2.0
f3.z // 3.0

f3[0] // f3.x と同じ
f3[1] // f3.y と同じ
f3[2] // f3.z と同じ

 

演算子

== や != での論理演算、符号の変更、四則演算が可能。
掛け算と割り算で片方がスカラーのものがあるが、左辺右辺が逆でも演算可能

var f3 = float3()
var f3_000 = float3(0)

f3 == f3_000 // true


var f3_222 = float3(2)
var f3_123 = float3( 1.0, 2.0, 3.0 )

f3_123 + f3_222 // float3( 3.0, 4.0, 5.0 )
f3_123 - f3_222 // float3(-1.0, 0.0, 1.0 )

-f3_222         // float3(-2.0, -2.0, -2.0)

f3_123 * f3_222 // float3( 2.0, 4.0, 6.0 )
f3_123 * 2      // float3( 2.0, 4.0, 6.0 )

f3_123 / f3_222 // float3(0.5, 1.0, 1.5)
f3_123 / 2      // float3(0.5, 1.0, 1.5)

var f3_Plus     = float3(6)
var f3_Minus    = f3_Plus
var f3_Product  = f3_Plus
var f3_Divide   = f3_Plus

f3_Plus    += f3_222 // float3(8.0, 8.0, 8.0)
f3_Minus   -= f3_222 // float3(4.0, 4.0, 4.0)
f3_Product *= f3_222 // float3(12.0, 12.0, 12.0)
f3_Divide  /= f3_222 // float3(3.0, 3.0, 3.0)

 

その他

Collection のプロトコルが適応されているため、map() や for in での列挙ができる。
また、CustomDebugStringConvertible に適合しているため、print などで文字出力がされる。

f3_123.map{ print("Value: \($0)") }
// Value: 1.0
// Value: 2.0
// Value: 3.0

for i in f3_123 {
    print(i)
}
// 1.0
// 2.0
// 3.0

print(f3_123) // float3(1.0, 2.0, 3.0)

 

float4 (simd_float4)

4つの Float 型を持つ型(構造体)
C / Objective-C の vector_float4 と C++ の simd::float4 と同等のもの。
simd_float4 は float4 の Type Alias。

演算子、その他に関しては float3 と同じなので割愛。

 

初期化

パラメーターが4つあるため x, y, z, w で Float 値の読み書きが可能。
float3 同様、初期化した際には x, y, z, w には 0 が入り、パラメーターが1つの場合は同じ値が4つ入る。

var f4:float4
f4 = float4()                               // float3(0.0, 0.0, 0.0, 0.0)
f4 = float4(1.0)                            // float3(1.0, 1.0, 1.0, 1.0)
f4 = float4(4.0, 3.0, 2.0, 1.0)             // float3(1.0, 2.0, 3.0, 1.0)
f4 = float4(x: 4.0, y: 3.0, z: 2.0, w: 1.0) // 上と同じ
f4 = float4([4.0, 3.0, 2.0, 1.0])           // 上と同じ

f4.x // 4.0
f4.y // 3.0
f4.z // 2.0
f4.w // 1.0

f4[0] // f4.x と同じ
f4[1] // f4.y と同じ
f4[2] // f4.z と同じ
f4[3] // f4.w と同じ

 

simd_make 系を使用した初期化

2パターンあり、1つは float2, float3 を使って初期化する。
引数の順番は全てのパターンが定義されているため自由。

// float4(0.0, 1.0, 2.0, 3.0)
let float4_3_1 = simd_make_float4(float3(0,1,2), 3)
let float4_2_2 = simd_make_float4(float2(0,1), float2(2,3))
let float4_2_1_1 = simd_make_float4(float2(0,1), 2, 3)

 

もう1つは引数で余った成分(要素)を 0 で埋める。

サフィックスで undef がつくものと付かないものがあるが、値の入れ忘れた時わかりやすいように 0 で埋める場合は undef の方が良いと思われる。

(Swift Playground で undef 系の返り値がおかしくなる場合があるので注意)

// float4(1.0, 0.0, 0.0, 0.0)
let float4_1 = simd_make_float4(1)

// float4(1.0, 2.0, 0.0, 0.0)
let float4_2 = simd_make_float4(float2(1,2))

// float4(1.0, 2.0, 3.0, 0.0)
let float4_3 = simd_make_float4(float3(1,2,3))

let float4_1u = simd_make_float4_undef(1)
let float4_2u = simd_make_float4_undef(float2(1,2))
let float4_3u = simd_make_float4_undef(float3(1,2,1))

 

SceneKit での使用例:nodeA の座標から nodeB の座標を求める

nodeA の子ノードに nodeB をする際、事前に nodeA からみた nodeB の座標を計算する。
ワールド座標を nodeB から nodeA に引くだけ。

ちなみに simd で用意されている関数でも同じことが可能。

f:id:x67x6fx74x6f:20181227164736p:plain

let nodeA = SCNNode()
let nodeB = SCNNode()

nodeA.simdPosition = float3(2.0, 0.0, 0.0)
nodeB.simdPosition = float3(2.0, 2.0, 0.0)

let calc = nodeB.simdWorldPosition - nodeA.simdWorldPosition
// float3(0.0, 2.0, 0.0)

 

まとめ

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

次回は simd 用意されている関数について。