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 で用意されている関数でも同じことが可能。
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 用意されている関数について。