本日は MRTK の調査枠です。
MRTK 2.5を使ってHoloLens2上でObject3Dフォルダのglbファイルを読み込む手順を記事にします。
今回は読み込んだ3Dモデルにアタリ判定と掴み操作の機能を追加します。
想定する動作
読み込まれた3Dモデルにコライダーと、MRTKのオブジェクトマニピュレータを追加して、掴んで移動できるようにします。
今回、追加するコライダーには Mesh Collider ではなく Box Collider を利用します。
docs.unity3d.com
docs.unity3d.com
Mesh Collider は物体の形状に忠実なアタリ判定を設定しますが、ポリゴン数の多いモデルでは負荷が高くなるためです。
形状のバウンドボックスを取得し、バウンドボックスと同じ大きさの Box Collider を割り当てます。
実装例
前回作成したサンプルシーンをそのまま利用します。
GLBLoadTest.cs のスクリプトを以下の通り、修正しました。
階層構造の3Dモデルが読み込まれた場合に対処するため、再帰的に処理を行う関数を追加しています。
・GLBLoadTest.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using Microsoft.MixedReality.Toolkit.Utilities.Gltf.Schema;
using Microsoft.MixedReality.Toolkit.Utilities.Gltf.Serialization;
using Microsoft.MixedReality.Toolkit.UI;
using Microsoft.MixedReality.Toolkit.Input;
#if WINDOWS_UWP
using Windows.Storage;
#endif
public class GLBLoadTest : MonoBehaviour
{
<summary>
</summary>
[SerializeField, Tooltip("読み込みモデルファイル名")]
private string p_LoadFileName;
<summary>
</summary>
void Start()
{
if (p_LoadFileName != null)
{
string glbFilePath = Get3DObjectFilePath(p_LoadFileName);
AsyncLoadGLBByte(glbFilePath);
}
}
<summary>
</summary>
void Update()
{
}
<summary>
</summary>
<param name="filepath"></param>
private async void AsyncLoadGLBByte(string filepath)
{
byte[] modelByteData = GetFileAsByteArray(filepath);
GltfObject gltfObject = GltfUtility.GetGltfObjectFromGlb(modelByteData);
try
{
await gltfObject.ConstructAsync();
}
catch (Exception e)
{
Debug.LogError($"GlbLoad failed - {e.Message}\n{e.StackTrace}");
return;
}
if (gltfObject != null)
{
GameObject loadedGlbObject = null;
loadedGlbObject = gltfObject.GameObjectReference;
if (loadedGlbObject != null)
{
loadedGlbObject.transform.parent = this.transform;
loadedGlbObject.transform.localPosition = Vector3.zero;
loadedGlbObject.transform.localEulerAngles = Vector3.zero;
loadedGlbObject.transform.localScale = Vector3.one;
RecursionSettingModel(loadedGlbObject);
Debug.Log("Import successful");
}
}
}
<summary>
</summary>
<param name="a_Object"></param>
private void RecursionSettingModel(GameObject a_Object)
{
foreach (Transform child in a_Object.transform)
{
MeshFilter filter = child.gameObject.GetComponent<MeshFilter>();
if (filter != null)
{
BoxCollider collider = child.gameObject.AddComponent<BoxCollider>();
Bounds meshBounds = filter.mesh.bounds;
collider.center = meshBounds.center;
collider.size = meshBounds.size;
child.gameObject.AddComponent<ObjectManipulator>();
child.gameObject.AddComponent<NearInteractionGrabbable>();
}
RecursionSettingModel(child.gameObject);
}
}
<summary>
</summary>
static byte[] GetFileAsByteArray(string filePath)
{
FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
BinaryReader binaryReader = new BinaryReader(fileStream);
return binaryReader.ReadBytes((int)fileStream.Length);
}
<summary>
</summary>
<param name="filename"></param>
<returns></returns>
public string Get3DObjectFilePath(string filename)
{
#if WINDOWS_UWP
string directorypath = KnownFolders.Objects3D.Path;
#else
string directorypath = UnityEngine.Application.streamingAssetsPath;
#endif
return Path.Combine(directorypath, filename);
}
}
以下の部分がアタリ判定とマニピュレータ操作の追加と処理になります。
MeshFilter filter = child.gameObject.GetComponent<MeshFilter>();
if (filter != null)
{
BoxCollider collider = child.gameObject.AddComponent<BoxCollider>();
Bounds meshBounds = filter.mesh.bounds;
collider.center = meshBounds.center;
collider.size = meshBounds.size;
child.gameObject.AddComponent<ObjectManipulator>();
child.gameObject.AddComponent<NearInteractionGrabbable>();
}
シーンを再生して動作を確認します。
読み込まれた3Dモデルを掴んで操作することができれば成功です。