【MagicLeap入門】3Dオブジェクトを任意の平面に設置する!
MagicLeap入門の第2弾は任意の平面に3Dオブジェクトを設置する方法をご紹介します。
MagicLeapではリアルタイムで空間を認識することができます。この技術によって平面(床・壁)にオブジェクトを設置することができます。
今回はUnityを利用して簡単なサンプルアプリを作成しながら平面に物を設置する方法を学んでいきます。
※本記事ではMagicLeapの環境構築方法などは省略しています。Unityのセットアップは下記の記事をご参考ください。
参考記事)【MagicLeap入門】Unityのセットアップ手順を1から解説!
※本記事はUnityを触ったことがある方向けの記事となっております。
※Unityの使用方法については以下記事をご参考ください。
参考記事)【Unity入門】ゲーム開発ができるようになる基礎知識まとめ
※MagicLeapの開発環境構築については以下をご参考ください。
参考記事)【MagicLeap公式】Install the Tools
参考記事)【MagicLeap公式】Get Started Unity
※本記事は以下記事を参考に作成いたしました。
参考記事)【MagicLeap公式】Unity User Input
空間認識とは
空間認識とはカメラによって空間を認識する技術のことです。
MagicLeapには複数のカメラがついており、高精度で空間を認識することができます。

これによって3Dオブジェクトをただ画面に描画するだけでなく、奥行きを意識した設置をすることが可能になります。
さらに、垂直・水平の認識をすることもできます。壁にしか貼り付けることができないオブジェクト、水平な平面にしか置くことができないオブジェクトなどを分けることでより現実空間と親和性の高い体験の開発が可能になります。
平面にオブジェクトを設置するサンプルアプリの作成
それではここから本題に入ります。
今回はコントローラー操作によって任意のオブジェクト(今回は1種類のみ)を設置するサンプルアプリを作成していきます。
仮想空間に平面をマッピングする
はじめにオブジェクトを設置するための平面を生成します。平面の生成はMagicLeapが提供するサンプルにそのまま使用可能なプレハブが存在しますのでそちらを利用します。
まずは適当なシーンを作成してください。
次にデフォルトのMainCameraを(任意フォルダ)→MagicLeap→Core→Prefabs→MainCameraに置き換えてください。
次に平面を仮想空間にマッピングするためのプレハブを設置します。(任意フォルダ)→MagicLeap→Examples→Prefabs→MLSpatialMapperをシーンに配置してください。これだけでオブジェクトを配置するための平面を作り出すことができます。

ここまで一旦実行してみると以下のようになります。

現実空間にメッシュが生成されていることがわかります。
メッシュを可視化してほしくない場合はMLSpatialMapperの子オブジェクトであるOriginalのMeshRendererをオフにすれば問題ありません。マテリアルを変更すれば自分の好きなメッシュを可視化することもできます。(本サンプルでは既存のメッシュプレハブをそのまま使用いたします)
また、このときMeshColliderをオフにしてしまうと平面としての機能を失ってしまうのでご注意ください。
コントローラーを操作できるようにする
次にMagicLeapのコントローラーを操作するための処理を追加していきます。
はじめにコントローラープレハブを準備します。こちらもMagicLeapが既に準備をしてくれているプレハブを使用します。(任意フォルダ)→MagicLeap→Examples→Prefabs→Controllerをシーンに配置してください。

次にコントローラーからRayCastを飛ばすための空のオブジェクト「InputController」を作成してください。
次にRayCastを可視化するためのスクリプト「DynamicBeam」を作成してください。
作成したスクリプトを以下のように編集してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR.MagicLeap; public class DynamicBeam : MonoBehaviour { [SerializeField, TooltipAttribute("MLのコントローラーオブジェクトをアタッチ")] private GameObject controller; [Header("Color")] [SerializeField, TooltipAttribute("レイの始まりの色を設定")] private Color startColor; [SerializeField, TooltipAttribute("レイの終わりの色を設定")] private Color endColor; // 可視化するためのレンダラー private LineRenderer lineRenderer; // Start is called before the first frame update void Start() { // 自分自身のLineRendererコンポーネントを取得して色を設定 lineRenderer = GetComponent<LineRenderer>(); lineRenderer.startColor = startColor; lineRenderer.endColor = endColor; } // Update is called once per frame void Update() { // コントローラーの位置と角度を取得 transform.position = controller.transform.position; transform.rotation = controller.transform.rotation; //コントローラーから正面に向かってレイを飛ばす RaycastHit hit; if (Physics.Raycast(transform.position,transform.forward,out hit)) { // ワールド座標系でレンダリング // コントローラーの位置からレイがぶつかった場所までレンダリング lineRenderer.useWorldSpace = true; lineRenderer.SetPosition(0, transform.position); lineRenderer.SetPosition(1, hit.point); } else { // ローカル座標系でレンダリング // コントローラーの位置から所定の距離までレンダリング lineRenderer.useWorldSpace = false; lineRenderer.SetPosition(0, transform.position); lineRenderer.SetPosition(1, transform.forward * 5); } } } |
このスクリプトではコントローラーからレイを飛ばして、ぶつかったところまでLineRendererをレンダリングしています。
参考記事)【Unity公式スクリプトリファレンス】LineRenderer
このスクリプトを先ほど作成した空のオブジェクト「InputController」にアタッチしてください。
次にInputControllerにLineRendererコンポーネントを追加します。
ここまで設定したらインスペクターで詳細を設定していきます。
以下の順序(以下画像の番号と連動)で値を変更してください。
- DynamicBeamスクリプトにControllerをアタッチ
- レイのStartColorとEndColorを設定(この際アルファ値が0に設定されている場合レイが表示されないのでご注意ください)
- Widthを0.01に変更(任意の太さで問題ありません)
- MaterialをDefault-Lineに変更(任意のマテリアルで問題ありません)

ここまで一旦実行してみると以下のようになります。

レイがコントローラーからレンダリングされていることが確認できました。
オブジェクトを平面に置く
次にオブジェクトを平面に置くための「ObjectController」スクリプトを作成します。
作成したスクリプトを以下のように編集してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR.MagicLeap; public class ObjectController : MonoBehaviour { [SerializeField, TooltipAttribute("設置するオブジェクト")] private GameObject objectToPlace; // コントローラー操作を制御するためのオブジェクト private MLInputController controller; // Start is called before the first frame update void Start() { // コントローラーを使用するための準備 MLInput.Start(); MLInput.OnControllerButtonDown += OnButtonDown; controller = MLInput.GetController(MLInput.Hand.Left); } void OnButtonDown(byte controller_id,MLInputControllerButton button) { // バンパーが押されたとき if (button == MLInputControllerButton.Bumper) { // レイが平面にぶつかったとき、設定されたオブジェクトを配置する RaycastHit hit; if(Physics.Raycast(controller.Position,transform.forward,out hit)) { GameObject placeObject = Instantiate(objectToPlace,hit.point,Quaternion.Euler(hit.normal)); } } } void OnDestroy() { // コントローラーの利用(input)を終了 MLInput.Stop(); MLInput.OnControllerButtonDown -= OnButtonDown; } } |
このスクリプトではコントローラーのインプットを制御しています。
これでバンパーを押してアタッチした任意のオブジェクトを平面に設置することができます。
「ObjectController」スクリプトを空のオブジェクト「InputController」にアタッチして、任意のプレハブを「ObjectController」スクリプトにアタッチしてください。
※本記事ではCeleblation FXを利用しています。
それでは実際に実行して確認してみましょう。

平面にオブジェクトを作成することができました。
追記:バージョン違いによるエラーの対応方法
Lumin OS 0.24.2と0.25.0では上記のスクリプトで以下のエラーが表示されます。(2021年6月現在)
CS0246: The type or namespace name ‘MLInputController’ could not be found (are you missing a using directive or an assembly reference?)
‘MLInputController’ を’Please use MLInput.Controller’と変更する必要があり、ObjectControllerのスクリプトを以下のように書き換えれば正常に動きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR.MagicLeap; public class ObjectController : MonoBehaviour { [SerializeField, TooltipAttribute("設置するオブジェクト")] private GameObject objectToPlace; // コントローラー操作を制御するためのオブジェクト private MLInput.Controller controller; // 変更① // Start is called before the first frame update void Start() { // コントローラーを使用するための準備 MLInput.Start(); MLInput.OnControllerButtonDown += OnButtonDown; controller = MLInput.GetController(MLInput.Hand.Left); } void OnButtonDown(byte controller_id,MLInput.Controller.Button button) // 変更② { // バンパーが押されたとき if (button == MLInput.Controller.Button.Bumper) // 変更③ { // レイが平面にぶつかったとき、設定されたオブジェクトを配置する RaycastHit hit; if(Physics.Raycast(controller.Position,transform.forward,out hit)) { GameObject placeObject = Instantiate(objectToPlace,hit.point,Quaternion.Euler(hit.normal)); } } } void OnDestroy() { // コントローラーの利用(input)を終了 MLInput.Stop(); MLInput.OnControllerButtonDown -= OnButtonDown; } } |
まとめ
いかがでしたでしょうか。
MagicLeapでは空間認識技術を利用することで平面にオブジェクトを設置することができます。
もっとコントローラーを使いこなせば、オブジェクトを移動させたり、拡大縮小したりすることもできます。
XR-HUBでは引き続きMagicLeapの使い方をご紹介していきますのでぜひご参考ください。
本記事が少しでもMagicLeapやMR開発の共創につながれば幸いです。
以下記事もぜひご参考ください。
参考記事)【MagicLeap入門】Unityのセットアップ手順を1から解説!
参考記事)【MagicLeap 入門】ハンドトラッキングの使い方を学ぶ!

この記事はいかがでしたか?
もし「参考になった」「面白かった」という場合は、応援シェアお願いします!