athome-developer’s blog

不動産情報サービスのアットホームの開発者が発信するブログ

HoloLensでオブジェクトを回転してみる

こんにちは、情報システム部の高野です。
ちょっと間が空いてしまいましたが
拡大縮小に引き続き、今度は回転です。
今回は、Y軸に対する回転だけやります。
(いまのところそれしか使わなそうなので)

準備

前回の拡大縮小で作成したプロジェクトにそのまま追加していきます。

回転用のハンドルCubeとスクリプトの作成

回転ハンドルを作成する

HierarchyウィンドウのCube内のWireを右クリックし
「3D Obejct」→「Sphere」を選択します。
名称をRotateHandle1に変更します。
サイズと位置を変更します。
Position X=0.5 Y=0 Z=-0.5
Size X/Y/Z=0.05
前回作成したHandle用のマテリアルをアタッチします。

スクリプトを作成する

Projectウィンドウで「C# Script」を作成し
名称をRotateControllerに変更します。
これをRotateHandle1オブジェクトにアタッチします。

RotateController.csをVisualStudioで開き以下の様に修正します。

using HoloToolkit.Unity.InputModule;
using UnityEngine;

public class RotateController : MonoBehaviour, IInputHandler, ISourceStateHandler
{
    private bool isHold;
    private IInputSource currentInputSource;
    private uint currentInputSourceId;
    private Vector3 prevPos;
    private GameObject targetObj;

    // Use this for initialization
    void Start()
    {
        // rootから取れば良かった
        targetObj = transform.root.gameObject;
    }

    // Update is called once per frame
    void Update()
    {
        if (!isHold) return;

        Vector3 handPos;
        currentInputSource.TryGetPosition(currentInputSourceId, out handPos);
        // ワールド空間からローカル空間に変換
        handPos = Camera.main.transform.InverseTransformDirection(handPos);

        var diff = prevPos - handPos;
        prevPos = handPos;

        targetObj.transform.Rotate(0f, diff.x * 360, 0f, Space.World);
    }

    public void OnInputUp(InputEventData eventData)
    {
        if (!isHold) return;

        isHold = false;
        InputManager.Instance.PopModalInputHandler();
    }

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

        if (isHold) return;

        isHold = true;
        InputManager.Instance.PushModalInputHandler(gameObject);

        currentInputSource = eventData.InputSource;
        currentInputSourceId = eventData.SourceId;

        currentInputSource.TryGetPosition(currentInputSourceId, out prevPos);
        prevPos = Camera.main.transform.InverseTransformDirection(prevPos);
    }

    public void OnSourceDetected(SourceStateEventData eventData)
    {
    }

    public void OnSourceLost(SourceStateEventData eventData)
    {
        if (!isHold) return;

        isHold = false;
        InputManager.Instance.PopModalInputHandler();
    }
}

TransformクラスのInverseTransformDirectionメソッドで
ワールド空間からローカル空間に変換してますが
オブジェクトの正面からだけ操作するのであればこれは必要ありません。
オブジェクトの横や後ろに回って操作すると
これが無いと手の動きと回転が合わなくなります。
下図のような位置関係の場合は、手を横に動かすとZ方向に動かすことになります。
このままだとXの移動距離では無くZの移動距離が必要になります。
f:id:taktak1974:20170620160225p:plain
自分とオブジェクトの位置関係に応じて
Xの移動距離だったりZの移動距離だったりに変更するのは大変なので
カメラのローカル空間に変換して手の横移動は常にXの移動にしました。
これがよくわからずに嵌りました(Unity初心者なので色々、嵌ります)


後は、各辺にハンドルをコピーします。
完成したものがこちらになります。

hololens rotate object


これを作っている間にMRDesignLabs_Unityが公開されて
作る必要なかったなって感じにはなったのですが
勉強にはなったので良かった。
MRDesignLabs_Unityは、HoloToolkitのイベントを使ってないので
やり方は結構違いますけどね。*1


弊社ではエンジニアを募集しています。
興味がある方は下記からエントリお願いします。
Unityできる人もいるとうれしいな
athome-inc.jp

*1:MRDesignLabs_UnityだとHoloLens以外でも動かせそう