壁からロゴを出してゴニョゴニョ動かす
この記事はMoAR - Museum of AR Advent Calendar 2022の16日目の記事です。
こんにちは
昨日に引き続き、岡田です。
ここの前段を書くのがとても好きなんですが、気付いたら息子の朝飯を作る時間になってしまって焦っているので、なし。泣ける。どうでもいいことをつらつらと書きたい。
今日は、モーションの話をします。
MoARのロゴ
デザイナーのニロさんが作ったMoARのロゴです。
このMやoの文字を実際3D化して動かすというのがMo(AR)^2。
Mo(AR)^2のコンテンツは3つ
りょうさん、ニロさんに、本当にたくさんたくさんアイデアを出していただきました。もっと自分に実装力(か、Unityだったらなあ…)があればもっと採用できたんですが!(すみません!!)
結果、以下3つの動きになりました。
『Motion』
一個目、Motionという名の案。
シンプルにロゴやQRが飛び出して、ビルの前でグルグルと回転し、再び集まって壁に入っていきます。
『Giant』
二個目、Giantという名の案。
ロゴやQRが拡大しながら分散、突然重力をもって床に落ちてくる。またフワーっと浮かんで集まり、壁に戻る。
『Color』
三つ目、Colorという名の案。
ロゴが分裂し、壁に散らばる。ウェーブをしながらロゴの色が変わっていく。再び結合、集合し、壁に戻っていく。
最初はUnityでモック作ってた
案がまだ全然固まる前。
慣れないSceneKitでモック作るより、一旦慣れているUnityでどんな動きができるかなあという感じで、テストしたりしていました。
途中から実機で動く現実的なオブジェクト数とか、ARで見た時の感覚を知る上でも早めにSceneKitに移行していきました。
SceneKit移行後はモック制作速度が遅くなってしまったんだけど、りょうさんニロさんの二人が、モック作成の前段階から動きを詰めていってくれたので、めちゃくちゃありがたかった。
QRコードの分割
動きを考えていく中で、壁に描かれているロゴだけじゃなく、文字やQRコードも一緒に飛び出す方が動くオブジェクトが増えて良いのではないかということになり。ニロさんにQRコードの分割方法を考えていただいて、それぞれのオブジェクトが立方体になるようBlenderでモデリングしたりしてました。
開発終盤にQRコードが変わってもう少し複雑になっちゃったにも関わらずモデリング調整する時間が無く、実際はちょっと中途半端な位置で分割することになってしまいました。
Blender、慣れない!楽しいけど!慣れない!
余談ですが、分割したQRコードオブジェクトの側面は、表面の図柄が伸びたような状態(金太郎飴みたいな)にしたいということで、これはUV設定してくだけで一日仕事だぞ…と思い、社内で普段からBlenderを触っているデザイナーのコモちゃんにやり方ないか尋ねたら、5分で出来てしまった。
「Blenderで面倒くさいと思う作業は、たいてい誰かが解決してる」という言葉をいただき、衝撃を受けたのでした。
ロゴの2D←→3D
3D風の2Dロゴなので、実際の3Dに直してみると、真正面でしか成立しないことがわかり、どうやって壁のロゴからシームレスに出現させようかと悩んでました。そんな相談をしたときにキャプチャした動画がこちら。
解決方法として、3Dロゴの奥行き軸を0にすれば、ペタッと平らになったロゴができあがるので、ペタッと平ら←→3Dロゴに変換するような頂点のモーフィングをBlenderでつけて、SceneKit上で制御できるようにしました。
以下ができたときのキャプチャ。(Youtubeの動画が1分以内だとショート動画になってnoteで埋め込みができない??どうすればいいんだろう、と思いつつ貼るので、リンク先で見てください。)
位置情報が消えるバグ
今回3Dデータは全てUSDZ形式で読み込んでいて、Blenderで実際の壁と同じ配置でモデリングし、モーフを付けて、glTF2.0(.glb)で書き出し。
Reality ConverterでインポートしてUSDZ書き出ししてみると、なぜか位置情報がなくなってロゴのMやoなどのオブジェクトが座標(0,0,0)になっているということがおきました。なんでや。
再びコモちゃんに相談して、M、o、A、Rを一つのボーンで繋ぐと位置固定されますよと裏技を教えてもらったのだけど、SceneKitにインポートしたあと、オブジェクトのパラメータを自由に変えながら動かそうと思うとボーンが邪魔で動かない。ので却下。
結局、原因はモーフを付けると位置情報が消えるみたいだったので、
1. モーフを無くして正しい位置に配置したロゴ
2. モーフを付けたロゴ
を同じUSDZファイルに内包して、SceneKitでインポートした後、2の座標を1の座標に合わせるという一手間で解決しました。
もっと正しい方法があったら教えて欲しい…。
モーションをつくってく
どうやってパラメータを動かすか
各オブジェクトのx, y, z座標を動かしつつ、スケールを変えつつ、回転もさせつつ、時間によって変化させつつ、そのパラメータや時間は全てランダム要素を入れつつ…といった実装。
もともとFlashから業界に入った人間としては、大好物な分野ではあるんですが、SceneKitではわりと沼にハマってしまって。
Swiftではパラメータをアニメーションさせる方法が色々あって、SCNAction、SCNTransaction、CABasicAnimation、SCNAnimationなど。
モーション作っていると、座標のx値を0.5秒でCubicOutで動かしながら、同時に0.1秒後からy軸を0.3秒でCubicInOutさせながら、余韻の0.1秒でAlphaをCubicInで0にしながら、回転は0.2秒で早めつつ後の0.3秒で止めて…みたいな複雑にパラメータを重ねながら気持ちいいモーション作っていくのはザラなので(その調整が気持ちよくできないとめっちゃしんどい)、パラメータが重ねやすいCABasicAnimationを採用しつつ、時間での実行はasync/awaitで
await Task.sleep()を差し込みまくりながら作っていきました。
ちなみに
ちなみに、モーション中はnode.positionの値が反映されないので、モーション終わりに毎回removeAnimation()する必要がある。でもそれを実行した瞬間にアニメーション前に値が戻ってしまうので、remove直前にnode.presentation.positionの値を保持しておいて、remove後にnode.positionを設定してあげる必要がある。
そういうルールにずっと苦しめられました・・。
UnityならLeanTweenでガシガシやるのが好きです。DOTweenでもいいです。
いや、もっと言うなら今でもBetweenAS3を使いたい。(リンク貼りたくて「Spark project」とかで検索したけど、先人たちのブログがいっぱいでてくるだけだった。)
ということで
パラメータをスクリプトでゴリゴリ動かしながらSceneKitでモーションさせるのは、結構つらかったです。。うまく動かないなあ…フェーズが長くて、もっともっと色んな案を出していただいたのに、あまり数が作れず悔しい思いをしました。
今の三つも、もっとブラッシュアップする予定です。作業時間作るぞー!!