프로젝트

일반

사용자정보

통계
| 개정판:

t1 / TFDContents / Assets / KinectScripts / AvatarController.cs @ 3

이력 | 보기 | 이력해설 | 다운로드 (52.5 KB)

1
using UnityEngine;
2
//using Windows.Kinect;
3

    
4
using System;
5
using System.Collections;
6
using System.Collections.Generic;
7
using System.Runtime.InteropServices;
8
using System.IO;
9
using System.Text; 
10

    
11

    
12
/// <summary>
13
/// Avatar controller is the component that transfers the captured user motion to a humanoid model (avatar).
14
/// </summary>
15
[RequireComponent(typeof(Animator))]
16
public class AvatarController : MonoBehaviour
17
{	
18
	[Tooltip("Index of the player, tracked by this component. 0 means the 1st player, 1 - the 2nd one, 2 - the 3rd one, etc.")]
19
	public int playerIndex = 0;
20
	
21
	[Tooltip("Whether the avatar is facing the player or not.")]
22
	public bool mirroredMovement = false;
23
	
24
	[Tooltip("Whether the avatar is allowed to move vertically or not.")]
25
	public bool verticalMovement = false;
26

    
27
	[Tooltip("Whether the avatar's root motion is applied by other component or script.")]
28
	public bool externalRootMotion = false;
29

    
30
    [Tooltip("Whether the head rotation is controlled externally (e.g. by VR-headset)" )]
31
    public bool externalHeadRotation = false;
32
	
33
	[Tooltip("Whether the finger orientations are allowed or not.")]
34
	public bool fingerOrientations = false;
35
	
36
	[Tooltip("Rate at which the avatar will move through the scene.")]
37
	public float moveRate = 1f;
38
	
39
	[Tooltip("Smooth factor used for avatar movements and joint rotations.")]
40
	public float smoothFactor = 10f;
41
	
42
	[Tooltip("Game object this transform is relative to (optional).")]
43
	public GameObject offsetNode;
44

    
45
	[Tooltip("If enabled, makes the avatar position relative to this camera to be the same as the player's position to the sensor.")]
46
	public Camera posRelativeToCamera;
47

    
48
	[Tooltip("Whether the avatar's position should match the color image (in Pos-rel-to-camera mode only).")]
49
	public bool posRelOverlayColor = false;
50
	
51
	[Tooltip("Whether z-axis movement needs to be inverted (Pos-Relative mode only).")]
52
	public bool posRelInvertedZ = false;
53
	
54
	[Tooltip("Whether the avatar's feet must stick to the ground.")]
55
	public bool groundedFeet = false;
56

    
57
	[Tooltip("Whether to apply the humanoid muscle limits or not.")]
58
	public bool applyMuscleLimits = false;
59

    
60
	[Tooltip("Whether to flip left and right, relative to the sensor.")]
61
	public bool flipLeftRight = false;
62

    
63

    
64
	[Tooltip("Vertical offset of the avatar with respect to the position of user's spine-base.")]
65
	[Range(-0.5f, 0.5f)]
66
	public float verticalOffset = 0f;
67

    
68
	[Tooltip("Forward (Z) offset of the avatar with respect to the position of user's spine-base.")]
69
	[Range(-0.5f, 0.5f)]
70
	public float forwardOffset = 0f;
71

    
72
	// userId of the player
73
	[NonSerialized]
74
	public Int64 playerId = 0;
75

    
76

    
77
	// The body root node
78
	protected Transform bodyRoot;
79

    
80
	// Variable to hold all them bones. It will initialize the same size as initialRotations.
81
	protected Transform[] bones;
82
	
83
	// Rotations of the bones when the Kinect tracking starts.
84
	protected Quaternion[] initialRotations;
85
	protected Quaternion[] localRotations;
86
	protected bool[] isBoneDisabled;
87

    
88
	// Local rotations of finger bones
89
	protected Dictionary<HumanBodyBones, Quaternion> fingerBoneLocalRotations = new Dictionary<HumanBodyBones, Quaternion>();
90
	protected Dictionary<HumanBodyBones, Vector3> fingerBoneLocalAxes = new Dictionary<HumanBodyBones, Vector3>();
91

    
92
	// Initial position and rotation of the transform
93
	protected Vector3 initialPosition;
94
	protected Quaternion initialRotation;
95
	protected Vector3 initialHipsPosition;
96
	protected Quaternion initialHipsRotation;
97

    
98
	protected Vector3 offsetNodePos;
99
	protected Quaternion offsetNodeRot;
100
	protected Vector3 bodyRootPosition;
101
	
102
	// Calibration Offset Variables for Character Position.
103
	[NonSerialized]
104
	public bool offsetCalibrated = false;
105
	protected Vector3 offsetPos = Vector3.zero;
106
	//protected float xOffset, yOffset, zOffset;
107
	//private Quaternion originalRotation;
108

    
109
	private Animator animatorComponent = null;
110
	private HumanPoseHandler humanPoseHandler = null;
111
	private HumanPose humanPose = new HumanPose();
112

    
113
	// whether the parent transform obeys physics
114
	protected bool isRigidBody = false;
115
	
116
	// private instance of the KinectManager
117
	protected KinectManager kinectManager;
118

    
119
	// last hand events
120
	private InteractionManager.HandEventType lastLeftHandEvent = InteractionManager.HandEventType.Release;
121
	private InteractionManager.HandEventType lastRightHandEvent = InteractionManager.HandEventType.Release;
122

    
123
	// fist states
124
	private bool bLeftFistDone = false;
125
	private bool bRightFistDone = false;
126

    
127
	// grounder constants and variables
128
	private const int raycastLayers = ~2;  // Ignore Raycast
129
	private const float maxFootDistanceGround = 0.02f;  // maximum distance from lower foot to the ground
130
	private const float maxFootDistanceTime = 0.2f; // 1.0f;  // maximum allowed time, the lower foot to be distant from the ground
131
	private Transform leftFoot, rightFoot;
132

    
133
	private float fFootDistanceInitial = 0f;
134
	private float fFootDistance = 0f;
135
	private float fFootDistanceTime = 0f;
136

    
137

    
138
	/// <summary>
139
	/// Gets the number of bone transforms (array length).
140
	/// </summary>
141
	/// <returns>The number of bone transforms.</returns>
142
	public int GetBoneTransformCount()
143
	{
144
		return bones != null ? bones.Length : 0;
145
	}
146

    
147
	/// <summary>
148
	/// Gets the bone transform by index.
149
	/// </summary>
150
	/// <returns>The bone transform.</returns>
151
	/// <param name="index">Index</param>
152
	public Transform GetBoneTransform(int index)
153
	{
154
		if(index >= 0 && index < bones.Length)
155
		{
156
			return bones[index];
157
		}
158

    
159
		return null;
160
	}
161

    
162
    /// <summary>
163
    /// Get joint position with respect of player world and kinect offsets   ( //!!still some problems with accurate Y pos, probably connected with kinect sensor height estimation ) 
164
    /// </summary>
165
    /// <param name="jointType"></param>
166
    /// <returns></returns>
167
    public Vector3 GetJointWorldPos( KinectInterop.JointType jointType )
168
    {
169
        if( !kinectManager )
170
        {
171
            return Vector3.zero;
172
        }
173
        
174
        Vector3 jointPosition = kinectManager.GetJointPosition( playerId, (int)jointType );
175
        Vector3 worldPosition = new Vector3(
176
            jointPosition.x - offsetPos.x, 
177
//            jointPosition.y - offsetPos.y + kinectManager.sensorHeight,  //!! this should be better investigated .. 
178
            jointPosition.y + offsetPos.y - kinectManager.sensorHeight,  //!! this workds better on my example 
179
            !mirroredMovement && !posRelativeToCamera ? (-jointPosition.z - offsetPos.z) : (jointPosition.z - offsetPos.z));
180

    
181
        Quaternion posRotation = mirroredMovement ? Quaternion.Euler (0f, 180f, 0f) * initialRotation : initialRotation;
182
        worldPosition = posRotation * worldPosition;
183

    
184
        return bodyRootPosition + worldPosition;
185
    }
186

    
187
	/// <summary>
188
	/// Disables the bone and optionally resets its orientation.
189
	/// </summary>
190
	/// <param name="index">Bone index.</param>
191
	/// <param name="resetBone">If set to <c>true</c> resets bone orientation.</param>
192
	public void DisableBone(int index, bool resetBone)
193
	{
194
		if(index >= 0 && index < bones.Length)
195
		{
196
			isBoneDisabled[index] = true;
197

    
198
			if (resetBone && bones[index] != null) 
199
			{
200
				bones[index].rotation = localRotations[index];
201
			}
202
		}
203
	}
204

    
205
	/// <summary>
206
	/// Enables the bone, so AvatarController could update its orientation.
207
	/// </summary>
208
	/// <param name="index">Bone index.</param>
209
	public void EnableBone(int index)
210
	{
211
		if(index >= 0 && index < bones.Length)
212
		{
213
			isBoneDisabled[index] = false;
214
		}
215
	}
216

    
217
	/// <summary>
218
	/// Determines whether the bone orientation update is enabled or not.
219
	/// </summary>
220
	/// <returns><c>true</c> if the bone update is enabled; otherwise, <c>false</c>.</returns>
221
	/// <param name="index">Bone index.</param>
222
	public bool IsBoneEnabled(int index)
223
	{
224
		if(index >= 0 && index < bones.Length)
225
		{
226
			return !isBoneDisabled[index];
227
		}
228

    
229
		return false;
230
	}
231

    
232
	/// <summary>
233
	/// Gets the bone index by joint type.
234
	/// </summary>
235
	/// <returns>The bone index.</returns>
236
	/// <param name="joint">Joint type</param>
237
	/// <param name="bMirrored">If set to <c>true</c> gets the mirrored joint index.</param>
238
	public int GetBoneIndexByJoint(KinectInterop.JointType joint, bool bMirrored)
239
	{
240
		int boneIndex = -1;
241
		
242
		if(jointMap2boneIndex.ContainsKey(joint))
243
		{
244
			boneIndex = !bMirrored ? jointMap2boneIndex[joint] : mirrorJointMap2boneIndex[joint];
245
		}
246
		
247
		return boneIndex;
248
	}
249
	
250
	/// <summary>
251
	/// Gets the special index by two joint types.
252
	/// </summary>
253
	/// <returns>The spec index by joint.</returns>
254
	/// <param name="joint1">Joint 1 type.</param>
255
	/// <param name="joint2">Joint 2 type.</param>
256
	/// <param name="bMirrored">If set to <c>true</c> gets the mirrored joint index.</param>
257
	public int GetSpecIndexByJoint(KinectInterop.JointType joint1, KinectInterop.JointType joint2, bool bMirrored)
258
	{
259
		int boneIndex = -1;
260
		
261
		if((joint1 == KinectInterop.JointType.ShoulderLeft && joint2 == KinectInterop.JointType.SpineShoulder) ||
262
		   (joint2 == KinectInterop.JointType.ShoulderLeft && joint1 == KinectInterop.JointType.SpineShoulder))
263
		{
264
			return (!bMirrored ? 25 : 26);
265
		}
266
		else if((joint1 == KinectInterop.JointType.ShoulderRight && joint2 == KinectInterop.JointType.SpineShoulder) ||
267
		        (joint2 == KinectInterop.JointType.ShoulderRight && joint1 == KinectInterop.JointType.SpineShoulder))
268
		{
269
			return (!bMirrored ? 26 : 25);
270
		}
271
		else if((joint1 == KinectInterop.JointType.HandTipLeft && joint2 == KinectInterop.JointType.HandLeft) ||
272
		        (joint2 == KinectInterop.JointType.HandTipLeft && joint1 == KinectInterop.JointType.HandLeft))
273
		{
274
			return (!bMirrored ? 27 : 28);
275
		}
276
		else if((joint1 == KinectInterop.JointType.HandTipRight && joint2 == KinectInterop.JointType.HandRight) ||
277
		        (joint2 == KinectInterop.JointType.HandTipRight && joint1 == KinectInterop.JointType.HandRight))
278
		{
279
			return (!bMirrored ? 28 : 27);
280
		}
281
		else if((joint1 == KinectInterop.JointType.ThumbLeft && joint2 == KinectInterop.JointType.HandLeft) ||
282
		        (joint2 == KinectInterop.JointType.ThumbLeft && joint1 == KinectInterop.JointType.HandLeft))
283
		{
284
			return (!bMirrored ? 29 : 30);
285
		}
286
		else if((joint1 == KinectInterop.JointType.ThumbRight && joint2 == KinectInterop.JointType.HandRight) ||
287
		        (joint2 == KinectInterop.JointType.ThumbRight && joint1 == KinectInterop.JointType.HandRight))
288
		{
289
			return (!bMirrored ? 30 : 29);
290
		}
291

    
292
		return boneIndex;
293
	}
294
	
295
	
296
	// transform caching gives performance boost since Unity calls GetComponent<Transform>() each time you call transform 
297
	private Transform _transformCache;
298
	public new Transform transform
299
	{
300
		get
301
		{
302
			if (!_transformCache) 
303
			{
304
				_transformCache = base.transform;
305
			}
306

    
307
			return _transformCache;
308
		}
309
	}
310

    
311

    
312
	public void Awake()
313
    {	
314
		// check for double start
315
		if(bones != null)
316
			return;
317
		if(!gameObject.activeInHierarchy) 
318
			return;
319

    
320
		// inits the bones array
321
		bones = new Transform[31];
322
		
323
		// get the animator reference
324
		animatorComponent = GetComponent<Animator>();
325

    
326
		// Map bones to the points the Kinect tracks
327
		MapBones();
328

    
329
		// Set model's arms to be in T-pose, if needed
330
		SetModelArmsInTpose();
331

    
332
		// Initial rotations and directions of the bones.
333
		initialRotations = new Quaternion[bones.Length];
334
		localRotations = new Quaternion[bones.Length];
335
		isBoneDisabled = new bool[bones.Length];
336

    
337
		// Get initial bone rotations
338
		GetInitialRotations();
339

    
340
		// enable all bones
341
		for(int i = 0; i < bones.Length; i++)
342
		{
343
			isBoneDisabled[i] = false;
344
		}
345

    
346
		// get initial distance to ground
347
		fFootDistanceInitial = GetDistanceToGround();
348
		fFootDistance = 0f;
349
		fFootDistanceTime = 0f;
350

    
351
		// if parent transform uses physics
352
		isRigidBody = (gameObject.GetComponent<Rigidbody>() != null);
353

    
354
		// get the pose handler reference
355
		if (animatorComponent && animatorComponent.avatar && animatorComponent.avatar.isHuman) 
356
		{
357
			//Transform hipsTransform = animator.GetBoneTransform(HumanBodyBones.Hips);
358
			//Transform rootTransform = hipsTransform.parent;
359
			Transform rootTransform = transform;
360

    
361
			humanPoseHandler = new HumanPoseHandler(animatorComponent.avatar, rootTransform);
362
			humanPoseHandler.GetHumanPose(ref humanPose);
363
		}
364
	}
365

    
366

    
367
	// applies the muscle limits for humanoid avatar
368
	private void CheckMuscleLimits()
369
	{
370
		if (humanPoseHandler == null)
371
			return;
372

    
373
		humanPoseHandler.GetHumanPose(ref humanPose);
374

    
375
		//Debug.Log(playerId + " - Trans: " + transform.position + ", body: " + humanPose.bodyPosition);
376

    
377
		bool isPoseChanged = false;
378

    
379
		float muscleMin = -1f;
380
		float muscleMax = 1f;
381

    
382
		for (int i = 0; i < humanPose.muscles.Length; i++) 
383
		{
384
			if (float.IsNaN(humanPose.muscles[i])) 
385
			{
386
				//humanPose.muscles[i] = 0f;
387
				continue;
388
			}
389

    
390
			if (humanPose.muscles[i] < muscleMin) 
391
			{
392
				humanPose.muscles[i] = muscleMin;
393
				isPoseChanged = true;
394
			}
395
			else if (humanPose.muscles[i] > muscleMax) 
396
			{
397
				humanPose.muscles[i] = muscleMax;
398
				isPoseChanged = true;
399
			}
400
		}
401

    
402
		if (isPoseChanged) 
403
		{
404
			Quaternion localBodyRot = Quaternion.Inverse(transform.rotation) * humanPose.bodyRotation;
405

    
406
			// recover the body position & orientation
407
			//humanPose.bodyPosition = Vector3.zero;
408
			//humanPose.bodyPosition.y = initialHipsPosition.y;
409
			humanPose.bodyPosition = initialHipsPosition;
410
			humanPose.bodyRotation = localBodyRot; // Quaternion.identity;
411

    
412
			humanPoseHandler.SetHumanPose(ref humanPose);
413
			//Debug.Log("  Human pose updated.");
414
		}
415

    
416
	}
417

    
418
	
419
	/// <summary>
420
	/// Updates the avatar each frame.
421
	/// </summary>
422
	/// <param name="UserID">User ID</param>
423
    public void UpdateAvatar(Int64 UserID)
424
    {	
425
		if(!gameObject.activeInHierarchy) 
426
			return;
427

    
428
		// Get the KinectManager instance
429
		if(kinectManager == null)
430
		{
431
			kinectManager = KinectManager.Instance;
432
		}
433
		
434
		// move the avatar to its Kinect position
435
		if(!externalRootMotion)
436
		{
437
			MoveAvatar(UserID);
438
		}
439

    
440
		// get the left hand state and event
441
		if(kinectManager && kinectManager.GetJointTrackingState(UserID, (int)KinectInterop.JointType.HandLeft) != KinectInterop.TrackingState.NotTracked)
442
		{
443
			KinectInterop.HandState leftHandState = kinectManager.GetLeftHandState(UserID);
444
			InteractionManager.HandEventType leftHandEvent = InteractionManager.HandStateToEvent(leftHandState, lastLeftHandEvent);
445

    
446
			if(leftHandEvent != InteractionManager.HandEventType.None)
447
			{
448
				lastLeftHandEvent = leftHandEvent;
449
			}
450
		}
451

    
452
		// get the right hand state and event
453
		if(kinectManager && kinectManager.GetJointTrackingState(UserID, (int)KinectInterop.JointType.HandRight) != KinectInterop.TrackingState.NotTracked)
454
		{
455
			KinectInterop.HandState rightHandState = kinectManager.GetRightHandState(UserID);
456
			InteractionManager.HandEventType rightHandEvent = InteractionManager.HandStateToEvent(rightHandState, lastRightHandEvent);
457
			
458
			if(rightHandEvent != InteractionManager.HandEventType.None)
459
			{
460
				lastRightHandEvent = rightHandEvent;
461
			}
462
		}
463
		
464
		// rotate the avatar bones
465
		for (var boneIndex = 0; boneIndex < bones.Length; boneIndex++)
466
		{
467
			if (!bones[boneIndex] || isBoneDisabled[boneIndex]) 
468
				continue;
469

    
470
			if(boneIndex2JointMap.ContainsKey(boneIndex))
471
			{
472
				KinectInterop.JointType joint = !(mirroredMovement ^ flipLeftRight) ? 
473
					boneIndex2JointMap[boneIndex] : boneIndex2MirrorJointMap[boneIndex];
474
				
475
                if( externalHeadRotation && joint == KinectInterop.JointType.Head )   // skip head if moved externally
476
                {
477
                    continue;
478
                }
479
                
480
				TransformBone(UserID, joint, boneIndex, !(mirroredMovement ^ flipLeftRight));
481
			}
482
			else if(specIndex2JointMap.ContainsKey(boneIndex))
483
			{
484
				// special bones (clavicles)
485
				List<KinectInterop.JointType> alJoints = !(mirroredMovement ^ flipLeftRight) ? 
486
					specIndex2JointMap[boneIndex] : specIndex2MirrorMap[boneIndex];
487

    
488
				if(alJoints.Count >= 2)
489
				{
490
					//Debug.Log(alJoints[0].ToString());
491
					Vector3 baseDir = alJoints[0].ToString().EndsWith("Left") ? Vector3.left : Vector3.right;
492
					TransformSpecialBone(UserID, alJoints[0], alJoints[1], boneIndex, baseDir, !(mirroredMovement ^ flipLeftRight));
493
				}
494
			}
495
		}
496

    
497
		if (applyMuscleLimits && kinectManager && kinectManager.IsUserTracked(UserID)) 
498
		{
499
			// check for limits
500
			CheckMuscleLimits();
501
		}
502
	}
503
	
504
	/// <summary>
505
	/// Resets bones to their initial positions and rotations. This also releases avatar control from KM, by settings playerId to 0 
506
	/// </summary>
507
	public virtual void ResetToInitialPosition()
508
	{
509
		playerId = 0;
510

    
511
		if(bones == null)
512
			return;
513
		
514
		// For each bone that was defined, reset to initial position.
515
		transform.rotation = Quaternion.identity;
516

    
517
		for(int pass = 0; pass < 2; pass++)  // 2 passes because clavicles are at the end
518
		{
519
			for(int i = 0; i < bones.Length; i++)
520
			{
521
				if(bones[i] != null)
522
				{
523
					bones[i].rotation = initialRotations[i];
524
				}
525
			}
526
		}
527

    
528
		// reset finger bones to initial position
529
		//Animator animatorComponent = GetComponent<Animator>();
530
		foreach(HumanBodyBones bone in fingerBoneLocalRotations.Keys)
531
		{
532
			Transform boneTransform = animatorComponent ? animatorComponent.GetBoneTransform(bone) : null;
533
			
534
			if(boneTransform)
535
			{
536
				boneTransform.localRotation = fingerBoneLocalRotations[bone];
537
			}
538
		}
539

    
540
//		if(bodyRoot != null)
541
//		{
542
//			bodyRoot.localPosition = Vector3.zero;
543
//			bodyRoot.localRotation = Quaternion.identity;
544
//		}
545

    
546
		// Restore the offset's position and rotation
547
		if(offsetNode != null)
548
		{
549
			offsetNode.transform.position = offsetNodePos;
550
			offsetNode.transform.rotation = offsetNodeRot;
551
		}
552

    
553
		transform.position = initialPosition;
554
		transform.rotation = initialRotation;
555

    
556
		if (bones[0]) 
557
		{
558
			bones[0].localPosition = initialHipsPosition;
559
			bones[0].localRotation = initialHipsRotation;
560
		}
561
    }
562
	
563
	/// <summary>
564
	/// Invoked on the successful calibration of the player.
565
	/// </summary>
566
	/// <param name="userId">User identifier.</param>
567
	public virtual void SuccessfulCalibration(Int64 userId, bool resetInitialTransform)
568
	{
569
		playerId = userId;
570

    
571
		// reset the models position
572
		if(offsetNode != null)
573
		{
574
			offsetNode.transform.position = offsetNodePos;
575
			offsetNode.transform.rotation = offsetNodeRot;
576
		}
577
		
578
        // reset initial position / rotation if needed 
579
        if(resetInitialTransform)
580
        {
581
            bodyRootPosition = transform.position;
582
            initialPosition = transform.position;
583
            initialRotation = transform.rotation;
584
        }
585

    
586
		transform.position = initialPosition;
587
		transform.rotation = initialRotation;
588

    
589
//		// enable all bones
590
//		for(int i = 0; i < bones.Length; i++)
591
//		{
592
//			isBoneDisabled[i] = false;
593
//		}
594

    
595
		// re-calibrate the position offset
596
		offsetCalibrated = false;
597
	}
598

    
599
    /// <summary>
600
    /// Moves the avatar to its initial/base position 
601
    /// </summary>
602
    /// <param name="position"> world position </param>
603
    /// <param name="rotation"> rotation offset </param>
604
    public void resetInitialTransform( Vector3 position, Vector3 rotation )
605
    {
606
        bodyRootPosition = position;
607
        initialPosition = position;
608
        initialRotation = Quaternion.Euler( rotation );
609
        
610
        transform.position = initialPosition;
611
        transform.rotation = initialRotation;
612
        
613
        offsetCalibrated = false;       // this cause also calibrating kinect offset in moveAvatar function 
614
    }
615
	
616
	// Apply the rotations tracked by kinect to the joints.
617
	protected void TransformBone(Int64 userId, KinectInterop.JointType joint, int boneIndex, bool flip)
618
    {
619
		Transform boneTransform = bones[boneIndex];
620
		if(boneTransform == null || kinectManager == null)
621
			return;
622
		
623
		int iJoint = (int)joint;
624
		if(iJoint < 0 || !kinectManager.IsJointTracked(userId, iJoint))
625
			return;
626
		
627
		// Get Kinect joint orientation
628
		Quaternion jointRotation = kinectManager.GetJointOrientation(userId, iJoint, flip);
629
		if(jointRotation == Quaternion.identity)
630
			return;
631

    
632
		// calculate the new orientation
633
		Quaternion newRotation = Kinect2AvatarRot(jointRotation, boneIndex);
634

    
635
		if(externalRootMotion)
636
		{
637
			newRotation = transform.rotation * newRotation;
638
		}
639

    
640
		// Smoothly transition to the new rotation
641
		if(smoothFactor != 0f)
642
        	boneTransform.rotation = Quaternion.Slerp(boneTransform.rotation, newRotation, smoothFactor * Time.deltaTime);
643
		else
644
			boneTransform.rotation = newRotation;
645
	}
646
	
647
	// Apply the rotations tracked by kinect to a special joint
648
	protected void TransformSpecialBone(Int64 userId, KinectInterop.JointType joint, KinectInterop.JointType jointParent, int boneIndex, Vector3 baseDir, bool flip)
649
	{
650
		Transform boneTransform = bones[boneIndex];
651
		if(boneTransform == null || kinectManager == null)
652
			return;
653
		
654
		if(!kinectManager.IsJointTracked(userId, (int)joint) || 
655
		   !kinectManager.IsJointTracked(userId, (int)jointParent))
656
		{
657
			return;
658
		}
659

    
660
		if(boneIndex >= 27 && boneIndex <= 30)
661
		{
662
			// fingers or thumbs
663
			if(fingerOrientations)
664
			{
665
				TransformSpecialBoneFingers(userId, (int)joint, boneIndex, flip);
666
			}
667

    
668
			return;
669
		}
670
		
671
		Vector3 jointDir = kinectManager.GetJointDirection(userId, (int)joint, false, true);
672
		Quaternion jointRotation = jointDir != Vector3.zero ? Quaternion.FromToRotation(baseDir, jointDir) : Quaternion.identity;
673
		
674
		if(!flip)
675
		{
676
			Vector3 mirroredAngles = jointRotation.eulerAngles;
677
			mirroredAngles.y = -mirroredAngles.y;
678
			mirroredAngles.z = -mirroredAngles.z;
679

    
680
			jointRotation = Quaternion.Euler(mirroredAngles);
681
		}
682
		
683
		if(jointRotation != Quaternion.identity)
684
		{
685
			// Smoothly transition to the new rotation
686
			Quaternion newRotation = Kinect2AvatarRot(jointRotation, boneIndex);
687
			
688
			if(externalRootMotion)
689
			{
690
				newRotation = transform.rotation * newRotation;
691
			}
692
			
693
			if(smoothFactor != 0f)
694
				boneTransform.rotation = Quaternion.Slerp(boneTransform.rotation, newRotation, smoothFactor * Time.deltaTime);
695
			else
696
				boneTransform.rotation = newRotation;
697
		}
698
		
699
	}
700

    
701
	// Apply the rotations tracked by kinect to fingers (one joint = multiple bones)
702
	protected void TransformSpecialBoneFingers(Int64 userId, int joint, int boneIndex, bool flip)
703
	{
704
		// check for hand grips
705
		if(joint == (int)KinectInterop.JointType.HandTipLeft || joint == (int)KinectInterop.JointType.ThumbLeft)
706
		{
707
			if(lastLeftHandEvent == InteractionManager.HandEventType.Grip)
708
			{
709
				if(!bLeftFistDone)
710
				{
711
					float angleSign = !mirroredMovement /**(boneIndex == 27 || boneIndex == 29)*/ ? -1f : -1f;
712
					float angleRot = angleSign * 60f;
713
					
714
					TransformSpecialBoneFist(boneIndex, angleRot);
715
					bLeftFistDone = (boneIndex >= 29);
716
				}
717
				
718
				return;
719
			}
720
			else if(bLeftFistDone && lastLeftHandEvent == InteractionManager.HandEventType.Release)
721
			{
722
				TransformSpecialBoneUnfist(boneIndex);
723
				bLeftFistDone = !(boneIndex >= 29);
724
			}
725
		}
726
		else if(joint == (int)KinectInterop.JointType.HandTipRight || joint == (int)KinectInterop.JointType.ThumbRight)
727
		{
728
			if(lastRightHandEvent == InteractionManager.HandEventType.Grip)
729
			{
730
				if(!bRightFistDone)
731
				{
732
					float angleSign = !mirroredMovement /**(boneIndex == 27 || boneIndex == 29)*/ ? -1f : -1f;
733
					float angleRot = angleSign * 60f;
734
					
735
					TransformSpecialBoneFist(boneIndex, angleRot);
736
					bRightFistDone = (boneIndex >= 29);
737
				}
738

    
739
				return;
740
			}
741
			else if(bRightFistDone && lastRightHandEvent == InteractionManager.HandEventType.Release)
742
			{
743
				TransformSpecialBoneUnfist(boneIndex);
744
				bRightFistDone = !(boneIndex >= 29);
745
			}
746
		}
747

    
748
		// get the animator component
749
		//Animator animatorComponent = GetComponent<Animator>();
750
		if(!animatorComponent)
751
			return;
752
		
753
		// Get Kinect joint orientation
754
		Quaternion jointRotation = kinectManager.GetJointOrientation(userId, joint, flip);
755
		if(jointRotation == Quaternion.identity)
756
			return;
757

    
758
		// calculate the new orientation
759
		Quaternion newRotation = Kinect2AvatarRot(jointRotation, boneIndex);
760

    
761
		if(externalRootMotion)
762
		{
763
			newRotation = transform.rotation * newRotation;
764
		}
765

    
766
		// get the list of bones
767
		//List<HumanBodyBones> alBones = flip ? specialIndex2MultiBoneMap[boneIndex] : specialIndex2MirrorBoneMap[boneIndex];
768
		List<HumanBodyBones> alBones = specialIndex2MultiBoneMap[boneIndex];
769
		
770
		// Smoothly transition to the new rotation
771
		for(int i = 0; i < alBones.Count; i++)
772
		{
773
			Transform boneTransform = animatorComponent.GetBoneTransform(alBones[i]);
774
			if(!boneTransform)
775
				continue;
776

    
777
			if(smoothFactor != 0f)
778
				boneTransform.rotation = Quaternion.Slerp(boneTransform.rotation, newRotation, smoothFactor * Time.deltaTime);
779
			else
780
				boneTransform.rotation = newRotation;
781
		}
782
	}
783

    
784
	// Apply the rotations needed to transform fingers to fist
785
	protected void TransformSpecialBoneFist(int boneIndex, float angle)
786
	{
787
//		// do fist only for fingers
788
//		if(boneIndex != 27 && boneIndex != 28)
789
//			return;
790

    
791
		// get the animator component
792
		//Animator animatorComponent = GetComponent<Animator>();
793
		if(!animatorComponent)
794
			return;
795
		
796
		// get the list of bones
797
		List<HumanBodyBones> alBones = specialIndex2MultiBoneMap[boneIndex];
798

    
799
		for(int i = 0; i < alBones.Count; i++)
800
		{
801
			if(i < 1 && (boneIndex == 29 || boneIndex == 30))  // skip the first two thumb bones
802
				continue;
803
			
804
			HumanBodyBones bone = alBones[i];
805
			Transform boneTransform = animatorComponent.GetBoneTransform(bone);
806

    
807
			// set the fist rotation
808
			if(boneTransform && fingerBoneLocalAxes[bone] != Vector3.zero)
809
			{
810
				Quaternion qRotFinger = Quaternion.AngleAxis(angle, fingerBoneLocalAxes[bone]);
811
				boneTransform.localRotation = fingerBoneLocalRotations[bone] * qRotFinger;
812
			}
813
		}
814

    
815
	}
816
	
817
	// Apply the initial rotations fingers
818
	protected void TransformSpecialBoneUnfist(int boneIndex)
819
	{
820
//		// do fist only for fingers
821
//		if(boneIndex != 27 && boneIndex != 28)
822
//			return;
823
		
824
		// get the animator component
825
		//Animator animatorComponent = GetComponent<Animator>();
826
		if(!animatorComponent)
827
			return;
828
		
829
		// get the list of bones
830
		List<HumanBodyBones> alBones = specialIndex2MultiBoneMap[boneIndex];
831
		
832
		for(int i = 0; i < alBones.Count; i++)
833
		{
834
			HumanBodyBones bone = alBones[i];
835
			Transform boneTransform = animatorComponent.GetBoneTransform(bone);
836

    
837
			// set the initial rotation
838
			if(boneTransform)
839
			{
840
				boneTransform.localRotation = fingerBoneLocalRotations[bone];
841
			}
842
		}
843
	}
844
	
845
	// Moves the avatar - gets the tracked position of the user and applies it to avatar.
846
	protected void MoveAvatar(Int64 UserID)
847
	{
848
		if((moveRate == 0f) || !kinectManager ||
849
		   !kinectManager.IsJointTracked(UserID, (int)KinectInterop.JointType.SpineBase))
850
		{
851
			return;
852
		}
853
		
854
		// get the position of user's spine base
855
		Vector3 trans = kinectManager.GetUserPosition(UserID);
856
		if(flipLeftRight)
857
			trans.x = -trans.x;
858

    
859
		// use the color overlay position if needed
860
		if(posRelativeToCamera && posRelOverlayColor)
861
		{
862
			Rect backgroundRect = posRelativeToCamera.pixelRect;
863
			PortraitBackground portraitBack = PortraitBackground.Instance;
864
			
865
			if(portraitBack && portraitBack.enabled)
866
			{
867
				backgroundRect = portraitBack.GetBackgroundRect();
868
			}
869
			
870
			trans = kinectManager.GetJointPosColorOverlay(UserID, (int)KinectInterop.JointType.SpineBase, posRelativeToCamera, backgroundRect);
871
			if(flipLeftRight)
872
				trans.x = -trans.x;
873
		}
874

    
875
		// invert the z-coordinate, if needed
876
		if(posRelativeToCamera && posRelInvertedZ)
877
		{
878
			trans.z = -trans.z;
879
		}
880
		
881
		if(!offsetCalibrated)
882
		{
883
			offsetCalibrated = true;
884
			
885
			offsetPos.x = trans.x;  // !mirroredMovement ? trans.x * moveRate : -trans.x * moveRate;
886
			offsetPos.y = trans.y;  // trans.y * moveRate;
887
			offsetPos.z = !mirroredMovement && !posRelativeToCamera ? -trans.z : trans.z;  // -trans.z * moveRate;
888

    
889
			if(posRelativeToCamera)
890
			{
891
				Vector3 cameraPos = posRelativeToCamera.transform.position;
892
				Vector3 bodyRootPos = bodyRoot != null ? bodyRoot.position : transform.position;
893
				Vector3 hipCenterPos = bodyRoot != null ? bodyRoot.position : (bones != null && bones.Length > 0 && bones[0] != null ? bones[0].position : Vector3.zero);
894

    
895
				float yRelToAvatar = 0f;
896
				if(verticalMovement)
897
				{
898
					yRelToAvatar = (trans.y - cameraPos.y) - (hipCenterPos - bodyRootPos).magnitude;
899
				}
900
				else
901
				{
902
					yRelToAvatar = bodyRootPos.y - cameraPos.y;
903
				}
904

    
905
				Vector3 relativePos = new Vector3(trans.x, yRelToAvatar, trans.z);
906
				Vector3 newBodyRootPos = cameraPos + relativePos;
907

    
908
//				if(offsetNode != null)
909
//				{
910
//					newBodyRootPos += offsetNode.transform.position;
911
//				}
912

    
913
				if(bodyRoot != null)
914
				{
915
					bodyRoot.position = newBodyRootPos;
916
				}
917
				else
918
				{
919
					transform.position = newBodyRootPos;
920
				}
921

    
922
				bodyRootPosition = newBodyRootPos;
923
			}
924
		}
925
	
926
		// transition to the new position
927
		Vector3 targetPos = bodyRootPosition + Kinect2AvatarPos(trans, verticalMovement);
928

    
929
		if(isRigidBody && !verticalMovement)
930
		{
931
			// workaround for obeying the physics (e.g. gravity falling)
932
			targetPos.y = bodyRoot != null ? bodyRoot.position.y : transform.position.y;
933
		}
934

    
935
		if (verticalMovement && verticalOffset != 0f && 
936
			bones[0] != null && bones[3] != null) 
937
		{
938
			Vector3 dirSpine = bones[3].position - bones[0].position;
939
			targetPos += dirSpine.normalized * verticalOffset;
940
		}
941

    
942
		if (forwardOffset != 0f && 
943
			bones[0] != null && bones[3] != null && bones[5] != null && bones[11] != null) 
944
		{
945
			Vector3 dirSpine = (bones[3].position - bones[0].position).normalized;
946
			Vector3 dirShoulders = (bones[11].position - bones[5].position).normalized;
947
			Vector3 dirForward = Vector3.Cross(dirShoulders, dirSpine).normalized;
948

    
949
			targetPos += dirForward * forwardOffset;
950
		}
951

    
952
		if(groundedFeet)
953
		{
954
			// keep the current correction
955
			float fLastTgtY = targetPos.y;
956
			targetPos.y += fFootDistance;
957

    
958
			float fNewDistance = GetDistanceToGround();
959
			float fNewDistanceTime = Time.time;
960

    
961
//			Debug.Log(string.Format("PosY: {0:F2}, LastY: {1:F2},  TgrY: {2:F2}, NewDist: {3:F2}, Corr: {4:F2}, Time: {5:F2}", bodyRoot != null ? bodyRoot.position.y : transform.position.y,
962
//				fLastTgtY, targetPos.y, fNewDistance, fFootDistance, fNewDistanceTime));
963
			
964
			if(Mathf.Abs(fNewDistance) >= 0.01f && Mathf.Abs(fNewDistance - fFootDistanceInitial) >= maxFootDistanceGround)
965
			{
966
				if((fNewDistanceTime - fFootDistanceTime) >= maxFootDistanceTime)
967
				{
968
					fFootDistance += (fNewDistance - fFootDistanceInitial);
969
					fFootDistanceTime = fNewDistanceTime;
970

    
971
					targetPos.y = fLastTgtY + fFootDistance;
972

    
973
//					Debug.Log(string.Format("   >> change({0:F2})! - Corr: {1:F2}, LastY: {2:F2},  TgrY: {3:F2} at time {4:F2}", 
974
//								(fNewDistance - fFootDistanceInitial), fFootDistance, fLastTgtY, targetPos.y, fFootDistanceTime));
975
				}
976
			}
977
			else
978
			{
979
				fFootDistanceTime = fNewDistanceTime;
980
			}
981
		}
982
		
983
		if(bodyRoot != null)
984
		{
985
			bodyRoot.position = smoothFactor != 0f ? 
986
				Vector3.Lerp(bodyRoot.position, targetPos, smoothFactor * Time.deltaTime) : targetPos;
987
		}
988
		else
989
		{
990
			transform.position = smoothFactor != 0f ? 
991
				Vector3.Lerp(transform.position, targetPos, smoothFactor * Time.deltaTime) : targetPos;
992
		}
993
	}
994
	
995
	// Set model's arms to be in T-pose
996
	protected void SetModelArmsInTpose()
997
	{
998
		Vector3 vTposeLeftDir = transform.TransformDirection(Vector3.left);
999
		Vector3 vTposeRightDir = transform.TransformDirection(Vector3.right);
1000

    
1001
		Transform transLeftUarm = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.ShoulderLeft, false)); // animator.GetBoneTransform(HumanBodyBones.LeftUpperArm);
1002
		Transform transLeftLarm = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.ElbowLeft, false)); // animator.GetBoneTransform(HumanBodyBones.LeftLowerArm);
1003
		Transform transLeftHand = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.WristLeft, false)); // animator.GetBoneTransform(HumanBodyBones.LeftHand);
1004
		
1005
		if(transLeftUarm != null && transLeftLarm != null)
1006
		{
1007
			Vector3 vUarmLeftDir = transLeftLarm.position - transLeftUarm.position;
1008
			float fUarmLeftAngle = Vector3.Angle(vUarmLeftDir, vTposeLeftDir);
1009
			
1010
			if(Mathf.Abs(fUarmLeftAngle) >= 5f)
1011
			{
1012
				Quaternion vFixRotation = Quaternion.FromToRotation(vUarmLeftDir, vTposeLeftDir);
1013
				transLeftUarm.rotation = vFixRotation * transLeftUarm.rotation;
1014
			}
1015
			
1016
			if(transLeftHand != null)
1017
			{
1018
				Vector3 vLarmLeftDir = transLeftHand.position - transLeftLarm.position;
1019
				float fLarmLeftAngle = Vector3.Angle(vLarmLeftDir, vTposeLeftDir);
1020
				
1021
				if(Mathf.Abs(fLarmLeftAngle) >= 5f)
1022
				{
1023
					Quaternion vFixRotation = Quaternion.FromToRotation(vLarmLeftDir, vTposeLeftDir);
1024
					transLeftLarm.rotation = vFixRotation * transLeftLarm.rotation;
1025
				}
1026
			}
1027
		}
1028
		
1029
		Transform transRightUarm = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.ShoulderRight, false)); // animator.GetBoneTransform(HumanBodyBones.RightUpperArm);
1030
		Transform transRightLarm = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.ElbowRight, false)); // animator.GetBoneTransform(HumanBodyBones.RightLowerArm);
1031
		Transform transRightHand = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.WristRight, false)); // animator.GetBoneTransform(HumanBodyBones.RightHand);
1032
		
1033
		if(transRightUarm != null && transRightLarm != null)
1034
		{
1035
			Vector3 vUarmRightDir = transRightLarm.position - transRightUarm.position;
1036
			float fUarmRightAngle = Vector3.Angle(vUarmRightDir, vTposeRightDir);
1037
			
1038
			if(Mathf.Abs(fUarmRightAngle) >= 5f)
1039
			{
1040
				Quaternion vFixRotation = Quaternion.FromToRotation(vUarmRightDir, vTposeRightDir);
1041
				transRightUarm.rotation = vFixRotation * transRightUarm.rotation;
1042
			}
1043
			
1044
			if(transRightHand != null)
1045
			{
1046
				Vector3 vLarmRightDir = transRightHand.position - transRightLarm.position;
1047
				float fLarmRightAngle = Vector3.Angle(vLarmRightDir, vTposeRightDir);
1048
				
1049
				if(Mathf.Abs(fLarmRightAngle) >= 5f)
1050
				{
1051
					Quaternion vFixRotation = Quaternion.FromToRotation(vLarmRightDir, vTposeRightDir);
1052
					transRightLarm.rotation = vFixRotation * transRightLarm.rotation;
1053
				}
1054
			}
1055
		}
1056
		
1057
	}
1058
	
1059
	// If the bones to be mapped have been declared, map that bone to the model.
1060
	protected virtual void MapBones()
1061
	{
1062
//		// make OffsetNode as a parent of model transform.
1063
//		offsetNode = new GameObject(name + "Ctrl") { layer = transform.gameObject.layer, tag = transform.gameObject.tag };
1064
//		offsetNode.transform.position = transform.position;
1065
//		offsetNode.transform.rotation = transform.rotation;
1066
//		offsetNode.transform.parent = transform.parent;
1067
		
1068
//		// take model transform as body root
1069
//		transform.parent = offsetNode.transform;
1070
//		transform.localPosition = Vector3.zero;
1071
//		transform.localRotation = Quaternion.identity;
1072
		
1073
		//bodyRoot = transform;
1074

    
1075
		// get bone transforms from the animator component
1076
		//Animator animatorComponent = GetComponent<Animator>();
1077
				
1078
		for (int boneIndex = 0; boneIndex < bones.Length; boneIndex++)
1079
		{
1080
			if (!boneIndex2MecanimMap.ContainsKey(boneIndex)) 
1081
				continue;
1082
			
1083
			bones[boneIndex] = animatorComponent ? animatorComponent.GetBoneTransform(boneIndex2MecanimMap[boneIndex]) : null;
1084
		}
1085
	}
1086
	
1087
	// Capture the initial rotations of the bones
1088
	protected void GetInitialRotations()
1089
	{
1090
		// save the initial rotation
1091
		if(offsetNode != null)
1092
		{
1093
			offsetNodePos = offsetNode.transform.position;
1094
			offsetNodeRot = offsetNode.transform.rotation;
1095
		}
1096

    
1097
		initialPosition = transform.position;
1098
		initialRotation = transform.rotation;
1099

    
1100
		initialHipsPosition = bones[0] ? bones[0].localPosition : Vector3.zero;
1101
		initialHipsRotation = bones[0] ? bones[0].localRotation : Quaternion.identity;
1102

    
1103
//		if(offsetNode != null)
1104
//		{
1105
//			initialRotation = Quaternion.Inverse(offsetNodeRot) * initialRotation;
1106
//		}
1107

    
1108
		transform.rotation = Quaternion.identity;
1109

    
1110
		// save the body root initial position
1111
		if(bodyRoot != null)
1112
		{
1113
			bodyRootPosition = bodyRoot.position;
1114
		}
1115
		else
1116
		{
1117
			bodyRootPosition = transform.position;
1118
		}
1119

    
1120
		if(offsetNode != null)
1121
		{
1122
			bodyRootPosition = bodyRootPosition - offsetNodePos;
1123
		}
1124
		
1125
		// save the initial bone rotations
1126
		for (int i = 0; i < bones.Length; i++)
1127
		{
1128
			if (bones[i] != null)
1129
			{
1130
				initialRotations[i] = bones[i].rotation;
1131
				localRotations[i] = bones[i].localRotation;
1132
			}
1133
		}
1134

    
1135
		// get finger bones' local rotations
1136
		//Animator animatorComponent = GetComponent<Animator>();
1137
		foreach(int boneIndex in specialIndex2MultiBoneMap.Keys)
1138
		{
1139
			List<HumanBodyBones> alBones = specialIndex2MultiBoneMap[boneIndex];
1140
			//Transform handTransform = animatorComponent.GetBoneTransform((boneIndex == 27 || boneIndex == 29) ? HumanBodyBones.LeftHand : HumanBodyBones.RightHand);
1141
			
1142
			for(int b = 0; b < alBones.Count; b++)
1143
			{
1144
				HumanBodyBones bone = alBones[b];
1145
				Transform boneTransform = animatorComponent ? animatorComponent.GetBoneTransform(bone) : null;
1146

    
1147
				// get the finger's 1st transform
1148
				Transform fingerBaseTransform = animatorComponent ? animatorComponent.GetBoneTransform(alBones[b - (b % 3)]) : null;
1149
				//Vector3 vBoneDirParent = handTransform && fingerBaseTransform ? (handTransform.position - fingerBaseTransform.position).normalized : Vector3.zero;
1150

    
1151
				// get the finger's 2nd transform
1152
				Transform baseChildTransform = fingerBaseTransform && fingerBaseTransform.childCount > 0 ? fingerBaseTransform.GetChild(0) : null;
1153
				Vector3 vBoneDirChild = baseChildTransform && fingerBaseTransform ? (baseChildTransform.position - fingerBaseTransform.position).normalized : Vector3.zero;
1154
				Vector3 vOrthoDirChild = Vector3.Cross(vBoneDirChild, Vector3.up).normalized;
1155

    
1156
				if(boneTransform)
1157
				{
1158
					fingerBoneLocalRotations[bone] = boneTransform.localRotation;
1159

    
1160
					if (vBoneDirChild != Vector3.zero) 
1161
					{
1162
						fingerBoneLocalAxes[bone] = boneTransform.InverseTransformDirection(vOrthoDirChild).normalized;
1163
					} 
1164
					else 
1165
					{
1166
						fingerBoneLocalAxes [bone] = Vector3.zero;
1167
					}
1168

    
1169
//					Transform bparTransform = boneTransform ? boneTransform.parent : null;
1170
//					Transform bchildTransform = boneTransform && boneTransform.childCount > 0 ? boneTransform.GetChild(0) : null;
1171
//
1172
//					// get the finger base transform (1st joint)
1173
//					Transform fingerBaseTransform = animatorComponent.GetBoneTransform(alBones[b - (b % 3)]);
1174
//					Vector3 vBoneDir2 = (handTransform.position - fingerBaseTransform.position).normalized;
1175
//
1176
//					// set the fist rotation
1177
//					if(boneTransform && fingerBaseTransform && handTransform)
1178
//					{
1179
//						Vector3 vBoneDir = bchildTransform ? (bchildTransform.position - boneTransform.position).normalized :
1180
//							(bparTransform ? (boneTransform.position - bparTransform.position).normalized : Vector3.zero);
1181
//
1182
//						Vector3 vOrthoDir = Vector3.Cross(vBoneDir2, vBoneDir).normalized;
1183
//						fingerBoneLocalAxes[bone] = boneTransform.InverseTransformDirection(vOrthoDir);
1184
//					}
1185
				}
1186
			}
1187
		}
1188

    
1189
		// Restore the initial rotation
1190
		transform.rotation = initialRotation;
1191
	}
1192
	
1193
	// Converts kinect joint rotation to avatar joint rotation, depending on joint initial rotation and offset rotation
1194
	protected Quaternion Kinect2AvatarRot(Quaternion jointRotation, int boneIndex)
1195
	{
1196
		Quaternion newRotation = jointRotation * initialRotations[boneIndex];
1197
		//newRotation = initialRotation * newRotation;
1198

    
1199
//		if(offsetNode != null)
1200
//		{
1201
//			newRotation = offsetNode.transform.rotation * newRotation;
1202
//		}
1203
//		else
1204
		{
1205
			newRotation = initialRotation * newRotation;
1206
		}
1207
		
1208
		return newRotation;
1209
	}
1210
	
1211
	// Converts Kinect position to avatar skeleton position, depending on initial position, mirroring and move rate
1212
	protected Vector3 Kinect2AvatarPos(Vector3 jointPosition, bool bMoveVertically)
1213
	{
1214
		float xPos = (jointPosition.x - offsetPos.x) * moveRate;
1215
		float yPos = (jointPosition.y - offsetPos.y) * moveRate;
1216
		float zPos = !mirroredMovement && !posRelativeToCamera ? (-jointPosition.z - offsetPos.z) * moveRate : (jointPosition.z - offsetPos.z) * moveRate;
1217
		
1218
		Vector3 newPosition = new Vector3(xPos, bMoveVertically ? yPos : 0f, zPos);
1219

    
1220
		Quaternion posRotation = mirroredMovement ? Quaternion.Euler (0f, 180f, 0f) * initialRotation : initialRotation;
1221
		newPosition = posRotation * newPosition;
1222

    
1223
		if(offsetNode != null)
1224
		{
1225
			//newPosition += offsetNode.transform.position;
1226
			newPosition = offsetNode.transform.position;
1227
		}
1228
		
1229
		return newPosition;
1230
	}
1231

    
1232
	// returns distance from the given transform to the underlying object. The player must be in IgnoreRaycast layer.
1233
	protected virtual float GetTransformDistanceToGround(Transform trans)
1234
	{
1235
		if(!trans)
1236
			return 0f;
1237

    
1238
//		RaycastHit hit;
1239
//		if(Physics.Raycast(trans.position, Vector3.down, out hit, 2f, raycastLayers))
1240
//		{
1241
//			return -hit.distance;
1242
//		}
1243
//		else if(Physics.Raycast(trans.position, Vector3.up, out hit, 2f, raycastLayers))
1244
//		{
1245
//			return hit.distance;
1246
//		}
1247
//		else
1248
//		{
1249
//			if (trans.position.y < 0)
1250
//				return -trans.position.y;
1251
//			else
1252
//				return 1000f;
1253
//		}
1254

    
1255
		return -trans.position.y;
1256
	}
1257

    
1258
	// returns the lower distance distance from left or right foot to the ground, or 1000f if no LF/RF transforms are found
1259
	protected virtual float GetDistanceToGround()
1260
	{
1261
		if(leftFoot == null && rightFoot == null)
1262
		{
1263
//			Animator animatorComponent = GetComponent<Animator>();
1264
//
1265
//			if(animatorComponent)
1266
//			{
1267
//				leftFoot = animatorComponent.GetBoneTransform(HumanBodyBones.LeftFoot);
1268
//				rightFoot = animatorComponent.GetBoneTransform(HumanBodyBones.RightFoot);
1269
//			}
1270

    
1271
			leftFoot = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.FootLeft, false));
1272
			rightFoot = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.FootRight, false));
1273

    
1274
			if (leftFoot == null || rightFoot == null) 
1275
			{
1276
				leftFoot = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.AnkleLeft, false));
1277
				rightFoot = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.AnkleRight, false));
1278
			}
1279
		}
1280

    
1281
		float fDistMin = 1000f;
1282
		float fDistLeft = leftFoot ? GetTransformDistanceToGround(leftFoot) : fDistMin;
1283
		float fDistRight = rightFoot ? GetTransformDistanceToGround(rightFoot) : fDistMin;
1284
		fDistMin = Mathf.Abs(fDistLeft) < Mathf.Abs(fDistRight) ? fDistLeft : fDistRight;
1285

    
1286
		if(fDistMin == 1000f)
1287
		{
1288
			fDistMin = 0f; // fFootDistanceInitial;
1289
		}
1290

    
1291
//		Debug.Log (string.Format ("LFootY: {0:F2}, Dist: {1:F2}, RFootY: {2:F2}, Dist: {3:F2}, Min: {4:F2}", leftFoot ? leftFoot.position.y : 0f, fDistLeft,
1292
//						rightFoot ? rightFoot.position.y : 0f, fDistRight, fDistMin));
1293

    
1294
		return fDistMin;
1295
	}
1296

    
1297
//	protected void OnCollisionEnter(Collision col)
1298
//	{
1299
//		Debug.Log("Collision entered");
1300
//	}
1301
//
1302
//	protected void OnCollisionExit(Collision col)
1303
//	{
1304
//		Debug.Log("Collision exited");
1305
//	}
1306
	
1307
	// dictionaries to speed up bones' processing
1308
	// the author of the terrific idea for kinect-joints to mecanim-bones mapping
1309
	// along with its initial implementation, including following dictionary is
1310
	// Mikhail Korchun (korchoon@gmail.com). Big thanks to this guy!
1311
	protected static readonly Dictionary<int, HumanBodyBones> boneIndex2MecanimMap = new Dictionary<int, HumanBodyBones>
1312
	{
1313
		{0, HumanBodyBones.Hips},
1314
		{1, HumanBodyBones.Spine},
1315
//        {2, HumanBodyBones.Chest},
1316
		{3, HumanBodyBones.Neck},
1317
//		{4, HumanBodyBones.Head},
1318
		
1319
		{5, HumanBodyBones.LeftUpperArm},
1320
		{6, HumanBodyBones.LeftLowerArm},
1321
		{7, HumanBodyBones.LeftHand},
1322
//		{8, HumanBodyBones.LeftIndexProximal},
1323
//		{9, HumanBodyBones.LeftIndexIntermediate},
1324
//		{10, HumanBodyBones.LeftThumbProximal},
1325
		
1326
		{11, HumanBodyBones.RightUpperArm},
1327
		{12, HumanBodyBones.RightLowerArm},
1328
		{13, HumanBodyBones.RightHand},
1329
//		{14, HumanBodyBones.RightIndexProximal},
1330
//		{15, HumanBodyBones.RightIndexIntermediate},
1331
//		{16, HumanBodyBones.RightThumbProximal},
1332
		
1333
		{17, HumanBodyBones.LeftUpperLeg},
1334
		{18, HumanBodyBones.LeftLowerLeg},
1335
		{19, HumanBodyBones.LeftFoot},
1336
//		{20, HumanBodyBones.LeftToes},
1337
		
1338
		{21, HumanBodyBones.RightUpperLeg},
1339
		{22, HumanBodyBones.RightLowerLeg},
1340
		{23, HumanBodyBones.RightFoot},
1341
//		{24, HumanBodyBones.RightToes},
1342
		
1343
		{25, HumanBodyBones.LeftShoulder},
1344
		{26, HumanBodyBones.RightShoulder},
1345
		{27, HumanBodyBones.LeftIndexProximal},
1346
		{28, HumanBodyBones.RightIndexProximal},
1347
		{29, HumanBodyBones.LeftThumbProximal},
1348
		{30, HumanBodyBones.RightThumbProximal},
1349
	};
1350
	
1351
	protected static readonly Dictionary<int, KinectInterop.JointType> boneIndex2JointMap = new Dictionary<int, KinectInterop.JointType>
1352
	{
1353
		{0, KinectInterop.JointType.SpineBase},
1354
		{1, KinectInterop.JointType.SpineMid},
1355
		{2, KinectInterop.JointType.SpineShoulder},
1356
		{3, KinectInterop.JointType.Neck},
1357
		{4, KinectInterop.JointType.Head},
1358
		
1359
		{5, KinectInterop.JointType.ShoulderLeft},
1360
		{6, KinectInterop.JointType.ElbowLeft},
1361
		{7, KinectInterop.JointType.WristLeft},
1362
		{8, KinectInterop.JointType.HandLeft},
1363
		
1364
		{9, KinectInterop.JointType.HandTipLeft},
1365
		{10, KinectInterop.JointType.ThumbLeft},
1366
		
1367
		{11, KinectInterop.JointType.ShoulderRight},
1368
		{12, KinectInterop.JointType.ElbowRight},
1369
		{13, KinectInterop.JointType.WristRight},
1370
		{14, KinectInterop.JointType.HandRight},
1371
		
1372
		{15, KinectInterop.JointType.HandTipRight},
1373
		{16, KinectInterop.JointType.ThumbRight},
1374
		
1375
		{17, KinectInterop.JointType.HipLeft},
1376
		{18, KinectInterop.JointType.KneeLeft},
1377
		{19, KinectInterop.JointType.AnkleLeft},
1378
		{20, KinectInterop.JointType.FootLeft},
1379
		
1380
		{21, KinectInterop.JointType.HipRight},
1381
		{22, KinectInterop.JointType.KneeRight},
1382
		{23, KinectInterop.JointType.AnkleRight},
1383
		{24, KinectInterop.JointType.FootRight},
1384
	};
1385
	
1386
	protected static readonly Dictionary<int, List<KinectInterop.JointType>> specIndex2JointMap = new Dictionary<int, List<KinectInterop.JointType>>
1387
	{
1388
		{25, new List<KinectInterop.JointType> {KinectInterop.JointType.ShoulderLeft, KinectInterop.JointType.SpineShoulder} },
1389
		{26, new List<KinectInterop.JointType> {KinectInterop.JointType.ShoulderRight, KinectInterop.JointType.SpineShoulder} },
1390
		{27, new List<KinectInterop.JointType> {KinectInterop.JointType.HandTipLeft, KinectInterop.JointType.HandLeft} },
1391
		{28, new List<KinectInterop.JointType> {KinectInterop.JointType.HandTipRight, KinectInterop.JointType.HandRight} },
1392
		{29, new List<KinectInterop.JointType> {KinectInterop.JointType.ThumbLeft, KinectInterop.JointType.HandLeft} },
1393
		{30, new List<KinectInterop.JointType> {KinectInterop.JointType.ThumbRight, KinectInterop.JointType.HandRight} },
1394
	};
1395
	
1396
	protected static readonly Dictionary<int, KinectInterop.JointType> boneIndex2MirrorJointMap = new Dictionary<int, KinectInterop.JointType>
1397
	{
1398
		{0, KinectInterop.JointType.SpineBase},
1399
		{1, KinectInterop.JointType.SpineMid},
1400
		{2, KinectInterop.JointType.SpineShoulder},
1401
		{3, KinectInterop.JointType.Neck},
1402
		{4, KinectInterop.JointType.Head},
1403
		
1404
		{5, KinectInterop.JointType.ShoulderRight},
1405
		{6, KinectInterop.JointType.ElbowRight},
1406
		{7, KinectInterop.JointType.WristRight},
1407
		{8, KinectInterop.JointType.HandRight},
1408
		
1409
		{9, KinectInterop.JointType.HandTipRight},
1410
		{10, KinectInterop.JointType.ThumbRight},
1411
		
1412
		{11, KinectInterop.JointType.ShoulderLeft},
1413
		{12, KinectInterop.JointType.ElbowLeft},
1414
		{13, KinectInterop.JointType.WristLeft},
1415
		{14, KinectInterop.JointType.HandLeft},
1416
		
1417
		{15, KinectInterop.JointType.HandTipLeft},
1418
		{16, KinectInterop.JointType.ThumbLeft},
1419
		
1420
		{17, KinectInterop.JointType.HipRight},
1421
		{18, KinectInterop.JointType.KneeRight},
1422
		{19, KinectInterop.JointType.AnkleRight},
1423
		{20, KinectInterop.JointType.FootRight},
1424
		
1425
		{21, KinectInterop.JointType.HipLeft},
1426
		{22, KinectInterop.JointType.KneeLeft},
1427
		{23, KinectInterop.JointType.AnkleLeft},
1428
		{24, KinectInterop.JointType.FootLeft},
1429
	};
1430
	
1431
	protected static readonly Dictionary<int, List<KinectInterop.JointType>> specIndex2MirrorMap = new Dictionary<int, List<KinectInterop.JointType>>
1432
	{
1433
		{25, new List<KinectInterop.JointType> {KinectInterop.JointType.ShoulderRight, KinectInterop.JointType.SpineShoulder} },
1434
		{26, new List<KinectInterop.JointType> {KinectInterop.JointType.ShoulderLeft, KinectInterop.JointType.SpineShoulder} },
1435
		{27, new List<KinectInterop.JointType> {KinectInterop.JointType.HandTipRight, KinectInterop.JointType.HandRight} },
1436
		{28, new List<KinectInterop.JointType> {KinectInterop.JointType.HandTipLeft, KinectInterop.JointType.HandLeft} },
1437
		{29, new List<KinectInterop.JointType> {KinectInterop.JointType.ThumbRight, KinectInterop.JointType.HandRight} },
1438
		{30, new List<KinectInterop.JointType> {KinectInterop.JointType.ThumbLeft, KinectInterop.JointType.HandLeft} },
1439
	};
1440
	
1441
	protected static readonly Dictionary<KinectInterop.JointType, int> jointMap2boneIndex = new Dictionary<KinectInterop.JointType, int>
1442
	{
1443
		{KinectInterop.JointType.SpineBase, 0},
1444
		{KinectInterop.JointType.SpineMid, 1},
1445
		{KinectInterop.JointType.SpineShoulder, 2},
1446
		{KinectInterop.JointType.Neck, 3},
1447
		{KinectInterop.JointType.Head, 4},
1448
		
1449
		{KinectInterop.JointType.ShoulderLeft, 5},
1450
		{KinectInterop.JointType.ElbowLeft, 6},
1451
		{KinectInterop.JointType.WristLeft, 7},
1452
		{KinectInterop.JointType.HandLeft, 8},
1453
		
1454
		{KinectInterop.JointType.HandTipLeft, 9},
1455
		{KinectInterop.JointType.ThumbLeft, 10},
1456
		
1457
		{KinectInterop.JointType.ShoulderRight, 11},
1458
		{KinectInterop.JointType.ElbowRight, 12},
1459
		{KinectInterop.JointType.WristRight, 13},
1460
		{KinectInterop.JointType.HandRight, 14},
1461
		
1462
		{KinectInterop.JointType.HandTipRight, 15},
1463
		{KinectInterop.JointType.ThumbRight, 16},
1464
		
1465
		{KinectInterop.JointType.HipLeft, 17},
1466
		{KinectInterop.JointType.KneeLeft, 18},
1467
		{KinectInterop.JointType.AnkleLeft, 19},
1468
		{KinectInterop.JointType.FootLeft, 20},
1469
		
1470
		{KinectInterop.JointType.HipRight, 21},
1471
		{KinectInterop.JointType.KneeRight, 22},
1472
		{KinectInterop.JointType.AnkleRight, 23},
1473
		{KinectInterop.JointType.FootRight, 24},
1474
	};
1475
	
1476
	protected static readonly Dictionary<KinectInterop.JointType, int> mirrorJointMap2boneIndex = new Dictionary<KinectInterop.JointType, int>
1477
	{
1478
		{KinectInterop.JointType.SpineBase, 0},
1479
		{KinectInterop.JointType.SpineMid, 1},
1480
		{KinectInterop.JointType.SpineShoulder, 2},
1481
		{KinectInterop.JointType.Neck, 3},
1482
		{KinectInterop.JointType.Head, 4},
1483
		
1484
		{KinectInterop.JointType.ShoulderRight, 5},
1485
		{KinectInterop.JointType.ElbowRight, 6},
1486
		{KinectInterop.JointType.WristRight, 7},
1487
		{KinectInterop.JointType.HandRight, 8},
1488
		
1489
		{KinectInterop.JointType.HandTipRight, 9},
1490
		{KinectInterop.JointType.ThumbRight, 10},
1491
		
1492
		{KinectInterop.JointType.ShoulderLeft, 11},
1493
		{KinectInterop.JointType.ElbowLeft, 12},
1494
		{KinectInterop.JointType.WristLeft, 13},
1495
		{KinectInterop.JointType.HandLeft, 14},
1496
		
1497
		{KinectInterop.JointType.HandTipLeft, 15},
1498
		{KinectInterop.JointType.ThumbLeft, 16},
1499
		
1500
		{KinectInterop.JointType.HipRight, 17},
1501
		{KinectInterop.JointType.KneeRight, 18},
1502
		{KinectInterop.JointType.AnkleRight, 19},
1503
		{KinectInterop.JointType.FootRight, 20},
1504
		
1505
		{KinectInterop.JointType.HipLeft, 21},
1506
		{KinectInterop.JointType.KneeLeft, 22},
1507
		{KinectInterop.JointType.AnkleLeft, 23},
1508
		{KinectInterop.JointType.FootLeft, 24},
1509
	};
1510

    
1511

    
1512
	protected static readonly Dictionary<int, List<HumanBodyBones>> specialIndex2MultiBoneMap = new Dictionary<int, List<HumanBodyBones>>
1513
	{
1514
		{27, new List<HumanBodyBones> {  // left fingers
1515
				HumanBodyBones.LeftIndexProximal,
1516
				HumanBodyBones.LeftIndexIntermediate,
1517
				HumanBodyBones.LeftIndexDistal,
1518
				HumanBodyBones.LeftMiddleProximal,
1519
				HumanBodyBones.LeftMiddleIntermediate,
1520
				HumanBodyBones.LeftMiddleDistal,
1521
				HumanBodyBones.LeftRingProximal,
1522
				HumanBodyBones.LeftRingIntermediate,
1523
				HumanBodyBones.LeftRingDistal,
1524
				HumanBodyBones.LeftLittleProximal,
1525
				HumanBodyBones.LeftLittleIntermediate,
1526
				HumanBodyBones.LeftLittleDistal,
1527
			}},
1528
		{28, new List<HumanBodyBones> {  // right fingers
1529
				HumanBodyBones.RightIndexProximal,
1530
				HumanBodyBones.RightIndexIntermediate,
1531
				HumanBodyBones.RightIndexDistal,
1532
				HumanBodyBones.RightMiddleProximal,
1533
				HumanBodyBones.RightMiddleIntermediate,
1534
				HumanBodyBones.RightMiddleDistal,
1535
				HumanBodyBones.RightRingProximal,
1536
				HumanBodyBones.RightRingIntermediate,
1537
				HumanBodyBones.RightRingDistal,
1538
				HumanBodyBones.RightLittleProximal,
1539
				HumanBodyBones.RightLittleIntermediate,
1540
				HumanBodyBones.RightLittleDistal,
1541
			}},
1542
		{29, new List<HumanBodyBones> {  // left thumb
1543
				HumanBodyBones.LeftThumbProximal,
1544
				HumanBodyBones.LeftThumbIntermediate,
1545
				HumanBodyBones.LeftThumbDistal,
1546
			}},
1547
		{30, new List<HumanBodyBones> {  // right thumb
1548
				HumanBodyBones.RightThumbProximal,
1549
				HumanBodyBones.RightThumbIntermediate,
1550
				HumanBodyBones.RightThumbDistal,
1551
			}},
1552
	};
1553

    
1554
}
1555