来たな~、新兵ども!まずはこいつ↑で、iPhoneやiPadのアプリケーションを作るための知識を一から積み上げる事。ないと、心が通じあえん。あと、以前書いたC言語や、Objective-C言語版もある。Objective-C言語版は永遠に更新中ね。入門本、ドリル本、デバッグ本、データ本!もよろしく。iPhoneアプリを作らないと「廃部ね」って言われたのですが、どうしたらいいですか?が出ました~。目次というわけで、今回からしばらく物理の時間っす。ちなみに物理学は英語でPhysicsと書いてフィジックスと呼ぶのだよ。私達もついに、現実世界の画面と3D仮想体をシンクロさせるだけじゃなく、仮想体に現実世界の物理運動を再現させるという、ARの新たな領域に踏み込むわけだが...いったいどうしろと?こういう時は、developer.apple.comを、キーワード「physics」あたりで検索すればよくってよ。目次」の「12、または私は如何にして心配するのを止めて...」で説明してるんで、わからん人はそっち読むようにhttps://developer.apple.com/search/?q=physics&type=Videos検索結果いっぱい出ます。2018で公開されたAR対戦ゲームで使われてる技術の説明で、ソースまで提供されとります。複数のiPhone実機間での実空間の共有や、そのための実機間通信、シェーダを使った旗を揺らす方法、そういった手法のとっかかりを紹介してます。具体的な手法を知るためには提供されてるプロジェクトを読み込まないとダメなんだけど、やれば、かなりの情報が手に入りそう。Realityこれまでの話を読んでる人なら、このサンプル使って自力でなんとかできるかもしれんけど、敷居は高めです。私は、とりあえずは、地道に進んでみようかと思ってます。SceneKitあたりを軽く見て、Phisycsで何ができるのか把握しておいて、検索結果のGuidesタブ側にある検索結果確認ですな。https://developer.apple.com/search/?q=physics&type=Guidesなんだけど、ヒットするのほとんどSpriteKitの方で、上のビデオで紹介されてるSceneKit側のSCNPhysicsBodyが出ねーんすよ。physics」で検索してもあんま変わらない。注意)SpriteKitはSceneKitの2D版です。SceneKitより先にこっちが用意された。2DならUIViewとかUIImageViewとかあるじゃんと思うかもしれないけど、UIKit系はボタンやナビゲーションバーや画面遷移といったGUIパーツの構築しやすさを優先してて、ゲームといったグラフィック性能バリバリ使います系にはスピード面でやや劣るんですな。そのため、ゲーム作る人は、UIKitより操作がめんどくさい(でも高速な)OpenGLなんかを使わないとダメだったんですが、その点を改善すべくUIKit風に使い勝手がよくて、OpenGL並みに描画性能が高いKitとしてSpriteKitが登場しますた仕方ないんで、とりあえず実際に、上のビデオの18分12秒あたりで紹介されてるように、SCNNodeのphysicsBodyプロパティにSCNPhysicsBodyのdynamicBodyで作ったオブジェクトを割り当ててみようかと。SCNPhysicsBodyビデオによると、SCNNodeは、こいつを割り当てられると物理学に従った挙動をするわけっす。これねこれを実際に試す。ベースにするのはXcodeのARテンプレね。App」テンプレからのARセットアップまでをテンプレ側で終わらせてくれてるすぐれもの。おまけに「見た目が大事」で紹介したSceneファイルからのSCNScene構築までやっちゃってるので、Runさせるだけで、そのまんま空間に宇宙船が浮いたりもするわけですよ。わけだで、こいつはSCNSceneのrootNodeに"ship"て名前のSCNNodeが追加されてるんで、childNode(withName:,recursively:)で取り出せます。Editorで見ればわかります。取り出したSCNNodeオブジェクト"ship"の、physicsBodyプロパティにSCNPhysicsBody.dynamic()で作ったオブジェクトを割り当ててみる。dynamicBody];と説明されてるんだけど、swift言語なんで、そのまま記述できんわけなんやね。SCNPhysicsBody.dynamic()となる。Documentationメニューで出てくる画面で調べられます。なんか宇宙船落ちたし(笑。一瞬すぎてわからんけど、目の前通り過ぎたような...SCNPhysicsBody.dynamic()を割り当てたんで、重力が効いてしまって自由落下しちゃうんですな。底がないんで、地球の中心に向かって落下してる模様。わけで底を用意します。あと、床に跳ね返る様子を見やすいように、ship.position.zに-3を指定して、宇宙船を3m後ろに移動させとく。もって、床の高さも、position.yに-1を設定して1m下にしてます。positionわからん人は「仮想体を置いてみる」ね。}SCNFloorてのは組み込み形状で無限xz平面です。Appleのサンプル色々見てて見つけますた。こいつのphysicsBodyプロパティには、ビデオで紹介されてたように、重力や外から加えられた物理的な力に影響されない静的な物理体(PhysicsBodyを直訳してみた)となるSCNPhysicsBodyを割り付ける。静的な物理体を作る場合はSCNPhysicsBody.static()を使う。これで今回作る床は、空間に固定されたSCNPhysicsBody付きSCNNodeになるわけです。空間に固定って、physicsBodyプロパティにSCNPhysicsBodyを割り付けられてないSCNNodeと一緒じゃんと思うかもしれないけど、SCNPhysicsBody.static()を割り当てた場合、SCNPhysicsBody同士が衝突した場合、お互いに弾きあうという性質が利用できるんですよ。SCNPhysicsBodyが設定されてないSCNNodeとは、衝突してもそのまますり抜けちゃうんで、宇宙船の落下を止めるには固定されたSCNPhysicsBodyを設定したSCNNodeが必要なんですな。これで落下した宇宙船は、固定された床にぶつかって止まる。Runさせると、無事床に着地しました。ま、ぶっちゃけ、突き刺さったわけだがおもろいやんけ〜、ということで、画面タップしたら宇宙船に力を加えてみることにしました。}Runすると、画面タップするたびに宇宙船が飛び跳ねるようになります。サンプル:http://tetera.jp/xcc/book-sample/ARPhysics.zip空中で浮いてる時にタップすれば、そこからまたジャンプだ。無限の宇宙へ!ここで使ってるapplyForceってメッセージは、SCNPhysicsBodyオブジェクトに対して力を加えるって指定です。DocumentationのSCNPhysicsBodyの説明だと、最初の引数で力の大きさと向き、asImpulse:引数をtrueにすることで、一瞬の衝撃(インパルス:Impulse)ってことになります。衝撃指定の場合の第1引数のSCNVector3は力積値を意味するらしい。力積て何?という話は長くなるんで次回。目次Xcodeではマテリアルを同じような値で指定しても、Blenderの時ほど金属ぽくない。なんか、イマイチなぜなのか?それはXcodeの方には金属に映り込む風景が存在しないから。テカテカする金属の表面を見るてっのは、金属の表面そのものを見てるわけじゃなく、金属の表面に映り込む周りの風景を見てるってことに他ならない。見る角度によって映り込む風景がチラチラと変わる。明るい風景を反射したら明るくなるし、暗い風景を反射したら暗くなる、この陰陽の変化を脳がとらえて金属っぽいって感じるわけです。なんだけど、Xcodeではその映り込むべき風景が何もない暗黒なんですよ。真っ暗闇の中にポツンと光が灯ってる状態。金属表面が陰陽の変化の少ないのっぺりした描写になる。なんか金属っぽくないなと...え、でも、それはBlenderでも同じなんじゃ...と思った人、残念、Blenderでは事前に風景を用意済みなんですな。Blenderの3Dビューのボトムバーにあるシェーディングってメニューをクリックするとわかります。実は設定済みというねちなみに、円で表示されてる風景をクリックしたら別の風景も選べます。この画像の円形での表示は、球体の内側に貼り付けられてる画像を見てる状態を表現してまして、実際は視線の後ろ側にも画像が広がってます。視線をどこに向けようが、360度全周に画像が存在するってわけです。そのため、割り当てる画像は、球体の裏側360度全周に貼り付けられることを前提にしたものが必要で、縦横比が1:2の横長画像のメルカトル図法っぽい画像が要求されます。Blenderではそうでない画像を指定してもいいんだけど、その場合、360度全周に貼り付けた時にどこかしら破綻する。注意)メルカトル図法なのかどうかは知らんけど具体的に言えばリコーのシータで撮った画像ね。ストリートビューみたいなアプリで作成した画像ね。パノラマ撮影の全周版って感じで撮るのめんどくさいけど、iPhone使って無料で上記の全天球用の写真が撮れます。ストリートビューで、Xcodeでは事前に設定はしてないものの、自分で設定することは可能っす。Catalogフォルダに入れちゃってください。Catalog.scnassetsってフォルダね。わからん人は「見た目が大事」を読み返すべし。フォルダに置くと、勝手にXcodeのナビゲーションエリアにファイル名が表示されます。inspectorタブを選んで、Environmentメニュークリックして、フォルダに入れた画像ファイルを選択する。これで金属っぽくなる。basedに変更してもARKit(SceneKit)が読み取ってくれません。なんか、もおおおおお、ね、色だけしか読み取ってくれない。素直にCOLLADAファイルをSCNファイルに変換してから修正するのがいいみたいっす。ダンスダンスダンス後編」で説明してるので各自でやってください。・・・に変えるように。COLLADAファイルそのまま使いたい人はプログラムで変更しましょう。}}前回、boomNode以外はオブジェクトとして取り出さなくてもいいようにしたんだけど、結局必要になってしまった...bucketNodeはboomNodeの子SCNNodeになってるんで、boomNodeからchildNodeで探し出してる。そのbucketNodeとboomNodeのgeometryのmaterialsに設定されてる"red"と"body"って名前のマテリアルを、物理ベースの設定に変更してます。Editorで変更したとこね。変更にはSCNNodeクラスにextensionでchangeToPhysicallyBased(name:)てメソッドを追加して利用するようにしてます。extensionがわからん人は「リファクタリング」ね。geometryのmaterialsから、指定の名前のSCNMaterialを探し出すには、Array構造体が持つfirstIndexメソッドを利用してる。Boolという形で渡され、探してるSCNMaterialならtrue、そうでないならfalseを返すという決まりになってるんで、引数であるSCNMaterialに適当な引数名(サンプルではmにした)与えてnameプロパティとnameの比較結果を返すようにしてます。}配列がわからん人は「色々と脱線」、クロージャがわからん人は「タップしてドン」ね。クロージャに関しては任意の処理を{・・・}で書けるとしか説明してないんで、ここでもうちょっと補足すると、必要なら、クロージャ呼び出し側がクロージャに引数を渡せるようにもなっていて、戻り値をもらえるようになっている。値で、呼び出し側に戻り値を返せるようになる。それが、上のサンプルでやってること。ここら辺はfirstIndexメソッド側が決めることで、使う側は、それに従ったクロージャを用意しなければいけないわけっすね。クイックヘルプで調べれば、どんな風にクロージャが呼び出されるかわかるようになってます。クイックヘルプがわからん人は「または私は如何にして心配するのを止めて...」ね。}てのは、materials側から、自分の要素SCNMaterialを1つ1つ取り出して、こいつが探してるSCNMaterialですかって聞かれることに対する処理になるわけですよ。nameならtrueを返すって処理なわけで、これでnameに一致するSCNMaterialをmaterials側から取り出せることになる。firstIndexて名前からわかると思うけど、配列内に該当する要素が複数ある場合、最初に見つかった要素のインディックスになります。見つかったSCNMaterialのlightingModelプロパティに物理ベースのパラメータを指定するよって指示して、関係するmetalness、roughnessプロパティを設定してる。lightingModel「光あれ」で説明したシェーディング時の演算に、物理ベースを指定するには、このプロパティにSCNMaterial.LightingModel.physicallyBasedを指定してやればいいわけです。省略形が.physicallyBasedね。他にどんなのがあるか興味ある人はクイックヘルプで調べましょう。物理ベースで使われるSCNMaterialのプロパティはmetalness、roughnessで、こいつは0.0〜1.0の数値を指定することになってる。指定するには、metalness、roughnessのcontentsプロパティにNSNumberで設定します。NSNumber数値を表現するクラスです。contentsプロパティは何らかのオブジェクトでないと指定できないので、float型の値を直接は設定できないんすよ。その代用としてNSNumberオブジェクトを使います。引数の後ろに設定したい値を書く。1.0)これでマテリアル側の設定は完了。.physicallyBasedを指定した場合、重要なのが映り込む風景の指定。COLLADAじゃなくSCNファイル使う場合でも、読み込んだSCNSceneをそのままARSCNViewのsceneとして使わないなら、映り込む周辺の画像は自前で設定する必要があります。サンプルではブーム、アーム、バケットの3形状を読み込んで使ってるだけなんでね。何言ってるのか、わからん人は「仮想体を置いてみる」、「見た目が大事」を読みなおしましょう。プログラムで風景画像を指定する場合はSCNSceneのlightingEnvironmentプロパティにUIImageとして設定するのが基本っす。lightingEnvironmentこいつにはSCNMaterialPropertyクラスのオブジェクトが設定されてて、この中のcontentsプロパティにさっきの風景写真をUIImageとして設定すれば、映り込む風景の指定は完了。}で、まあ、これで十分テカテカなんだけど、クイックヘルプの.physicallyBasedの説明では.physicallyBased使うなら、SCNCameraのwantsHDRプロパティをtrueにしろとか書かれてるんで、やってみました。Range(ハイダイナミックレンジ:豊かな階調)のイニシャルです。黒にも様々な黒があるわけで、漆黒から淡い黒まで、きめ細やかに表現する場合に指定します。wantsHDRプロパティをtrueにすることで、HDR希望ってことになるのかな。このプロパティを持ってるオブジェクトがSCNCameraこいつは仮想体撮影用の仮想カメラっす。もって画面描画に使用されるSCNCameraは、ARSCNView(その派生元であるSCNView)のpointOfViewプロパティのcameraプロパティからゲットできます。pointOfViewこのプロパティには視点となるSCNNodeが指定されるっぽい。バケットSCNNodeのcameraプロパティにSCNCameraを設定しておいて、このpointOfViewプロパティにバケットSCNNodeを設定すると、バケットから見た風景が表示されるんじゃないかと...ゲームで言うところの本人視点シューティングゲームぽく。ま、それは置いといて、とにかくwantsHDRプロパティを設定。}うーん、変わらんような...よくわかりません。サンプルはRunするとこんな感じになる。ちなみに、このダイアモンドカット的なエッジの効いたバケットもいいけど、曲線部は滑らかにしたいよねえな人は、Blenderで、bucketオブジェクト選んだ状態で、3Dビューのボトムバーからオブジェクト>スムーズ面メニューを選びましょう。注意)もちろんXcode側で設定する方法もあるが、それはいずれスムーズ面スムーズ面指定するとこうなる。元に戻したい場合は、オブジェクト>フラット面メニューを選びましょう。これって、シェーディング時に法線をどう扱うかって話なんだけど、ARKitでもgeometryオブジェクト単位では対応してくれるみたいっす。法線によって、周辺の風景のどの部分が反射して見えるかを計算してる法線、なんすかそれな人は「光あれ」を読み返しましょう。Blenderオンリーだと、もうちょっと小技が指定できて、プロパティビューのオブジェクトタブに、面と面が指定した角度以下の場合はスムーズ面にしないって指定もあったりする。これだと側面は平坦になる。ARKitは認識してくれませんでした。注意)もっと細かいので、編集モードでスムース面化させたい面だけ選んでおいて、面>スムーズ面を選ぶってのもあるんだけど、もちろんARKitは未対応で、法線もそうだけど、色の分布や粗さ具合の分布を平面単位じゃなく、平面に対応する2Dの分布図として設定するには、マテリアルタブの下にあるテクスチャタブを使います。MMDでは使ってるし、ARKitでも表示されたんで、ある程度対応できてるぽいけど、どこまで対応かは不明。ちなみにMMDのテクスチャ設定はマテリアルタブの下の方にあったりします。テクスチャタブの下の物理演算タブなんかも、フォースフィールドやコリジョン、剛体なんかあって面白いんだけど、COLLADAファイルでどこまで引き継げるか、ARKitでどこまで対応なのか不明。いうか対応してないっぽい。いうわけで、Blenderの話は一旦終了。Xcodeで「ダンスダンスダンス後編」で軽く触れた、リジッドボディや物理計算に突入します。突入せよ!あさま山荘。目次てなわけでバケット(bucket)は省略。これまでに紹介したやり方で作れるからね。これねブーム、アーム、バケットはそれぞれローカル空間で、次のような原点にしておくと、ARKit側では読み込んで親子関係結ぶだけで済みます。ピボット調整(光あれでやったpivotプロパティね)しなくていいわけです。ちなみに各オブジェクトのローカル空間での素の状態(グローバル側でトランスフォームされてない)を確認するには、オブジェクトモードでオブジェクト選んでおいて、3Dビューのボトムバーからオブジェクト>クリア>位置、オブジェクト>クリア>回転、オブジェクト>クリア>拡大縮小を選べばいいんだけど、これって一時的にクリアするとかできないもんなのか?めんどくさいんだが...マニュアルに何か書いてるかもしれんが未確認。クリアされてるかはnキー打ちでサイドバー出してトランスフォームグループの位置や回転が0.0に、拡大縮小が1.0になってるのを確認すればよくってよ。プロパティビューのオブジェクトタブのトランスフォームグループ側でもOK。どっちも連動してます。上記のクリアメニュー使わずに、ここで直接値を入れるってのもありです。確認して思ってた位置とずれてたら編集モードで調整。オブジェクトモードのまま移動させても、ローカル空間での位置調整にはならんでな。調整できたらオブジェクトモードに戻る。オブジェクトモードでは見やすい位置に配置しても問題ナッシング。さっき言ったようにローカル空間での形状の位置には影響しない。実際「見た目が大事」ではグローバル側の位置をずらしてるのを読み込ませてる。別に重なったままでもいいけどね。COLLADAでの書き出しは「親子関係を確認」を参考にしましょう。今回はモディファイアーを適用にチェックだ!何の指定かはもうわかるよね。「親子関係を確認」でやったようにブーム、アーム、バケット、3つのオブジェクトを別々に読み込んで、その後親子関係結ぶのもいいんですが、Blender側で親子関係結んでおくってのも有りです。この場合、AR側ではブームだけを探して、土台と親子関係結んでおしまい。アームやバケットの連結作業は不要になる。}サンプル:http://tetera.jp/xcc/book-sample/yumbo-blender-linked.zipBlenderファイル:http://tetera.jp/xcc/book-sample/yumbo-linked.blend.zipただ、これを試してみて気づいたんだけど、XcodeではCOLLADAファイルのオブジェクトの名前にスペースが入ってると、そこで名前が確定するみたいっす。3は、どれもarmの後ろにスペースがあるんで、全部armになっちゃう。なんで、あっちゃこっちゃの階層にarmってオブジェクトができて、検索に支障をきたすんですな。最上位のワールド空間に3つのオブジェクトを配置したい場合は、最初に見つかるのは最上位のboom、arm、bucketなんで問題なかったんだけど、階層構造にしておくと、boomからのarm、bucketの検索になるんで具合悪い。何言ってるかわからん人は「ムーブムーブムーブ」のchildNodeメッセージの話を読みましょう。(ハイフン)に置き換えてます。実際使ってみると色々あるわな。形状についてはこんなところで。最後にマテリアルについて。ブームやアーム作って気づいたと思うけど、Blenderは新規作成のオブジェクトの色は白色にしてるんですよ。これを油圧ショベルっぽく、各パーツを黄色にするって話っす。マテリアル「光あれ」で説明したように3Dの場合、単純に色を指定するって話にはなりません。金属っぽいとかザラついてるとか、いくつかのパラメータで表面の質感を指定することになるんですな。これがマテリアルの指定。このマテリアルの指定、Blender自体はオブジェクトといわず、面の1つ1つに個別のマテリアルを指定できるんだけど、ARKitがどこまで対応してるかは不明。オブジェクト単位では対応してるみたいなので、今回はオブジェクトごとの指定方法を説明します。bucketあたりを選択しちゃってください。選択したら、プロパティビューのマテリアルタブを選択。表示される画面がマテリアルの設定画面っす。マテリアルタブbucketにはすでにbodyてマテリアルを作って設定してるんで、こんな感じの画面になる。見ての通りSCNMaterialでも扱えそうな名前が並んどります。SCNMaterialのプロパティ名と関連させるとこんな感じかな。ベースカラー:diffuseメタリック:metalness粗さ:roughnessスペキュラーは、どうなるか不明。ちなみに「ノードを使う」は今のところ使わない方向で。きめ細やかなパラメータ指定ができるんだけど、ARKit側で対応してないっす。対応する場合、自分でカスタムシェーダーを用意する必要がある。カスタムシェーダーについてはいずれ。とりま、ベースカラーをいじりゃ色が変わります。金属っぽくしたけりゃメタリックを1.0よりにすればいいし、ツルツルの鏡面仕上げにしたけりゃ粗さを0.0寄りにすればいい。その結果がどうなるかがプレビューで確認できるんだけど、いまいち分かりずらいっす。効果がわかりずらいんだ、これがこんな時は、もう、直接3Dビューで確認しちゃっていんじゃないかと思われ。3DビューのボトムバーのシェーディングをLookDevに変えましょう。注意)見えない場合、ボトムバー上にマウスを合わせて右にスクロールでマテリアルbodyのパラメータ、メタリックを1.0、粗さを0.0にしてから、3Dビューで視点をグリグリ動かしてみる。パラメータ変えて変化の具合をみてください。ちなみにマテリアルbodyは、ブームやアームにも設定されてるんで、一緒に変化してます。bucketだけのマテリアルを用意したい場合は、新規にマテリアルを作成する必要がある。その場合は、マテリアル名の横にある「×」マークをクリック。これでbucketだけ、割り当てられたマテリアルbodyが解除され、新規ボタンが表示されることになる。新規ボタンをクリックすれば、新しくマテリアルが作成されてbucketに割り当てられます。redとかつけてみる。ここまで書いててなんだけど、残念な知らせがあります。バージョン2.90βのBlenderで設定したマテリアル、ARKitで理解できないみたいっす。注意)「ダンスダンスダンス後編」で使ったscntoolでSCNファイルにコンバートしてもダメでした。冗長指定で変換処理を細かくレポートさせても特に何も言ってこないBlenderファイル:http://tetera.jp/xcc/book-sample/yumbo-red.blend.zipまあ、ベータ版だしね。今はXcode側でマテリアル設定するしかないです。ちなみに、今回の元凶はマテリアルのパラメータTransparentに設定されてる色っぽい。inspectorタブ選んで、Transparentを変更します。based(こっちも読み込み時に、判定できてないみたい)にして、MetalnessやRoughnessを調整しておしまい。これ指定しても、Blenderの時みたいにピカピカにはなりません。何でかというと、金属面が反射するべき周りの風景を何も指定してないから。特定商取引法に基づく表記ヘルプ。