VR Development Framework
v 1.0.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Events Pages
AVR_Hand.cs
1 using System.Collections;
2 using System.Collections.Generic;
3 using UnityEngine;
4 
5 namespace AVR.Phys {
6  /// <summary>
7  /// Interactive hand model that adapts itself to grabbed objects. Only works with Offset- or AdvancedOffset- GrabProviders.
8  /// </summary>
9  [AVR.Core.Attributes.DocumentationUrl("class_a_v_r_1_1_phys_1_1_a_v_r___hand.html")]
10  public class AVR_Hand : AVR.Core.AVR_ControllerComponent
11  {
12  // For fingers:
13  public List<AVR_Finger> fingers = new List<AVR_Finger>();
14  public Animator animator;
15  public Transform index_tip, middle_tip, ring_tip, pinky_tip, thumb_tip;
16  public float delta = 0.05f;
17 
18  // For hand
19  public Transform glove_transform;
20  private Transform fake_parent;
21  private Vector3 def_pos;
22  private Quaternion def_rot;
23  private Transform handControllerTransform;
24 
25  public bool hand_colliders;
26  public bool physical_hand;
27  public Rigidbody physical_hand_rb;
28 
29  public List<Collider> colliders = new List<Collider>();
30 
31  // Where Hand is drawn/rendered
32  public Transform HandVisualTransform() {
33  return glove_transform;
34  }
35 
36  // Position HandVisual *should* be, or strive towards
37  public Transform HandControllerTransform() {
38  return handControllerTransform;
39  }
40 
41  // Where the actual VR Controller itself is
42  public Transform ControllerTransform() {
43  return controller.transform;
44  }
45 
46  public void disableColliders() {
47  foreach(Collider c in colliders) c.enabled = false;
48  }
49 
50  public void enableColliders()
51  {
52  foreach (Collider c in colliders) c.enabled = true;
53  }
54 
55  protected override void Start()
56  {
57  fingers.Add(new AVR_Finger(index_tip, 1, "Proc_IndexFinger", animator));
58  fingers.Add(new AVR_Finger(middle_tip, 2, "Proc_MiddleFinger", animator));
59  fingers.Add(new AVR_Finger(ring_tip, 3, "Proc_RingFinger", animator));
60  fingers.Add(new AVR_Finger(pinky_tip, 4, "Proc_PinkyFinger", animator));
61  fingers.Add(new AVR_Finger(thumb_tip, 5, "Proc_ThumbFinger", animator));
62  colliders.AddRange(GetComponentsInChildren<Collider>());
63  if(!hand_colliders) {
64  foreach(Collider c in colliders) {
65  Destroy(c);
66  }
67  colliders.Clear();
68  }
69 
70  if(physical_hand && !physical_hand_rb) {
71  physical_hand_rb = GetComponent<Rigidbody>();
72  }
73 
74  handControllerTransform = new GameObject("handControllerTransform").transform;
75  handControllerTransform.SetParent(ControllerTransform());
76  handControllerTransform.position = HandVisualTransform().position;
77  handControllerTransform.rotation = HandVisualTransform().rotation;
78  def_pos = HandVisualTransform().localPosition;
79  def_rot = HandVisualTransform().localRotation;
80  //fingers.Add(new AVR_Finger(index_tip, 1, "Proc_IndexFinger", animator));
81  //fingers.Add(new AVR_Finger(middle_tip, 2, "Proc_MiddleFinger", animator));
82  //fingers.Add(new AVR_Finger(ring_tip, 3, "Proc_RingFinger", animator));
83  //fingers.Add(new AVR_Finger(pinky_tip, 4, "Proc_PinkyFinger", animator));
84  //fingers.Add(new AVR_Finger(thumb_tip, 5, "Proc_ThumbFinger", animator));
85 
86  foreach (AVR_Finger f in fingers) f.Calibrate(HandVisualTransform(), delta);
87  }
88 
89  public void ApplyNodePose(AVR_GrabNode node) {
90  fingers[0].setStateImmediate(node.index_pose);
91  fingers[0].setWeightImmediate(1.0f);
92  fingers[1].setStateImmediate(node.middle_pose);
93  fingers[1].setWeightImmediate(1.0f);
94  fingers[2].setStateImmediate(node.ring_pose);
95  fingers[2].setWeightImmediate(1.0f);
96  fingers[3].setStateImmediate(node.pinky_pose);
97  fingers[3].setWeightImmediate(1.0f);
98  fingers[4].setStateImmediate(node.thumb_pose);
99  fingers[4].setWeightImmediate(1.0f);
100  }
101 
102  public void SqueezeOn(Collider collider) {
103  foreach (AVR_Finger f in fingers) f.SqueezeOn(HandVisualTransform(), collider);
104  }
105 
106  public void SqueezeOn(Collider collider, Vector3 collider_offset) {
107  collider.transform.position += collider_offset;
108  SqueezeOn(collider);
109  collider.transform.position -= collider_offset;
110  }
111 
112  public void SqueezeOn(AVR_Grabbable g)
113  {
114  foreach (AVR_Finger f in fingers) f.SqueezeOn(HandVisualTransform(), g.colliders);
115  }
116 
117  public void SqueezeOn(AVR_Grabbable g, Vector3 grabbable_offset)
118  {
119  g.transform.position += grabbable_offset;
120  SqueezeOn(g);
121  g.transform.position -= grabbable_offset;
122  }
123 
124  public void Relax() {
125  SetSqueezeWeight(0.0f);
126  }
127 
128  public void SetSqueezeWeight(float w) {
129  foreach (AVR_Finger f in fingers) f.setWeight(w);
130  }
131 
132  void Update() {
133 #if AVR_NET
134  if (IsOnline && !IsOwner) return;
135 #endif
136  foreach (AVR_Finger f in fingers) f.Update();
137  }
138 
139  void LateUpdate() {
140 #if AVR_NET
141  if (IsOnline && !IsOwner) return;
142 #endif
143  if (fake_parent!=null) {
144  HandVisualTransform().position = fake_parent.position;
145  HandVisualTransform().rotation = fake_parent.rotation;
146  }
147  }
148 
149  void FixedUpdate() {
150 #if AVR_NET
151  if (IsOnline && !IsOwner) return;
152 #endif
153  if (fake_parent==null && physical_hand) {
154  //TODO: Make HandVisualTransform() follow ControllerTransform() as if it was a grabbed object
155  //pos
156  Vector3 pDelta = (HandControllerTransform().position - HandVisualTransform().position);
157  Vector3 vel = pDelta / Time.fixedDeltaTime;
158 
159  physical_hand_rb.velocity = vel;
160 
161  //ang
162  Quaternion rotationDelta = HandControllerTransform().rotation * Quaternion.Inverse(HandVisualTransform().rotation);
163 
164  rotationDelta.ToAngleAxis(out float angle, out Vector3 axis);
165  while (angle > 180) angle -= 360; // Prevent object from doing sudden >180° turns instead of negative <180° ones
166 
167  physical_hand_rb.maxAngularVelocity = 99999.0f;
168 
169  Vector3 angvel = (angle * axis * Mathf.Deg2Rad) / Time.fixedDeltaTime;
170  if (!float.IsNaN(angvel.z)) physical_hand_rb.angularVelocity = angvel;
171  }
172  else {
173 
174  }
175  }
176 
177  public void SetFakeParent(Transform fp) {
178  def_pos = HandVisualTransform().localPosition;
179  def_rot = HandVisualTransform().localRotation;
180  fake_parent = new GameObject("DummyParent").transform;
181  fake_parent.position = HandVisualTransform().position;
182  fake_parent.rotation = HandVisualTransform().rotation;
183  fake_parent.SetParent(fp);
184  }
185 
186  public void UnsetFakeParent() {
187  if(fake_parent==null) return;
188  HandVisualTransform().localPosition = def_pos;
189  HandVisualTransform().localRotation = def_rot;
190  GameObject.Destroy(fake_parent.gameObject);
191  fake_parent = null;
192  }
193 
194  public class AVR_Finger
195  {
196  public Animator animator;
197 
198  public List<Vector3> positions;
199  public Transform tip;
200  public int layer;
201  public string AnimationState;
202 
203  private float state;
204  private float weigth;
205 
206  private float delta;
207 
208  private float state_target;
209  private float weigth_target;
210 
211  public AVR_Finger(Transform tip, int layer, string AnimationState, Animator anim)
212  {
213  this.animator = anim;
214  this.tip = tip;
215  this.layer = layer;
216  this.AnimationState = AnimationState;
217  this.positions = new List<Vector3>();
218  }
219 
220  public void setStateImmediate(float state)
221  {
222  this.state_target = this.state = state;
223  animator.Play(this.AnimationState, this.layer, state);
224  animator.Update(0.0f);
225  }
226 
227  public void setState(float state)
228  {
229  state_target = state;
230  }
231 
232  public void setWeightImmediate(float w)
233  {
234  this.weigth_target = this.weigth = w;
235  animator.SetLayerWeight(this.layer, w);
236  animator.Update(0.0f);
237  }
238 
239  public void setWeight(float w)
240  {
241  weigth_target = w;
242  }
243 
244  public void Update()
245  {
246  this.weigth = Mathf.Lerp(this.weigth, this.weigth_target, 10f * Time.deltaTime);
247  animator.SetLayerWeight(this.layer, this.weigth);
248 
249  this.state = Mathf.Lerp(this.state, this.state_target, 10f * Time.deltaTime);
250  animator.Play(this.AnimationState, this.layer, this.state);
251  }
252 
253  public void Calibrate(Transform handVisualTransform, float delta)
254  {
255  this.delta = delta;
256  this.setWeightImmediate(1.0f);
257  animator.speed = 0.0f;
258 
259  for (float i = 0.0f; i <= 1.0f; i += delta)
260  {
261  this.setStateImmediate(i);
262 
263  this.positions.Add(handVisualTransform.InverseTransformPoint(this.tip.position));
264 
265  //Debug.DrawLine(handVisualTransform.position, this.tip.position, Color.white, 10.0f);
266  }
267  this.setWeightImmediate(0.0f);
268  }
269 
270  public void SqueezeOn(Transform handVisualTransform, Collider coll) {
271  int i;
272  for (i = 0; i < this.positions.Count; i++)
273  {
274  Vector3 pos = handVisualTransform.TransformPoint(this.positions[i]);
275  if (ColliderContains(coll, pos)) break;
276  }
277  float offset = Mathf.Clamp(-0.5f * delta + (float)(i) / (float)this.positions.Count, 0.0f, 1.0f);
278  this.setState(offset);
279  this.setWeight(1.0f);
280  }
281 
282  public void SqueezeOn(Transform handVisualTransform, List<Collider> colls)
283  {
284  if(colls.Count<1) return;
285  if(colls.Count==1) this.SqueezeOn(handVisualTransform, colls[0]);
286 
287  int i;
288  for (i = 0; i < this.positions.Count; i++)
289  {
290  Vector3 pos = handVisualTransform.TransformPoint(this.positions[i]);
291  if (ColliderContains(colls[0], pos)) break;
292  }
293 
294  if(i>=positions.Count) i--; // Fix: i could be = posiitons.count leading to an out-of-array in the next step.
295 
296  // For each of the other colliders (beyond the first one) un-squeeze the finger until it is no longer inside
297  for(int j=1; j<colls.Count; j++) {
298  while(i>0 && ColliderContains(colls[j], handVisualTransform.TransformPoint(this.positions[i]))) i--;
299  }
300 
301  float offset = Mathf.Clamp((float)(i) / (float)this.positions.Count, 0.0f, 1.0f);
302  this.setState(offset);
303  this.setWeight(1.0f);
304  }
305  }
306 
307  //TODO: Helper method, consider moving it somewhere else, if used elsewhere
308  protected static bool ColliderContains(Collider c, Vector3 pos) {
309  return Vector3.Distance(pos, c.ClosestPoint(pos)) < 0.001f;
310  }
311  }
312 }
Transform thumb_tip
Definition: AVR_Hand.cs:15
void SqueezeOn(Collider collider)
Definition: AVR_Hand.cs:102
void disableColliders()
Definition: AVR_Hand.cs:46
Transform HandControllerTransform()
Definition: AVR_Hand.cs:37
Transform ControllerTransform()
Definition: AVR_Hand.cs:42
Rigidbody physical_hand_rb
Definition: AVR_Hand.cs:27
void UnsetFakeParent()
Definition: AVR_Hand.cs:186
void SqueezeOn(AVR_Grabbable g)
Definition: AVR_Hand.cs:112
void ApplyNodePose(AVR_GrabNode node)
Definition: AVR_Hand.cs:89
Represents a grabbable object.
Transform HandVisualTransform()
Definition: AVR_Hand.cs:32
void SetSqueezeWeight(float w)
Definition: AVR_Hand.cs:128
void SqueezeOn(Collider collider, Vector3 collider_offset)
Definition: AVR_Hand.cs:106
void setWeightImmediate(float w)
Definition: AVR_Hand.cs:232
void LateUpdate()
Definition: AVR_Hand.cs:139
Sets the documentation html file inside of Packages/com.avr.core/Documentation/html of a given class...
void FixedUpdate()
Definition: AVR_Hand.cs:149
void SetFakeParent(Transform fp)
Definition: AVR_Hand.cs:177
void SqueezeOn(Transform handVisualTransform, Collider coll)
Definition: AVR_Hand.cs:270
void SqueezeOn(AVR_Grabbable g, Vector3 grabbable_offset)
Definition: AVR_Hand.cs:117
List< Vector3 > positions
Definition: AVR_Hand.cs:198
Transform glove_transform
Definition: AVR_Hand.cs:19
Quaternion def_rot
Definition: AVR_Hand.cs:22
override void Start()
Definition: AVR_Hand.cs:55
void enableColliders()
Definition: AVR_Hand.cs:50
Represents a grabbable node on an AVR_Grabbable. Nodes have preset poses/constraints for the hand tha...
Definition: AVR_GrabNode.cs:15
AVR_Finger(Transform tip, int layer, string AnimationState, Animator anim)
Definition: AVR_Hand.cs:211
Transform handControllerTransform
Definition: AVR_Hand.cs:23
void SqueezeOn(Transform handVisualTransform, List< Collider > colls)
Definition: AVR_Hand.cs:282
Transform fake_parent
Definition: AVR_Hand.cs:20
Interactive hand model that adapts itself to grabbed objects. Only works with Offset- or AdvancedOffs...
Definition: AVR_Hand.cs:10
Animator animator
Definition: AVR_Hand.cs:14
void setState(float state)
Definition: AVR_Hand.cs:227
bool physical_hand
Definition: AVR_Hand.cs:26
void setStateImmediate(float state)
Definition: AVR_Hand.cs:220
void Calibrate(Transform handVisualTransform, float delta)
Definition: AVR_Hand.cs:253
static bool ColliderContains(Collider c, Vector3 pos)
Definition: AVR_Hand.cs:308
bool hand_colliders
Definition: AVR_Hand.cs:25
Vector3 def_pos
Definition: AVR_Hand.cs:21