forked from microsoft/MixedRealityToolkit-Unity
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTapToPlace.cs
More file actions
166 lines (145 loc) · 6.87 KB
/
TapToPlace.cs
File metadata and controls
166 lines (145 loc) · 6.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
using HoloToolkit.Unity.InputModule;
using UnityEngine;
namespace HoloToolkit.Unity.SpatialMapping
{
/// <summary>
/// The TapToPlace class is a basic way to enable users to move objects
/// and place them on real world surfaces.
/// Put this script on the object you want to be able to move.
/// Users will be able to tap objects, gaze elsewhere, and perform the
/// tap gesture again to place.
/// This script is used in conjunction with GazeManager, GestureManager,
/// and SpatialMappingManager.
/// TapToPlace also adds a WorldAnchor component to enable persistence.
/// </summary>
public class TapToPlace : MonoBehaviour, IInputClickHandler
{
[Tooltip("Supply a friendly name for the anchor as the key name for the WorldAnchorStore.")]
public string SavedAnchorFriendlyName = "SavedAnchorFriendlyName";
[Tooltip("Place parent on tap instead of current game object.")]
public bool PlaceParentOnTap;
[Tooltip("Specify the parent game object to be moved on tap, if the immediate parent is not desired.")]
public GameObject ParentGameObjectToPlace;
/// <summary>
/// Keeps track of if the user is moving the object or not.
/// Setting this to true will enable the user to move and place the object in the scene.
/// Useful when you want to place an object immediately.
/// </summary>
[Tooltip("Setting this to true will enable the user to move and place the object in the scene without needing to tap on the object. Useful when you want to place an object immediately.")]
public bool IsBeingPlaced;
/// <summary>
/// Manages persisted anchors.
/// </summary>
protected WorldAnchorManager anchorManager;
/// <summary>
/// Controls spatial mapping. In this script we access spatialMappingManager
/// to control rendering and to access the physics layer mask.
/// </summary>
protected SpatialMappingManager spatialMappingManager;
protected virtual void Start()
{
// Make sure we have all the components in the scene we need.
anchorManager = WorldAnchorManager.Instance;
if (anchorManager == null)
{
Debug.LogError("This script expects that you have a WorldAnchorManager component in your scene.");
}
spatialMappingManager = SpatialMappingManager.Instance;
if (spatialMappingManager == null)
{
Debug.LogError("This script expects that you have a SpatialMappingManager component in your scene.");
}
if (anchorManager != null && spatialMappingManager != null)
{
anchorManager.AttachAnchor(gameObject, SavedAnchorFriendlyName);
}
else
{
// If we don't have what we need to proceed, we may as well remove ourselves.
Destroy(this);
}
if (PlaceParentOnTap)
{
if (ParentGameObjectToPlace != null && !gameObject.transform.IsChildOf(ParentGameObjectToPlace.transform))
{
Debug.LogError("The specified parent object is not a parent of this object.");
}
DetermineParent();
}
}
protected virtual void Update()
{
// If the user is in placing mode,
// update the placement to match the user's gaze.
if (IsBeingPlaced)
{
// Do a raycast into the world that will only hit the Spatial Mapping mesh.
Vector3 headPosition = Camera.main.transform.position;
Vector3 gazeDirection = Camera.main.transform.forward;
RaycastHit hitInfo;
if (Physics.Raycast(headPosition, gazeDirection, out hitInfo, 30.0f, spatialMappingManager.LayerMask))
{
// Rotate this object to face the user.
Quaternion toQuat = Camera.main.transform.localRotation;
toQuat.x = 0;
toQuat.z = 0;
// Move this object to where the raycast
// hit the Spatial Mapping mesh.
// Here is where you might consider adding intelligence
// to how the object is placed. For example, consider
// placing based on the bottom of the object's
// collider so it sits properly on surfaces.
if (PlaceParentOnTap)
{
// Place the parent object as well but keep the focus on the current game object
Vector3 currentMovement = hitInfo.point - gameObject.transform.position;
ParentGameObjectToPlace.transform.position += currentMovement;
ParentGameObjectToPlace.transform.rotation = toQuat;
}
else
{
gameObject.transform.position = hitInfo.point;
gameObject.transform.rotation = toQuat;
}
}
}
}
public virtual void OnInputClicked(InputClickedEventData eventData)
{
// On each tap gesture, toggle whether the user is in placing mode.
IsBeingPlaced = !IsBeingPlaced;
// If the user is in placing mode, display the spatial mapping mesh.
if (IsBeingPlaced)
{
spatialMappingManager.DrawVisualMeshes = true;
Debug.Log(gameObject.name + " : Removing existing world anchor if any.");
anchorManager.RemoveAnchor(gameObject);
}
// If the user is not in placing mode, hide the spatial mapping mesh.
else
{
spatialMappingManager.DrawVisualMeshes = false;
// Add world anchor when object placement is done.
anchorManager.AttachAnchor(gameObject, SavedAnchorFriendlyName);
}
}
private void DetermineParent()
{
if (ParentGameObjectToPlace == null)
{
if (gameObject.transform.parent == null)
{
Debug.LogError("The selected GameObject has no parent.");
PlaceParentOnTap = false;
}
else
{
Debug.LogError("No parent specified. Using immediate parent instead: " + gameObject.transform.parent.gameObject.name);
ParentGameObjectToPlace = gameObject.transform.parent.gameObject;
}
}
}
}
}