HoloLensでお絵かきする

# 経緯

AR_Fukuokaで行われたHoloLensアプリハンズオンの内容を、
まるで自分が手順を作った様に記事した。

AR_Fukuokaで講師をされた吉永様本家資料がSlideShareに公開されました。
[HoloLensハンズオン](https://www.slideshare.net/ssuserc0d7fb/hololens-76412075)
本記事よりも丁寧に説明されてあるので、
もっと細かな部分を知りたい方はぜひ[本家資料](https://www.slideshare.net/ssuserc0d7fb/hololens-76412075)を参照してください。

吉永様に感謝ですm(_ _)m

## 今回やる事

HoloLensでお絵かきアプリを作る。
ドラッグ中にお絵かきできる。
カッコいい。

## 環境

 + Windows 10
 + Unity 5.6.1
 + Visual Studio 2017

そのほかHoloLendsToolKitなどは適宜インストール。

# まずはメッシュが手に追従するものを作る

## 扱うメッシュを追加

Unityを起動して,好きな3D Objectを追加する。

Name : Cube

デフォルトだと大きすぎるので、
サイズをすべて0.05へ変更する。

分かりやすいようにマテリアルを追加して色を付ける。

## HoloLends固有設定

カメラ等をデフォルトの物からHoloLens様に入れ替える。

 + 追加
    + SpatialMapping
    + InputManager
 + 変更
    + Camera to HoloLendsCamera

HoloLendsCamera.ClippingNearを0.2へ変更。
(手元のCGを表示する為)

## スクリプトを追加

ヒエラルキーで右クリックしてcreate empty。
作成されたGameObjectを選択し、InspectorからAdd Component ->new script。


``` csharp
using HoloToolkit.Unity.InputModule;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class Receiver : MonoBehaviour , ISourceStateHandler, IInputHandler
{
    IInputSource currentInputSource;
    private uint id;
    private bool isDrag = false;
    public GameObject obj;

    public void OnInputDown(InputEventData eventData)
    {
        if( !eventData.InputSource.SupportsInputInfo(eventData.SourceId, SupportedInputInfo.Position))
        {
            return;
        }

        currentInputSource = eventData.InputSource;
        id = eventData.SourceId;

        isDrag = true;
        Debug.Log("finger down");
    }

    public void OnInputUp(InputEventData eventData)
    {
        isDrag = false;
        Debug.Log("finger up");
    }

    public void OnSourceDetected(SourceStateEventData eventData)
    {
        Debug.Log("Detected");
    }

    public void OnSourceLost(SourceStateEventData eventData)
    {
        isDrag = false;
        Debug.Log("Lost");
    }

    // Use this for initialization
    void Start () {
        InputManager.Instance.PushFallbackInputHandler(gameObject);
    }

    // Update is called once per frame
    void Update () {
        if (isDrag)
        {
            Vector3 pos;
            currentInputSource.TryGetPosition(id, out pos);

            Debug.Log(pos);
            obj.transform.position = pos;
        }
	}
}
```

Unityに戻り、GameObjectのInspectorへ下記設定を行う。

 + objにcubeをDrag&Drop


## ビルド用のVisualStudioプロジェクトを作成する

Edit menu -> Project Settings -> Player
Inspector.Product Nameを好きな名前へ。

Inspector.Icon.Short Name
Inspector.Other Settings.Virtual Reality Supported


File -> Build Settings
Add Open Scene
Choice Windows Store 
Click Switch Platform

check settings
 + SDK Universal 10
 + Target device  Hololends
 + UWP Build Type D3D

Buildボタンをクリックする。
Appディレクトリを作成し、フォルダを選択して出力する。


## Visual Studioで開き、HoloLendsで動作確認する。

ビルド設定を変更

 + Debug/Release : Release
 + CPU : x86
 + Target : device

HoloLendsを接続してペアリングを行う。

Tool Menu -> デバッグ -> デバッグなしで開始

# 線を書けるようにする

## 線のロジックを追加する

cubeのInspectorからAdd Component->Trail Renderer

Trail Rendererの設定

 + Material
     + Element 0 : cubeのmaterial
 + Time : Infinity
 + Min Vertex Distance : 0.05
 + Width : 0.02

このままでは一本しか線が引けないので、
cubeオブジェクトの複製を行う事で複数の線を引けるようにする。

HieralchyのcubeをAssetsへD&Dする。
hierarlchyのcubeを削除する。

Receiverを編集して複製を行う。

``` csharp
using HoloToolkit.Unity.InputModule;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class Receiver : MonoBehaviour , ISourceStateHandler, IInputHandler
{
    IInputSource currentInputSource;
    private uint id;
    private bool isDrag = false;
    GameObject obj;
    public GameObject original;
    private List<GameObject> cubes = new List<GameObject>();

    public void OnInputDown(InputEventData eventData)
    {
        if( !eventData.InputSource.SupportsInputInfo(eventData.SourceId, SupportedInputInfo.Position))
        {
            return;
        }

        GameObject tmp = GameObject.Instantiate(original);
        obj = tmp;
        cubes.Add(tmp);

        currentInputSource = eventData.InputSource;
        id = eventData.SourceId;

        isDrag = true;
        Debug.Log("finger down");
    }

    public void OnInputUp(InputEventData eventData)
    {
        isDrag = false;
        Debug.Log("finger up");
    }

    public void OnSourceDetected(SourceStateEventData eventData)
    {
        Debug.Log("Detected");
    }

    public void OnSourceLost(SourceStateEventData eventData)
    {
        isDrag = false;
        Debug.Log("Lost");
    }

    // Use this for initialization
    void Start () {
        InputManager.Instance.PushFallbackInputHandler(gameObject);
    }

    // Update is called once per frame
    void Update () {
        if (isDrag)
        {
            Vector3 pos;
            currentInputSource.TryGetPosition(id, out pos);

            Debug.Log(pos);
            obj.transform.position = pos;
        }
	}


    public void ResetLines()
    {
        for(int i = 0; i < cubes.Count; i++)
        {
            Destroy(cubes[i]);
            cubes[i] = null;
        }
        cubes.Clear();

    }
}
```

GameObjectのInspector.OriginalへAssetsのcubeをD&D。

## 削除できるようにする。

InputManager.Inspector->Add Component->Keyword Managerを追加。
KeywordManager.sizeを1へ。

 + element 0.Key Word : reset
 + element 0.Key Code : R
 + Response() * ``+``を押して追加
     + GameObjectを設定
     + Receiver->ResetLines