「ロボットやろうぜ!- toio & Unity 作品動画コンテスト -」というのにアプリを出したのですが,それで「toio SDK for Unity」を触ったのでTipsとか書くシリーズです.
コンテストに出したアプリについてはこちら:
mu-777.hatenablog.com
コードのレポジトリはこちら:
github.com
マット上における各Cubeの絶対位置が取得できることが大きな特徴・魅力なtoioですが,SDK上で取得できる位置座標系が個人的にはかなり罠だったので記録を残しておきます.
たぶん,toio SDK for Unity のドキュメントにも,「toio コアキューブ技術仕様」にも情報が載ってないと思います(読み逃してるだけなら申し訳ないです)
ちなみに実機は持っていないので,純粋にUnity Editor上でシミュレータとして使う用途に関する話だけになります.
toioの座標系がややこしい点
CubeのGameObjectをUnityのtransform.position
で0.1動かした場合,toio SDKのCube.pos
で取得できる位置は73動く,という不思議な関係になっています.
アプリを作ってたときの苦しみのツイート:
うーん..まだ #toio のUnityシミュレータの座標系わからん..
— むぅー777 (@mu_777_) 2020年11月29日
マットのど中心(=Unity座標系の[0,0])のCube.posが[250, 250]なのでtoio座標系はmmで表されてるのかと思いきや,Unity座標系で[0.1, 0.1]のCube.posは[323, 177]
期待はUnity座標系の0.1がtoio座標系で100になることだったのだが..
Unity上における1単位は1mを表す(参考)ので,transform.position
で0.1動かした場合にCube.pos
が100動く,とかならサイズ感的にも「あーtoioにおける座標系はmm系なんだな」と理解できるのですが,73はかなり謎です.
さらに,toioのマットごとにオフセットがついています.
マット上の正規化座標系でのCube位置を取得する方法
今回の自分のアプリでは,結局マットの左上を[0,0],右下を[1,1]に正規化した座標系でCubeの位置を取得したかっただけでした.
なので,Cube.pos.x
が45のときに0, Cube.pos.x
が455のときに1, になるときの1次関数を算出し,それを使いました.
つまり,
の連立方程式の解,,を用い,以下のようにCubeクラスの拡張メソッドを入れることでそれを実現しました.
(「トイコレ付属マット(土俵面)」を使用している場合のみ有効です)
public static class ToioUtils { public static Vector2 GetPosInMatUV(this Cube self) { var a = 1.0f / 410f; var b = -45f / 410f; return new Vector2(self.x * a + b, self.y * a + b); } }
以下のように,Cubeクラスのメンバ関数的にGetPosInMatUV()
関数を使用できます.
using UnityEngine; using toio; public class TestCubeController : MonoBehaviour { Cube _cube; async void Start() { var peripheral = await new NearestScanner().Scan(); _cube = await new CubeConnecter().Connect(peripheral); } void Update() { Debug.Log(_cube.GetPosInMatUV()); } }
今回はシミュレータ上のみで都合が合えばよかったので,無理やり合わせ込むことで対応させました💪
実機がないので,Unity上のCubeをtransform.position
で0.1動かした場合に,現実世界の実機は100mm動くのか,それとも73mm動くのかは不明です.
さいごに
Unityみたいなプラットフォームに対応するなら,SDKで座標系あたりはそのプラットフォームを基準にしたものにしてもらって,開発者は座標系など気にせずに実装できるようにほしかったなぁというのが正直な気持ちです.
でもまぁ作ってる側はそんなこともちろんわかってると思うので,何かそのようにすると別の問題が起こる,とか,教育用途なのでそういうのも勉強してもらうためにあえて,スケジュールと工数とメリットを考えて,など理由はあるとは思うのですが.
とはいえ,ローレイヤの情報を各種プラットフォームに合わせる,というのはプラットフォームをサポートするSDKの重要な役割なんじゃないかなぁと思わなくはないです.
(特にUnity/UE4,DirectX/OpenGLなどにまとめて対応などするときは座標系の混乱が必至なので,うまくやっといてくれよという気持ち......)