がんばって USD ファイルをテキストで書いてみる
SCNScene から USDA が書きだせたので調べながら手書きで書いてみる。
今回は Apple 製品で動くものなので、実際の USD の仕様と異なるので注意。
本来は公式ページから GitHub へ行きツール群をビルドしそこから振る舞いを調べるべきなのだが、自分の環境だと USD 関連でビルドに必要な PySide がビルドできないため諦めた。
多分、Qt が悪さをしている。
プリミティブを描画してみる
USDA では最初の行に「#usda 1.0」が必要になる。
ひとまず、球体を描画してみる。
#usda 1.0 def Sphere "sphere" {}
立方体、円錐などが描画できる。
#usda 1.0 def Cube "cube" {}
#usda 1.0 def Cone "cone" {}
空のノード追加してみる
「def Scope "ノード名"」で SceneKit で言う所の SCNNode として定義し追加できる。
#usda 1.0 def Scope "Node" { }
また、入れ子にもできる。
#usda 1.0 def Scope "Node" { def Scope "Node2" { } }
メッシュ(ジオメトリ)をつくってみる
メッシュは「def Mesh」で定義でき、 基本的には SceneKit のカスタムジオメトリと作り方は同じで、 頂点の位置とインデックス、面を貼るためのカウント、テクスチャ用の UV、法線を設定してジオメトリが完成する。
以下のコードでは三角形のメッシュを描画する。
#usda 1.0 def Mesh "CustomMesh" { uniform bool doubleSided = 0 float3[] extent = [(0, 0, 0), (1, 1, 0)] int[] faceVertexCounts = [3] int[] faceVertexIndices = [0, 1, 2] normal3f[] normals = [(0, 0, 1),(0, 0, 1),(0, 0, 1)] point3f[] points = [(0, 0, 0),(1, 0, 0),(0, 1, 0)] float2[] primvars:Texture_uv = [(0.0, 0.0),(1.0, 0.0),(0.0, 1.0)]( interpolation = "vertex" ) }
以下、コードを軽く説明。
パラメーター | 説明 |
---|---|
doubleSided | メッシュの表示設定。0 で片面、1で両面。省略可。 |
extent | メッシュの大きさ。省略可。 |
faceVertexCounts | 面の頂点数。3で Xcode では三角ポリゴン意外は表示できない模様 |
faceVertexIndices | あとで設定するポイントの配列の順番。時計回りで座標プラス値方向に面が貼られる。 |
normals | 各頂点の法線。 |
points | 各頂点の座標。 |
primvars:Texture_uv | 各頂点の 0 〜 1 の UV 値。「(interpolation = "vertex")」は頂点を参照してつけるためこれを省略するとテクスチャが貼られない。 |
ちなみにポイント4点のメッシュを作る場合は三角形のポリゴンを2つ組み合わせる。
#usda 1.0 def Mesh "CustomMesh" { uniform bool doubleSided = 0 float3[] extent = [(0, 0, 0), (1, 1, 0)] int[] faceVertexCounts = [3,3] int[] faceVertexIndices = [0, 1, 2, 2, 1, 3] normal3f[] normals = [(0, 0, 1),(0, 0, 1),(0, 0, 1),(0, 0, 1)] point3f[] points = [(0, 0, 0),(1, 0, 0),(0, 1, 0),(1, 1, 0)] float2[] primvars:Texture_uv = [(0.0, 0.0),(1.0, 0.0),(0.0, 1.0),(1.0, 1.0)]( interpolation = "vertex" ) }
scn ファイルに変換してテクスチャを貼るとこんな感じ。
カメラを追加する
「def Camera」で定義できる。
以下、SceneKit のカメラ設定と名前が同じなので分かりやすいだろう。
下から2つの xformOp:transform と xformOpOrder はカメラの位置、回転、拡大縮小を設定するトランスフォームの値。
#usda 1.0 def Camera "camera" { float2 clippingRange = (100, 10000) float focalLength = 20.784609 float focusDistance = 300 float fStop = 5.6 float horizontalAperture = 36 float verticalAperture = 24 matrix4d xformOp:transform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0.5, 0.5, 1.0, 1) ) uniform token[] xformOpOrder = ["xformOp:transform"] }
その他設定
初期設定。
defaultPrim は起点となる Scope(ノード)、endTimeCode、startTimeCode、timeCodesPerSecond はアニメーション設定。
upAxis は上方向の軸。
#usda 1.0 ( defaultPrim = "Node" endTimeCode = 1 startTimeCode = 1 timeCodesPerSecond = 60 upAxis = "Z" ) def Sphere "sphere" {}
まとめ
気合いがあれば書けるがかなり面倒。
Blender とかで直接書き出せるようになってほしい。
SceneKit アプリで使用しているシーンを Pixar USD として書き出す
Model I/O framework は Metal で使用する一連をアセット操作するものがああり、ファイルを読み込んでアセットにしたり、アセットを別のファイル形式に書き出すことができる。
アセットの設定は Model I/O の MDLAsset を使用するのだが、MDLAsset では SceneKit のシーンファイル以外にも SCNScene 自体を読み込みアセットとして作成すること可能。
自分の場合 iOS でファイル操作をするのが面倒だったので macOS の NSOpenPanel で書き出すフォルダを調べてそこに書き出したが、 iOS の場合はアプリのドキュメントフォルダに保存するなどで書き出せると思われる。
注意点
SCNScene が正確に書き出されるわけではないの注意。
現状、基礎情報、ジオメトリ、カメラのみ書き出され、ライトなどは無視される。
ジオメトリはマテリアル、位置や回転や拡大縮小、アニメーション情報など付加されないので、この書き出しは Xcode のコマンドラインから USDZ に変換する用のものと考えてよいと思われる。
また、ワールド座標が Z 軸が上の Z up で書き出されるのでかなり罠。
USD の仕様に合わせていると思われ、xcrun usdz_converter では Y up かつ Physically Based のマテリアルが再設定される。
内容的には Xcode 上のデバッグの View UI Hierarchy で SCNScene を選択した際の「Export」から吐き出されるファイルに近い。
コード
SceneKit は Model I/O を内包しているが、SceneKit の機能を参照する Model I/O の機能であるため、以下のインポートが必要。
import SceneKit.ModelIO
以下のコードで SCNScene と書き出し先のフォルダを設定する。
var assets = MDLAsset.init(scnScene: scene) var fileURL = URL(string: "書き出しフォルダまでのパス")! fileURL.appendPathComponent("export.usda") if(MDLAsset.canExportFileExtension("usda")){ do { try self.assets.export(to: fileURL) } catch let error { DispatchQueue.main.async { print(error.localizedDescription) } } }else{ print("This file format (extension) is not supported") }
コードではアスキーファイルの USDA を設定しているが、バイナリ版の USDC も可能。
USDZ での書き出しはできない。
iOS の場合、USDC は USDZ 同様に QuickLook でプレビューできるため、USDC ファイルを直接もしくは Mac などの AirDrop でファイルアプリに保存すると AR のプレビューができる。
(ただし、そのままだとワールド座標が Z up になる)
まとめ
使い道はあまりないが、アプリで使用している SCNScene の USD 書き出しが簡単できることがわかった。
Xcode 10 系で scnassets フォルダにファイルを追加すると CodeSign failed エラーになる件
原因不明。
現象
Automatically manage signing で Team を設定し実機にビルド。
最初は実機で動作したが、scnassets フォルダにファイルを追加すると
「Command CodeSign failed with a nonzero exit code」でビルドが止まる。
対処法
scnassets フォルダを選択し Identity and Type (Command + Option + 1) で Target Membership のチェックを外して一度ビルド。
再度チェックを入れてビルドする。
もしくは scnassets フォルダ を使用しない。
根本的な解決方法があったら教えて欲しい。
ARKit (SceneKit) で Unreal Engine や Unity のようなグローパーティクルをつくる
SceneKit でグローなパーティクルのサンプルがなかったのでつくってみることにした。
つくってから気がついたが Apple 謹製のサンプルファイル Fox 2 での背景の火の粉のパーティクルがそれに当たる。
パーティクルにグローができる原理
3DCG におけるグローとは、カメラにおける光の滲みのような状態で、強い光源にレンズを向けた際に光が白っぽくかぶるフレア現象。
または、デジカメで強い光源がイメージセンサーに画素の許容量を超えた際に光が滲んだように周囲に広がるブルーミングのこと。
SceneKit では HDR 設定をオンにして Bloom の設定をいじり、ジオメトリでマテリアルの輝きの値である Emission をあげるとグローができる。
これと同様にパーティクルも輝きの値をあげるとグローの表現が実現できる。
パーティクルで追加された設定
iOS 11 の SCNParticleSystem では、パーティクルに輝度を与える以下のプロパティが追加されている。
- particleIntensity
- particleIntensityVariation
particleIntensity は輝度で、particleIntensityVariation 他の variation と同様にパーティクル生成時に入れた値をプラスマイナスする。
particleIntensity が 4、particleIntensityVariation 2 の場合、4 ± 2 となるので、2 〜 6 の値が生成時にランダムで設定される。
HDR の設定をしてみる
今回、作成したサンプルが ARKit のプロジェクトであるためカメラ設定をコードで書いているが、Scene Editor でカメラを設置して値をいじった方が楽だと思われる。
hdrCamera = sceneView.pointOfView?.camera hdrCamera.wantsHDR = true hdrCamera.wantsExposureAdaptation = true hdrCamera.exposureAdaptationBrighteningSpeedFactor = 0.4 hdrCamera.exposureAdaptationDarkeningSpeedFactor = 0.6 hdrCamera.minimumExposure = -15 hdrCamera.maximumExposure = 15 hdrCamera.bloomIntensity = 2.0 hdrCamera.bloomThreshold = 0.6 hdrCamera.bloomBlurRadius = 30
軽く説明すると wantsHDR = true で HDR カメラ表示に変更、wantsExposureAdaptation と以下で露出の自動調整を行なっている。
その下の bloomIntensity、bloomThreshold、bloomBlurRadius でブルーム効果の設定を行なっている。
文字通り bloomIntensity でブルームの強さ、bloomThreshold でしきい値、bloomBlurRadius で光の滲み具合の半径設定している。
bloomIntensity や bloomBlurRadius を小さくしすぎたり、bloomThreshold を大きすると効果が現れないので注意。
パーティクルの設定
画像や下の方にある GitHub のサンプルファイルを参照。 particleIntensity は強めの 3 を設定している。
今回のグローとは関係ないが、Animate Color で色を設定するとパーティクルが消えるまで左から右へと色が変化する。右側のアルファ値を 0 にすると徐々に消えていくようになる。
また、Color variation で HSB の色のヴァリエージョン値を設定すると各パーティクルで色が変わる。
サンプルファイル
まとめ
HDR とパーティクルの設定を行うだけでもわりとドラマチック?な表現ができると思われる。
サンプルファイルではジオメトリが大きすぎてわかりづらいが、Depth Of Field をちゃんと設定すると背景のボケが付加できたりするとさらに効果的になる。
Blackmagic eGPU / eGPU Pro、Vega 16 / 20 どれを選ぶか
Apple、Macbook Pro の Web ページに eGPU Pro のグラフが追加されていたのでまとめてみた。
eGPU Pro と eGPU の価格差は 1.66 倍。
Apple のページを信じると妥当な感じである。
GPU | 税別価格 |
---|---|
eGPU Pro (Vega 56) | 149,000 |
eGPU (RX 580) | 89,800 |
以下、MacBook Pro 15 inch の GPU Radeon RX 560X を 1 とした時の割合。
一応、PC で動作させている GPU の差でも 40〜60% ぐらいなので許容範囲。
eGPU | eGPU Pro | 差 | |
---|---|---|---|
Unity Editor | 2.3倍 | 3.8倍 | 1.65倍 |
Rise of the Tomb Raider | 2倍 | 3倍 | 1.5倍 |
Blackmagic DaVinci Resolve Studio | 1.8倍 | 2.7倍 | 1.5倍 |
Maxon Cinema 4D | 3.1倍 | 4.7倍 | 1.51倍 |
Final Cut Pro X | 1.3倍 | 1.6倍 | 1.23倍 |
MacBook Pro 15inch Vega 16 / 20
公式では Vega20 で RX 560X と比べて 60% UP らしい、ページのものと照らし合わせてみるとこの様な感じ。
Vega 20 | eGPU | eGPU Pro | |
---|---|---|---|
Unity Editor | 1.6倍 | 2.3倍 | 3.8倍 |
Rise of the Tomb Raider | 1.5倍 | 2倍 | 3倍 |
Blackmagic DaVinci Resolve Studio | 1.55倍 | 1.8倍 | 2.7倍 |
Maxon Cinema 4D | 1.6倍 | 3.1倍 | 4.7倍 |
Vega 20 は ¥38,500(税別)なので 38500 / 6 = 6416.66。
10%当たりの価格でいうと優秀。
60%までしか増えないが。
Vega 16 は 48% ぐらいのスペックアップだと思われるので、コスパで考えるとお得だが、1万ちょいで 20 になるので悩みどころ。
まとめ
RX 560X の約1.4 または 1.6 倍性能の一体型を望むか、外付けでも約 2 または 3倍の性能を求めるかになる。
60%までの増加でよければ、eGPU よりコストが若干価格が安いので MacBook Pro 15inch + Vega 20(¥302,800〜 + ¥38,500)はよいと思われる。
RX 560 の1.6倍以上欲しいか、他の Thunderbolt 3 が接続可能な Mac なら eGPU、eGPU Pro。
大体価格に見合う性能向上なので、お金に余裕があれば Pro を買ってもよいかと。
MacBook Pro 13inch は CPU が 4 Core なので、持ち運ぶ用途がなく、ディスプレイがあるなら Mac mini を選んだ方が良さげ。
また、iMac Pro 8 Core が ¥558,800 (税別) となっているため、
他の Mac のカスタマイズで、メモリ 32GB / 1TB SSD に設定した場合に eGPU / eGPU Pro で本体価格以下の価格に近いと 5K のディスプレイを持った iMac Pro が購入できてしまうので注意。
- iMac Pro 8 Core = 本体 ¥469,000 - 27inch 5K ディスプレイ + eGPU
- iMac Pro 8 Core = 本体 ¥409,800 - 27inch 5K ディスプレイ + eGPU Pro
Blackmagic のものはそれなりにするので、ケースとボードを別に買うとやすくなるかも。
Mac でサポートしているケース一覧があるのでこちらを参照。
特に Vega 64 系や Pro WX 9100 は電源が 650W のケースじゃないと正常に動かないので注意。
おまけ
eGPU のケースは割とでかいので、ラップトップは縦置きできるスタンドがあると便利。
2019年はじめに思う Apple におこなってもらいたいこと
なんとなく書いてみた。
あまり内容はない。
iPhone のカメラ性能をよくする
スマートフォンのアプリでもっとも長い時間使われているのは SNS アプリであり、 SNS のアプリで閲覧や文字を書く以外で時間が使われているのは写真(動画)撮影だろう。
絵を描いたり、楽器の演奏や作曲、歌唱などは長い期間の練習を経て習得する技術であるが、 カメラに関しては習得するべき技術が身体的なものではないので、機械で技能を拡張することができる。
そのため、カメラ性能を上げる戦略は正しく、 Hauwei の様にレンズやセンサーを工夫したり、Google Pixel 3 のように専用チップを開発して、カメラ機能にウエイトを置くのは当然だと思われる。
噂では次期 iPhone では3つ目のカメラを搭載するとのことだが、個人的にはカメラセンサーの向上による鮮明さと夜間で撮影した際のノイズ除去を頑張ってほしい。
Siri をより賢く
正直、AR や VR の世界より先に Siri 等のヴァーチャルアシスタントシステムの機能向上の方が人々の生活に役立つとは思っている。
現状、アメリカで使用できて日本で使用できない Siri の機能があるので、まずはそこから。
HomeKit 製品の拡充
生活の中心となる家電でとして Media Hub や Home Hub などの構想はあったが、いまだに実現されておらず、生活の中ではスマートフォンがその役割を奪ってしまった。
ただ、家電の操作をリモートで行うことができれば、便利さが上がり、生活はもっと楽なものになるだろう。
家電各社は色々な試みを行なっているが HomeKit に対応していただきたいところ。
HomeKit 対応する場合、Lightning ケーブルの様に専用のチップや契約が必要であるため、 厳しさはあるが、今年の CES ではテレビなど HomeKit 対応を謳ったものが増えてきた。
とりあえず、日本では2年間費用無償とか土下座でもして Panasonic あたりに Apple は HomeKit 対応をしてもらってほしい。
照明スイッチやエアコンなど Apple TV 経由で家に近づくと ON になるとか可能になるので。
HomeKit 対応製品が増え広まれば、Apple が人々の生活を掌握できる様になる。
Apple 製品が売れている国に関しては早急にホームオートメーションのシェアを掴んでいく必要性があると思われる。
AR や VR と仮想現実空間
AR に関しては Siri や HomeKit の機能強化の先の話だと思われるが、 AR グラスなど常時体験できるならアシスタントデバイスとして、製品ラインナップやプラットフォームの強化がされる。
今の ARKit ではできない遮蔽物の認識が可能になれば、2.0 で追加された空間共有とともに仮想空間での幅広い表現で可能になるだろう。
また、A12 / A12X Bionic での Metal 機能強化で macOS の GPU 機能と同等のもの(性能ではないので注意)が使える様になったため、 AR グラスや VR なども期待できそうではある。
Apple Watch の高機能版
Apple Watch Pro のような存在。
ある程度需要はある気はする。
現状、iPhone アプリからのデータ転送なので、プリインストールされている Apple 謹製アプリはセルラーで動く場合があるが、多くのアプリが iPhone なしではちゃんと動作しないので。
バッテリー持たなそうだけど。
インナーイヤー型の AirPods
現状の AirPods は、東京など人が密になっているところでは、外界の音がうるさすぎてボリュームを上げる必要があり面倒なので。
Beats X を使えばよいのだが、バッテリーの問題でインナーイヤー型の AirPods が出てくれればと思っている。
Apple の中の人は山手線とか鉄道の駅や電車で AirPods を使ってフィールドテストして欲しい。わりと辛い。
今後の macOS
多分、いつか iOS と macOS は同等のものになるとは思っている。
Apple A チップの機能がディスクトップに迫ったり、Metal 機能が同じ様になったりと歩み寄っており、iOS のアプリにメニューバーやタッチバーつけるぐらいの手軽さにはなってほしい。
問題があるとするなら OpenGL が廃止になり Metal でアプリの表示を描画することになる点だろう。
ただ Metal は WWDC 2014 で発表されており、もう 5 年目を迎えそうなので、もうそろそろ諦めて OpenGL から解脱してほしい。
まとめ
Apple はハードとソフトを上手く融合させてユーザー体験を提供するメーカーではあるが、来るべき PC/Mac などのコンピューターの終焉(専門職以外使わなくなる)とスマートフォンのコモディティ化を考えると、Siri や AR などを絡めたアシスタントや Apple Music などサービスの提供を強化していく流れになるだろう。
ARKit や SceneKit で使用している simd について - クォータニオンでの関数編 その2 -
今回はクォータニオンで使用する線形補間の関数について。
基本的には球状での回転の補間となる。
用意されている関数は以下のもの。
- simd_slerp
- simd_slerp_longest
- simd_spline
- simd_bezier
ちなみに線形補間に関しては iOS でサンプルアプリがあるのでそちらを参考に。
Rotating a Cube by Transforming Its Vertices | Apple Developer Documentation
ちゃんとした説明は WWDC 2018 でも行なっているのでそちらを参照。
以下、コードを書いていく。
macOS の Swift Playground で試していたので、iOS で使用する場合は NSColor を UIColor に変更するべし。
simd_slerp
クォータニオン q0 と q1 の間の最短の弧に沿った線形補間を行う。
let rotations: [simd_quatf] = [ simd_quatf(angle: 0, axis: simd_normalize(simd_float3(x: 0, y: 0, z: 1))), simd_quatf(angle: .pi * 0.05, axis: simd_normalize(simd_float3(x: 0, y: 1, z: 0))), simd_quatf(angle: .pi * 0.8, axis: simd_normalize(simd_float3(x: 1, y: 0, z: -1))), simd_quatf(angle: .pi * 0.15, axis: simd_normalize(simd_float3(x: 0, y: 1, z: 0))), simd_quatf(angle: .pi * 0.2, axis: simd_normalize(simd_float3(x: -1, y: 0, z: 1))) ] for i in 0 ... rotations.count - 2 { for t: Float in stride(from: 0, to: 1, by: 0.001) { let q = simd_slerp( rotations[i], rotations[i + 1], t ) let node = SCNNode() let sphere = SCNNode(geometry: SCNSphere(radius: CGFloat(t/4))) sphere.geometry?.firstMaterial?.diffuse.contents = NSColor(red: 1.0, green: CGFloat(t), blue: CGFloat(t), alpha: 1.0) node.addChildNode(sphere) node.simdPosition = q.act(float3(0,0,5)) scene.rootNode.addChildNode(node) } }
simd_slerp_longest
クォータニオン q0 と q1 の間からもっとも遠い弧に沿った線形補間を行う。
let rotations: [simd_quatf] = [ simd_quatf(angle: 0, axis: simd_normalize(simd_float3(x: 0, y: 0, z: 1))), simd_quatf(angle: .pi * 0.05, axis: simd_normalize(simd_float3(x: 0, y: 1, z: 0))), simd_quatf(angle: .pi * 0.8, axis: simd_normalize(simd_float3(x: 1, y: 0, z: -1))), simd_quatf(angle: .pi * 0.15, axis: simd_normalize(simd_float3(x: 0, y: 1, z: 0))), simd_quatf(angle: .pi * 0.2, axis: simd_normalize(simd_float3(x: -1, y: 0, z: 1))) ] for i in 0 ... rotations.count - 2 { for t: Float in stride(from: 0, to: 1, by: 0.001) { let q = simd_slerp_longest( rotations[i], rotations[i + 1], t ) let node = SCNNode() let sphere = SCNNode(geometry: SCNSphere(radius: CGFloat(t/4))) sphere.geometry?.firstMaterial?.diffuse.contents = NSColor(red: 1.0, green: CGFloat(t), blue: CGFloat(t), alpha: 1.0) node.addChildNode(sphere) node.simdPosition = q.act(float3(0,0,5)) scene.rootNode.addChildNode(node) } }
simd_spline
クォータニオン q1 と q2 の間を補間し、q0 は始点であり、q3 は終点。
回転するシーケンス間をスムーズに補間する場合は slerp ではなくこちらを使う。
let rotations: [simd_quatf] = [ simd_quatf(angle: 0, axis: simd_normalize(simd_float3(x: 0, y: 0, z: 1))), simd_quatf(angle: 0, axis: simd_normalize(simd_float3(x: 0, y: 0, z: 1))), simd_quatf(angle: .pi * 0.05, axis: simd_normalize(simd_float3(x: 0, y: 1, z: 0))), simd_quatf(angle: .pi * 0.8, axis: simd_normalize(simd_float3(x: 1, y: 0, z: -1))), simd_quatf(angle: .pi * 0.15, axis: simd_normalize(simd_float3(x: 0, y: 1, z: 0))), simd_quatf(angle: .pi * 0.2, axis: simd_normalize(simd_float3(x: -1, y: 0, z: 1))), simd_quatf(angle: .pi * 0.2, axis: simd_normalize(simd_float3(x: -1, y: 0, z: 1))) ] for i in 1 ... rotations.count - 3 { for t: Float in stride(from: 0, to: 1, by: 0.001) { let q = simd_spline(rotations[i - 1], rotations[i], rotations[i + 1], rotations[i + 2], t) let node = SCNNode() let sphere = SCNNode(geometry: SCNSphere(radius: CGFloat(t/4))) sphere.geometry?.firstMaterial?.diffuse.contents = NSColor(red: 1.0, green: CGFloat(t), blue: CGFloat(t), alpha: 1.0) node.addChildNode(sphere) node.simdPosition = q.act(float3(0,0,5)) scene.rootNode.addChildNode(node) } }
simd_bezier
De Casteljau アルゴリズムを使用しクォータニオン q0、q3 をコントロールポイントとして扱う3次ベジェ曲線の補間を行う。
補間の終点が q0 か q3 になり、曲線は q1 または q2 を通過しない。
標準的なベジェ曲線のように凸包のプロパティが球上には保持されないので注意。
let rotations: [simd_quatf] = [ simd_quatf(angle: 0, axis: simd_normalize(simd_float3(x: 0, y: 0, z: 1))), simd_quatf(angle: .pi * 0.05, axis: simd_normalize(simd_float3(x: 0, y: 1, z: 0))), simd_quatf(angle: .pi * 0.8, axis: simd_normalize(simd_float3(x: 1, y: 0, z: -1))), simd_quatf(angle: .pi * 0.15, axis: simd_normalize(simd_float3(x: 0, y: 1, z: 0))) ] for t: Float in stride(from: 0, to: 1, by: 0.001) { let q = simd_bezier(rotations[0], rotations[1], rotations[2], rotations[3], t) let node = SCNNode() let sphere = SCNNode(geometry: SCNSphere(radius: CGFloat(t/4))) sphere.geometry?.firstMaterial?.diffuse.contents = NSColor(red: 1.0, green: CGFloat(t), blue: CGFloat(t), alpha: 1.0) node.addChildNode(sphere) node.simdPosition = q.act(float3(0,0,5)) scene.rootNode.addChildNode(node) }
まとめ
クォータニオンでの線形補間を使用した回転は行列での回転より早く処理できる可能性があるため、状況によっては積極的に使用すべきだろう。
simd に関しては一通り説明が終わった。
ARKit のアンカーや SceneKit のノードで多くのものを素早く変更する場合に有用な機能ではある。
また、Float、Double など、型の値の取り出しが可能であるため、ARKit や SceneKit 以外にも行列の処理で使用できる状況はあると思われる。