MRが楽しい

MRやVRについて学習したことを書き残す

HoloLensのRestAPIをPythonで実行する その3(ファイルのアップロード)

本日は HoloLens の調査枠です。
前回記事の続きです。
bluebirdofoz.hatenablog.com

今回はPOSTメッセージを使って HoloLens の特定のディレクトリにファイルをアップロードしてみます。

なお、HoloLens で利用可能な API は以下の公式ページにまとめられています。
・デバイス ポータル コア API リファレンス(すべての Windows 10 デバイスに共通する API)
docs.microsoft.com
・デバイス ポータル Mixed Reality API リファレンス(HoloLens で利用できるすべての REST API の拡張リスト)
docs.microsoft.com

pythonサンプルコード

HoloLens の特定のディレクトリにファイルをアップロードする python スクリプトを作成します。
ファイルアクセスの API は以下の /api/filesystem/apps/file です。
f:id:bluebirdofoz:20190130093817j:plain

ファイルをアップロードする場合、POSTメッセージを利用する必要があります。
また、ブラウザを介さないWifi接続の場合はSSLを無効にしないとPOSTが失敗するようです。
DevicePortalから Preferences -> SSLconnection -> required のチェックを外しておきます。
f:id:bluebirdofoz:20190130094144j:plain

ローカルフォルダにある upload.jpg を、HoloLens の Picuture フォルダにアップロードする python スクリプトを作成してみました。
・UpLoadJPG.py

import requests
import base64
import os

# 実行指定で呼び出されているかチェック
if __name__ == "__main__":

     print('--------------------------- START ---------------------------')
     # DevicePortal接続のための設定項目
     # username:ユーザ名
     # password:パスワード
     # Wifi接続ではSSLを無効にする必要がある(よってhttp接続)
     # DevicePortalのPreferences->SSLconnectionのrequiredのチェックを外す
     username = 'USERNAME'
     password = 'PASSWORD'
     ipaddress = '192.168.XX.XXX'

     # RestAPIアクセスのURLを作成
     api = '/api/filesystem/apps/file'
     url = 'http://' + ipaddress + api

     # パラメータを指定(Pictureフォルダ直下に保存)
     payload = {'knownfolderid': 'Pictures', 'packagefullname': '\\', 'path': '\\'}

     # アップロードファイルの指定
     uploadDir = 'C:\\Users\\PCNAME\\Desktop\\hololens\\20190119\\HoloLensAPITest\\HoloLensAPITest\\TestProgram\\Upload'
     fileName = 'upload.jpg'
     uploadFilePath = os.path.join(uploadDir, fileName)

     # RestAPIのURLと設定を指定してGET/POST実行
     header = {'Content-Type': 'multipart/form-data'}
     fileBinary = open(uploadFilePath, 'rb')
     file = {'file': (fileName, fileBinary, 'image/jpeg')}
     response = requests.post(url, params = payload, files = file, auth=(username, password))

     # RestAPIの応答メッセージを受信(正常の場合 code=200 が返却)
     print(response.text)
     print(response.status_code)

     print('--------------------------- END ---------------------------')

実行してみた結果が以下になります。
f:id:bluebirdofoz:20190130093958j:plain

指定したアップロード先フォルダを確認すると、画像ファイルがアップロードできています。
f:id:bluebirdofoz:20190130094014j:plain

HoloLens特化のホロ恋子モデルを作成する その29(自動ウェイトによるスキニング)

本日はホロ恋子モデル2の作成枠です。
メッシュをリグに関連付ける「スキニング」の作業を行います。
f:id:bluebirdofoz:20190129075940j:plain

アーマチュアの関連付け

まずはメッシュオブジェクトをアーマチュアオブジェクトに関連付けます。
最初に、関連付ける全てのメッシュオブジェクト → アーマチュアオブジェクト の順にオブジェクトを選択します。
f:id:bluebirdofoz:20190129075953j:plain

Ctrl+Pキーで「ペアレント対象」のウィンドウを表示します。
メニューから[アーマチュア変形]の[自動ウェイトで]を選択します。
f:id:bluebirdofoz:20190129080005j:plain

すると、メッシュオブジェクトがアーマチュアオブジェクトの子オブジェクトにペアレント(親子関係)されます。
更にメッシュオブジェクトには自動的にアーマチュアモディファイアが設定されます。
f:id:bluebirdofoz:20190129080021j:plain

自動ウェイトの確認

[自動ウェイトで]を選択してアーマチュアの関連付けを行った場合、自動的にボーンとメッシュとのウェイト設定が行われます。
ウェイトはボーンの動きに対してメッシュがどれだけ追従するかを表します。

試しに頭部ボーンに対するウェイト設定を確認してみます。
メッシュオブジェクトを選択して[ウェイトペイントモード]に切り替えます。
頭部ボーンを選択すると、対象のボーンにウェイト付けられたメッシュが赤く表示されます。
青い箇所はウェイト付けがされていない、またはウェイトの重みが低い箇所です。赤いほど重みが大きいことを表します。
f:id:bluebirdofoz:20190129080050j:plain

自動ウェイトではボーンに近しい場所のメッシュが自動的にウェイト付けされます。
これで頭部のメッシュが頭部ボーンにウェイト付けされていることが分かりました。
試しに、ボーンを動かしてどういった動きになるか確認してみます。

アーマチュアオブジェクトを選択して[ポーズモード]に切り替えます。
頭部ボーンを選択して、ボーンを回転させてみます。
f:id:bluebirdofoz:20190129080108j:plain

このようにボーンに追従してメッシュが変形すれば正しく関連付けが行われています。
もしメッシュが追従しない場合は[ポーズモード]でボーンを動かしているか確認しましょう。
[編集モード]でのボーン編集にはメッシュは追従しません。

現時点ではあくまで自動でのウェイト付けなのでボーンの繋ぎ目など綺麗に変形しない箇所もあります。
f:id:bluebirdofoz:20190129080137j:plain

[ウェイトペイントモード]で確認すると、ウェイト付けにムラがあることが分かります。
こういった箇所は手動で修正していく必要があります。
f:id:bluebirdofoz:20190129080158j:plain

ボーン位置のリセット

因みに変形したボーンを基本位置に戻したい場合は以下の手順で元に戻せます。
1.[ポーズモード]で元の位置/回転/スケールに戻したいボーンを選択する
2.メニューから ポーズ -> トランスフォームをクリア -> すべて を選択する
f:id:bluebirdofoz:20190129080213j:plain

これでボーンの位置がリセットされます。
ボーンのリセット位置は、[編集モード]で編集したボーンの位置が基本位置になります。
因みに、より手早くリセットしたい場合は以下のショートカットキーが利用可能です。
・位置のリセット(Alt+Gキー)
・回転のリセット(Alt+Rキー)
・拡縮のリセット(Alt+Sキー)

次はウェイトの手動調整です。
bluebirdofoz.hatenablog.com

VRoidHubにVRMファイルをアップロードする

本日は VRoid Hub の調査枠です。
VRoidHubにVRMファイルをアップロードする手順をまとめます。

VRoid Hubはピクシブ株式会社が提供する3Dキャラクターの投稿用プラットフォームです。
hub.vroid.com
f:id:bluebirdofoz:20190128091050j:plain

その名の通り VRoid と連携しており、VRoidから直接モデルをアップロードすることが可能です。
f:id:bluebirdofoz:20190128091117j:plain

VRoid 以外の自作モデルもVRMファイルであればアップロードが可能です。
今回は修正を行ったホロ恋子モデルをアップロードしてみます。

アカウントの作成

アップロードにはログインが必要です。
トップページの[キャラクターを登録]または[PixivIDでログイン]でログインを行います。
f:id:bluebirdofoz:20190128091131j:plain

PixivIDを持っていなくても、以下のいずれかのアカウントを持っていればログイン可能です。
Google
FaceBook
Twitter
f:id:bluebirdofoz:20190128091149j:plain

VRMファイルのアップロード

ログインが完了すると[キャラクターを登録]ダイアログが表示されます。
キャラクターの名称を入力し、アップロードするVRMファイルをドラッグします。
利用規約およびガイドラインを確認し、[アップロード]ボタンをクリックします。
f:id:bluebirdofoz:20190128091203j:plain

モデルのアップロードが行われ、キャラクタプロフィールの設定画面に移行します。
「プロフィール」にキャラクタの説明文を入力します。
参照してほしいWebサイトがあれば「Webサイト」にURLを追加します。
f:id:bluebirdofoz:20190128091222j:plain

更にページ下部で追加設定を行います。
「タグ」はキャラクタに関連するタグを設定します。
「モーション」は紹介ページでのキャラクタのアクションを9種類の中から選べます。
「利用条件」はデフォルト設定はVRMから自動的に読み込まれます。
「利用条件の変更」で設定を変更することも可能です。
f:id:bluebirdofoz:20190128091237j:plain

「モデルの画像」は検索画面で表示されるキャラクタの画像です。
画像をアップロードすることもページ内でキャラクタを撮影することもできます。
f:id:bluebirdofoz:20190128091251j:plain

全て設定が完了したら[登録して公開]をクリックします。
これでモデルが公開できました。
f:id:bluebirdofoz:20190128091304j:plain

作成した公開ページが以下になります。
[このモデルを利用する]をクリックすると、VRMファイルをダウンロードできます。
hub.vroid.com

MRTKを用いてHoloLensのフォーカスイベントを検出する

本日は MRTK の技術調査枠です。
MRTKを用いてフォーカスイベントを設定する方法をまとめます。

プロジェクトとシーンの準備

以下の記事を元にHoloLens(WindowsMR)プロジェクトを作成します。
bluebirdofoz.hatenablog.com

2019/1/27現在、MRTK 2017 の最新バージョンは 2017.4.3.0 です。
f:id:bluebirdofoz:20190127155335j:plain

フォーカスイベント

フォーカスイベントはユーザが特定のオブジェクトにカーソルを合わせた事を検出するイベントです。
HoloLens では視点がカーソルになるので、特定のオブジェクトを注視したことを検出できます。

MRTK の基本設定を行っていれば IFocusable インタフェースの以下の関数を利用してイベントを取得できます。
・IFocusable.cs

using UnityEngine.EventSystems;

namespace HoloToolkit.Unity.InputModule
{
    /// <summary>
    /// Interface to implement to react to focus enter/exit.
    /// </summary>
    public interface IFocusable : IEventSystemHandler
    {
        void OnFocusEnter(); // フォーカス開始時イベント
        void OnFocusExit();  // フォーカス終了時イベント
    }
}

実際にスクリプトを作成してみます。
フォーカス時にオブジェクトサイズが大きくなるスクリプトを作成しました。
・FocusEvent.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// IFocusable を利用するため InputModule を追加
using HoloToolkit.Unity.InputModule;

public class FocusEvent : MonoBehaviour,
    IFocusable // IFocusable インタフェースを継承
{
    private Vector3 DefaultScale = new Vector3();

    /// <summary>
    /// 起動時処理
    /// </summary>
    void Start()
    {
        // 初期サイズを保存
        DefaultScale = new Vector3(
            transform.localScale.x,
            transform.localScale.y,
            transform.localScale.z);
    }

    /// <summary>
    /// フォーカス開始時イベント
    /// </summary>
    public void OnFocusEnter()
    {
        // フォーカス時、2倍の大きさに変更
        transform.localScale = DefaultScale * 2.0f;
    }

    /// <summary>
    /// フォーカス終了時イベント
    /// </summary>
    public void OnFocusExit()
    {
        // フォーカスが外れると、元の大きさに戻る
        transform.localScale = DefaultScale;
    }
}

作成したスクリプトSphere オブジェクトにアタッチします。
f:id:bluebirdofoz:20190127155409j:plain

[再生]ボタンを押してシーンを開始します。
視点を Sphere に合わせたときのみ、オブジェクトが大きくなります。
f:id:bluebirdofoz:20190127155419j:plain

インタラクテタブルオブジェクト

今回はスクリプトを用いて直接フォーカス時のアクションを実装しました。
MRTK にはオブジェクトに様々なアクションを設定できるインタラクテタブルオブジェクトという機能があります。
オブジェクトをフォーカス時に色変化させたり、タップ時にアニメーションさせることがノンコーディングで可能です。

HoloLens特化のホロ恋子モデルを作成する その28(ボーンの追加)

本日はホロ恋子モデル2の作成枠です。
今回作成中のホロ恋子は軽量化を目指したモデルのため、Humanoidリグからの追加ボーンは作成しません。
しかし多くの場合は、髪やスカートといった揺れ物を独立して動かすための追加ボーンを設定します。
ボーンの追加手順についても簡単にまとめておきます。
f:id:bluebirdofoz:20190126111118j:plain

ボーンの追加

ボーンの追加には[編集モード]で押し出し(Eキー)を利用します。

このとき、押し出し元となったボーンが生成されたボーンと親子関係となります。
例えば、ポニーテールのボーンを作成する場合、頭部ボーンの動きに追従させたいところです。
この場合、頭部ボーンの終端を選択し、押し出し(Eキー)を行います。
f:id:bluebirdofoz:20190126111147j:plain

押し出したボーンはそのままだと親ボーンのテールに接続された状態です。
ポニーテールの起点から揺らしたいため、ボーンの接続を切り離して任意の位置にボーンを移動します。
ボーンを選択した状態で、[ボーン]タブを開きます。
[関係]パネルにある[接続]のチェックボックスを外せば、接続が切れます。
f:id:bluebirdofoz:20190126111201j:plain

後はボーンを移動(Gキー)と回転(Rキー)をさせ、任意の位置に配置します。
f:id:bluebirdofoz:20190126111215j:plain

揺れ物にボーンを設定する場合はトポロジーに合わせてボーンを追加すると、後々の頂点のウェイト設定が楽になります。
f:id:bluebirdofoz:20190126111227j:plain

左右対称なボーン

因みに左右対称にボーンを追加する場合は、SHIFT+Eキーで押し出しを行うと、左右対称なボーンが生成されます。
f:id:bluebirdofoz:20190126111238j:plain

SHIFT+Eキーで押し出したボーンは左右対称なボーンであることを示す (ボーン名)_L, (ボーン名)_R という名前が設定されます。
f:id:bluebirdofoz:20190126111250j:plain

次はボーンとメッシュを関連付ける「スキニング」作業に着手します。
bluebirdofoz.hatenablog.com

HoloLensのRestAPIをPythonで実行する その2(ファイルのダウンロード)

本日は HoloLens の調査枠です。
前回記事の続きです。
bluebirdofoz.hatenablog.com

今回はパラメータを用いて、HoloLensの特定のディレクトリのファイルをダウンロードしてみます。

なお、HoloLens で利用可能な API は以下の公式ページにまとめられています。
・デバイス ポータル コア API リファレンス(すべての Windows 10 デバイスに共通する API)
docs.microsoft.com
・デバイス ポータル Mixed Reality API リファレンス(HoloLens で利用できるすべての REST API の拡張リスト)
docs.microsoft.com

pythonサンプルコード

HoloLens の特定ディレクトリのファイルを取得する python スクリプトを作成します。
ファイルアクセスの API は以下の /api/filesystem/apps/file です。
f:id:bluebirdofoz:20190125001625j:plain

/api/filesystem/apps/file は knownfolderid や filename をパラメータとして指定する必要があります
Picuture フォルダから TestImage.jpg を取得する python スクリプトを作成してみました。
・GetPicture.py

# import
import requests
import base64
import os
from datetime import datetime

# 実行指定で呼び出されているかチェック
if __name__ == "__main__":

    print('--------------------------- START ---------------------------')
    # DevicePortal接続のための設定項目
    # username:DevicePortalアクセスのユーザ名
    # password:DevicePortalアクセスのパスワード
    # ipaddress:DevicePortalアクセスのIPアドレス
    # isVerify:証明書の利用(自己証明書なので無視する)
    username = 'USERNAME'
    password = 'PASSWORD'
    ipaddress = '192.168.XX.XXX'
    isVerify = False

    # RestAPIアクセスのURLを作成
    api = '/api/filesystem/apps/file'
    url = 'http://' + ipaddress + api

    # パラメータを指定
    payload = {'knownfolderid': 'Pictures', 'filename': 'TestImage.jpg', 'packagefullname': '\\', 'path': '\\Camera Roll', 'op': 'stream'}

    # RestAPIのURLと設定を指定してGET/POST実行
    response = requests.get(url, params = payload, auth=(username, password), verify = isVerify, stream = True)

    # RestAPIの応答メッセージを受信
    response.status_code
    image = response.content

    # 受信したメッセージタイプを標準出力で確認
    print('--------------------------- RESPONSE JSON ---------------------------')
    print(response.headers['content-type'])
    print(response.status_code)

    # ダウンロードディレクトリの指定
    downloadDir = 'C:\\Users\\PCNAME\\Desktop\\hololens\\20190119\\HoloLensAPITest\\HoloLensAPITest\\TestProgram\\Download'
    fileName = 'download.jpg'

    # バイナリデータをファイルに書き込み
    saveFileName = datetime.now().strftime("%Y%m%d_%H%M%S_") + fileName
    saveFilePath = os.path.join(downloadDir, saveFileName)
    with open(saveFilePath, 'wb') as saveFile:
        saveFile.write(image)

    print('--------------------------- END ---------------------------')

実行してみた結果が以下になります。
f:id:bluebirdofoz:20190125001702j:plain

指定したダウンロード先フォルダを確認すると、画像ファイルがダウンロードできています。
f:id:bluebirdofoz:20190125001712j:plain

パラメータの調査方法

例えば、対象ディレクトリの knownfolderid のタグを調べたい場合です。

DevicePortal が実際にこのRestAPIを用いた通信を行っています。
GoogleChrome の場合、F12 でデベロッパーツールを開くことで、通信しているメッセージ内容を確認できます。
メッセージを確認するには[Network]タブを開きます。
f:id:bluebirdofoz:20190125001722j:plain

例えば、この状態で Picture ディレクトリにあるファイルに対して[Delete]ボタンを押してみます。
すると新しいメッセージがリストに追加され、これをクリックするとその詳細が確認できます。

内容を確認すると、/api/filesystem/apps/file の RestAPI に対して DELETE メッセージを送信しています。
更に URL を読みとくと knownfolderid に Pictures を設定していることが分かります。
f:id:bluebirdofoz:20190125001741j:plain

次はPOSTメッセージを利用し、ファイルをアップロードしてみます。
bluebirdofoz.hatenablog.com

HoloLens特化のホロ恋子モデルを作成する その27(ボーンの位置合わせ)

本日はホロ恋子モデル2の作成枠です。
前回作成したボーンの位置合わせを行っていきます。
f:id:bluebirdofoz:20190124093822j:plain

Tスタンスの作成

ボーンのポーズをTスタンスに変更します。
アーマチュアオブジェクトはメッシュオブジェクト同様、[編集モード]で移動(Gキー),回転(Rキー),拡縮(Sキー)などの編集が可能です。
最初に全てのボーンを選択し、拡縮(Sキー)で大体の大きさを合わせます。
f:id:bluebirdofoz:20190124093834j:plain

後はメッシュと同じように下絵の骨格に合わせてボーンの位置を調整していきます。
f:id:bluebirdofoz:20190124093847j:plain

改めて以下のTスタンスのルールを確認してポーズを作ります。

- Z軸方向に向かって、まっすぐに立っていること
- 頭および目がZ軸方向に向いていること
- Z軸に対して平行に、両足が接地していること
- X軸に沿って地面に対し平行に、両腕が開いていること
- X軸に沿って地面に対して平行に、両手は平らにし、かつ手のひらは下向きであること
- X軸に沿って地面に対して平行に、各指(親指を除く)はまっすぐに伸ばしていること
- 親指は、X軸とZ軸に対して半分ぐらいの角度(45度)で、かつ地面に対して平行にまっすぐに伸ばしていること

ボーン位置の微調整とレントゲン機能

凡その位置合わせを行ったら、実際のメッシュに合わせてより詳細な位置合わせを行っていきます。
メッシュのレイヤーとアーマチュアのレイヤの両方を表示状態にします。
f:id:bluebirdofoz:20190124093900j:plain

この状態だと、アーマチュアのボーンがメッシュにめり込んでしまい、位置がよく見えません。
そこで「レントゲン」の機能を利用します。
これは指定のオブジェクトが他のオブジェクト重なっていても必ず見える機能です。

アーマチュアオブジェクトを選択した状態で、[データ]タブを開きます。
[表示]パネルにある[レントゲン]のチェックを入れると、アーマチュアが表示されるようになります。
合わせて、ボーンが[八面体]の形だと細かい位置合わせが難しいので、[スティック]の形に変更しておきます。
f:id:bluebirdofoz:20190124093913j:plain

指などトポロジーと細かく位置合わせしたい部分は、合わせてメッシュの表示をワイヤーフレームにすると調整しやすいです。
f:id:bluebirdofoz:20190124093924j:plain

ボーン配置の注意点

肘や膝などはボーンを真っ直ぐ接続せず、予め関節が曲がってほしい方向に僅かに角度を付けておきます。
これにより、手や足の位置が動いた際、関節部分が逆方向に折れるといった事を回避できます。
f:id:bluebirdofoz:20190124093935j:plain

肩の内側にあるボーンは肩関節より上に配置します。
これにより、肩らから腕ボーンが落ちて、なで肩になるのを回避できます。
また肩ボーンのテールは腕ボーンのヘッドと位置を合わせます。
f:id:bluebirdofoz:20190126111323j:plain

位置的に鎖骨をイメージしてしまいますが、肩全体の可動を示すボーンなので鎖骨とは位置が異なります。
Humanoidリグで示される位置をイメージします。
f:id:bluebirdofoz:20190124094002j:plain

尻ボーンのヘッダのY座標と、太腿ボーンのY座標を合わせておきます。
フルボディトラッキングやIKを用いる際にはこうしておかないと破綻しやすくなるようです。
f:id:bluebirdofoz:20190124094013j:plain

その他のボーンもHumanoidリグで示される位置に合わせて、ボーン位置の調整を完了しました。f:id:bluebirdofoz:20190126111338j:plain

次はボーンの追加方法です。
bluebirdofoz.hatenablog.com