WWDC 2017 の SceneKit サンプル Fox 2 を調べる その11
今回は SimdExtensions.swift を調べていく。
以前から Apple の SceneKit のサンプルでは simd (Accelerate Framework と simd.h) を使用しており、 通常の Swift の計算より高速に行う事ができる。
https://developer.apple.com/documentation/accelerate/simd
Fox 2 では、ノードのトランスフォームを 4x4 の行列で行なっており、 iOS 11 SDK などから SceneKit に追加された simd のプロパティを使用して値を入れている。
SIMD とは?
雑に説明すると複数のデータ(レーン)を1回の処理で実行する並列化の形。
通常は SISD の形をとっており変数単位で計算を行うが、
SIMD は画像のように X,Y,Z,W の足し算を1度で行う事ができる。
SceneKit の SCNNode で使用できる simd 系の命令
simd_float3、simd_float4x4、simd_quatf、vector_float3 (simd_float3 の typealias) を入出力する。
最初の simd 省くと SCNNode 自体に大体存在するものなのでわかるかと。
- simdTransform
- simdPosition
- simdRotation
- simdEulerAngles
- simdOrientation
- simdScale
- simdPivot
- simdRotate
- simdLocalTranslate
- simdLocalRotate
- simdLook
- simdLocalRight
- simdLocalUp
- simdLocalFront
- simdWorldRight
- simdWorldUp
- simdWorldFront
- simdWorldTransform
- simdWorldPosition
- simdConvertPosition
- simdConvertTransform
- simdConvertVector
SimdExtensions.swift の中身
SimdExtensions.swift は simd の変数を簡単に扱うための extension が実装されており、
simd_float2, 3, 4, simd_float4x4 で機能追加がされている。
import
import Foundation のすぐ下に simd の呼び出しがある。
コアライブラリなので、GameplayKit のように「Linked Frameworks and Libraries」で追加しなくても大丈夫。
import simd
simd_float2
simd_float2 は float2 と同様に x, y の値を持つ。
extension simd_float2 { static let zero = simd_float2(0.0, 0.0) func allZero() -> Bool { return x == 0 && y == 0 } static func ==(left: simd_float2, right: simd_float2) -> simd_int2 { return simd_int2(left.x == right.x ? -1: 0, left.y == right.y ? -1: 0) } }
static の zero は simd_float2(0.0, 0.0) を返し、allZero() は x、y がゼロであった場合 true を返す。
比較して simd_int2 を返す == のオペレーターは Fox2 では使用されていない。
出力サンプル
let s1:simd_float2 = simd_float2.zero let s2:simd_float2 = simd_float2(0.0, 0.5) let o = simd_any(s1 == s2) // s1 == s2 は int2(-1, 0) /* 拡張した == オペレータでは互いの simd_float2 の x, y 比較した際に同じであれば -1 を返し、 simd_any はいずれかのベクトルレーンを比較した際、真である場合に true を返す。(ここでの真はー1) */ Swift.print("OUT: \(o)") // true Swift.print("OUT: \(s1.allZero())") // true Swift.print("OUT: \(s2.allZero())") // false
simd_float3
simd_float3 は float3 と同様に x, y, z の値を持つ。
extension simd_float3 { static let zero = simd_float3(0.0, 0.0, 0.0) func allZero() -> Bool { return x == 0 && y == 0 && z == 0 } static func ==(left: simd_float3, right: simd_float3) -> simd_int3 { return simd_int3(left.x == right.x ? -1: 0, left.y == right.y ? -1: 0, left.z == right.z ? -1: 0) } static func !=(left: simd_float3, right: simd_float3) -> simd_int3 { return simd_int3(left.x != right.x ? -1: 0, left.y != right.y ? -1: 0, left.z != right.z ? -1: 0) } }
static の zero は simd_float3(0.0, 0.0, 0.0) を返し、allZero() は x、y、z がゼロであった場合 true を返す。
比較して simd_int3 を返す == のオペレーターは Fox2 では使用されていない。振る舞いは simd_float2 と同じ。
!= のオペレーターは互いのレーンの x、y、z の値が異なっていたら真の値(ここでは-1)を返す。
simd_float4
simd_float4 は float4 と同様に x, y, z, w の値を持つ。
extension simd_float4 { static let zero = simd_float4(0.0, 0.0, 0.0, 0.0) static func ==(left: simd_float4, right: simd_float4) -> simd_int4 { return simd_int4(left.x == right.x ? -1: 0, left.y == right.y ? -1: 0, left.z == right.z ? -1: 0, left.w == right.w ? -1: 0) } var xyz: simd_float3 { get { return simd_float3(x, y, z) } set { x = newValue.x y = newValue.y z = newValue.z } } }
static の zero は simd_float4(0.0, 0.0, 0.0, 0.0) を返し、xyz はこの simd_float4 の x、y、z に値を入れたり、 x、y、z の simd_float3 を返す。
比較して simd_int4 を返す == のオペレーターは Fox2 では使用されていない。振る舞いは simd_float2 と同じ。
simd_float4x4
4 x 4 の行列。
extension simd_float4x4 { var position: simd_float3 { get { return columns.3.xyz } set { columns.3.xyz = newValue } } }
position というコンピューテッドプロパティを追加しており、4列目の x、y、z の値を設定している。
次回は、Character.swift を見てゆく。