Apple Engine

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

ARKit や SceneKit で寿司を回す

前回の横に流れる文字の続き。

SpriteKit の SKScene でラベルをアニメーションさせたものを円筒状のジオメトリのマテリアルにテクスチャとして貼り付けて 🍣 を流すとARKit で寿司を回る。

f:id:x67x6fx74x6f:20190307190007g:plain
寿司を回す

 

ARBoardSK からの変更

ジオメトリ

ジオメトリを平面から円筒形に変更し、円筒になったため SKScene の幅が大きくなった。
学生の頃に習ったと思われるの 2πr で円周が取れるので、半径から計算して SKScene の幅を設定する。   (よくよく考えるとジオメトリのバウンダリボックスの値から半径を算出できるので自動で値を設定する様にしてもよかった)

SKScene の幅と高さを同じにして、円筒の円周と高さを同じにすると処理と引き換えに使いまわせる気はする。
一応、サンプルファイルに Blender や obj を入れたので調整してもよいかも。

 

マテリアル

透過する場合は通常の設定だと、テクスチャは透過されてもマテリアルの重なりが透過されないので、 Transparency のモードを Dual Layer にする。

f:id:x67x6fx74x6f:20190307185308p:plain
Transparency のモードを Dual Layer にする

 

Dual Layer は処理負荷が高いので、透過などの表現が必要なければ他のものにする。

 

アニメーションスピード

ジオメトリを平面から円筒形に変更したため文字の表示時間が長くなった。
アニメーション時間の「* 0.4」だった部分を倍の速さの「* 0.2」に変更し文字の移動を速くしている。

let duration = (totalTextSize / labelNode.frame.height) * 0.2

 

サンプルコード

ARBoardSK2 がこいつに該当。
文字入力確定か画面タップで文字や🍣が横に流れるよ。

github.com

 

まとめ

Touch Bar、Apple Watch の Digital Crown で寿司を回してきたが、3次元空間でも簡単に寿司は回ることがわかった。

ARKit や SceneKit で電光掲示板的な横に流れる文字を表示する

f:id:x67x6fx74x6f:20190307171630g:plain
横に流れる文字(SceneKit)

AR 空間で文字数の多いテキストを表示する場合、 紙のように板ポリゴン一面や空間にするケースがあると思われる。

AR は現実空間と密接になっているため、サイズが小さいと近くに寄る必要があり、逆に大きいと全体を見る為に遠ざかる必要がある。

初代 Microsoft HoloLens のようにウインドウとして表示し、エアタップからスクロールして見る方法もあるが操作が面倒ではある。

以上の2つのように、身体的に動作が伴う場合、反復する状況だと操作が面倒になる。

 

回避策としては、音声でガイダンスをしたり、動画として伝えるべきことを表示したりすることもできるし、 今回のように電光掲示板のような横に流れる自動で流れる文字を採用するのも良いだろう。

 

横に流れる文字 iOS のネイティブ環境で実現させるには以下の3つの方法が考えられる。

  • SpriteKit などから動画のテクスチャを表示する
  • 文字のテクスチャ画像を作成して、UV 座標の移動をアニメーションさせる
  • SpriteKit でラベル(SKLabelNode)をアニメーションさせる

 

以下ではこの3点について実装していきたいと思う。

 

SpriteKit で動画のテクスチャを表示する

実装的にはもっとも簡単。
動画のテクスチャに関しては過去の記事や下のサンプルファイルを参考にしてもらいたい。

動画の場合文字の表示スピードや背景の演出など様々表現ができる上に、アプリ制作する際にアニメーション部分もデザイナ側に任せるため、この部分の作業の切り分けができる。

デメリットは、iPhone や SpriteKit で Apple Pro Res のデータが扱えないため、動画ファイルだけでは背景を透過することができない。
(SpriteKit でマスクをかけることができるがかなり処理が重くなる)
また、再生をループする場合、再生場所を最初に戻す処理があるため、滑らかにループされることが期待できない。

 

UV 座標の移動で実現する

実装的にはかなり簡単で、使用する画像が少なければ他の2つに比べて一番負荷が少なくなる可能性が高い。
特に同じ文字のループを表示する場合、デフォルトのテクスチャ設定がループになっているので UV 座標の移動を繰り返すだけで簡単にループし続け、かつ処理が軽い。
(下のサンプルファイルを参照)

任意の文字を表示したい場合ではなく固定の文字を画像として表示したい場合はもっとも有効である。
(UIKit など OS のフレームワークから画像として文字を作成すれば事前に画像をつくるれば可能だが……)

 

以下の様に SCNAction で U 座標に移動するカスタムアクションを設定するとこの関数を呼ぶだけでアニメーションされるので便利。

extension SCNAction {

    open class func moveDiffuseU(_ duration:TimeInterval = 1) -> SCNAction{
        
        var uvPostion = float4x4.init(1)
        
        return SCNAction.customAction(duration: duration, action: { (node, elapsedTime) in
            uvPostion[3].x = Float(elapsedTime) / Float(duration)
            node.geometry?.firstMaterial?.diffuse.contentsTransform = SCNMatrix4(uvPostion)
        })
    }
}

 

SpriteKit でラベル(SKLabelNode)をアニメーションさせる

SpriteKit で動画を表示させるようにラベル(SKLabelNode)を配置しアニメーションさせる。
SKScene にノードを貼り付けるため、テキストフィールドなどから任意の文字を表示しアニメーションすることができる。

デメリットとしては動画や画像と異なり文字装飾が NSAttributedString ぐらいとなる。
一応、SKEffectNode から CIFilter でフィルター処理をしたり、シェーダーを書くことで装飾することはできるが。

 

少しだけコードの解説

// シーンの設定
skScene = SKScene(size: CGSize.init(width: 1024, height: 256))
skScene.anchorPoint = CGPoint(x:0.5, y: 0.5)

// カメラ設定
let cameraNode = SKCameraNode()

cameraNode.position = CGPoint(x: 0, y: 0)
cameraNode.yScale = -1

skScene.addChild(cameraNode) // addChild しないとカメラが適応されない
skScene.camera = cameraNode
// アニメーションさせる SKLabelNode の設定
func setScrollText(_ text:String){
    
    // フォント設定(fontSize と labelPosY は雑に設定している)
    let systemFont = UIFont.systemFont(ofSize: 140, weight: UIFont.Weight.bold)
    let fontSize:CGFloat = 140
    let labelPosY = -CGFloat(fontSize / 3)
    
    // ラベル設定
    let labelNode = SKLabelNode()
    labelNode.fontName = systemFont.fontName
    labelNode.text = text
    labelNode.fontSize = fontSize
    labelNode.horizontalAlignmentMode = .left
    labelNode.fontColor = SKColor.white
    labelNode.position = CGPoint(x: skScene.size.width / 2, y: labelPosY) // シーンのアンカーが中央なので幅を2で割ったものを X 軸とする。
    
    skScene.addChild(labelNode)
    
    // アニメーション設定
    let totalTextSize = labelNode.frame.width + skScene.size.width // シーンの幅とラベルの大きさ = 移動距離
    
    let duration = (totalTextSize / labelNode.frame.height) * 0.4 // 移動距離をラベルの高さで割る。早すぎるので 0.4 かけて遅くする。0.4 の値を増やせば遅く、少なくすると速くなる
    let endPos   = CGPoint(x: -totalTextSize, y: labelPosY) // ラベル移動アニメーションの最終位置
    
    // SKAction で移動を設定し、移動が完了したらラベルを消す。
    let move = SKAction.move(to: endPos, duration: TimeInterval(duration))
    labelNode.run(move, completion: {() -> Void in
        labelNode.removeFromParent()
    })
}

 

サンプルコード

ARBoardSK は文字入力確定か画面タップで文字が横に流れる。
ARBoardSK2 の解説はまた後ほど。

github.com

 

まとめ

ARKit や SceneKit で電光掲示板ような横に流れる文字の実装のやり方がわかったと思う。

ケースバイケースなので、状況にあった方法で設定していくとよいのではというところ。

SceneKit のテクスチャに SpriteKit の SKScene を貼り付けて複雑な動きをするマテリアルをつくる

f:id:x67x6fx74x6f:20190307153212g:plain  

以前の記事で SpriteKit の SKVideoNode を使用して SceneKit のテクスチャに動画をループ再生する記事を書いた。

SpriteKit のシーンを貼り付けているため、基本的には SpriteKit で使用している機能を使いアニメーションや インタラクションをテクスチャとして使用することができる。

本来は Metal シェーダーでつくるべきだが、SpriteKit は SceneKit と同じような方法でコンテンツをつくることができるため学習コストが少なくインパクトのあるマテリアルを表示することができる Unity など他のゲームエンジンにない珍しい機能である。

SceneKit でマテリアルを表示する前に SpriteKit で画像つくってから表示するため、ある程度処理で負荷がかかる。
SceneKit の showsStatistics = true で表示される統計情報の 2D や Rendering で負荷が上がるのでここら辺を見ながら調整することになるだろう。

 

試してみる

f:id:x67x6fx74x6f:20190307152721g:plain

見た目でわかりやすく、他のゲームエンジンで面倒なのはマテリアル内で表示されるパーティクル。

SceneKit + SpriteKit の場合、particle.sks (SpriteKit のシーンファイル) のパーティクルを設定して SpriteKit のシーンに設定、再生して、それを SceneKit のテクスチャとして貼るだけだ。

f:id:x67x6fx74x6f:20190307152518p:plain
Xcode で SKEmitterNode のパーティクルを編集

 

気をつけてほしいのは SpriteKit のシーンである SKScene は SKView を設定することでフレームが動き時間を刻み始める。
そのため、SKAction や動画の再生などシーン内でフレームに関与するもの以外では SKScene は再生されない。
パーティクルなどフレームに依存するものは置いただけでは再生さないので、isPaused を false にする必要がある。

skScene = SKScene(fileNamed: "texture.sks")
skScene.isPaused = false

 

今回は、シーンの sks でパーティクルを設定して、シーン全体をテクスチャにしているが、 コード上で空のシーンを設定して、SKEmitterNode でパーティクルの sks 読み込んだりしても良いだろう。

シーン全体を sks でつくると特にインタラクションがないと場合は sks ファイルだけで振る舞いを確認ができるので便利。

 

SceneKit で SKScene をテクスチャで設定する際の注意点

SceneKit では もう1つ SKScene を設定することができ、 overlaySKScene で画面最前面に SKScene を設定し HUD のように UI としてするものがある。

overlaySKScene は SKScene を貼り付けた場合そのまま表示されるが、
SKScene をテクスチャとして使用する場合は Y 軸が反転されてしまうため、
文字など上下(天地)で見た目が異なるものがを表示する際はそれをなおす必要がある。

 

修正方法はいくつかあるためまとめてみた。

  • SKScene の Y スケールを -1 にする
  • SKScene に SKCameraNode を置きカメラを反転、Y スケールを -1 にする
  • マテリアルの contentsTransform でテクスチャを配置する座標を行列から変更する
  • ジオメトリを反転させる(板ポリなど平面に貼る場合など)
  • ジオメトリの UV の設定(Texture Coordinate)を事前に反転させる

 

SKCameraNode で反転すると SKScene 内で完結するため、sks ファイルで SKScene を設定している場合、イニシャライズ後反転処理をしなくてもよくなる。

ものによっては SceneKit からのインタラクションでジオメトリのタップした場所を SKScene に渡す際に面倒になるかもしれない。

 

サンプルファイル

github.com

 

まとめ

シェーダーを書く場合と比べ、SKSpriteNode などのノードを SKScene に addChild させて、状況によっては SKAction を入れてアニメーションをさせたり、インタラクションを入れたり、簡易的かつ高度なことができることがわかる。

一応、それなりの負荷がかかるのでご利用は計画的にといったところ。

RICOH THETA Z1 が発表された

SceneKit、3DCG などの背景画像や Image Based Lighting (IBL) で RICOH THETA V を使用していたが、
新機種である RICOH THETA Z1 が出るため調べてみた。

f:id:x67x6fx74x6f:20190227190227j:plain
THETA Z1

ワンショットで360°の全天球イメージを撮影できるカメラ 「RICOH THETA Z1」を新発売|RICOH IMAGING

 

RICOH THETA とは?

魚眼レンズが前面と背面に付いており、ボタン一発で360度写真を撮ることができるカメラ。

のちの製品アップデートで動画や USB で PC / Mac につなげることで360度映像のライブストリーミングが可能になった

 

以前との違い

  • 1.0 型裏面照射型 CMOS イメージセンサー
  • ISO 6400 までの高感度撮影
  • レンズ変更
  • F2.1、F3.5、F5.6 の3段階からF値を選択可能
  • 新しい画像処理アルゴリズムによる低ノイズで解像感の高い画像
  • 星の光跡の記録などに使える「インターバル合成機能」
  • JPEG + RAW(DNG)での保存
  • 動画撮影時の高い手ぶれ補正機能の追加
  • カメラの撮影情報を確認できる OLED でディスプレイ
  • ファンクションキー(スマートフォンアプリからの設定変更可能)
  • ボディをマグネシウム合金に変更
  • 大きさや重さがやや増加
  • USB Type-C コネクタ
  • 価格が 126,900円(税込)

 

個人的には CMOS イメージセンサーが変更されたため、保存される画像サイズが 1.25倍の 6720 x 3360 px の 7K と大きくなり、 レンズの進化でゴースト、フレア、パープルフリンジが抑制される点がうれしい。

また、静止画の場合 V は ISO が 3200 が上限だったが 6400 まであげられるようになったため、夜間や薄暗い場所での撮影が綺麗になると予想される。

いしたにさんのツイートで紹介されているが画質はかなり向上した感じ。

 

実際触っていないのでなんとも言えないが、F値の変更で面白そうな画が撮れそうだし、手ぶれ補正がどのぐらい強化されているかも期待している。

 

ウィークポイント

価格が 126,900円(税込)となっており、プロ向けのラインナップとなった。
ただ、競合である Insta360 のプロ向けと比べると、かなり低価格かつ簡単に扱えるため魅力的な商品だとは思う。

バッテリーとストレージは内蔵である。
バッテリーに関しては、正直取り換える手間や事前にバッテリーをもう一つ充電させずとも、
モバイルバッテリーで十分代用できが、 ストレージが V と同様に 19GByte までしか使えない。

画像サイズが大きくなったり、RAW が保存できるため以前より容量を逼迫するだろうと予想される。

動画に関しては 4K 最大5分、2K 最大25分と変化はないため V と変わらないだろう。

 

競合他社 Insta360 との違い

Insta360 は早い段階でコピー品として世に出し利便性やスペックも高く、Apple Store でも製品が販売されている台湾のメーカー。

 

f:id:x67x6fx74x6f:20190227191330j:plain
Insta360 ONE X

現行の最新製品で THETA V の同価格帯ある Insta360 ONE X は THETA V のスペックを若干上回り、動画撮影時の手振れが完全になくなるぐらいに補正される。
あと、バッテリー脱着ができ、データ保存は micro SD カードにできる。

 

f:id:x67x6fx74x6f:20190227191404j:plain
Insta360 PRO 2

プロ向けの Insta360 Pro 2。
6 個の魚眼レンズを持ち、2ずつカメラを使うことで視差を利用した 3D の 360 度の写真や映像をつくることができる。

6 個の魚眼レンズを搭載しているということで想像はできると思われるが、スイカぐらいの大きさがあり、1.5Kg ぐらいある。

静止画・動画共に 3D で 7680 × 7680 (動画 30fps)、2D で 7680 × 3840 (動画 60fps)。

静止画は10枚連続で撮ることによって最大 12K となるらしい。

価格が60万を超える点と 1 枚の SD カードと 6 枚の micro SD カードを使用するため、転送に時間がかかる部分はプロ向けなので致し方ない。

 

購入を検討するには?

自分が Insta360 ではなく THETA を選んだ理由は静止画での綺麗さ。
また、2つの魚眼レンズから合成し仕上げる際の処理も甘い感じはある。
(かなり前に触ったので今は違うかも?)

THETA V の手ブレ補正はあまり期待できないので動画を撮る場合はジンバル必須。

Insta360 Pro 2 については価格と大きさや重さが個人で扱う感じではないので THETA Z1 は良い選択肢だとは思われる。
静止画の場合 Insta360 Pro 2 は 8K で、THETA Z1 は 7K であるためそれなりの解像度かつ片手で持てる。

 

まとめてみるとこんな感じ

  • 360 度動画中心で5万円内なら Insta360 ONE X
  • バッテリー脱着や micro SD 保存が必要なら Insta360 ONE X
  • 360 度静止画なら THETA S/SC (ストレージ 8GB) 、THETA V (ストレージ 19GB)
  • プロ向けで静止画を手軽に扱いたいなら THETA Z1
  • プロ向けで動画を綺麗に撮りたいなら Insta360 Pro 2

 

Insta360 Pro 2 はお高いので、レンタルして試しに触ってみてからの購入でも良いかも。

 

まとめ

THETA Z1 は V から大幅な進化を遂げ、Insta360 Pro 2 の 20 %以下の価格に抑えた点はかなり評価できる。
以前の THETA アクセサリがかなり使えなくなってしまったが。

 

 

2019/3/4 追記: CP+ 2019 で RICOH さんの説明とデモ機を触った感想

画質

静止画の360度カメラで最高の画質を目指したとのことで写真の綺麗さは値段分は強化されていると感じ、
第3世代の iPad Pro 12.9 inch で作例の紹介がされており、かなり拡大しても綺麗だった。

パープルフリンジもかなり提言されており好感触。
下の写真は iPhone XS でサクッと撮ったものなのでわかりづらいが Z1 の方がフリンジが改善されている。

f:id:x67x6fx74x6f:20190302152558j:plain
THETA Z1 / THETA V

 

本体

本体の大きさと重さは変わったが個人的にはあまり気にならない。
厚みが増えたのでそこが気になる人が居るかも。
発売日に量販店で実機が展示されると思うので触ってから買っても良いかも。

 

動画

ハードウェア的に動画の機能はアップデートされていないので、動画機能を重点に置くなら THETA V でも変わらないとのこと。

ただ、センサーとレンズが性能強化されたので絵は綺麗になるかもとのこと。

(諸事情があるのだと思うが、説明されていた方は動画のサンプルが見ることができていないらしく断言されていなかった)

 

新しい手ブレ処理は THETA V の方でもアップデートで対応予定とのことなので、
センサーとレンズで画が変わるか否かと言うところ。

 


iOS 12 において注目すべき UI はショートカットアプリである

WWDC 2018 のセッションでは Fluid Interface の名の下に、 思考の延長のように感じ、そして振る舞うような UI をユーザーの体験を大きく改善すると尊い教えをいただいた。

UI / UX の大半はインタラクションとか見た目にとらわれがちだが、
そんなものは UI 設計の後の話であり、
本来は情報の整理しどうすれば利便性がよくなるかを先に考えるべきである。

 

ショートカットアプリに関しては下部に存在する半分なモーダルに注目されるが、
その真価はタスクが実行されていく部分の UI にある。

 

本来はショートカットアプリのようなタスクを実装するアプリはノードベースになるのが望ましい。

f:id:x67x6fx74x6f:20190227183958j:plain
Unreal Engine のノード UI である Blue Print

 

しかし、このアプリは上から下に命令が流れるリスト(テーブルビュー)のような UI をしている。

f:id:x67x6fx74x6f:20190227184943p:plain
ショートカットアプリの画面

 

なぜ、このような形をとっているのかは想像しやすく、単にスマートフォンのサイズでノードベースの UI だと操作しづらいからである。

 

単に上から下にタスクが流れるだけであれば、若干分かりづらくなるのは繰り返しや分岐ぐらいで、
難しくなく理解できるだろう。

 

だがタスクを遂行するにあたって、事前、または別で処理をしたものを最終的に取得するものが必要になる。
その際にノードベースであれば処理を最後につなげればできるが、リストのように上から下に流れるものでは処理できない。

 

そのために考えられたのは マジック変数 である。

 

ショートカットアプリ自体、通常のプログラムのように変数、テキストなどの入力の値の設定や取得できるのだが、
それとは別にマジック変数がというものが用意されており、タスクが流れの途中の値を取得することができる。

 

f:id:x67x6fx74x6f:20190227185506p:plain
マジック変数を使う
f:id:x67x6fx74x6f:20190227185529p:plain
マジック変数を選択

 

右の写真の命令の間にある青い角丸矩形が取得できる変数となっており、
流れの間で値が取得できる構造となることで、ノードをつなげる事をせずにリストで再現することを可能にしたのである。

素晴らしい。

 

P.S.

マジック変数を束ねすぎると流れが分かりづらくはなってしまうのが難点。

結局のところノードで扱っても表示領域の問題で同様になるため、50歩100歩といった感じではあるが。

Xcode 10 の Scene Editor で Metal のカスタムシェーダーを設定する

Xcode の多分 10.1 から Metal のシェーダーファイルを Material Inspetor > Propaties > Shading で設定できるようになった。

f:id:x67x6fx74x6f:20190128191925p:plain

 

内容的には SCNProgram が Scene Editor でできるようになった感じ。

 

Metal のカスタムシェーダーファイルを作成する

新規ファイル(Command + N)で Metal File をつくるか、
.metal の拡張子を持つテキストファイルを作成して以下のものを書く。
内容的にはテクスチャを表示するだけのもの。

#include <metal_stdlib>
using namespace metal;

#include <SceneKit/scn_metal >

// 頂点
struct VertexInput {
    float3 position [[ attribute(SCNVertexSemanticPosition) ]];
    float2 texcoord [[ attribute(SCNVertexSemanticTexcoord0) ]];
};

// モデル
struct NodeBuffer {
    float4x4 modelViewProjectionTransform;
};

// 変数
struct CustomBuffer {
    float4 color;
};

struct VertexOut {
    float4 position [[ position ]];
    float2 texcoord;
    float4 color;
};

vertex VertexOut textureVertex(VertexInput in [[ stage_in ]],
                               constant SCNSceneBuffer& scn_frame [[ buffer(0) ]],
                               constant NodeBuffer& scn_node [[ buffer(1) ]],
                               constant CustomBuffer& custom [[ buffer(2) ]]) {
    VertexOut out;
    out.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0);
    out.texcoord = in.texcoord;
    out.color = custom.color;
    return out;
}

fragment float4 textureFragment(VertexOut in [[ stage_in ]],
                               texture2d<float> texture [[ texture(0) ]]) {
    constexpr sampler defaultSampler;
    float4 color;
    color = texture.sample(defaultSampler, in.texcoord) + in.color;
    
    return color;
}

 

こちらを保存すると .metal ファイルを自動的に metallib に変換されて Scene Editor から呼び出せるような振る舞いになる。(と思っている)

 

Scene Editor でつくったカスタムシェーダーを設定してみる

Scene Editor の Material Inspetor (Command + Option + 4) で Shading を Custom にすると
Diffuse、Source File、Vertex Function、Fragment Function と Opaque が設定できるようになる。

f:id:x67x6fx74x6f:20190128191717p:plain

 

よくわからないが次開くと Diffuse の項目が設定できなくなる。謎。

 

先ほど作成した metal を選択すると設定した Vertex Function、Fragment Function が選択できるのだが、「#include <SceneKit/scn_metal>」がインクルードできないとエラーが出てマテリアルがマゼンタピンクで塗りつぶされたままになる。

f:id:x67x6fx74x6f:20190128191801p:plain

 

ということで、SceneKit フレームワークの scn_metal のヘッダーの記述を持っていこう。
「#include <SceneKit/scn_metal>」の部分を以下のコードに変えてみる。
一応、ヘッダの記述全てを書いたが全て使う必要はないのいらないものは消してもよいと思われる、

enum {
    SCNVertexSemanticPosition,
    SCNVertexSemanticNormal,
    SCNVertexSemanticTangent,
    SCNVertexSemanticColor,
    SCNVertexSemanticBoneIndices,
    SCNVertexSemanticBoneWeights,
    SCNVertexSemanticTexcoord0,
    SCNVertexSemanticTexcoord1,
    SCNVertexSemanticTexcoord2,
    SCNVertexSemanticTexcoord3,
    SCNVertexSemanticTexcoord4,
    SCNVertexSemanticTexcoord5,
    SCNVertexSemanticTexcoord6,
    SCNVertexSemanticTexcoord7
};

struct SCNSceneBuffer {
    float4x4    viewTransform;
    float4x4    inverseViewTransform; // transform from view space to world space
    float4x4    projectionTransform;
    float4x4    viewProjectionTransform;
    float4x4    viewToCubeTransform; // transform from view space to cube texture space (canonical Y Up space)
    float4x4    lastFrameViewProjectionTransform;
    float4      ambientLightingColor;
    float4        fogColor;
    float3        fogParameters; // x:-1/(end-start) y:1-start*x z:exp
    float2      inverseResolution;
    float       time;
    float       sinTime;
    float       cosTime;
    float       random01;
    float       motionBlurIntensity;
    // new in macOS 10.12 and iOS 10
    float       environmentIntensity;
    float4x4    inverseProjectionTransform;
    float4x4    inverseViewProjectionTransform;
    // new in macOS 10.13 and iOS 11
    float2      nearFar; // x: near, y: far
    float4      viewportSize; // xy:size, zw:origin
    // new in macOS 10.14 and iOS 12
    float4x4    inverseTransposeViewTransform;
    
    // internal, DO NOT USE
    float4      clusterScale; // w contains z bias
};

 

これで動くかと思ったが、Diffuse が消えてしまうため外部からテクスチャを取る手段がなくテクスチャは割り当てられない。
ドキュメントがないのでバグなのか仕様なのかわからない。

f:id:x67x6fx74x6f:20190128192042p:plain

 

諦めて Fragment Shader だけ設定してみる

ということで、書き直ししてみることにする。
フラグメントの return で float4(1.0, 0.0, 0.0, 1.0) に設定しているためマテリアルが真っ赤になる。

fragment float4 textureFragment(VertexOut in [[ stage_in ]],
                               texture2d<float> texture [[ texture(0) ]]) {
//    constexpr sampler defaultSampler;
//    float4 color;
//    color = texture.sample(defaultSampler, in.texcoord) + in.color;
    
    return float4(1.0, 0.0, 0.0, 1.0);
}

 

f:id:x67x6fx74x6f:20190128192208p:plain

 

ちなみに SCNSceneBuffer で定義されているものは使用可能なので呼び出してみる。

以下の VertexOut の構造体と vertex、fragment を修正。
再生ボタンを押したり、カメラ移動させたりすると Scene Editor のフレームがすすみランダムで赤く点滅する。

struct VertexOut {
    float4 position [[ position ]];
    float2 texcoord;
    float4 color;
    float random01;
};

vertex VertexOut textureVertex(VertexInput in [[ stage_in ]],
                               constant SCNSceneBuffer& scn_frame [[ buffer(0) ]],
                               constant NodeBuffer& scn_node [[ buffer(1) ]],
                               constant CustomBuffer& custom [[ buffer(2) ]]) {
    VertexOut out;
    out.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0);
    out.texcoord = in.texcoord;
    out.color = custom.color;
    out.random01 = scn_frame.random01;
    return out;
}

fragment float4 textureFragment(VertexOut in [[ stage_in ]],
                               texture2d<float> texture [[ texture(0) ]]) {
//    constexpr sampler defaultSampler;
//    float4 color;
//    color = texture.sample(defaultSampler, in.texcoord) + in.color;
    
    VertexOut out = in;
    float random = out.random01;
    
    return float4(random, 0.0, 0.0, 1.0);
}

 

サンプルファイル

github.com

 

まとめ

軽く触った感じではテクスチャの設定方法がわからないが、Metal シェーダーを Scene Editor で試すことができるため、わざわざビルドしなくても済む。

動作チェックが手軽になるかと思われる。

Xcode 10.2 Beta 1 (iOS 12.2 など) での ARKit、SceneKit、SpriteKit の更新

今回、更新はない。

Swift の場合は、Swift 5 へのアップデートに伴い構造体のイニシャライズで変更 (Modified) があるため、ARKit、SceneKit、SpriteKit でも広範囲で更新がかかっている。

更新はかかっているが機能的な変更はない。

 

まとめ

多分、今回更新がないとなると ARKit、SceneKit、SpriteKit など、ここら辺のライブラリは WWDC 2019 まで大きな更新はないように思われる。

逆に WWDC 2019 では大きな更新があるような気はしている。 

 

 

 

Swift 版での ARKit、SceneKit、SpriteKit の変更

一応、変更を列挙してみた。
自分のメモ用。

 

SceneKit

SCNScene
SCNScene.Attribute

init(rawValue: String)

 

SCNView
SCNView.Option

init(rawValue: String)

 

SCNNode
SCNHitTestOption

init(rawValue: String)

 

SCNSceneRenderer
SCNDebugOptions

init(rawValue: UInt)

 

SCNLight
SCNLight.LightType

init(rawValue: String)

 

SCNMaterial
SCNMaterial.LightingModel

init(rawValue: String)

 

SCNGeometrySource
SCNGeometrySource.Semantic

init(rawValue: String)

 

SCNBillboardConstraint
SCNBillboardAxis

init(rawValue: UInt)

 

SCNPhysicsBody
SCNPhysicsCollisionCategory

init(rawValue: UInt)

 

SCNPhysicsShape
SCNPhysicsShape.Option

init(rawValue: String)

SCNPhysicsShape.ShapeType

init(rawValue: String)

 

SCNPhysicsWorld
SCNPhysicsWorld.TestOption

init(rawValue: String)

SCNPhysicsWorld.TestSearchMode

init(rawValue: String)

 

SCNParticleSystem
SCNParticleSystem.ParticleProperty

init(rawValue: String)

 

SCNShadable
SCNShaderModifierEntryPoint

init(rawValue: String)

 

SCNSceneSource
SCNSceneSource.LoadingOption

init(rawValue: String)

SCNSceneSource.AnimationImportPolicy

init(rawValue: String)

 

 

ARKit

ARSession
ARSession.RunOptions

init(rawValue: UInt)

 

ARWorldTrackingConfiguration
ARWorldTrackingConfiguration.PlaneDetection

init(rawValue: UInt)

 

ARObjectScanningConfiguration

ARWorldTrackingConfiguration と同じ

 

ARHitTestResult
ARHitTestResult.ResultType

init(rawValue: UInt)

 

ARFaceAnchor
ARFaceAnchor.BlendShapeLocation

init(rawValue: String)

 

 

SpriteKit

Swift 版の SpriteKit では init(columns:rows:sourcePositions:destinationPositions:) のデフォルトパラメーターの一部が変更されている。

developer.apple.com

 

また、以下のものでは廃止された 「var customPlaygroundQuickLook: PlaygroundQuickLook { get }」とドキュメントで言う Conforms To 部分が更新されている。

  • SKSpriteNode
  • SKShapeNode
  • SKTexture
  • SKTextureAtlas
  • SKTileAdjacencyMask

 

SKMutableTexture では Conforms To。

SKTileAdjacencyMask で init(rawValue: UInt) が更新されている。