MRTKそれ自体はサービスロケータパターンな作りになっており、MRTKではMixedRealityInputSystemやMixedRealityBoundarySystemのようなサービスを自作して、利用することができます。
Extension services | Mixed Reality Toolkit Documentation
サービスを作成する
自作の拡張サービスを作るには、Toolsに含まれるextension service creation wizardを使って作ることになります。
Mixed Reality Toolkit > Utilities > Create Extension Service から順に従って作成します。
最初のページでは、Serviceの名前、対応プラットフォームの指定、生成されるスクリプトのネームスペースを入力します。Serviceには重複した名前が指定できません
次のページでは、生成されるスクリプトの詳細及びプロファイルの生成先が表示されます。
もしServiceの設定をInspectorをカスタマイズしたければ、Inspectorにチェックを入れましょう。Profileにチェックを入れると、ScriptableObjectが生成されます。設定を差し替えたい場合は作っておくといいでしょう。
サービスを追加する
サービスを追加するには、MRTKのProfileのExtensionsに自身で登録する必要があります。
MRTKのProfileからExtensionsを選びRegisterで登録します。
サービスを呼び出す
コードから登録したサービスへアクセスするには以下のようにMixedRealityServiceRegistry
を通じてアクセスします。
この手法で依存解決を行う場合、このようにMixedRealityServiceRegistryに依存することになります。
INewService service = null; if (MixedRealityServiceRegistry.TryGetService<INewService>(out service)) { // Succeeded in getting the service, perform any desired tasks. }
実際に使ってみる
今回は本番ではネットワーク経由で画像をとってきて、開発中の段階ではStreamingAssetsから画像をとってくるというのをやってみます。
まず、PhotoStorageService
という名前のサービスを作ります。InspectorとProfileは今回は使わないのでチェックを外して大丈夫です。
IPhotoStorageServiceは、呼び出すとどこからかTexture2Dを返してくれる仕様とします。
public interface IPhotoStorageService : IMixedRealityExtensionService { Task<Texture2D> GetPhotoAsync(); }
次にこのサービスを実装した本番用のサービスを作ります。twitterの自分の画像のURLを突っ込んでます。(エラー処理とかはサンプル実装なので省いてます。)
[MixedRealityExtensionService(SupportedPlatforms.WindowsStandalone|SupportedPlatforms.MacStandalone|SupportedPlatforms.LinuxStandalone|SupportedPlatforms.WindowsUniversal)] public class PhotoStorageService : BaseExtensionService, IPhotoStorageService, IMixedRealityExtensionService { public PhotoStorageService(string name, uint priority, BaseMixedRealityProfile profile) : base(name, priority, profile) { } public async Task<Texture2D> GetPhotoAsync() { using (var request = UnityWebRequestTexture.GetTexture("https://pbs.twimg.com/profile_images/1041161611782705157/hj7diH8H_400x400.jpg")) { await request.SendWebRequest(); return DownloadHandlerTexture.GetContent(request); } } }
続いて開発中はStreamingAssetsから画像を引っ張ってきたいので、StreamingAssetsに適当な画像を置いて呼び出すモックサービスを作ります。
[MixedRealityExtensionService(SupportedPlatforms.WindowsStandalone|SupportedPlatforms.MacStandalone|SupportedPlatforms.LinuxStandalone|SupportedPlatforms.WindowsUniversal)] public class PhotoStorageServiceMock : BaseExtensionService, IPhotoStorageService, IMixedRealityExtensionService { public PhotoStorageServiceMock(string name, uint priority, BaseMixedRealityProfile profile) : base(name, priority, profile) { } public async Task<Texture2D> GetPhotoAsync() { var url = System.IO.Path.Combine (Application.streamingAssetsPath, "sample.png"); url = "file://" + url; using (var request = UnityWebRequestTexture.GetTexture(url)) { await request.SendWebRequest(); return DownloadHandlerTexture.GetContent(request); } } }
これらサービスを実装する上での注意点なのですが、どうやらname, priority, profileをコンストラクタの引数として渡す必要があるようです。
public PhotoStorageService(string name, uint priority, BaseMixedRealityProfile profile) : base(name, priority, profile) { }
最後に、サービスを呼び出すクラスです。Quadにアタッチします。MixedRealityServiceRegistryからIPhotoStorageServiceを取得し、画像の読み込みを行い自身のTextureを差し替えます。
public class TextureViewer : MonoBehaviour { // Start is called before the first frame update async void Start() { if (MixedRealityServiceRegistry.TryGetService<IPhotoStorageService>(out var service)) { var photo = await service.GetPhotoAsync(); this.GetComponent<Renderer>().material.mainTexture = photo; }; } }
あとは、サービスを切り替えて動作させてみましょう。
まとめ
というわけでMRTKの仕組みでサービスロケータな使い方ができました。ぱちぱち。 まあ取得するサービスは常にSingleなのであまり柔軟な使い方はできない訳ですし、CleanArchitectureライクでレイヤーが深いものをMRTKのサービスに任せるのは大変なので、普通にZenject(Extenject)使った方が良いんじゃない?というツッコミがありそうですが、MRTK単体でもこういったことができるよーという紹介でした。はい。 他にもInitializeやUpdateをoverrideできるので初期化処理や毎フレーム処理とかも組めます。