夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

SpatialMeshでeffectを作ってみた。 HoloLensMeetup Val.20 登壇記事

先日オンライン上で行われたHoloLens Meetup Val.20でSpatialMeshに関する表現の知見をシェアしました。

〇HoloLensMeetup Val.20

LTでの筆者の登壇以外のイベント内容は先日の記事にしています。 参考にしてください。

redhologerbera.hatenablog.com

〇SpatialMesh×PulseShaderでエフェクトを作ってみた。

〇スライド

〇SpatialMesh とは?

 HoloLensではSpatialAwareness(空間認識)と呼ばれる機能によって常に周囲の物理空間情報を取得することで周囲の環境に合わせた仮想情報と現実情報とのMixedRealityな空間を作りだしています。

 この際に壁や床など周囲の物理情報に沿って生成されるメッシュのことをSpatialMesh(空間メッシュ)と呼んでいます。

 SpatialMeshは多くの場合物理判定や空間内の位置推定に使用されます。

 前者はコップ等のオブジェクトにコライダーと重力を与えた場合、現実の床やテーブルに沿って『置く』ことができます。

 後者は経路案内や複数人でのシェアリングなどで特徴点から自己位置を推定して正確に位置をとらえることができます。

〇SpatialMeshのマテリアル

 SpatialMeshは通常のオブジェクトと同じようにマテリアルが設定されており、見え方を変えることができます。

 MRTKでは主に次の三種が用意されています。

・Occlusion

不可視のマテリアルです。 深度情報は持っているためオブジェクトの裏側のオブジェクトはクリップされます。

www.youtube.com

 現実に一番近い表現となります。

・wireFrame

f:id:Holomoto-Sumire:20200719221943j:plain

 メッシュの輪郭のみが表示されるマテリアルです。

・Pulse

f:id:Holomoto-Sumire:20200719222020g:plain

 MRTK2.3以降のバージョンで導入されたMaterialで常にMeshが表示されているわけでも、常に非表示なわけでもなく周期的にメッシュが見えるパルスが流れます。

 PulseはSR_TrianglesShaderと呼ばれるShaderで実現していますが、これは非常に多くのpropertyで細かく表現を行うことができます。

 今回はこのSR_TrianglesShaderを用いて新しい表現に挑戦しました。

〇エフェクト

 今回作成したものは次のようなものです。

www.youtube.com

 ライトセーバー自体は今年の明けにHoloLens 2向け作成していたものですが、今回はダメージエフェクトをSR_TrianglesShaderを用いて行いました。

〇作り方

 SR_TrianglesShaderはパルスの大きさや色だけではなくどこを波源にするかというPulseOriginと呼ばれるプロパティがあります。

f:id:Holomoto-Sumire:20200719222119j:plain

 これはスクリプトで動的に変更し反映させることが可能です。

以下のようなスクリプトライトセーバーのブレードにアタッチしました

public class DamageEfect : MonoBehaviour
{
  //ブレードが発振しているときのみパルスを発生
   bool isOn = true; 
  //SR_TrianglesShaderのマテリアル。
    public Material _targetMaterial;

    void Start()
    {
   //パルスを初期化
        _targetMaterial.SetFloat("_Pulse_", 0f);
    }
 void Update()
    {
        Vector3 _originPoint;
        _originPoint = this.gameObject.transform.position;
        _targetMaterial.SetFloat("Pulse_", 0.3f);
        _targetMaterial.SetVector("_Pulse_Origin_", _originPoint);
        Debug.Log(_targetMaterial.GetVector("_Pulse_Origin_"));
    }


   //ライトセーバーの起動ボタンでこのメソッドを実行、発振している場合StartDamage()を処理
 public void damageEfect()
    {
        if (isOn)
        {
            startDamage();
        }
        else
        {
            stopDamage();
        }
    }

 //パルスを実行
    public void startDamage()
    {
        _targetMaterial.SetFloat("_Pulse_", 0.3f);
        isOn = false;
    }
    public void stopDamage()
    {
        _targetMaterial.SetFloat("_Pulse_",0f);
        isOn = true;
    }
}

ブレードがアクティブ(発振している)状態で自身の位置をPulse_Originに代入しています。

これによってブレードを波源にパルスが発進します。

このパルスの周期を非常に短く、そしてパルスの値を小さくすることでeffectが完成しました。

〇何に使えるか?

MRTKで標準で用意されているShaderで任意の場所のみSpatialMeshを表示させるという利点があり非常に面白い(自画自賛ですが)表現ですが、一点大きな問題があります。

 SR_TrianglesShaderでは一つのマテリアルで一つのパルスしかさせることができません。つまりこの表現ではライトセーバーが二本になった場合など複数のエフェクトを行うことができません。

 では何に使えるかですが、オブジェクトやユーザーの立ち位置等でこれを起こすことでユーザーの誘導が行うことができます。

 通常のエフェクトと異なりSpatialAwarenessで認識した空間そのものを使用するので、オブジェクトやエフェクトが障害物などの裏側にあり、オブジェクトやエフェクトが通常カリングされ見えないときでもかべ伝いにメッシュをたどり使用でき、使い方次第で今までよりわかりやすい誘導が行えます。

 今回の表現は技術的にはMRTKで提供されていることの気づきと応用ですがなかなかいいアプローチができたと思います。 SR_TrianglesShaderを参考に複数のパルスを表示できるShaderなど自作していみたいです。