Apple Engine

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

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度で行う事ができる。

f:id:x67x6fx74x6f:20180515183839p:plain

SIMD - Wikipedia

 

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 を見てゆく。