Last active
July 6, 2017 10:28
-
-
Save dykarohora/ea3aa186f751c850a08e75e5da5601bf to your computer and use it in GitHub Desktop.
BoundingBox with Gaze interaction
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Copyright (c) Microsoft Corporation. All rights reserved. | |
// Licensed under the MIT License. See LICENSE in the project root for license information. | |
// | |
using HUX.Buttons; | |
using System.Collections.Generic; | |
using UnityEngine; | |
namespace HUX.Interaction { | |
/// <summary> | |
/// Draws a bounding box gizmo in the style of the hololens shell | |
/// </summary> | |
[ExecuteInEditMode] | |
public class BoundingBoxGizmoShell : BoundingBoxGizmo { | |
#region public | |
/// <summary> | |
/// Mesh used to draw scale handles | |
/// </summary> | |
public Mesh BoxMesh; | |
/// <summary> | |
/// Mesh used to draw rotate handles | |
/// </summary> | |
public Mesh SphereMesh; | |
/// <summary> | |
/// Material used for drawing handles (must have _Color property) | |
/// </summary> | |
public Material HandleMaterial; | |
/// <summary> | |
/// Color of active handles | |
/// </summary> | |
public Color ActiveColor = Color.blue; | |
/// <summary> | |
/// Color of inactive handles | |
/// </summary> | |
public Color InactiveColor = Color.gray; | |
/// <summary> | |
/// Color of the handle being manipulated by player | |
/// </summary> | |
public Color TargetColor = Color.red; | |
public Color FocusColor = Color.green; | |
#endregion | |
#region private | |
[SerializeField] | |
private Renderer edgeRenderer; | |
[SerializeField] | |
private int activeHandleIndex = -1; | |
[SerializeField] | |
private int focusHandleIndex = -1; | |
private Vector3[] handlePositions; | |
private Material edgeMaterial; | |
private List<Matrix4x4> cubeHandleMatrixes = new List<Matrix4x4>(); | |
private List<Matrix4x4> sphereHandleMatrixes = new List<Matrix4x4>(); | |
private Bounds localBounds = new Bounds(); | |
private MaterialPropertyBlock propertyBlock; | |
private int colorID; | |
#endregion | |
#region initialization | |
void OnEnable() { | |
edgeMaterial = new Material(HandleMaterial); | |
edgeRenderer.material = edgeMaterial; | |
HandleMaterial.enableInstancing = true; | |
propertyBlock = new MaterialPropertyBlock(); | |
colorID = Shader.PropertyToID("_EmissionColor"); | |
} | |
void OnDisable() { | |
if (Application.isPlaying) { | |
GameObject.Destroy(edgeMaterial); | |
} else { | |
GameObject.DestroyImmediate(edgeMaterial); | |
} | |
} | |
#endregion | |
#region handle drawing | |
protected override void DrawGizmoObjects() { | |
if (boundingBox.Target == null) { | |
edgeRenderer.enabled = false; | |
return; | |
} | |
// Reset our scale - only scaleTransform can be changed | |
transform.localScale = Vector3.one; | |
// Get the positions of our handles | |
localBounds.size = scaleTransform.localScale; | |
localBounds.center = Vector3.zero; | |
localBounds.GetCornerAndMidPointPositions(transform, ref handlePositions); | |
cubeHandleMatrixes.Clear(); | |
sphereHandleMatrixes.Clear(); | |
// Pos / rot / scale for our handles | |
// Scale is based on smallest dimension to ensure handles don't overlap | |
// Rotation is just the rotation of our gizmo | |
Vector3 pos = Vector3.zero; | |
Quaternion rotation = transform.rotation; | |
Vector3 scale = Vector3.one * Mathf.Min(Mathf.Min(localBounds.size.x, localBounds.size.y), localBounds.size.z); | |
// Get the index of our active handle so we can draw it with a different material | |
activeHandleIndex = -1; | |
focusHandleIndex = -1; | |
BoundingBoxManipulate manipulate = boundingBox.GetComponent<BoundingBoxManipulate>(); | |
if (manipulate.ActiveHandle != null && manipulate.ActiveHandle.HandleType != BoundingBoxHandle.HandleTypeEnum.Drag) { | |
activeHandleIndex = (int)manipulate.ActiveHandle.HandleType; | |
} | |
if (manipulate.FocusHandle != null) { | |
focusHandleIndex = (int)manipulate.FocusHandle.HandleType; | |
} | |
// If we're not accepting input, just draw the box bounds | |
if (!manipulate.AcceptInput) { | |
edgeRenderer.enabled = true; | |
edgeMaterial.SetColor("_EmissionColor", InactiveColor); | |
} else { | |
switch (manipulate.CurrentOperation) { | |
default: | |
case BoundingBoxManipulate.OperationEnum.None: | |
// No visible bounds | |
// No visible handles | |
edgeRenderer.enabled = false; | |
break; | |
case BoundingBoxManipulate.OperationEnum.Drag: | |
// Target bounds | |
// Inactive scale handles | |
// Inactive rotate handles (based on permitted operations) | |
edgeRenderer.enabled = true; | |
edgeMaterial.SetColor("_EmissionColor", manipulate.ManipulatingNow ? TargetColor : ActiveColor); | |
// Get all our handle positions | |
GetAllHandleMatrixes(handlePositions, rotation, scale, cubeHandleMatrixes, sphereHandleMatrixes, activeHandleIndex); | |
// Draw our handles | |
DrawHandleMeshes(cubeHandleMatrixes, BoxMesh, InactiveColor); | |
DrawHandleMeshes(sphereHandleMatrixes, SphereMesh, InactiveColor); | |
break; | |
case BoundingBoxManipulate.OperationEnum.RotateY: | |
case BoundingBoxManipulate.OperationEnum.RotateZ: | |
case BoundingBoxManipulate.OperationEnum.RotateX: | |
// Visible bounds | |
// Inactive scale handles | |
// Active / Target rotate handles (based on permitted operations) | |
edgeRenderer.enabled = true; | |
edgeMaterial.SetColor("_EmissionColor", InactiveColor); | |
// Get all our handle positions | |
GetAllHandleMatrixes(handlePositions, rotation, scale, cubeHandleMatrixes, sphereHandleMatrixes, activeHandleIndex); | |
// Draw our handles | |
DrawHandleMeshes(cubeHandleMatrixes, BoxMesh, InactiveColor); | |
DrawHandleMeshes(sphereHandleMatrixes, SphereMesh, ActiveColor); | |
// DrawTargetMesh(activeHandleIndex, SphereMesh, handlePositions, rotation, scale, manipulate.ManipulatingNow ? TargetColor : ActiveColor); | |
if (manipulate.ManipulatingNow) { | |
DrawTargetMesh(activeHandleIndex, SphereMesh, handlePositions, rotation, scale, TargetColor); | |
} else if (activeHandleIndex != focusHandleIndex) { | |
DrawTargetMesh(activeHandleIndex, SphereMesh, handlePositions, rotation, scale, ActiveColor); | |
} | |
break; | |
case BoundingBoxManipulate.OperationEnum.ScaleUniform: | |
// Inactive bounds | |
// Active / Target scale handles | |
// Inactive rotate handles (based on permitted operations) | |
edgeRenderer.enabled = true; | |
edgeMaterial.SetColor("_EmissionColor", InactiveColor); | |
// Get all our handle positions | |
GetAllHandleMatrixes(handlePositions, rotation, scale, cubeHandleMatrixes, sphereHandleMatrixes, activeHandleIndex); | |
// Draw our handles | |
DrawHandleMeshes(cubeHandleMatrixes, BoxMesh, ActiveColor); | |
DrawHandleMeshes(sphereHandleMatrixes, SphereMesh, InactiveColor); | |
// DrawTargetMesh(activeHandleIndex, BoxMesh, handlePositions, rotation, scale, manipulate.ManipulatingNow ? TargetColor : ActiveColor); | |
if (manipulate.ManipulatingNow) { | |
DrawTargetMesh(activeHandleIndex, BoxMesh, handlePositions, rotation, scale, TargetColor); | |
} else if (activeHandleIndex != focusHandleIndex) { | |
DrawTargetMesh(activeHandleIndex, BoxMesh, handlePositions, rotation, scale, ActiveColor); | |
} | |
break; | |
} | |
if (!manipulate.ManipulatingNow) { | |
switch (focusHandleIndex) { | |
case 0: | |
case 1: | |
case 2: | |
case 3: | |
case 4: | |
case 5: | |
case 6: | |
case 7: | |
DrawTargetMesh(focusHandleIndex, BoxMesh, handlePositions, rotation, scale, FocusColor); | |
break; | |
case 8: | |
case 9: | |
case 10: | |
case 11: | |
case 12: | |
case 13: | |
case 14: | |
case 15: | |
case 16: | |
case 17: | |
case 18: | |
case 19: | |
DrawTargetMesh(focusHandleIndex, SphereMesh, handlePositions, rotation, scale, FocusColor); | |
break; | |
case 20: | |
edgeMaterial.SetColor("_EmissionColor", FocusColor); | |
break; | |
} | |
} | |
} | |
} | |
private void DrawTargetMesh(int targetIndex, Mesh mesh, Vector3[] positions, Quaternion rotation, Vector3 scale, Color color) { | |
if (targetIndex < 0) | |
return; | |
propertyBlock.SetColor(colorID, color); | |
Graphics.DrawMesh(mesh, Matrix4x4.TRS(positions[targetIndex], rotation, scale), HandleMaterial, PhysicsLayer, Camera.current, 0, propertyBlock, UnityEngine.Rendering.ShadowCastingMode.Off, false); | |
} | |
private void DrawHandleMeshes(List<Matrix4x4> matrixes, Mesh mesh, Color color) { | |
propertyBlock.SetColor(colorID, color); | |
Graphics.DrawMeshInstanced(mesh, 0, HandleMaterial, matrixes, propertyBlock, UnityEngine.Rendering.ShadowCastingMode.Off, false, PhysicsLayer); | |
} | |
private void GetAllHandleMatrixes(Vector3[] positions, Quaternion rotation, Vector3 scale, List<Matrix4x4> cubeMatrixes, List<Matrix4x4> sphereMatrixes, int targetIndex) { | |
BoundingBoxManipulate manipulate = boundingBox.GetComponent<BoundingBoxManipulate>(); | |
// Get all our handle positions for cubes | |
if ((manipulate.PermittedOperations & BoundingBoxManipulate.OperationEnum.ScaleUniform) == BoundingBoxManipulate.OperationEnum.ScaleUniform) { | |
for (int i = BoundsExtentions.LBF; i <= BoundsExtentions.RTB; i++) { | |
if (i == targetIndex) | |
continue; | |
cubeMatrixes.Add(Matrix4x4.TRS(handlePositions[i], rotation, scale)); | |
} | |
} | |
// Get all our handle positions for rotation | |
if ((manipulate.PermittedOperations & BoundingBoxManipulate.OperationEnum.RotateX) == BoundingBoxManipulate.OperationEnum.RotateX) { | |
for (int i = BoundsExtentions.LTF_RTF; i <= BoundsExtentions.RBB_LBB; i++) { | |
if (i == targetIndex) | |
continue; | |
sphereMatrixes.Add(Matrix4x4.TRS(handlePositions[i], rotation, scale)); | |
} | |
} | |
if ((manipulate.PermittedOperations & BoundingBoxManipulate.OperationEnum.RotateY) == BoundingBoxManipulate.OperationEnum.RotateY) { | |
for (int i = BoundsExtentions.LTF_LBF; i <= BoundsExtentions.RTF_RBF; i++) { | |
if (i == targetIndex) | |
continue; | |
sphereMatrixes.Add(Matrix4x4.TRS(handlePositions[i], rotation, scale)); | |
} | |
} | |
if ((manipulate.PermittedOperations & BoundingBoxManipulate.OperationEnum.RotateZ) == BoundingBoxManipulate.OperationEnum.RotateZ) { | |
for (int i = BoundsExtentions.RBF_RBB; i <= BoundsExtentions.LTF_LTB; i++) { | |
if (i == targetIndex) | |
continue; | |
sphereMatrixes.Add(Matrix4x4.TRS(handlePositions[i], rotation, scale)); | |
} | |
} | |
} | |
#endregion | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Copyright (c) Microsoft Corporation. All rights reserved. | |
// Licensed under the MIT License. See LICENSE in the project root for license information. | |
// | |
using HUX.Buttons; | |
using HUX.Focus; | |
using HUX.Receivers; | |
using System.Collections.Generic; | |
using UnityEngine; | |
namespace HUX.Interaction { | |
/// <summary> | |
/// Listens to messages from attached BoundingBoxHandle objects and manipulates the target | |
/// </summary> | |
public class BoundingBoxManipulate : BoundingBox { | |
[System.Flags] | |
public enum OperationEnum { | |
None = 0, | |
Drag = 1, | |
ScaleUniform = 2, | |
RotateX = 4, | |
RotateZ = 8, | |
RotateY = 16, | |
ScaleX = 32, | |
ScaleY = 64, | |
ScaleZ = 128, | |
} | |
#region public | |
/// <summary> | |
/// Makes bounding box manipulatable by user | |
/// </summary> | |
public bool AcceptInput { | |
get { | |
return acceptInput; | |
} | |
set { | |
if (value & !acceptInput) { | |
// Reset to drag operation | |
CurrentOperation = OperationEnum.Drag; | |
} | |
acceptInput = value; | |
} | |
} | |
/// <summary> | |
/// Which operations this bounding box is allowed to perform | |
/// </summary> | |
public OperationEnum PermittedOperations { | |
get { | |
return permittedOperations; | |
} | |
set { | |
if (permittedOperations != value) { | |
permittedOperations = value; | |
RefreshActiveHandles(); | |
} | |
} | |
} | |
/// <summary> | |
/// How quickly objects move when being dragged | |
/// </summary> | |
public float DragMultiplier = 10f; | |
/// <summary> | |
/// How much to scale rotation input | |
/// </summary> | |
public float RotateMultiplier = 10f; | |
/// <summary> | |
/// How much to scale scale input | |
/// </summary> | |
public float ScaleMultiplier = 10f; | |
/// <summary> | |
/// The smallest an object can be scaled with one gesture | |
/// </summary> | |
public float MinScalePercentage = 0.05f; | |
/// <summary> | |
/// The current operation of the bounding box | |
/// </summary> | |
public OperationEnum CurrentOperation { | |
get { | |
if (target == null || activeHandle == null) { | |
return OperationEnum.None; | |
} | |
return GetBoundingBoxOperationFromHandleType(activeHandle.HandleType); | |
} | |
set { | |
SetHandleByOperation(value); | |
} | |
} | |
/// <summary> | |
/// Whether the user is manipulating the bb using a handle | |
/// </summary> | |
public bool ManipulatingNow { | |
get { | |
if (Application.isPlaying) { | |
return manipulatingNow; | |
} else { | |
return true; | |
} | |
} | |
set { | |
if (value) { | |
StartManipulating(); | |
} else { | |
StopManipulating(); | |
} | |
} | |
} | |
/// <summary> | |
/// The handle being manipulated by the user, if any | |
/// </summary> | |
public BoundingBoxHandle ActiveHandle { | |
get { | |
return activeHandle; | |
} | |
set { | |
activeHandle = value; | |
} | |
} | |
public BoundingBoxHandle FocusHandle { | |
get { | |
return focusHandle; | |
} | |
set { | |
focusHandle = value; | |
} | |
} | |
/// <summary> | |
/// The target object being manipulated | |
/// </summary> | |
public override GameObject Target { | |
get { | |
return target; | |
} | |
set { | |
if (target != value) { | |
// Send a message to the new / old targets | |
if (value != null) { | |
value.SendMessage("OnTargetSelected", SendMessageOptions.DontRequireReceiver); | |
} | |
if (target != null) { | |
target.SendMessage("OnTargetDeselected", SendMessageOptions.DontRequireReceiver); | |
} | |
target = value; | |
// Reset active handle to drag | |
SetHandleByOperation(OperationEnum.Drag); | |
ManipulatingNow = false; | |
} | |
if (target != null) { | |
CreateTransforms(); | |
// Set our transforms to the target immediately | |
targetStandIn.position = target.transform.position; | |
targetStandIn.rotation = target.transform.rotation; | |
targetStandIn.localScale = target.transform.lossyScale; | |
RefreshTargetBounds(); | |
} else { | |
ActiveHandle = null; | |
} | |
} | |
} | |
/// <summary> | |
/// Convenience function to help determine what function a handle serves | |
/// </summary> | |
/// <param name="handleType"></param> | |
/// <returns></returns> | |
public static OperationEnum GetBoundingBoxOperationFromHandleType(BoundingBoxHandle.HandleTypeEnum handleType) { | |
switch (handleType) { | |
case BoundingBoxHandle.HandleTypeEnum.Drag: | |
return OperationEnum.Drag; | |
//TODO - break this up into axis scales | |
case BoundingBoxHandle.HandleTypeEnum.Scale_LBF: | |
case BoundingBoxHandle.HandleTypeEnum.Scale_LBB: | |
case BoundingBoxHandle.HandleTypeEnum.Scale_LTF: | |
case BoundingBoxHandle.HandleTypeEnum.Scale_LTB: | |
case BoundingBoxHandle.HandleTypeEnum.Scale_RBF: | |
case BoundingBoxHandle.HandleTypeEnum.Scale_RBB: | |
case BoundingBoxHandle.HandleTypeEnum.Scale_RTF: | |
case BoundingBoxHandle.HandleTypeEnum.Scale_RTB: | |
return OperationEnum.ScaleUniform; | |
case BoundingBoxHandle.HandleTypeEnum.Rotate_LTF_RTF: | |
case BoundingBoxHandle.HandleTypeEnum.Rotate_LBF_RBF: | |
case BoundingBoxHandle.HandleTypeEnum.Rotate_RTB_LTB: | |
case BoundingBoxHandle.HandleTypeEnum.Rotate_RBB_LBB: | |
return OperationEnum.RotateX; | |
case BoundingBoxHandle.HandleTypeEnum.Rotate_LTF_LBF: | |
case BoundingBoxHandle.HandleTypeEnum.Rotate_RTB_RBB: | |
case BoundingBoxHandle.HandleTypeEnum.Rotate_LTB_LBB: | |
case BoundingBoxHandle.HandleTypeEnum.Rotate_RTF_RBF: | |
return OperationEnum.RotateY; | |
case BoundingBoxHandle.HandleTypeEnum.Rotate_RBF_RBB: | |
case BoundingBoxHandle.HandleTypeEnum.Rotate_RTF_RTB: | |
case BoundingBoxHandle.HandleTypeEnum.Rotate_LBF_LBB: | |
case BoundingBoxHandle.HandleTypeEnum.Rotate_LTF_LTB: | |
return OperationEnum.RotateZ; | |
default: | |
return OperationEnum.None; | |
} | |
} | |
public override void OnEnable() { | |
base.OnEnable(); | |
manipulatingNow = false; | |
} | |
#endregion | |
#region manipulation events | |
protected override void OnFocusEnter(GameObject obj, FocusArgs args) { | |
if (!ManipulatingNow) { | |
//TODO show handle mesh | |
TryToSetFocusHandle(obj); | |
} | |
base.OnFocusEnter(obj, args); | |
} | |
protected override void OnFocusExit(GameObject obj, FocusArgs args) { | |
if (!ManipulatingNow) { | |
//TODO hide handle mesh | |
focusHandle = null; | |
} | |
base.OnFocusExit(obj, args); | |
} | |
/// <summary> | |
/// Chooses our manipulation handle so we know how to interpret future input events | |
/// </summary> | |
/// <param name="obj"></param> | |
/// <param name="eventArgs"></param> | |
protected override void OnManipulationStarted(GameObject obj, InteractionManager.InteractionEventArgs eventArgs) { | |
base.OnManipulationStarted(obj, eventArgs); | |
TryToSetHandle(obj, eventArgs.Position, eventArgs.Focuser); | |
// Compute a vector as a reference for determining the amount of rotation. | |
// In order to operate with the vertical and horizontal movements of the hand, | |
// the reference vector is assumed to be the coordinate axis of the BoundingBox projected on the screen | |
if (CurrentOperation == OperationEnum.RotateX || CurrentOperation == OperationEnum.RotateY || CurrentOperation == OperationEnum.RotateZ) { | |
Vector3 axisVect = Vector3.ProjectOnPlane( | |
CurrentOperation == OperationEnum.RotateX ? transform.right : | |
CurrentOperation == OperationEnum.RotateY ? transform.up : | |
transform.forward, | |
Camera.main.transform.forward); | |
orthogonalVect = Vector3.Cross(Camera.main.transform.forward, axisVect); | |
orthogonalVect.Normalize(); | |
} | |
} | |
protected override void OnManipulationCanceled(GameObject obj, InteractionManager.InteractionEventArgs eventArgs) { | |
ManipulatingNow = false; | |
base.OnManipulationCanceled(obj, eventArgs); | |
} | |
protected override void OnManipulationCompleted(GameObject obj, InteractionManager.InteractionEventArgs eventArgs) { | |
ManipulatingNow = false; | |
base.OnManipulationCompleted(obj, eventArgs); | |
} | |
protected override void OnManipulationUpdated(GameObject obj, InteractionManager.InteractionEventArgs eventArgs) { | |
base.OnManipulationUpdated(obj, eventArgs); | |
if (!acceptInput) | |
return; | |
if (target == null) | |
return; | |
if (!manipulatingNow) | |
return; | |
Vector3 eventPos = eventArgs.Position; | |
// Transform the direction if necessary | |
if (eventArgs.IsPosRelative) { | |
eventPos = Veil.Instance.HeadTransform.TransformDirection(eventPos); | |
} | |
// See how much our position has changed | |
navigateVelocity = lastNavigatePos - eventPos; | |
lastNavigatePos = eventPos; | |
smoothVelocity = Vector3.Lerp(smoothVelocity, navigateVelocity, 0.5f); | |
} | |
#endregion | |
#region private | |
/// <summary> | |
/// Override so we're not overwhelmed by button gizmos | |
/// </summary> | |
#if UNITY_EDITOR | |
protected override void OnDrawGizmos() { | |
// nothing | |
if (!Application.isPlaying) { | |
// Do this here to ensure continuous updates in editor | |
UpdateTargetManipulation(); | |
RefreshTargetBounds(); | |
} | |
} | |
#endif | |
protected override void Update() { | |
if (!Application.isPlaying) | |
return; | |
// Check to see if our hands have exited the screen | |
// If they have, stop manipulating | |
if (!Veil.Instance.HandVisible) { | |
ManipulatingNow = false; | |
} | |
UpdateUserManipulation(); | |
UpdateTargetManipulation(); | |
base.Update(); | |
} | |
/// <summary> | |
/// Applies changes gathered during manipulation udpate events | |
/// </summary> | |
private void UpdateUserManipulation() { | |
if (ManipulatingNow) { | |
// Projecting the movement vector of the hand on the reference vector | |
Vector3 proj = Vector3.Project(smoothVelocity, orthogonalVect); | |
// Change the transform helper based on the current operation | |
// We're using some magic numbers in here to keep the multiplier ranges intuitive | |
switch (CurrentOperation) { | |
case OperationEnum.Drag: | |
transformHelper.position -= (smoothVelocity * DragMultiplier); | |
break; | |
case OperationEnum.ScaleUniform: | |
case OperationEnum.ScaleX: | |
case OperationEnum.ScaleY: | |
case OperationEnum.ScaleZ: | |
// Translate velocity direction based on camera | |
Vector3 orientedVelocity = Camera.main.transform.TransformDirection(smoothVelocity); | |
// See whether handle is to left or right of gizmo center | |
Vector3 handleScreenPoint = Camera.main.WorldToScreenPoint(activeHandle.transform.position); | |
Vector3 gizmoScreenPoint = Camera.main.WorldToScreenPoint(targetBoundsWorldCenter); | |
float dragAmount = orientedVelocity.x; | |
if (handleScreenPoint.x > gizmoScreenPoint.x) { | |
dragAmount = -dragAmount; | |
} | |
transformHelper.localScale += Vector3.one * (dragAmount * ScaleMultiplier); | |
break; | |
case OperationEnum.RotateX: | |
// transformHelper.Rotate(-smoothVelocity.y * RotateMultiplier * 360, 0f, 0f, Space.World); | |
transformHelper.RotateAround(transformHelper.position, transform.right, smoothVelocity.magnitude * Vector3.Dot(proj.normalized, orthogonalVect.normalized) * -360); | |
break; | |
case OperationEnum.RotateY: | |
// transformHelper.Rotate(0f, smoothVelocity.x * RotateMultiplier * 360, 0f, Space.World); | |
transformHelper.RotateAround(transformHelper.position, transform.up, smoothVelocity.magnitude * Vector3.Dot(proj.normalized, orthogonalVect.normalized) * -360); | |
break; | |
case OperationEnum.RotateZ: | |
// transformHelper.Rotate(0f, 0f, smoothVelocity.x * RotateMultiplier * 360, Space.World); | |
transformHelper.RotateAround(transformHelper.position, transform.forward, smoothVelocity.magnitude * Vector3.Dot(proj.normalized, orthogonalVect.normalized) * -360); | |
break; | |
default: | |
break; | |
} | |
} | |
} | |
/// <summary> | |
/// Alters the target based on changes applied to bounding box | |
/// </summary> | |
private void UpdateTargetManipulation() { | |
// Goes without saying | |
if (!acceptInput) | |
return; | |
// If we don't have a target, nothing to do here | |
if (target == null) | |
return; | |
// If we're NOT actively manipulating the target, nothing to do here | |
if (!ManipulatingNow) | |
return; | |
if (!Application.isPlaying) | |
return; | |
CreateTransforms(); | |
// Apply the target stand-in's transform info to the target | |
Target.transform.position = targetStandIn.position; | |
Target.transform.rotation = targetStandIn.rotation; | |
Target.transform.localScale = targetStandIn.lossyScale; | |
} | |
/// <summary> | |
/// Stores target under our transform helper and prepares for manipulation | |
/// </summary> | |
private void StartManipulating() { | |
// Goes without saying | |
if (!acceptInput) | |
return; | |
if (target == null) | |
return; | |
if (manipulatingNow) | |
return; | |
manipulatingNow = true; | |
if (!Application.isPlaying) | |
return; | |
CreateTransforms(); | |
// Reset the transform helper to 1,1,1 / idenity | |
transformHelper.localScale = Vector3.one; | |
transformHelper.rotation = Quaternion.identity; | |
adjustedScaleTarget = Vector3.one; | |
smoothVelocity = Vector3.zero; | |
// Set up our transforms and gestures based on the operation we're performing | |
OperationEnum operation = GetBoundingBoxOperationFromHandleType(ActiveHandle.HandleType); | |
switch (operation) { | |
case OperationEnum.ScaleUniform: | |
case OperationEnum.ScaleX: | |
case OperationEnum.ScaleY: | |
case OperationEnum.ScaleZ: | |
// If we're scaling, move the transform helper to the position OPPOSITE the scale handle | |
// That way the object will grow in the right direction | |
BoundingBoxHandle oppositeHandle = null; | |
BoundingBoxHandle.HandleTypeEnum oppositeHandleType = BoundingBoxHandle.GetOpposingHandle(ActiveHandle.HandleType); | |
foreach (GameObject bbhGo in Interactibles) { | |
BoundingBoxHandle bbh = bbhGo.GetComponent<BoundingBoxHandle>(); | |
if (bbh != null && bbh.HandleType == oppositeHandleType) { | |
oppositeHandle = bbh; | |
break; | |
} | |
} | |
if (oppositeHandle == null) { | |
Debug.LogWarning("Couldn't find opposing handle for type " + ActiveHandle.HandleType); | |
transformHelper.position = transform.position; | |
targetStandIn.position = target.transform.position; | |
} else { | |
transformHelper.position = oppositeHandle.transform.position; | |
targetStandIn.position = target.transform.position; | |
} | |
break; | |
case OperationEnum.Drag: | |
// If we're rotating or moving, move the transform helper to the center of the gizmo | |
transformHelper.position = transform.position; | |
targetStandIn.position = target.transform.position; | |
break; | |
case OperationEnum.RotateX: | |
case OperationEnum.RotateY: | |
case OperationEnum.RotateZ: | |
default: | |
// Rotation | |
// If we're rotating or moving, move the transform helper to the center of the gizmo | |
transformHelper.position = transform.position; | |
targetStandIn.position = target.transform.position; | |
break; | |
} | |
scaleOnStartManipulation = targetStandIn.localScale; | |
if (target != null) { | |
// Set our transforms to the target immediately | |
targetStandIn.position = target.transform.position; | |
targetStandIn.rotation = target.transform.rotation; | |
targetStandIn.localScale = target.transform.lossyScale; | |
} | |
} | |
private void StopManipulating() { | |
if (!manipulatingNow) | |
return; | |
manipulatingNow = false; | |
if (focuser != null) { | |
focuser.ReleaseFocus(); | |
focuser = null; | |
} | |
} | |
private void SetHandleByOperation(OperationEnum operation) { | |
switch (operation) { | |
case OperationEnum.None: | |
ActiveHandle = null; | |
break; | |
case OperationEnum.Drag: | |
foreach (GameObject obj in Interactibles) { | |
BoundingBoxHandle h = obj.GetComponent<BoundingBoxHandle>(); | |
if (h.HandleType == BoundingBoxHandle.HandleTypeEnum.Drag) { | |
ActiveHandle = h; | |
break; | |
} | |
} | |
break; | |
default: | |
//TODO link up other operations here | |
break; | |
} | |
} | |
private void RefreshActiveHandles() { | |
foreach (GameObject handleGo in Interactibles) { | |
BoundingBoxHandle handle = handleGo.GetComponent<BoundingBoxHandle>(); | |
OperationEnum handleOperation = GetBoundingBoxOperationFromHandleType(handle.HandleType); | |
handleGo.SetActive((handleOperation & permittedOperations) != 0); | |
} | |
} | |
private void TryToSetHandle(GameObject obj, Vector3 position, AFocuser newFocuser) { | |
if (!acceptInput) { | |
Debug.Log("Not accepting input"); | |
return; | |
} | |
BoundingBoxHandle newHandle = obj.GetComponent<BoundingBoxHandle>(); | |
if (newHandle != null) { | |
activeHandle = newHandle; | |
lastNavigatePos = position; | |
ManipulatingNow = true; | |
focuser = newFocuser; | |
focuser.LockFocus(); | |
} | |
} | |
private void TryToSetFocusHandle(GameObject obj) { | |
BoundingBoxHandle newHandle = obj.GetComponent<BoundingBoxHandle>(); | |
if (newHandle != null) { | |
focusHandle = newHandle; | |
} | |
} | |
[SerializeField] | |
private BoundingBoxHandle activeHandle; | |
private BoundingBoxHandle focusHandle; | |
[SerializeField] | |
private bool acceptInput = true; | |
[SerializeField] | |
private bool manipulatingNow = false; | |
[SerializeField] | |
private OperationEnum permittedOperations = OperationEnum.Drag | OperationEnum.RotateY | OperationEnum.ScaleUniform; | |
private Vector3 lastNavigatePos = Vector3.zero; | |
private Vector3 navigateVelocity = Vector3.zero; | |
private Vector3 smoothVelocity = Vector3.zero; | |
private Vector3 adjustedScaleTarget = Vector3.one; | |
private Vector3 targetPosition = Vector3.zero; | |
/// <summary> | |
/// A vector orthogonal to the rotation axis. | |
/// </summary> | |
private Vector3 orthogonalVect = Vector3.one; | |
private Vector3 scaleOnStartManipulation = Vector3.one; | |
private AFocuser focuser = null; | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment