Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
5
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

Organization

HoloLensでFilepickerから選択したVRMファイルを読み込む

はじめに

HoloLensでVRMファイルを読み込んで表示してみました。
VRMファイルはFilePickerを使ってフォルダから選択できるようにしました。

サンプルプロジェクトこちら ⇒ VRMRuntimeLoaderSampleForHoloLens

いくつかハマりどころがありましたが、ポイントは以下の2点です。

  • Player SettingsのScripting BackendをIL2CPPに設定する。
  • IL2CPPビルドでファイルを読み込む時はWWWクラスを使う。 (WWWクラスを使わないとDirectoryNotFoundExceptionが発生する)

VRMHoloLens01.jpg
VRMHoloLens02.jpg

開発・検証環境

  • UniVRM v0.43
  • Unity 2017.4.9f1
  • Visual Studio 2017
  • HoloLens RS5 Preview (OS Build: 17720.1000)

事前準備・設定

UniVRMのインポート

UniVRM v0.43のunitypackageをダウンロードしてインポートする。
UniVRM.png

IL2CPPビルドの設定

Player Settings/Other SettingsのScripting BackendをIL2CPPに設定する。
IL2CPP.png

Capabilitiesの設定

VRMファイルが置いてあるフォルダにアクセスできるようにCapabilitiesを設定する。
今回はObjects3Dフォルダを使うため、Player Settings/Publishing Settings/CapabilitiesのObjects3Dにチェックを入れておく。
Capabilities.png

VRMファイルを選択してランタイムロードする

サンプルスクリプト

以下のようなスクリプトを空のゲームオブジェクトにアタッチします。

VRMRuntimeLoaderUsingFilePicker.cs
using System.Collections;
using UnityEngine;
using System.IO;

#if !UNITY_EDITOR && UNITY_WSA_10_0
using System;
using System.Threading.Tasks;
using Windows.Storage.Pickers;
#endif

public class VRMRuntimeLoaderUsingFilePicker : MonoBehaviour
{
    public GameObject VRMRoot;

    void Start ()
    {
#if !UNITY_EDITOR && UNITY_WSA_10_0

        UnityEngine.WSA.Application.InvokeOnUIThread(async () =>
        {
            var openPicker = new FileOpenPicker();
            openPicker.SuggestedStartLocation = PickerLocationId.Objects3D;
            openPicker.FileTypeFilter.Add(".vrm");

            var file = await openPicker.PickSingleFileAsync();
            UnityEngine.WSA.Application.InvokeOnAppThread(() => 
            {
                if(file != null)
                {
                    StartCoroutine(LoadVrmCoroutine(file.Path));
                }
            }, false);
        }, false);

#elif UNITY_EDITOR

        string path = Application.dataPath + "/Models/" + "default.vrm";
        StartCoroutine(LoadVrmCoroutine(path));

#endif
    }

    IEnumerator LoadVrmCoroutine(string path)
    {
        var www = new WWW("file://" + path);
        yield return www;
        VRM.VRMImporter.LoadVrmAsync(www.bytes, OnLoaded);
    }

    void OnLoaded(GameObject vrm)
    {
        if(VRMRoot != null)
        {
            vrm.transform.SetParent(VRMRoot.transform, false);
        }
    }
}

ファイル選択

FileOpenPickerを使うことで、ファイルエクスプローラーを表示してファイルを選択することができます。
FileOpenPickerは、UnityのMainThreadでは利用できないため、UIThreadで動作させます。
選択されたファイルのパスをファイル読み込み用のメソッドに渡します。

"#if"の書き方はいくつかありますが、WINDOWS_UWPと書いてもIL2CPPで動くようです。
(参考:HoloLensのUnity内でFilepicker使ってみた


#if !UNITY_EDITOR && UNITY_WSA_10_0

        UnityEngine.WSA.Application.InvokeOnUIThread(async () =>
        {
            var openPicker = new FileOpenPicker();
            openPicker.SuggestedStartLocation = PickerLocationId.Objects3D;
            openPicker.FileTypeFilter.Add(".vrm");

            var file = await openPicker.PickSingleFileAsync();
            UnityEngine.WSA.Application.InvokeOnAppThread(() => 
            {
                if(file != null)
                {
                    StartCoroutine(LoadVrmCoroutine(file.Path));
                }
            }, false);
        }, false);

#elif UNITY_EDITOR

        string path = Application.dataPath + "/Models/" + "default.vrm";
        StartCoroutine(LoadVrmCoroutine(path));

#endif

VRMファイルの読み込み

WWWクラスでファイルを読み込み、byte配列をVRM.VRMImporter.LoadVrmAsyncに渡します。
IL2CPPビルドの場合、WWWクラスを使わないとDirectoryNotFoundExceptionが発生してファイルが読み込めませんでした。

また、VRMオブジェクトの位置や向きを調整できるように、OnLoadedメソッドでSetParentしています。
SetParentの第2引数(worldPositionStays)をfalseにしておくと調整可能です。(trueだとワールド座標系の位置・回転・スケールがキープされる)


    IEnumerator LoadVrmCoroutine(string path)
    {
        var www = new WWW("file://" + path);
        yield return www;
        VRM.VRMImporter.LoadVrmAsync(www.bytes, OnLoaded);
    }

    void OnLoaded(GameObject vrm)
    {
        if(VRMRoot != null)
        {
            vrm.transform.SetParent(VRMRoot.transform, false);
        }
    }

参考情報

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
5
Help us understand the problem. What are the problem?