Skip to content

Instantly share code, notes, and snippets.

@kasari

kasari/DualGrabbable.cs

Last active Jan 1, 2019
Embed
What would you like to do?
両手によるtransform操作コンポーネント for VIVE Input Utility
using UnityEngine;
using HTC.UnityPlugin.ColliderEvent;
using HTC.UnityPlugin.Utility;
public class DualGrabbable : MonoBehaviour
, IColliderEventDragStartHandler
, IColliderEventDragUpdateHandler
, IColliderEventDragEndHandler
{
public class Grabber
{
// コントローラー
public IColliderEventCaster eventCaster { get; private set; }
// 掴んでいるオブジェクト
public GameObject grabbingObj { get; private set; }
// コントローラーの位置と向き
public RigidPose grabberOrigin { get { return new RigidPose(eventCaster.transform); } }
// コントローラーからオブジェクトまでの offset (コントローラーを親、オブジェクトを子としたときの localPosition のようなもの)
public RigidPose grabOffset { get; private set; }
// コントローラーの現在の位置と向き、offset から計算したオブジェクトの位置と向き
public RigidPose grabPose { get { return grabberOrigin * grabOffset; } }
public Grabber(IColliderEventCaster eventCaster, GameObject obj)
{
this.eventCaster = eventCaster;
this.grabbingObj = obj;
this.grabOffset = RigidPose.FromToPose(new RigidPose(eventCaster.transform), new RigidPose(obj.transform));
}
}
public class DualGrabber
{
public Grabber oneGrabber;
public Grabber otherGrabber;
public bool isNotGrabbed { get { return oneGrabber == null && otherGrabber == null; } }
public bool isSoloGrabbed { get { return oneGrabber != null && otherGrabber == null; } }
public bool isDualGrabbed { get { return oneGrabber != null && otherGrabber != null; } }
private Transform targetTransform;
// 両手で掴んだときの、オブジェクトのscale
Vector3 _initScale;
// 両手で掴んだときの、オブジェクトのrotation
Quaternion _initRot;
// 両手で掴んだときの、両手間の距離
private float _initMagnitude;
// 両手で掴んだときの、片方の手からもう片方の手への向き
private Vector3 _initDir;
public void UpdateTransform()
{
// 片手で掴んでいるとき
if (isSoloGrabbed)
{
targetTransform.position = oneGrabber.grabPose.pos;
targetTransform.rotation = oneGrabber.grabPose.rot;
}
// 両手で掴んでいるとき
else if (isDualGrabbed)
{
var currentDir = (otherGrabber.grabberOrigin.pos - oneGrabber.grabberOrigin.pos).normalized;
var rot = Quaternion.FromToRotation(_initDir, currentDir);
var currentMagnitude = (otherGrabber.grabberOrigin.pos - oneGrabber.grabberOrigin.pos).magnitude;
var scale = currentMagnitude / _initMagnitude;
targetTransform.position = (oneGrabber.grabPose.pos + otherGrabber.grabPose.pos) / 2;
targetTransform.rotation = rot * _initRot;
targetTransform.localScale = scale * _initScale;
}
}
public void AddGrabber(Grabber grabber)
{
if (oneGrabber == null)
{
oneGrabber = grabber;
// 片手で掴み始めたときに、対象とするオブジェクトの transform を取得する
targetTransform = grabber.grabbingObj.transform;
}
else
{
otherGrabber = grabber;
// 両手で掴み始めたとき
// 両手の距離、片方の手からもう片方の手までの向き
_initMagnitude = (otherGrabber.grabberOrigin.pos - oneGrabber.grabberOrigin.pos).magnitude;
_initDir = (otherGrabber.grabberOrigin.pos - oneGrabber.grabberOrigin.pos).normalized;
// 両手で掴んだときのオブジェクトの scale と rotation を保存
_initScale = targetTransform.localScale;
_initRot = targetTransform.rotation;
}
}
public void Clear()
{
oneGrabber = null;
otherGrabber = null;
}
}
private DualGrabber _dualGrabber = new DualGrabber();
// Trigger を引いたとき
public void OnColliderEventDragStart(ColliderButtonEventData eventData)
{
if (eventData.button != ColliderButtonEventData.InputButton.Trigger) { return; }
// 掴んでいるコントローラーと掴んでいるオブジェクトを指定して grabber を生成
var grabber = new Grabber(eventData.eventCaster, gameObject);
_dualGrabber.AddGrabber(grabber);
}
// Trigger を引いている間
public void OnColliderEventDragUpdate(ColliderButtonEventData eventData)
{
_dualGrabber.UpdateTransform();
}
// Trigger を離したとき
public void OnColliderEventDragEnd(ColliderButtonEventData eventData)
{
_dualGrabber.Clear();
}
}
@kasari

This comment has been minimized.

Copy link
Owner Author

@kasari kasari commented Dec 14, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.