프로젝트

일반

사용자정보

통계
| 개정판:

t1 / TFDContents / Assets / KinectDemos / VisualizerDemo / Scripts / UserHandVisualizer.cs @ 3

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

1
using UnityEngine;
2
using System.Collections;
3

    
4

    
5
public class UserHandVisualizer : MonoBehaviour
6
{
7
	[Tooltip("Index of the player, tracked by this component. 0 - the 1st player, 1 - the 2nd player, 2 - the 3rd player, etc.")]
8
	public int playerIndex = 0;
9
	
10
	[Tooltip("Whether the mesh is facing the player or not.")]
11
	public bool mirroredMovement = true;
12
	
13
	[Tooltip("Kinect origin position.")]
14
	public Vector3 originPosition = Vector3.zero;
15
	
16
	[Tooltip("Whether the z-movement is inverted or not.")]
17
	public bool invertedZMovement = false;
18
	
19
	[Tooltip("Smooth factor used for the camera re-orientation.")]
20
	public float smoothFactor = 0f;
21
	
22
	[Tooltip("Camera that may be used to overlay the mesh over the color background.")]
23
	public Camera foregroundCamera;
24

    
25
	[Tooltip("Whether to update the mesh collider as well, when the user mesh changes.")]
26
	public bool updateMeshCollider = false;
27

    
28
	[Tooltip("Number of pixels per direction in a sample.")]
29
	private const int sampleSize = 1;
30

    
31

    
32
    private Mesh mesh;
33
    private Vector3[] vertices;
34
    private Vector2[] uvs;
35
    private int[] triangles;
36

    
37
	private KinectManager manager = null;
38

    
39
	private KinectInterop.SensorData sensorData = null;
40
	//private Vector3[] spaceCoords = null;
41
	private Matrix4x4 kinectToWorld = Matrix4x4.identity;
42

    
43
	private int depthWidth = 0;
44
	private int depthHeight = 0;
45

    
46
	private int sampledWidth = 0;
47
	private int sampledHeight = 0;
48

    
49
	private long userId = 0;
50
	private byte userBodyIndex = 255;
51
	private Vector3 userMeshPos = Vector3.zero;
52

    
53
	private Vector3 leftHandPos = Vector3.zero;
54
	private Vector3 rightHandPos = Vector3.zero;
55
	private Vector3 leftFingerPos = Vector3.zero;
56
	private Vector3 rightFingerPos = Vector3.zero;
57
	private Vector3 leftThumbPos = Vector3.zero;
58
	private Vector3 rightThumbPos = Vector3.zero;
59

    
60
	private byte[] vertexType;
61
	private int[] vertexIndex;
62

    
63

    
64
    void Start()
65
    {
66
		manager = KinectManager.Instance;
67

    
68
		if (manager != null)
69
        {
70
			sensorData = manager.GetSensorData();
71

    
72
			depthWidth = manager.GetDepthImageWidth();
73
			depthHeight = manager.GetDepthImageHeight();
74
			
75
			sampledWidth = depthWidth / sampleSize;
76
			sampledHeight = depthHeight / sampleSize;
77

    
78
			//spaceCoords = new Vector3[depthWidth * depthHeight];
79

    
80
			if(sensorData.depth2SpaceCoords == null)
81
			{
82
				sensorData.depth2SpaceCoords = new Vector3[depthWidth * depthHeight];
83
			}
84

    
85
			vertexType = new byte[sampledWidth * sampledHeight];
86
			vertexIndex = new int[sampledWidth * sampledHeight];
87

    
88
			CreateMesh(sampledWidth, sampledHeight);
89
        }
90
    }
91

    
92
    private void CreateMesh(int width, int height)
93
    {
94
        mesh = new Mesh();
95
		mesh.name = "UserMesh";
96

    
97
        GetComponent<MeshFilter>().mesh = mesh;
98
    }
99
    
100
    void Update()
101
    {
102
		if (manager == null || !manager.IsInitialized())
103
			return;
104
		
105
		// get user texture
106
		Renderer renderer = GetComponent<Renderer>();
107
		if(renderer && renderer.material && renderer.material.mainTexture == null)
108
		{
109
			BackgroundRemovalManager backManager = BackgroundRemovalManager.Instance;
110
			renderer.material.mainTexture = backManager ? (Texture)sensorData.depth2ColorTexture : (Texture)manager.GetUsersLblTex();
111
		}
112

    
113
		// get kinect-to-world matrix
114
		kinectToWorld = manager.GetKinectToWorldMatrix();
115

    
116
		if(playerIndex >= 0)
117
		{
118
			long lastUserId = userId;
119
			userId = manager.GetUserIdByIndex(playerIndex);
120

    
121
			userBodyIndex = (byte)manager.GetBodyIndexByUserId(userId);
122
			if(userBodyIndex == 255)
123
				userBodyIndex = 222;
124

    
125
			// hand positions
126
			leftHandPos = manager.GetJointKinectPosition(userId, (int)KinectInterop.JointType.HandLeft);
127
			rightHandPos = manager.GetJointKinectPosition(userId, (int)KinectInterop.JointType.HandRight);
128
			leftFingerPos = manager.GetJointKinectPosition(userId, (int)KinectInterop.JointType.HandTipLeft);
129
			rightFingerPos = manager.GetJointKinectPosition(userId, (int)KinectInterop.JointType.HandTipRight);
130
			leftThumbPos = manager.GetJointKinectPosition(userId, (int)KinectInterop.JointType.ThumbLeft);
131
			rightThumbPos = manager.GetJointKinectPosition(userId, (int)KinectInterop.JointType.ThumbRight);
132

    
133
			// check for color overlay
134
			if (foregroundCamera) 
135
			{
136
				// get the background rectangle (use the portrait background, if available)
137
				Rect backgroundRect = foregroundCamera.pixelRect;
138
				PortraitBackground portraitBack = PortraitBackground.Instance;
139

    
140
				if (portraitBack && portraitBack.enabled) 
141
				{
142
					backgroundRect = portraitBack.GetBackgroundRect ();
143
				}
144

    
145
				// get user position
146
				userMeshPos = manager.GetJointPosColorOverlay(userId, (int)KinectInterop.JointType.SpineBase, foregroundCamera, backgroundRect);
147
			}
148
			else
149
			{
150
				// get user position
151
				userMeshPos = manager.GetJointKinectPosition(userId, (int)KinectInterop.JointType.SpineBase);
152
			}
153

    
154
			if(!mirroredMovement)
155
			{
156
				userMeshPos.x = -userMeshPos.x;
157
			}
158

    
159
			if (foregroundCamera == null) 
160
			{
161
				// convert kinect pos to world coords, when there is no color overlay
162
				userMeshPos = kinectToWorld.MultiplyPoint3x4(userMeshPos);
163
			}
164

    
165
			// set transform position
166
			Vector3 newUserPos = userMeshPos + originPosition; // manager.GetJointPosition(userId, (int)KinectInterop.JointType.SpineBase) + originPosition;
167
			
168
			if(invertedZMovement)
169
			{
170
				newUserPos.z = -newUserPos.z;
171
			}
172
			
173
			transform.position = lastUserId != 0 && smoothFactor != 0f ? Vector3.Lerp(transform.position, newUserPos, smoothFactor * Time.deltaTime) : newUserPos;
174
		}
175
		else
176
		{
177
			userId = 0;
178
			userBodyIndex = 255;
179
			userMeshPos = Vector3.zero;
180

    
181
			leftHandPos = rightHandPos = Vector3.zero;
182
			leftFingerPos = rightFingerPos = Vector3.zero;
183
			leftThumbPos = rightThumbPos = Vector3.zero;
184
		}
185

    
186
		// update the mesh
187
		UpdateMesh();
188
    }
189
    
190
    private void UpdateMesh()
191
    {
192
		if(sensorData.depthImage != null && sensorData.bodyIndexImage != null &&
193
			sensorData.depth2SpaceCoords != null && sensorData.spaceCoordsBufferReady)
194
		{
195
			int vCount = 0, tCount = 0;
196
			EstimateUserVertices(out vCount, out tCount);
197

    
198
			vertices = new Vector3[vCount];
199
			uvs = new Vector2[vCount];
200
			triangles = new int[6 * tCount];
201

    
202
			int index = 0, vIndex = 0, tIndex = 0, xyIndex = 0;
203
			for (int y = 0; y < depthHeight; y += sampleSize)
204
			{
205
				int xyStartIndex = xyIndex;
206

    
207
				for (int x = 0; x < depthWidth; x += sampleSize)
208
				{
209
					//Vector3 vSpacePos = spaceCoords[xyIndex];
210
					Vector3 vSpacePos = sensorData.depth2SpaceCoords[xyIndex];
211

    
212
					if(vertexType[index] != 0 &&
213
					   !float.IsInfinity(vSpacePos.x) && !float.IsInfinity(vSpacePos.y) && !float.IsInfinity(vSpacePos.z))
214
					{
215
						// check for color overlay
216
						if (foregroundCamera) 
217
						{
218
							// get the background rectangle (use the portrait background, if available)
219
							Rect backgroundRect = foregroundCamera.pixelRect;
220
							PortraitBackground portraitBack = PortraitBackground.Instance;
221

    
222
							if(portraitBack && portraitBack.enabled)
223
							{
224
								backgroundRect = portraitBack.GetBackgroundRect();
225
							}
226

    
227
							Vector2 vColorPos = sensorData.depth2ColorCoords[xyIndex];
228
							ushort depthValue = sensorData.depthImage[xyIndex];
229

    
230
							if(!float.IsInfinity(vColorPos.x) && !float.IsInfinity(vColorPos.y) && depthValue > 0)
231
							{
232
								float xScaled = (float)vColorPos.x * backgroundRect.width / sensorData.colorImageWidth;
233
								float yScaled = (float)vColorPos.y * backgroundRect.height / sensorData.colorImageHeight;
234

    
235
								float xScreen = backgroundRect.x + xScaled;
236
								float yScreen = backgroundRect.y + backgroundRect.height - yScaled;
237
								float zDistance = (float)depthValue / 1000f;
238

    
239
								vSpacePos = foregroundCamera.ScreenToWorldPoint(new Vector3(xScreen, yScreen, zDistance));
240
							}
241
						}
242

    
243
						if(!mirroredMovement)
244
						{
245
							vSpacePos.x = -vSpacePos.x;
246
						}
247

    
248
						if(foregroundCamera == null) 
249
						{
250
							// convert space to world coords, when there is no color overlay
251
							vSpacePos = kinectToWorld.MultiplyPoint3x4(vSpacePos);
252
						}
253

    
254
						vertices[vIndex] = vSpacePos - userMeshPos;
255
						uvs[vIndex] = new Vector2((float)x / depthWidth, (float)y / depthHeight);
256
						vIndex++;
257

    
258
						if(vertexType[index] == 3)
259
						{
260
							if(mirroredMovement)
261
							{
262
								triangles[tIndex++] = vertexIndex[index];  // top left
263
								triangles[tIndex++] = vertexIndex[index + 1];  // top right
264
								triangles[tIndex++] = vertexIndex[index + sampledWidth];  // bottom left
265
								
266
								triangles[tIndex++] = vertexIndex[index + sampledWidth];  // bottom left
267
								triangles[tIndex++] = vertexIndex[index + 1];  // top right
268
								triangles[tIndex++] = vertexIndex[index + sampledWidth + 1];  // bottom right
269
							}
270
							else
271
							{
272
								triangles[tIndex++] = vertexIndex[index + 1];  // top left
273
								triangles[tIndex++] = vertexIndex[index];  // top right
274
								triangles[tIndex++] = vertexIndex[index + sampledWidth + 1];  // bottom left
275
								
276
								triangles[tIndex++] = vertexIndex[index + sampledWidth + 1];  // bottom left
277
								triangles[tIndex++] = vertexIndex[index];  // top right
278
								triangles[tIndex++] = vertexIndex[index + sampledWidth];  // bottom right
279
							}
280
						}
281
					}
282

    
283
					index++;
284
					xyIndex += sampleSize;
285
				}
286

    
287
				xyIndex = xyStartIndex + sampleSize * depthWidth;
288
			}
289

    
290
			// buffer is released
291
			lock(sensorData.spaceCoordsBufferLock)
292
			{
293
				sensorData.spaceCoordsBufferReady = false;
294
			}
295

    
296
			mesh.Clear();
297
			mesh.vertices = vertices;
298
			mesh.uv = uvs;
299
			//mesh.normals = normals;
300
			mesh.triangles = triangles;
301
			mesh.RecalculateNormals();
302
			mesh.RecalculateBounds();
303

    
304
			if (updateMeshCollider) 
305
			{
306
				MeshCollider meshCollider = GetComponent<MeshCollider>();
307

    
308
				if (meshCollider) 
309
				{
310
					meshCollider.sharedMesh = null;
311
					meshCollider.sharedMesh = mesh;
312
				}
313
			}
314
		}
315
    }
316

    
317
	// estimates which and how many sampled vertices are valid
318
	private void EstimateUserVertices(out int count1, out int count3)
319
	{
320
		System.Array.Clear(vertexType, 0, vertexType.Length);
321

    
322
		Vector3[] vSpacePos = new Vector3[4];
323
		int rowIndex = 0;
324

    
325
		for (int y = 0; y < sampledHeight - 1; y++)
326
		{
327
			int pixIndex = rowIndex;
328

    
329
			for (int x = 0; x < sampledWidth - 1; x++)
330
			{
331
				if(IsUserSampleValid(x, y, ref vSpacePos[0]) && IsUserSampleValid(x + 1, y, ref vSpacePos[1]) &&
332
				   IsUserSampleValid(x, y + 1, ref vSpacePos[2]) && IsUserSampleValid(x + 1, y + 1, ref vSpacePos[3]))
333
				{
334
					if(IsSpacePointsCloseToEachOther(vSpacePos, 0.01f) && IsSpacePointsCloseToHands(vSpacePos, 0.01f))
335
					{
336
						vertexType[pixIndex] = 3;
337
						
338
						vertexType[pixIndex + 1] = 1;
339
						vertexType[pixIndex + sampledWidth] = 1;
340
						vertexType[pixIndex + sampledWidth + 1] = 1;
341
					}
342
				}
343

    
344
				pixIndex++;
345
			}
346

    
347
			rowIndex += sampledWidth;
348
		}
349

    
350
		// estimate counts
351
		count1 = 0;
352
		count3 = 0;
353
		
354
		for(int i = 0; i < vertexType.Length; i++)
355
		{
356
			if(vertexType[i] != 0)
357
			{
358
				vertexIndex[i] = count1;
359
				count1++;
360
			}
361
			else
362
			{
363
				vertexIndex[i] = 0;
364
			}
365

    
366
			if(vertexType[i] == 3)
367
			{
368
				count3++;
369
			}
370
		}
371
	}
372

    
373
	// checks if the space points are closer to each other than the minimum squared distance
374
	private bool IsSpacePointsCloseToEachOther(Vector3[] vSpacePos, float fMinDistSquared)
375
	{
376
		int iPosLength = vSpacePos.Length;
377

    
378
		for(int i = 0; i < iPosLength; i++)
379
		{
380
			for(int j = i + 1; j < iPosLength; j++)
381
			{
382
				Vector3 vDist = vSpacePos[j] - vSpacePos[i];
383
				if(vDist.sqrMagnitude > fMinDistSquared)
384
					return false;
385
			}
386
		}
387

    
388
		return true;
389
	}
390

    
391
	// checks if the space points are closer to hand, finger or thumb joints than the minimum squared distance
392
	private bool IsSpacePointsCloseToHands(Vector3[] vSpacePos, float fMinDistSquared)
393
	{
394
		if(IsSpacePointsCloseToJoint(vSpacePos, leftHandPos, fMinDistSquared) || IsSpacePointsCloseToJoint(vSpacePos, rightHandPos, fMinDistSquared) ||
395
			IsSpacePointsCloseToJoint(vSpacePos, leftFingerPos, fMinDistSquared) || IsSpacePointsCloseToJoint(vSpacePos, rightFingerPos, fMinDistSquared) ||
396
			IsSpacePointsCloseToJoint(vSpacePos, leftThumbPos, fMinDistSquared) || IsSpacePointsCloseToJoint(vSpacePos, rightThumbPos, fMinDistSquared)) 
397
		{
398
			return true;
399
		}
400

    
401
		return false;
402
	}
403

    
404
	// checks if the space points are closer to joint position than the minimum squared distance
405
	private bool IsSpacePointsCloseToJoint(Vector3[] vSpacePos, Vector3 vJointPos, float fMinDistSquared)
406
	{
407
		int iPosLength = vSpacePos.Length;
408

    
409
		for(int i = 0; i < iPosLength; i++)
410
		{
411
			Vector3 vDist = vSpacePos[i] - vJointPos;
412
			if(vDist.sqrMagnitude > fMinDistSquared)
413
				return false;
414
		}
415

    
416
		return true;
417
	}
418

    
419
	// checks whether this sample block is valid for this user
420
	private bool IsUserSampleValid(int x, int y, ref Vector3 vSpacePos)
421
	{
422
		int startIndex = y * sampleSize * depthWidth + x * sampleSize;
423

    
424
		//for (int y1 = 0; y1 < SampleSize; y1++)
425
		{
426
			int pixelIndex = startIndex;
427
			//vSpacePos = spaceCoords[pixelIndex];
428
			vSpacePos = sensorData.depth2SpaceCoords[pixelIndex];
429

    
430
			//for (int x1 = 0; x1 < SampleSize; x1++)
431
			{
432
				if(userBodyIndex != 255)
433
				{
434
					if(sensorData.bodyIndexImage[pixelIndex] == userBodyIndex &&
435
					   !float.IsInfinity(vSpacePos.x) && !float.IsInfinity(vSpacePos.y) && !float.IsInfinity(vSpacePos.z))
436
					{
437
						return true;
438
					}
439
				}
440
//				else
441
//				{
442
//					if(sensorData.bodyIndexImage[pixelIndex] != 255 &&
443
//					   !float.IsInfinity(vSpacePos.x) && !float.IsInfinity(vSpacePos.y) && !float.IsInfinity(vSpacePos.z))
444
//					{
445
//						return true;
446
//					}
447
//				}
448

    
449
				pixelIndex++;
450
			}
451

    
452
			startIndex += depthWidth;
453
		}
454
		
455
		return false;
456
	}
457

    
458
}