t1 / TFDContents / Assets / KinectScripts / FacetrackingManager.cs @ 3
이력 | 보기 | 이력해설 | 다운로드 (42.6 KB)
1 | 3 | KTH | using UnityEngine; |
---|---|---|---|
2 | using System; |
||
3 | using System.Collections; |
||
4 | using System.Collections.Generic; |
||
5 | //using System.Runtime.InteropServices; |
||
6 | using System.Text; |
||
7 | |||
8 | |||
9 | /// <summary> |
||
10 | /// Facetracking manager is the component that manages the head and face tracking. |
||
11 | /// </summary> |
||
12 | public class FacetrackingManager : MonoBehaviour |
||
13 | { |
||
14 | [Tooltip("Index of the player, tracked by this component. 0 means the 1st player, 1 - the 2nd one, 2 - the 3rd one, etc.")] |
||
15 | public int playerIndex = 0; |
||
16 | |||
17 | [Tooltip("Whether to poll the HD-face model data or not.")] |
||
18 | public bool getFaceModelData = false; |
||
19 | |||
20 | [Tooltip("Whether to display the face rectangle over the color camera feed.")] |
||
21 | public bool displayFaceRect = false; |
||
22 | |||
23 | [Tooltip("Time tolerance in seconds, when the face may not to be tracked, without considering it lost.")] |
||
24 | public float faceTrackingTolerance = 0.5f; |
||
25 | |||
26 | [Tooltip("Game object that will be used to display the HD-face model mesh in the scene.")] |
||
27 | public GameObject faceModelMesh = null; |
||
28 | |||
29 | [Tooltip("Whether the HD-face model mesh should be mirrored or not.")] |
||
30 | private bool mirroredModelMesh = true; |
||
31 | |||
32 | //[Tooltip("Whether to skip the continuous updates of the HD-face model mesh, or not.")] |
||
33 | //public bool dontUpdateModelMesh = false; |
||
34 | |||
35 | [Tooltip("Whether to pause the updates of the HD-face model mesh.")] |
||
36 | public bool pauseModelMeshUpdates = false; |
||
37 | |||
38 | public enum TextureType : int { None, ColorMap, FaceRectangle } |
||
39 | [Tooltip("How the HD-face model mesh should be textured.")] |
||
40 | public TextureType texturedModelMesh = TextureType.ColorMap; |
||
41 | |||
42 | [Tooltip("Whether to move the face model mesh, to be the same as user's head position.")] |
||
43 | public bool moveModelMesh = false; |
||
44 | |||
45 | [Tooltip("Camera that may be used to overlay face mesh over the color background.")] |
||
46 | public Camera foregroundCamera; |
||
47 | |||
48 | [Tooltip("Scale factor for the face mesh.")] |
||
49 | [Range(0.1f, 2.0f)] |
||
50 | public float modelMeshScale = 1f; |
||
51 | |||
52 | [Tooltip("Vertical offset of the mesh above the head (in meters).")] |
||
53 | [Range(-0.5f, 0.5f)] |
||
54 | public float verticalMeshOffset = 0f; |
||
55 | |||
56 | [Tooltip("GUI-Text to display the FT-manager debug messages.")] |
||
57 | public GUIText debugText; |
||
58 | |||
59 | // // nose and head transforms |
||
60 | // public Transform noseTransform; |
||
61 | // public Transform headTransform; |
||
62 | // public GUIText debugText2; |
||
63 | |||
64 | |||
65 | // Is currently tracking user's face |
||
66 | private bool isTrackingFace = false; |
||
67 | private float lastFaceTrackedTime = 0f; |
||
68 | |||
69 | // Skeleton ID of the tracked face |
||
70 | //private long faceTrackingID = 0; |
||
71 | |||
72 | // Animation units |
||
73 | private Dictionary<KinectInterop.FaceShapeAnimations, float> dictAU = new Dictionary<KinectInterop.FaceShapeAnimations, float>(); |
||
74 | private bool bGotAU = false; |
||
75 | |||
76 | // Shape units |
||
77 | private Dictionary<KinectInterop.FaceShapeDeformations, float> dictSU = new Dictionary<KinectInterop.FaceShapeDeformations, float>(); |
||
78 | private bool bGotSU = false; |
||
79 | |||
80 | // whether the face model mesh was initialized |
||
81 | private bool bFaceModelMeshInited = false; |
||
82 | private Vector3[] vMeshVertices = null; |
||
83 | |||
84 | // Vertices, UV and triangles of the face model |
||
85 | private Vector3[] avModelVertices = null; |
||
86 | private Vector2[] avModelUV = null; |
||
87 | private bool bGotModelVertices = false; |
||
88 | //private bool bGotModelVerticesFromDC = false; |
||
89 | |||
90 | private int[] avModelTriangles = null; |
||
91 | private bool bGotModelTriangles = false; |
||
92 | private bool bGotModelTrianglesFromDC = false; |
||
93 | |||
94 | // Head position and rotation |
||
95 | private Vector3 headPos = Vector3.zero; |
||
96 | private bool bGotHeadPos = false; |
||
97 | |||
98 | private Quaternion headRot = Quaternion.identity; |
||
99 | private bool bGotHeadRot = false; |
||
100 | |||
101 | // offset vector from head to face center |
||
102 | private Vector3 faceHeadOffset = Vector3.zero; |
||
103 | |||
104 | // Tracked face rectangle |
||
105 | private Rect faceRect = new Rect(); |
||
106 | //private bool bGotFaceRect; |
||
107 | |||
108 | // primary user ID, as reported by KinectManager |
||
109 | private long primaryUserID = 0; |
||
110 | private long lastUserID = 0; |
||
111 | |||
112 | // primary sensor data structure |
||
113 | private KinectInterop.SensorData sensorData = null; |
||
114 | |||
115 | // Bool to keep track of whether face-tracking system has been initialized |
||
116 | private bool isFacetrackingInitialized = false; |
||
117 | private bool wasFacetrackingActive = false; |
||
118 | |||
119 | // The single instance of FacetrackingManager |
||
120 | private static FacetrackingManager instance; |
||
121 | |||
122 | // update times |
||
123 | private float facePosUpdateTime = 0f; |
||
124 | private float faceMeshUpdateTime = 0f; |
||
125 | |||
126 | // used when dontUpdateModelMesh is true |
||
127 | //private bool faceMeshGotOnce = false; |
||
128 | |||
129 | // whether UpdateFaceModelMesh() is running |
||
130 | private bool updateFaceMeshStarted = false; |
||
131 | |||
132 | private RenderTexture faceMeshTexture = null; |
||
133 | private Vector3 nosePos = Vector3.zero; |
||
134 | |||
135 | /// <summary> |
||
136 | /// Gets the single FacetrackingManager instance. |
||
137 | /// </summary> |
||
138 | /// <value>The FacetrackingManager instance.</value> |
||
139 | public static FacetrackingManager Instance |
||
140 | { |
||
141 | get |
||
142 | { |
||
143 | return instance; |
||
144 | } |
||
145 | } |
||
146 | |||
147 | /// <summary> |
||
148 | /// Determines the facetracking system was successfully initialized, false otherwise. |
||
149 | /// </summary> |
||
150 | /// <returns><c>true</c> if the facetracking system was successfully initialized; otherwise, <c>false</c>.</returns> |
||
151 | public bool IsFaceTrackingInitialized() |
||
152 | { |
||
153 | return isFacetrackingInitialized; |
||
154 | } |
||
155 | |||
156 | /// <summary> |
||
157 | /// Determines whether this the sensor is currently tracking a face. |
||
158 | /// </summary> |
||
159 | /// <returns><c>true</c> if the sensor is tracking a face; otherwise, <c>false</c>.</returns> |
||
160 | public bool IsTrackingFace() |
||
161 | { |
||
162 | return isTrackingFace; |
||
163 | } |
||
164 | |||
165 | /// <summary> |
||
166 | /// Gets the current user ID, or 0 if no user is currently tracked. |
||
167 | /// </summary> |
||
168 | /// <returns>The face tracking I.</returns> |
||
169 | public long GetFaceTrackingID() |
||
170 | { |
||
171 | return isTrackingFace ? primaryUserID : 0; |
||
172 | } |
||
173 | |||
174 | /// <summary> |
||
175 | /// Determines whether the sensor is currently tracking the face of the specified user. |
||
176 | /// </summary> |
||
177 | /// <returns><c>true</c> if the sensor is currently tracking the face of the specified user; otherwise, <c>false</c>.</returns> |
||
178 | /// <param name="userId">User ID</param> |
||
179 | public bool IsTrackingFace(long userId) |
||
180 | { |
||
181 | if(sensorData != null && sensorData.sensorInterface != null) |
||
182 | { |
||
183 | return sensorData.sensorInterface.IsFaceTracked(userId); |
||
184 | } |
||
185 | |||
186 | return false; |
||
187 | } |
||
188 | |||
189 | /// <summary> |
||
190 | /// Gets the last face position & rotation update time, in seconds since game start. |
||
191 | /// </summary> |
||
192 | /// <returns>The last face position & rotation update time.</returns> |
||
193 | public float GetFacePosUpdateTime() |
||
194 | { |
||
195 | return facePosUpdateTime; |
||
196 | } |
||
197 | |||
198 | /// <summary> |
||
199 | /// Gets the last face mesh update time, in seconds since game start. |
||
200 | /// </summary> |
||
201 | /// <returns>The last face mesh update time.</returns> |
||
202 | public float GetFaceMeshUpdateTime() |
||
203 | { |
||
204 | return faceMeshUpdateTime; |
||
205 | } |
||
206 | |||
207 | /// <summary> |
||
208 | /// Gets the head position of the currently tracked user. |
||
209 | /// </summary> |
||
210 | /// <returns>The head position.</returns> |
||
211 | /// <param name="bMirroredMovement">If set to <c>true</c> returns mirorred head position.</param> |
||
212 | public Vector3 GetHeadPosition(bool bMirroredMovement) |
||
213 | { |
||
214 | Vector3 vHeadPos = headPos; // bGotHeadPos ? headPos : Vector3.zero; |
||
215 | |||
216 | if(!bMirroredMovement) |
||
217 | { |
||
218 | vHeadPos.z = -vHeadPos.z; |
||
219 | } |
||
220 | |||
221 | return vHeadPos; |
||
222 | } |
||
223 | |||
224 | /// <summary> |
||
225 | /// Gets the head position of the specified user. |
||
226 | /// </summary> |
||
227 | /// <returns>The head position.</returns> |
||
228 | /// <param name="userId">User ID</param> |
||
229 | /// <param name="bMirroredMovement">If set to <c>true</c> returns mirorred head position.</param> |
||
230 | public Vector3 GetHeadPosition(long userId, bool bMirroredMovement) |
||
231 | { |
||
232 | Vector3 vHeadPos = Vector3.zero; |
||
233 | bool bGotPosition = sensorData.sensorInterface.GetHeadPosition(userId, ref vHeadPos); |
||
234 | |||
235 | if(bGotPosition) |
||
236 | { |
||
237 | if(!bMirroredMovement) |
||
238 | { |
||
239 | vHeadPos.z = -vHeadPos.z; |
||
240 | } |
||
241 | |||
242 | return vHeadPos; |
||
243 | } |
||
244 | |||
245 | return Vector3.zero; |
||
246 | } |
||
247 | |||
248 | /// <summary> |
||
249 | /// Gets the head rotation of the currently tracked user. |
||
250 | /// </summary> |
||
251 | /// <returns>The head rotation.</returns> |
||
252 | /// <param name="bMirroredMovement">If set to <c>true</c> returns mirorred head rotation.</param> |
||
253 | public Quaternion GetHeadRotation(bool bMirroredMovement) |
||
254 | { |
||
255 | Vector3 rotAngles = headRot.eulerAngles; // bGotHeadRot ? headRot.eulerAngles : Vector3.zero; |
||
256 | |||
257 | if(bMirroredMovement) |
||
258 | { |
||
259 | rotAngles.x = -rotAngles.x; |
||
260 | rotAngles.z = -rotAngles.z; |
||
261 | } |
||
262 | else |
||
263 | { |
||
264 | rotAngles.x = -rotAngles.x; |
||
265 | rotAngles.y = -rotAngles.y; |
||
266 | } |
||
267 | |||
268 | return Quaternion.Euler(rotAngles); |
||
269 | } |
||
270 | |||
271 | /// <summary> |
||
272 | /// Gets the head rotation of the specified user. |
||
273 | /// </summary> |
||
274 | /// <returns>The head rotation.</returns> |
||
275 | /// <param name="userId">User ID</param> |
||
276 | /// <param name="bMirroredMovement">If set to <c>true</c> returns mirorred head rotation.</param> |
||
277 | public Quaternion GetHeadRotation(long userId, bool bMirroredMovement) |
||
278 | { |
||
279 | Quaternion vHeadRot = Quaternion.identity; |
||
280 | bool bGotRotation = sensorData.sensorInterface.GetHeadRotation(userId, ref vHeadRot); |
||
281 | |||
282 | if(bGotRotation) |
||
283 | { |
||
284 | Vector3 rotAngles = vHeadRot.eulerAngles; |
||
285 | |||
286 | if(bMirroredMovement) |
||
287 | { |
||
288 | rotAngles.x = -rotAngles.x; |
||
289 | rotAngles.z = -rotAngles.z; |
||
290 | } |
||
291 | else |
||
292 | { |
||
293 | rotAngles.x = -rotAngles.x; |
||
294 | rotAngles.y = -rotAngles.y; |
||
295 | } |
||
296 | |||
297 | return Quaternion.Euler(rotAngles); |
||
298 | } |
||
299 | |||
300 | return Quaternion.identity; |
||
301 | } |
||
302 | |||
303 | /// <summary> |
||
304 | /// Gets the tracked face rectangle of the specified user in color image coordinates, or zero-rect if the user's face is not tracked. |
||
305 | /// </summary> |
||
306 | /// <returns>The face rectangle, in color image coordinates.</returns> |
||
307 | /// <param name="userId">User ID</param> |
||
308 | public Rect GetFaceColorRect(long userId) |
||
309 | { |
||
310 | Rect faceColorRect = new Rect(); |
||
311 | sensorData.sensorInterface.GetFaceRect(userId, ref faceColorRect); |
||
312 | |||
313 | return faceColorRect; |
||
314 | } |
||
315 | |||
316 | /// <summary> |
||
317 | /// Determines whether there are valid anim units. |
||
318 | /// </summary> |
||
319 | /// <returns><c>true</c> if there are valid anim units; otherwise, <c>false</c>.</returns> |
||
320 | public bool IsGotAU() |
||
321 | { |
||
322 | return bGotAU; |
||
323 | } |
||
324 | |||
325 | /// <summary> |
||
326 | /// Gets the animation unit value at given index, or 0 if the index is invalid. |
||
327 | /// </summary> |
||
328 | /// <returns>The animation unit value.</returns> |
||
329 | /// <param name="faceAnimKey">Face animation unit.</param> |
||
330 | public float GetAnimUnit(KinectInterop.FaceShapeAnimations faceAnimKey) |
||
331 | { |
||
332 | if(dictAU.ContainsKey(faceAnimKey)) |
||
333 | { |
||
334 | return dictAU[faceAnimKey]; |
||
335 | } |
||
336 | |||
337 | return 0.0f; |
||
338 | } |
||
339 | |||
340 | /// <summary> |
||
341 | /// Gets all animation units for the specified user. |
||
342 | /// </summary> |
||
343 | /// <returns><c>true</c>, if the user's face is tracked, <c>false</c> otherwise.</returns> |
||
344 | /// <param name="userId">User ID</param> |
||
345 | /// <param name="dictAnimUnits">Animation units dictionary, to get the results.</param> |
||
346 | public bool GetUserAnimUnits(long userId, ref Dictionary<KinectInterop.FaceShapeAnimations, float> dictAnimUnits) |
||
347 | { |
||
348 | if(sensorData != null && sensorData.sensorInterface != null) |
||
349 | { |
||
350 | bool bGotIt = sensorData.sensorInterface.GetAnimUnits(userId, ref dictAnimUnits); |
||
351 | return bGotIt; |
||
352 | } |
||
353 | |||
354 | return false; |
||
355 | } |
||
356 | |||
357 | /// <summary> |
||
358 | /// Determines whether there are valid shape units. |
||
359 | /// </summary> |
||
360 | /// <returns><c>true</c> if there are valid shape units; otherwise, <c>false</c>.</returns> |
||
361 | public bool IsGotSU() |
||
362 | { |
||
363 | return bGotSU; |
||
364 | } |
||
365 | |||
366 | /// <summary> |
||
367 | /// Gets the shape unit value at given index, or 0 if the index is invalid. |
||
368 | /// </summary> |
||
369 | /// <returns>The shape unit value.</returns> |
||
370 | /// <param name="faceShapeKey">Face shape unit.</param> |
||
371 | public float GetShapeUnit(KinectInterop.FaceShapeDeformations faceShapeKey) |
||
372 | { |
||
373 | if(dictSU.ContainsKey(faceShapeKey)) |
||
374 | { |
||
375 | return dictSU[faceShapeKey]; |
||
376 | } |
||
377 | |||
378 | return 0.0f; |
||
379 | } |
||
380 | |||
381 | /// <summary> |
||
382 | /// Gets all animation units for the specified user. |
||
383 | /// </summary> |
||
384 | /// <returns><c>true</c>, if the user's face is tracked, <c>false</c> otherwise.</returns> |
||
385 | /// <param name="userId">User ID</param> |
||
386 | /// <param name="dictShapeUnits">Shape units dictionary, to get the results.</param> |
||
387 | public bool GetUserShapeUnits(long userId, ref Dictionary<KinectInterop.FaceShapeDeformations, float> dictShapeUnits) |
||
388 | { |
||
389 | if(sensorData != null && sensorData.sensorInterface != null) |
||
390 | { |
||
391 | bool bGotIt = sensorData.sensorInterface.GetShapeUnits(userId, ref dictShapeUnits); |
||
392 | return bGotIt; |
||
393 | } |
||
394 | |||
395 | return false; |
||
396 | } |
||
397 | |||
398 | /// <summary> |
||
399 | /// Gets the count of face model vertices. |
||
400 | /// </summary> |
||
401 | /// <returns>The count of face model vertices.</returns> |
||
402 | public int GetFaceModelVertexCount() |
||
403 | { |
||
404 | if (avModelVertices != null) |
||
405 | { |
||
406 | return avModelVertices.Length; |
||
407 | } |
||
408 | |||
409 | return 0; |
||
410 | } |
||
411 | |||
412 | /// <summary> |
||
413 | /// Gets the face model vertex, if a face model is available and the index is in range; Vector3.zero otherwise. |
||
414 | /// </summary> |
||
415 | /// <returns>The face model vertex.</returns> |
||
416 | /// <param name="index">Vertex index, or Vector3.zero</param> |
||
417 | public Vector3 GetFaceModelVertex(int index) |
||
418 | { |
||
419 | if (avModelVertices != null) |
||
420 | { |
||
421 | if(index >= 0 && index < avModelVertices.Length) |
||
422 | { |
||
423 | return avModelVertices[index]; |
||
424 | } |
||
425 | } |
||
426 | |||
427 | return Vector3.zero; |
||
428 | } |
||
429 | |||
430 | /// <summary> |
||
431 | /// Gets all face model vertices, if a face model is available; null otherwise. |
||
432 | /// </summary> |
||
433 | /// <returns>The face model vertices, or null.</returns> |
||
434 | public Vector3[] GetFaceModelVertices() |
||
435 | { |
||
436 | return avModelVertices; |
||
437 | } |
||
438 | |||
439 | /// <summary> |
||
440 | /// Gets the count of face model vertices for the specified user |
||
441 | /// </summary> |
||
442 | /// <returns>The count of face model vertices.</returns> |
||
443 | /// <param name="userId">User ID</param> |
||
444 | public int GetUserFaceVertexCount(long userId) |
||
445 | { |
||
446 | if(sensorData != null && sensorData.sensorInterface != null) |
||
447 | { |
||
448 | int iVertCount = sensorData.sensorInterface.GetFaceModelVerticesCount(userId); |
||
449 | return iVertCount; |
||
450 | } |
||
451 | |||
452 | return 0; |
||
453 | } |
||
454 | |||
455 | /// <summary> |
||
456 | /// Gets all face model vertices for the specified user. |
||
457 | /// </summary> |
||
458 | /// <returns><c>true</c>, if the user's face is tracked, <c>false</c> otherwise.</returns> |
||
459 | /// <param name="userId">User ID</param> |
||
460 | /// <param name="avVertices">Reference to array of vertices, to get the result.</param> |
||
461 | public bool GetUserFaceVertices(long userId, ref Vector3[] avVertices) |
||
462 | { |
||
463 | if(sensorData != null && sensorData.sensorInterface != null) |
||
464 | { |
||
465 | bool bGotIt = sensorData.sensorInterface.GetFaceModelVertices(userId, ref avVertices); |
||
466 | return bGotIt; |
||
467 | } |
||
468 | |||
469 | return false; |
||
470 | } |
||
471 | |||
472 | /// <summary> |
||
473 | /// Gets the count of face model triangles. |
||
474 | /// </summary> |
||
475 | /// <returns>The count of face model triangles.</returns> |
||
476 | public int GetFaceModelTriangleCount() |
||
477 | { |
||
478 | if (avModelTriangles != null) |
||
479 | { |
||
480 | return avModelTriangles.Length; |
||
481 | } |
||
482 | |||
483 | return 0; |
||
484 | } |
||
485 | |||
486 | /// <summary> |
||
487 | /// Gets the face model triangle indices, if a face model is available; null otherwise. |
||
488 | /// </summary> |
||
489 | /// <returns>The face model triangle indices, or null.</returns> |
||
490 | /// <param name="bMirroredModel">If set to <c>true</c> gets mirorred model indices.</param> |
||
491 | public int[] GetFaceModelTriangleIndices(bool bMirroredModel) |
||
492 | { |
||
493 | if (avModelTriangles != null) |
||
494 | { |
||
495 | return avModelTriangles; |
||
496 | } |
||
497 | |||
498 | return null; |
||
499 | } |
||
500 | |||
501 | |||
502 | //----------------------------------- end of public functions --------------------------------------// |
||
503 | |||
504 | void Awake() |
||
505 | { |
||
506 | instance = this; |
||
507 | } |
||
508 | |||
509 | void Start() |
||
510 | { |
||
511 | try |
||
512 | { |
||
513 | // get sensor data |
||
514 | KinectManager kinectManager = KinectManager.Instance; |
||
515 | if(kinectManager && kinectManager.IsInitialized()) |
||
516 | { |
||
517 | sensorData = kinectManager.GetSensorData(); |
||
518 | } |
||
519 | |||
520 | if(sensorData == null || sensorData.sensorInterface == null) |
||
521 | { |
||
522 | throw new Exception("Face tracking cannot be started, because KinectManager is missing or not initialized."); |
||
523 | } |
||
524 | |||
525 | if(debugText != null) |
||
526 | { |
||
527 | debugText.text = "Please, wait..."; |
||
528 | } |
||
529 | |||
530 | // ensure the needed dlls are in place and face tracking is available for this interface |
||
531 | bool bNeedRestart = false; |
||
532 | if(sensorData.sensorInterface.IsFaceTrackingAvailable(ref bNeedRestart)) |
||
533 | { |
||
534 | if(bNeedRestart) |
||
535 | { |
||
536 | KinectInterop.RestartLevel(gameObject, "FM"); |
||
537 | return; |
||
538 | } |
||
539 | } |
||
540 | else |
||
541 | { |
||
542 | string sInterfaceName = sensorData.sensorInterface.GetType().Name; |
||
543 | throw new Exception(sInterfaceName + ": Face tracking is not supported!"); |
||
544 | } |
||
545 | |||
546 | // Initialize the face tracker |
||
547 | wasFacetrackingActive = sensorData.sensorInterface.IsFaceTrackingActive(); |
||
548 | if(!wasFacetrackingActive) |
||
549 | { |
||
550 | if (!sensorData.sensorInterface.InitFaceTracking(getFaceModelData, displayFaceRect)) |
||
551 | { |
||
552 | throw new Exception("Face tracking could not be initialized."); |
||
553 | } |
||
554 | } |
||
555 | |||
556 | isFacetrackingInitialized = true; |
||
557 | |||
558 | //DontDestroyOnLoad(gameObject); |
||
559 | |||
560 | if(debugText != null) |
||
561 | { |
||
562 | debugText.text = "Ready."; |
||
563 | } |
||
564 | } |
||
565 | catch(DllNotFoundException ex) |
||
566 | { |
||
567 | Debug.LogError(ex.ToString()); |
||
568 | if(debugText != null) |
||
569 | debugText.text = "Please check the Kinect and FT-Library installations."; |
||
570 | } |
||
571 | catch (Exception ex) |
||
572 | { |
||
573 | Debug.LogError(ex.ToString()); |
||
574 | if(debugText != null) |
||
575 | debugText.text = ex.Message; |
||
576 | } |
||
577 | } |
||
578 | |||
579 | void OnDestroy() |
||
580 | { |
||
581 | if(isFacetrackingInitialized && !wasFacetrackingActive && sensorData != null && sensorData.sensorInterface != null) |
||
582 | { |
||
583 | // finish face tracking |
||
584 | sensorData.sensorInterface.FinishFaceTracking(); |
||
585 | } |
||
586 | |||
587 | if (faceMeshTexture != null) |
||
588 | { |
||
589 | faceMeshTexture.Release(); |
||
590 | faceMeshTexture = null; |
||
591 | } |
||
592 | |||
593 | // // clean up |
||
594 | // Resources.UnloadUnusedAssets(); |
||
595 | // GC.Collect(); |
||
596 | |||
597 | isFacetrackingInitialized = false; |
||
598 | instance = null; |
||
599 | } |
||
600 | |||
601 | void Update() |
||
602 | { |
||
603 | if(isFacetrackingInitialized) |
||
604 | { |
||
605 | KinectManager kinectManager = KinectManager.Instance; |
||
606 | if(kinectManager && kinectManager.IsInitialized()) |
||
607 | { |
||
608 | lastUserID = primaryUserID; |
||
609 | primaryUserID = kinectManager.GetUserIdByIndex(playerIndex); |
||
610 | |||
611 | if (primaryUserID != lastUserID && primaryUserID != 0) |
||
612 | { |
||
613 | //faceMeshGotOnce = false; |
||
614 | } |
||
615 | } |
||
616 | |||
617 | // update the face tracker |
||
618 | isTrackingFace = false; |
||
619 | |||
620 | bool bFacetrackingUpdated = !wasFacetrackingActive ? sensorData.sensorInterface.UpdateFaceTracking() : true; |
||
621 | if(bFacetrackingUpdated) |
||
622 | { |
||
623 | // estimate the tracking state |
||
624 | isTrackingFace = sensorData.sensorInterface.IsFaceTracked(primaryUserID); |
||
625 | |||
626 | if(!isTrackingFace && (Time.realtimeSinceStartup - lastFaceTrackedTime) <= faceTrackingTolerance) |
||
627 | { |
||
628 | // allow tolerance in tracking |
||
629 | isTrackingFace = true; |
||
630 | } |
||
631 | |||
632 | // get the facetracking parameters |
||
633 | if(isTrackingFace) |
||
634 | { |
||
635 | lastFaceTrackedTime = Time.realtimeSinceStartup; |
||
636 | facePosUpdateTime = Time.time; |
||
637 | |||
638 | // get face rectangle |
||
639 | /**bGotFaceRect =*/ sensorData.sensorInterface.GetFaceRect(primaryUserID, ref faceRect); |
||
640 | |||
641 | // get head position |
||
642 | bGotHeadPos = sensorData.sensorInterface.GetHeadPosition(primaryUserID, ref headPos); |
||
643 | |||
644 | // get head rotation |
||
645 | bGotHeadRot = sensorData.sensorInterface.GetHeadRotation(primaryUserID, ref headRot); |
||
646 | |||
647 | // get the animation units |
||
648 | bGotAU = sensorData.sensorInterface.GetAnimUnits(primaryUserID, ref dictAU); |
||
649 | |||
650 | // get the shape units |
||
651 | bGotSU = sensorData.sensorInterface.GetShapeUnits(primaryUserID, ref dictSU); |
||
652 | |||
653 | //if(faceModelMesh != null && faceModelMesh.activeInHierarchy) |
||
654 | { |
||
655 | // apply model vertices to the mesh |
||
656 | if(!bFaceModelMeshInited) |
||
657 | { |
||
658 | bFaceModelMeshInited = CreateFaceModelMesh(); |
||
659 | } |
||
660 | } |
||
661 | |||
662 | if (getFaceModelData && bFaceModelMeshInited && primaryUserID != 0) |
||
663 | { |
||
664 | if (!pauseModelMeshUpdates && !updateFaceMeshStarted) |
||
665 | { |
||
666 | StartCoroutine(UpdateFaceModelMesh()); |
||
667 | } |
||
668 | } |
||
669 | } |
||
670 | } |
||
671 | |||
672 | // // set mesh activity flag |
||
673 | // bool bFaceMeshActive = isTrackingFace && primaryUserID != 0; |
||
674 | // if(faceModelMesh != null && bFaceModelMeshInited && faceModelMesh.activeSelf != bFaceMeshActive) |
||
675 | // { |
||
676 | // faceModelMesh.SetActive(bFaceMeshActive); |
||
677 | // } |
||
678 | } |
||
679 | } |
||
680 | |||
681 | void OnGUI() |
||
682 | { |
||
683 | if(isFacetrackingInitialized) |
||
684 | { |
||
685 | if(debugText != null) |
||
686 | { |
||
687 | if(isTrackingFace) |
||
688 | { |
||
689 | debugText.text = "Tracking - BodyID: " + primaryUserID; |
||
690 | } |
||
691 | else |
||
692 | { |
||
693 | debugText.text = "Not tracking..."; |
||
694 | } |
||
695 | } |
||
696 | } |
||
697 | } |
||
698 | |||
699 | |||
700 | protected bool CreateFaceModelMesh() |
||
701 | { |
||
702 | // if(faceModelMesh == null) |
||
703 | // return false; |
||
704 | |||
705 | if (avModelVertices == null /**&& !bGotModelVerticesFromDC*/) |
||
706 | { |
||
707 | int iNumVertices = sensorData.sensorInterface.GetFaceModelVerticesCount(0); |
||
708 | if(iNumVertices <= 0) |
||
709 | return false; |
||
710 | |||
711 | avModelVertices = new Vector3[iNumVertices]; |
||
712 | bGotModelVertices = sensorData.sensorInterface.GetFaceModelVertices(0, ref avModelVertices); |
||
713 | |||
714 | avModelUV = new Vector2[iNumVertices]; |
||
715 | |||
716 | if(!bGotModelVertices) |
||
717 | return false; |
||
718 | } |
||
719 | |||
720 | // estimate face mesh vertices with respect to the head joint |
||
721 | Vector3[] vMeshVertices = new Vector3[avModelVertices.Length]; |
||
722 | |||
723 | //if (!bGotModelVerticesFromDC) |
||
724 | { |
||
725 | Vector3 vFaceCenter = Vector3.zero; |
||
726 | for (int i = 0; i < avModelVertices.Length; i++) |
||
727 | { |
||
728 | vFaceCenter += avModelVertices[i]; |
||
729 | } |
||
730 | |||
731 | vFaceCenter /= (float)avModelVertices.Length; |
||
732 | |||
733 | faceHeadOffset = Vector3.zero; |
||
734 | if (vFaceCenter.sqrMagnitude >= 1f) |
||
735 | { |
||
736 | Vector3 vHeadToFace = (vFaceCenter - headPos); |
||
737 | |||
738 | faceHeadOffset = Quaternion.Inverse(headRot) * vHeadToFace; |
||
739 | faceHeadOffset.y += verticalMeshOffset; |
||
740 | } |
||
741 | |||
742 | vFaceCenter -= headRot * faceHeadOffset; |
||
743 | |||
744 | for(int i = 0; i < avModelVertices.Length; i++) |
||
745 | { |
||
746 | //avModelVertices[i] = kinectToWorld.MultiplyPoint3x4(avModelVertices[i]) - headPosWorld; |
||
747 | //avModelVertices[i] -= vFaceCenter; |
||
748 | |||
749 | vMeshVertices[i] = avModelVertices[i] - vFaceCenter; |
||
750 | } |
||
751 | } |
||
752 | |||
753 | if (avModelTriangles == null && !bGotModelTrianglesFromDC) |
||
754 | { |
||
755 | int iNumTriangles = sensorData.sensorInterface.GetFaceModelTrianglesCount(); |
||
756 | if(iNumTriangles <= 0) |
||
757 | return false; |
||
758 | |||
759 | avModelTriangles = new int[iNumTriangles]; |
||
760 | bGotModelTriangles = sensorData.sensorInterface.GetFaceModelTriangles(mirroredModelMesh, ref avModelTriangles); |
||
761 | |||
762 | if(!bGotModelTriangles) |
||
763 | return false; |
||
764 | } |
||
765 | |||
766 | if (faceModelMesh) |
||
767 | { |
||
768 | Mesh mesh = new Mesh(); |
||
769 | mesh.name = "FaceMesh"; |
||
770 | faceModelMesh.GetComponent<MeshFilter>().mesh = mesh; |
||
771 | |||
772 | mesh.vertices = vMeshVertices; // avModelVertices; |
||
773 | //mesh.uv = avModelUV; |
||
774 | |||
775 | mesh.triangles = avModelTriangles; |
||
776 | mesh.RecalculateNormals(); |
||
777 | |||
778 | // if (moveModelMesh) |
||
779 | // { |
||
780 | // faceModelMesh.transform.position = headPos; |
||
781 | // //faceModelMesh.transform.rotation = faceModelRot; |
||
782 | // } |
||
783 | |||
784 | SetFaceModelMeshTexture(); |
||
785 | } |
||
786 | |||
787 | //bFaceModelMeshInited = true; |
||
788 | return true; |
||
789 | } |
||
790 | |||
791 | // sets the proper face mesh texture |
||
792 | protected void SetFaceModelMeshTexture() |
||
793 | { |
||
794 | if (texturedModelMesh == TextureType.ColorMap) |
||
795 | { |
||
796 | KinectManager kinectManager = KinectManager.Instance; |
||
797 | Texture texColorMap = kinectManager ? kinectManager.GetUsersClrTex() : null; |
||
798 | |||
799 | if (!faceMeshTexture && kinectManager && texColorMap) |
||
800 | { |
||
801 | faceMeshTexture = new RenderTexture (texColorMap.width, texColorMap.height, 0); |
||
802 | faceModelMesh.GetComponent<MeshRenderer>().material.mainTexture = faceMeshTexture; // kinectManager.GetUsersClrTex(); |
||
803 | } |
||
804 | |||
805 | if (faceMeshTexture && texColorMap) |
||
806 | { |
||
807 | // update the color texture |
||
808 | Graphics.Blit(texColorMap, faceMeshTexture); |
||
809 | } |
||
810 | } |
||
811 | else if (texturedModelMesh == TextureType.FaceRectangle) |
||
812 | { |
||
813 | if (faceMeshTexture != null) |
||
814 | { |
||
815 | faceMeshTexture = null; |
||
816 | } |
||
817 | } |
||
818 | else if(texturedModelMesh == TextureType.None) |
||
819 | { |
||
820 | if (faceModelMesh.GetComponent<MeshRenderer>().material.mainTexture != null) |
||
821 | { |
||
822 | faceMeshTexture = null; |
||
823 | faceModelMesh.GetComponent<MeshRenderer>().material.mainTexture = null; |
||
824 | } |
||
825 | } |
||
826 | } |
||
827 | |||
828 | |||
829 | protected IEnumerator UpdateFaceModelMesh() |
||
830 | { |
||
831 | updateFaceMeshStarted = true; |
||
832 | |||
833 | //if (!dontUpdateModelMesh || !faceMeshGotOnce /**&& !bGotModelVerticesFromDC*/) |
||
834 | { |
||
835 | // init the vertices array if needed |
||
836 | if(avModelVertices == null) |
||
837 | { |
||
838 | int iNumVertices = sensorData.sensorInterface.GetFaceModelVerticesCount(primaryUserID); |
||
839 | avModelVertices = new Vector3[iNumVertices]; |
||
840 | } |
||
841 | |||
842 | // get face model vertices |
||
843 | bGotModelVertices = sensorData.sensorInterface.GetFaceModelVertices(primaryUserID, ref avModelVertices); |
||
844 | } |
||
845 | |||
846 | if(bGotModelVertices && faceModelMesh != null) |
||
847 | { |
||
848 | //Quaternion faceModelRot = faceModelMesh.transform.rotation; |
||
849 | //faceModelMesh.transform.rotation = Quaternion.identity; |
||
850 | |||
851 | bool bFaceMeshUpdated = false; |
||
852 | //if (!dontUpdateModelMesh || !faceMeshGotOnce) |
||
853 | { |
||
854 | AsyncTask<bool> task = new AsyncTask<bool>(() => { |
||
855 | // estimate face mesh vertices with respect to the head joint |
||
856 | vMeshVertices = null; |
||
857 | |||
858 | KinectManager kinectManager = KinectManager.Instance; |
||
859 | Matrix4x4 kinectToWorld = kinectManager ? kinectManager.GetKinectToWorldMatrix() : Matrix4x4.identity; |
||
860 | Vector3 headPosWorld = kinectToWorld.MultiplyPoint3x4(headPos); |
||
861 | |||
862 | Vector3 lastNosePos = nosePos; |
||
863 | //if (!bGotModelVerticesFromDC) |
||
864 | { |
||
865 | // Vector3 vFaceCenter = Vector3.zero; |
||
866 | // for (int i = 0; i < avModelVertices.Length; i++) |
||
867 | // { |
||
868 | // vFaceCenter += avModelVertices[i]; |
||
869 | // } |
||
870 | // |
||
871 | // vFaceCenter /= (float)avModelVertices.Length; |
||
872 | // |
||
873 | // Vector3 vHeadToFace = (vFaceCenter - headPos); |
||
874 | // if (vHeadToFace.sqrMagnitude < 0.015f) // max 0.12 x 0.12 |
||
875 | // { |
||
876 | // faceHeadOffset = Quaternion.Inverse(headRot) * vHeadToFace; |
||
877 | // faceHeadOffset.y += verticalMeshOffset; |
||
878 | // } |
||
879 | |||
880 | nosePos = GetFaceModelNosePos(); |
||
881 | Vector3 vHeadToNose = Quaternion.Inverse(headRot) * (nosePos - headPos); |
||
882 | float headToNoseLen = vHeadToNose.magnitude; |
||
883 | |||
884 | // string sHeadToNose = string.Format("({0:F2}, {0:F2}, {0:F2})", vHeadToNose.x, vHeadToNose.y, vHeadToNose.z); |
||
885 | // Debug.Log("U-Face nosePos: " + nosePos + ", headPos: " + headPos + "\noffset: " + sHeadToNose + ", len: " + headToNoseLen); |
||
886 | |||
887 | if(headToNoseLen >= 0.08f && headToNoseLen <= 0.18f) |
||
888 | { |
||
889 | //vFaceCenter -= headRot * faceHeadOffset; |
||
890 | |||
891 | vMeshVertices = new Vector3[avModelVertices.Length]; |
||
892 | for(int i = 0; i < avModelVertices.Length; i++) |
||
893 | { |
||
894 | //avModelVertices[i] = kinectToWorld.MultiplyPoint3x4(avModelVertices[i]) - headPosWorld; |
||
895 | //avModelVertices[i] -= vFaceCenter; |
||
896 | |||
897 | //vMeshVertices[i] = avModelVertices[i] - vFaceCenter; |
||
898 | vMeshVertices[i] = kinectToWorld.MultiplyPoint3x4(avModelVertices[i]) - headPosWorld; // avModelVertices[i] - headPos; |
||
899 | } |
||
900 | } |
||
901 | } |
||
902 | |||
903 | if(vMeshVertices == null || lastNosePos == nosePos) |
||
904 | { |
||
905 | return false; |
||
906 | } |
||
907 | |||
908 | //if (!bGotModelVerticesFromDC) |
||
909 | { |
||
910 | if(texturedModelMesh != TextureType.None) |
||
911 | { |
||
912 | float colorWidth = (float)kinectManager.GetColorImageWidth(); |
||
913 | float colorHeight = (float)kinectManager.GetColorImageHeight(); |
||
914 | |||
915 | //bool bGotFaceRect = sensorData.sensorInterface.GetFaceRect(userId, ref faceRect); |
||
916 | bool faceRectValid = /**bGotFaceRect &&*/ faceRect.width > 0 && faceRect.height > 0; |
||
917 | |||
918 | for(int i = 0; i < avModelVertices.Length; i++) |
||
919 | { |
||
920 | Vector2 posDepth = kinectManager.MapSpacePointToDepthCoords(avModelVertices[i]); |
||
921 | |||
922 | bool bUvSet = false; |
||
923 | if(posDepth != Vector2.zero) |
||
924 | { |
||
925 | ushort depth = kinectManager.GetDepthForPixel((int)posDepth.x, (int)posDepth.y); |
||
926 | Vector2 posColor = kinectManager.MapDepthPointToColorCoords(posDepth, depth); |
||
927 | |||
928 | if(posColor != Vector2.zero && !float.IsInfinity(posColor.x) && !float.IsInfinity(posColor.y)) |
||
929 | { |
||
930 | if(texturedModelMesh == TextureType.ColorMap) |
||
931 | { |
||
932 | avModelUV[i] = new Vector2(posColor.x / colorWidth, posColor.y / colorHeight); |
||
933 | bUvSet = true; |
||
934 | } |
||
935 | else if(texturedModelMesh == TextureType.FaceRectangle && faceRectValid) |
||
936 | { |
||
937 | avModelUV[i] = new Vector2(Mathf.Clamp01((posColor.x - faceRect.x) / faceRect.width), |
||
938 | -Mathf.Clamp01((posColor.y - faceRect.y) / faceRect.height)); |
||
939 | bUvSet = true; |
||
940 | } |
||
941 | } |
||
942 | } |
||
943 | |||
944 | if(!bUvSet) |
||
945 | { |
||
946 | avModelUV[i] = Vector2.zero; |
||
947 | } |
||
948 | } |
||
949 | } |
||
950 | } |
||
951 | |||
952 | return true; |
||
953 | }); |
||
954 | |||
955 | task.Start(); |
||
956 | |||
957 | while (task.State == AsyncTaskState.Running) |
||
958 | { |
||
959 | yield return null; |
||
960 | } |
||
961 | |||
962 | // // show nose & head positions |
||
963 | // Matrix4x4 kinectToWorld2 = KinectManager.Instance.GetKinectToWorldMatrix(); |
||
964 | // if (noseTransform) |
||
965 | // noseTransform.position = kinectToWorld2.MultiplyPoint3x4(nosePos); |
||
966 | // if(headTransform) |
||
967 | // headTransform.position = kinectToWorld2.MultiplyPoint3x4(headPos); |
||
968 | // |
||
969 | // Vector3 vHeadToNose2 = Quaternion.Inverse(headRot) * (nosePos - headPos); |
||
970 | // string sHeadToNose2 = string.Format("({0:F2}, {0:F2}, {0:F2})", vHeadToNose2.x, vHeadToNose2.y, vHeadToNose2.z); |
||
971 | // if(debugText2) |
||
972 | // debugText2.text = "h2n: " + sHeadToNose2 + ", len: " + vHeadToNose2.magnitude; |
||
973 | |||
974 | bFaceMeshUpdated = task.Result; |
||
975 | if(bFaceMeshUpdated) |
||
976 | { |
||
977 | Mesh mesh = faceModelMesh.GetComponent<MeshFilter>().mesh; |
||
978 | mesh.vertices = vMeshVertices; // avModelVertices; |
||
979 | vMeshVertices = null; |
||
980 | |||
981 | if(texturedModelMesh != TextureType.None && avModelUV != null) |
||
982 | { |
||
983 | mesh.uv = avModelUV; |
||
984 | } |
||
985 | |||
986 | faceMeshUpdateTime = Time.time; |
||
987 | //faceMeshGotOnce = true; |
||
988 | |||
989 | mesh.RecalculateNormals(); |
||
990 | mesh.RecalculateBounds(); |
||
991 | |||
992 | // set the face mesh texture |
||
993 | SetFaceModelMeshTexture(); |
||
994 | } |
||
995 | } |
||
996 | |||
997 | if (moveModelMesh) |
||
998 | { |
||
999 | KinectManager kinectManager = KinectManager.Instance; |
||
1000 | Matrix4x4 kinectToWorld = kinectManager ? kinectManager.GetKinectToWorldMatrix() : Matrix4x4.identity; |
||
1001 | Vector3 newHeadPos = kinectToWorld.MultiplyPoint3x4(headPos); |
||
1002 | |||
1003 | // check for head pos overlay |
||
1004 | if(foregroundCamera) |
||
1005 | { |
||
1006 | // get the background rectangle (use the portrait background, if available) |
||
1007 | Rect backgroundRect = foregroundCamera.pixelRect; |
||
1008 | PortraitBackground portraitBack = PortraitBackground.Instance; |
||
1009 | |||
1010 | if(portraitBack && portraitBack.enabled) |
||
1011 | { |
||
1012 | backgroundRect = portraitBack.GetBackgroundRect(); |
||
1013 | } |
||
1014 | |||
1015 | if(kinectManager) |
||
1016 | { |
||
1017 | Vector3 posColorOverlay = kinectManager.GetJointPosColorOverlay(primaryUserID, (int)KinectInterop.JointType.Head, foregroundCamera, backgroundRect); |
||
1018 | |||
1019 | if(posColorOverlay != Vector3.zero) |
||
1020 | { |
||
1021 | newHeadPos = posColorOverlay; |
||
1022 | } |
||
1023 | } |
||
1024 | } |
||
1025 | |||
1026 | faceModelMesh.transform.position = newHeadPos; // Vector3.Lerp(faceModelMesh.transform.position, newHeadPos, 20f * Time.deltaTime); |
||
1027 | //faceModelMesh.transform.rotation = faceModelRot; |
||
1028 | } |
||
1029 | |||
1030 | // don't rotate the transform - mesh follows the head rotation |
||
1031 | if (faceModelMesh.transform.rotation != Quaternion.identity) |
||
1032 | { |
||
1033 | faceModelMesh.transform.rotation = Quaternion.identity; |
||
1034 | } |
||
1035 | |||
1036 | // apply scale factor |
||
1037 | if(faceModelMesh.transform.localScale.x != modelMeshScale) |
||
1038 | { |
||
1039 | faceModelMesh.transform.localScale = new Vector3(modelMeshScale, modelMeshScale, modelMeshScale); |
||
1040 | } |
||
1041 | |||
1042 | if(!faceModelMesh.activeSelf) |
||
1043 | { |
||
1044 | faceModelMesh.SetActive(true); |
||
1045 | } |
||
1046 | } |
||
1047 | else |
||
1048 | { |
||
1049 | if(faceModelMesh && faceModelMesh.activeSelf) |
||
1050 | { |
||
1051 | faceModelMesh.SetActive(false); |
||
1052 | } |
||
1053 | } |
||
1054 | |||
1055 | updateFaceMeshStarted = false; |
||
1056 | } |
||
1057 | |||
1058 | // returns the nose tip position, or Vector3.zero if not found |
||
1059 | private Vector3 GetFaceModelNosePos() |
||
1060 | { |
||
1061 | if (avModelVertices != null) |
||
1062 | { |
||
1063 | int iNoseIndex = -1; |
||
1064 | if (sensorData.sensorIntPlatform == KinectInterop.DepthSensorPlatform.KinectSDKv2 || |
||
1065 | sensorData.sensorIntPlatform == KinectInterop.DepthSensorPlatform.KinectUWPv2 || |
||
1066 | sensorData.sensorIntPlatform == KinectInterop.DepthSensorPlatform.DummyK2) |
||
1067 | { |
||
1068 | iNoseIndex = 18; // Microsoft.Kinect.Face.HighDetailFacePoints.NoseTip |
||
1069 | } |
||
1070 | else if (sensorData.sensorIntPlatform == KinectInterop.DepthSensorPlatform.KinectSDKv1 || |
||
1071 | sensorData.sensorIntPlatform == KinectInterop.DepthSensorPlatform.DummyK1) |
||
1072 | { |
||
1073 | iNoseIndex = 89; // |
||
1074 | } |
||
1075 | |||
1076 | if (iNoseIndex >= 0 && iNoseIndex < avModelVertices.Length) |
||
1077 | { |
||
1078 | return avModelVertices[iNoseIndex]; |
||
1079 | } |
||
1080 | } |
||
1081 | |||
1082 | return Vector3.zero; |
||
1083 | } |
||
1084 | |||
1085 | // gets face basic parameters as csv line |
||
1086 | public string GetFaceParamsAsCsv() |
||
1087 | { |
||
1088 | // create the output string |
||
1089 | StringBuilder sbBuf = new StringBuilder(); |
||
1090 | const char delimiter = ','; |
||
1091 | |||
1092 | if (bGotHeadPos || bGotHeadRot) |
||
1093 | { |
||
1094 | sbBuf.Append("fp").Append(delimiter); |
||
1095 | |||
1096 | // head pos |
||
1097 | sbBuf.Append (bGotHeadPos ? "1" : "0").Append(delimiter); |
||
1098 | |||
1099 | if (bGotHeadPos) |
||
1100 | { |
||
1101 | sbBuf.AppendFormat ("{0:F3}", headPos.x).Append (delimiter); |
||
1102 | sbBuf.AppendFormat ("{0:F3}", headPos.y).Append (delimiter); |
||
1103 | sbBuf.AppendFormat ("{0:F3}", headPos.z).Append (delimiter); |
||
1104 | } |
||
1105 | |||
1106 | // head rot |
||
1107 | sbBuf.Append (bGotHeadRot ? "1" : "0").Append(delimiter); |
||
1108 | Vector3 vheadRot = headRot.eulerAngles; |
||
1109 | |||
1110 | if (bGotHeadRot) |
||
1111 | { |
||
1112 | sbBuf.AppendFormat ("{0:F3}", vheadRot.x).Append (delimiter); |
||
1113 | sbBuf.AppendFormat ("{0:F3}", vheadRot.y).Append (delimiter); |
||
1114 | sbBuf.AppendFormat ("{0:F3}", vheadRot.z).Append (delimiter); |
||
1115 | } |
||
1116 | |||
1117 | // face rect |
||
1118 | sbBuf.Append ("1").Append(delimiter); |
||
1119 | sbBuf.AppendFormat ("{0:F0}", faceRect.x).Append (delimiter); |
||
1120 | sbBuf.AppendFormat ("{0:F0}", faceRect.y).Append (delimiter); |
||
1121 | sbBuf.AppendFormat ("{0:F0}", faceRect.width).Append (delimiter); |
||
1122 | sbBuf.AppendFormat ("{0:F0}", faceRect.height).Append (delimiter); |
||
1123 | |||
1124 | // animation units |
||
1125 | sbBuf.Append (bGotAU ? "1" : "0").Append(delimiter); |
||
1126 | |||
1127 | if (bGotAU) |
||
1128 | { |
||
1129 | int enumCount = Enum.GetNames (typeof(KinectInterop.FaceShapeAnimations)).Length; |
||
1130 | sbBuf.Append (enumCount).Append(delimiter); |
||
1131 | |||
1132 | for (int i = 0; i < enumCount; i++) |
||
1133 | { |
||
1134 | float dictValue = dictAU [(KinectInterop.FaceShapeAnimations)i]; |
||
1135 | sbBuf.AppendFormat ("{0:F3}", dictValue).Append (delimiter); |
||
1136 | } |
||
1137 | } |
||
1138 | |||
1139 | // shape units |
||
1140 | sbBuf.Append (bGotSU ? "1" : "0").Append(delimiter); |
||
1141 | |||
1142 | if (bGotSU) |
||
1143 | { |
||
1144 | int enumCount = Enum.GetNames (typeof(KinectInterop.FaceShapeDeformations)).Length; |
||
1145 | sbBuf.Append (enumCount).Append(delimiter); |
||
1146 | |||
1147 | for (int i = 0; i < enumCount; i++) |
||
1148 | { |
||
1149 | float dictValue = dictSU [(KinectInterop.FaceShapeDeformations)i]; |
||
1150 | sbBuf.AppendFormat ("{0:F3}", dictValue).Append (delimiter); |
||
1151 | } |
||
1152 | } |
||
1153 | |||
1154 | // any other parameters... |
||
1155 | } |
||
1156 | |||
1157 | // remove the last delimiter |
||
1158 | if(sbBuf.Length > 0 && sbBuf[sbBuf.Length - 1] == delimiter) |
||
1159 | { |
||
1160 | sbBuf.Remove(sbBuf.Length - 1, 1); |
||
1161 | } |
||
1162 | |||
1163 | return sbBuf.ToString(); |
||
1164 | } |
||
1165 | |||
1166 | // sets basic face parameters from a csv line |
||
1167 | public bool SetFaceParamsFromCsv(string sCsvLine) |
||
1168 | { |
||
1169 | if(sCsvLine.Length == 0) |
||
1170 | return false; |
||
1171 | |||
1172 | // split the csv line in parts |
||
1173 | char[] delimiters = { ',' }; |
||
1174 | string[] alCsvParts = sCsvLine.Split(delimiters); |
||
1175 | |||
1176 | if(alCsvParts.Length < 1 || alCsvParts[0] != "fp") |
||
1177 | return false; |
||
1178 | |||
1179 | int iIndex = 1; |
||
1180 | int iLength = alCsvParts.Length; |
||
1181 | |||
1182 | if (iLength < (iIndex + 1)) |
||
1183 | return false; |
||
1184 | |||
1185 | // head pos |
||
1186 | bGotHeadPos = (alCsvParts[iIndex] == "1"); |
||
1187 | iIndex++; |
||
1188 | |||
1189 | if (bGotHeadPos && iLength >= (iIndex + 3)) |
||
1190 | { |
||
1191 | float x = 0f, y = 0f, z = 0f; |
||
1192 | |||
1193 | float.TryParse(alCsvParts[iIndex], out x); |
||
1194 | float.TryParse(alCsvParts[iIndex + 1], out y); |
||
1195 | float.TryParse(alCsvParts[iIndex + 2], out z); |
||
1196 | iIndex += 3; |
||
1197 | |||
1198 | headPos = new Vector3(x, y, z); |
||
1199 | } |
||
1200 | |||
1201 | // head rot |
||
1202 | bGotHeadRot = (alCsvParts[iIndex] == "1"); |
||
1203 | iIndex++; |
||
1204 | |||
1205 | if (bGotHeadRot && iLength >= (iIndex + 3)) |
||
1206 | { |
||
1207 | float x = 0f, y = 0f, z = 0f; |
||
1208 | |||
1209 | float.TryParse(alCsvParts[iIndex], out x); |
||
1210 | float.TryParse(alCsvParts[iIndex + 1], out y); |
||
1211 | float.TryParse(alCsvParts[iIndex + 2], out z); |
||
1212 | iIndex += 3; |
||
1213 | |||
1214 | headRot = Quaternion.Euler(x, y, z); |
||
1215 | } |
||
1216 | |||
1217 | // face rect |
||
1218 | bool bGotFaceRect = (alCsvParts[iIndex] == "1"); |
||
1219 | iIndex++; |
||
1220 | |||
1221 | if (bGotFaceRect && iLength >= (iIndex + 4)) |
||
1222 | { |
||
1223 | float x = 0f, y = 0f, w = 0f, h = 0f; |
||
1224 | |||
1225 | float.TryParse(alCsvParts[iIndex], out x); |
||
1226 | float.TryParse(alCsvParts[iIndex + 1], out y); |
||
1227 | float.TryParse(alCsvParts[iIndex + 2], out w); |
||
1228 | float.TryParse(alCsvParts[iIndex + 3], out h); |
||
1229 | iIndex += 4; |
||
1230 | |||
1231 | faceRect.x = x; faceRect.y = y; |
||
1232 | faceRect.width = w; faceRect.height = h; |
||
1233 | } |
||
1234 | |||
1235 | // animation units |
||
1236 | bGotAU = (alCsvParts[iIndex] == "1"); |
||
1237 | iIndex++; |
||
1238 | |||
1239 | if (bGotAU && iLength >= (iIndex + 1)) |
||
1240 | { |
||
1241 | int count = 0; |
||
1242 | int.TryParse(alCsvParts[iIndex], out count); |
||
1243 | iIndex++; |
||
1244 | |||
1245 | for (int i = 0; i < count && iLength >= (iIndex + 1); i++) |
||
1246 | { |
||
1247 | float v = 0; |
||
1248 | float.TryParse(alCsvParts[iIndex], out v); |
||
1249 | iIndex++; |
||
1250 | |||
1251 | dictAU [(KinectInterop.FaceShapeAnimations)i] = v; |
||
1252 | } |
||
1253 | } |
||
1254 | |||
1255 | // shape units |
||
1256 | bGotSU = (alCsvParts[iIndex] == "1"); |
||
1257 | iIndex++; |
||
1258 | |||
1259 | if (bGotSU && iLength >= (iIndex + 1)) |
||
1260 | { |
||
1261 | int count = 0; |
||
1262 | int.TryParse(alCsvParts[iIndex], out count); |
||
1263 | iIndex++; |
||
1264 | |||
1265 | for (int i = 0; i < count && iLength >= (iIndex + 1); i++) |
||
1266 | { |
||
1267 | float v = 0; |
||
1268 | float.TryParse(alCsvParts[iIndex], out v); |
||
1269 | iIndex++; |
||
1270 | |||
1271 | dictSU [(KinectInterop.FaceShapeDeformations)i] = v; |
||
1272 | } |
||
1273 | } |
||
1274 | |||
1275 | // any other parameters here... |
||
1276 | |||
1277 | // emulate face tracking |
||
1278 | lastFaceTrackedTime = Time.realtimeSinceStartup; |
||
1279 | facePosUpdateTime = Time.time; |
||
1280 | |||
1281 | return true; |
||
1282 | } |
||
1283 | |||
1284 | // gets face model vertices as csv line |
||
1285 | public string GetFaceVerticesAsCsv() |
||
1286 | { |
||
1287 | // create the output string |
||
1288 | StringBuilder sbBuf = new StringBuilder(); |
||
1289 | const char delimiter = ','; |
||
1290 | |||
1291 | if (bGotModelVertices && avModelVertices != null) |
||
1292 | { |
||
1293 | sbBuf.Append("fv").Append(delimiter); |
||
1294 | |||
1295 | // model vertices |
||
1296 | int vertCount = avModelVertices.Length; |
||
1297 | sbBuf.Append (vertCount).Append(delimiter); |
||
1298 | |||
1299 | for (int i = 0; i < vertCount; i++) |
||
1300 | { |
||
1301 | sbBuf.AppendFormat ("{0:F3}", avModelVertices[i].x).Append (delimiter); |
||
1302 | sbBuf.AppendFormat ("{0:F3}", avModelVertices[i].y).Append (delimiter); |
||
1303 | sbBuf.AppendFormat ("{0:F3}", avModelVertices[i].z).Append (delimiter); |
||
1304 | } |
||
1305 | } |
||
1306 | |||
1307 | // remove the last delimiter |
||
1308 | if(sbBuf.Length > 0 && sbBuf[sbBuf.Length - 1] == delimiter) |
||
1309 | { |
||
1310 | sbBuf.Remove(sbBuf.Length - 1, 1); |
||
1311 | } |
||
1312 | |||
1313 | return sbBuf.ToString(); |
||
1314 | } |
||
1315 | |||
1316 | // sets face model vertices from a csv line |
||
1317 | public bool SetFaceVerticesFromCsv(string sCsvLine) |
||
1318 | { |
||
1319 | if(sCsvLine.Length == 0) |
||
1320 | return false; |
||
1321 | |||
1322 | // split the csv line in parts |
||
1323 | char[] delimiters = { ',' }; |
||
1324 | string[] alCsvParts = sCsvLine.Split(delimiters); |
||
1325 | |||
1326 | if(alCsvParts.Length < 1 || alCsvParts[0] != "fv") |
||
1327 | return false; |
||
1328 | |||
1329 | int iIndex = 1; |
||
1330 | int iLength = alCsvParts.Length; |
||
1331 | |||
1332 | if (iLength < (iIndex + 1)) |
||
1333 | return false; |
||
1334 | |||
1335 | // model vertices |
||
1336 | int vertCount = 0; |
||
1337 | int.TryParse(alCsvParts[iIndex], out vertCount); |
||
1338 | iIndex++; |
||
1339 | |||
1340 | if (vertCount > 0) |
||
1341 | { |
||
1342 | if (avModelVertices == null || avModelVertices.Length != vertCount) |
||
1343 | { |
||
1344 | avModelVertices = new Vector3[vertCount]; |
||
1345 | } |
||
1346 | |||
1347 | for (int i = 0; i < vertCount && iLength >= (iIndex + 3); i++) |
||
1348 | { |
||
1349 | float x = 0f, y = 0f, z = 0f; |
||
1350 | |||
1351 | float.TryParse(alCsvParts[iIndex], out x); |
||
1352 | float.TryParse(alCsvParts[iIndex + 1], out y); |
||
1353 | float.TryParse(alCsvParts[iIndex + 2], out z); |
||
1354 | iIndex += 3; |
||
1355 | |||
1356 | avModelVertices[i] = new Vector3(x, y, z); |
||
1357 | } |
||
1358 | |||
1359 | bGotModelVertices = true; |
||
1360 | //bGotModelVerticesFromDC = true; |
||
1361 | } |
||
1362 | |||
1363 | faceMeshUpdateTime = Time.time; |
||
1364 | |||
1365 | return true; |
||
1366 | } |
||
1367 | |||
1368 | // gets face model UVs as csv line |
||
1369 | public string GetFaceUvsAsCsv() |
||
1370 | { |
||
1371 | // create the output string |
||
1372 | StringBuilder sbBuf = new StringBuilder(); |
||
1373 | const char delimiter = ','; |
||
1374 | |||
1375 | if (bGotModelVertices && avModelUV != null) |
||
1376 | { |
||
1377 | sbBuf.Append("fu").Append(delimiter); |
||
1378 | |||
1379 | // face rect width & height |
||
1380 | sbBuf.AppendFormat ("{0:F0}", faceRect.width).Append (delimiter); |
||
1381 | sbBuf.AppendFormat ("{0:F0}", faceRect.height).Append (delimiter); |
||
1382 | |||
1383 | // model UVs |
||
1384 | int uvCount = avModelUV.Length; |
||
1385 | sbBuf.Append (uvCount).Append(delimiter); |
||
1386 | |||
1387 | for (int i = 0; i < uvCount; i++) |
||
1388 | { |
||
1389 | sbBuf.AppendFormat ("{0:F3}", avModelUV[i].x).Append (delimiter); |
||
1390 | sbBuf.AppendFormat ("{0:F3}", avModelUV[i].y).Append (delimiter); |
||
1391 | } |
||
1392 | } |
||
1393 | |||
1394 | // remove the last delimiter |
||
1395 | if(sbBuf.Length > 0 && sbBuf[sbBuf.Length - 1] == delimiter) |
||
1396 | { |
||
1397 | sbBuf.Remove(sbBuf.Length - 1, 1); |
||
1398 | } |
||
1399 | |||
1400 | return sbBuf.ToString(); |
||
1401 | } |
||
1402 | |||
1403 | // sets face model UVs from a csv line |
||
1404 | public bool SetFaceUvsFromCsv(string sCsvLine) |
||
1405 | { |
||
1406 | if(sCsvLine.Length == 0) |
||
1407 | return false; |
||
1408 | |||
1409 | // split the csv line in parts |
||
1410 | char[] delimiters = { ',' }; |
||
1411 | string[] alCsvParts = sCsvLine.Split(delimiters); |
||
1412 | |||
1413 | if(alCsvParts.Length < 1 || alCsvParts[0] != "fu") |
||
1414 | return false; |
||
1415 | |||
1416 | int iIndex = 1; |
||
1417 | int iLength = alCsvParts.Length; |
||
1418 | |||
1419 | if (iLength < (iIndex + 2)) |
||
1420 | return false; |
||
1421 | |||
1422 | // face width & height |
||
1423 | float w = 0f, h = 0f; |
||
1424 | |||
1425 | float.TryParse(alCsvParts[iIndex], out w); |
||
1426 | float.TryParse(alCsvParts[iIndex + 1], out h); |
||
1427 | iIndex += 2; |
||
1428 | |||
1429 | faceRect.width = w; faceRect.height = h; |
||
1430 | |||
1431 | // model UVs |
||
1432 | int uvCount = 0; |
||
1433 | if (iLength >= (iIndex + 1)) |
||
1434 | { |
||
1435 | int.TryParse(alCsvParts[iIndex], out uvCount); |
||
1436 | iIndex++; |
||
1437 | } |
||
1438 | |||
1439 | if (uvCount > 0) |
||
1440 | { |
||
1441 | if (avModelUV == null || avModelUV.Length != uvCount) |
||
1442 | { |
||
1443 | avModelUV = new Vector2[uvCount]; |
||
1444 | } |
||
1445 | |||
1446 | for (int i = 0; i < uvCount && iLength >= (iIndex + 2); i++) |
||
1447 | { |
||
1448 | float x = 0f, y = 0f; |
||
1449 | |||
1450 | float.TryParse(alCsvParts[iIndex], out x); |
||
1451 | float.TryParse(alCsvParts[iIndex + 1], out y); |
||
1452 | iIndex += 2; |
||
1453 | |||
1454 | avModelUV[i] = new Vector2(x, y); |
||
1455 | } |
||
1456 | } |
||
1457 | |||
1458 | return true; |
||
1459 | } |
||
1460 | |||
1461 | // gets face model triangles as csv line |
||
1462 | public string GetFaceTrianglesAsCsv() |
||
1463 | { |
||
1464 | // create the output string |
||
1465 | StringBuilder sbBuf = new StringBuilder(); |
||
1466 | const char delimiter = ','; |
||
1467 | |||
1468 | if (avModelTriangles != null) |
||
1469 | { |
||
1470 | sbBuf.Append("ft").Append(delimiter); |
||
1471 | |||
1472 | // model triangles |
||
1473 | int triCount = avModelTriangles.Length; |
||
1474 | sbBuf.Append (triCount).Append(delimiter); |
||
1475 | |||
1476 | for (int i = 0; i < triCount; i++) |
||
1477 | { |
||
1478 | sbBuf.Append(avModelTriangles[i]).Append (delimiter); |
||
1479 | } |
||
1480 | } |
||
1481 | |||
1482 | // remove the last delimiter |
||
1483 | if(sbBuf.Length > 0 && sbBuf[sbBuf.Length - 1] == delimiter) |
||
1484 | { |
||
1485 | sbBuf.Remove(sbBuf.Length - 1, 1); |
||
1486 | } |
||
1487 | |||
1488 | return sbBuf.ToString(); |
||
1489 | } |
||
1490 | |||
1491 | // sets face model model from a csv line |
||
1492 | public bool SetFaceTrianglesFromCsv(string sCsvLine) |
||
1493 | { |
||
1494 | if(sCsvLine.Length == 0) |
||
1495 | return false; |
||
1496 | |||
1497 | // split the csv line in parts |
||
1498 | char[] delimiters = { ',' }; |
||
1499 | string[] alCsvParts = sCsvLine.Split(delimiters); |
||
1500 | |||
1501 | if(alCsvParts.Length < 1 || alCsvParts[0] != "ft") |
||
1502 | return false; |
||
1503 | |||
1504 | int iIndex = 1; |
||
1505 | int iLength = alCsvParts.Length; |
||
1506 | |||
1507 | if (iLength < (iIndex + 1)) |
||
1508 | return false; |
||
1509 | |||
1510 | // model triangles |
||
1511 | int triCount = 0; |
||
1512 | int.TryParse(alCsvParts[iIndex], out triCount); |
||
1513 | iIndex++; |
||
1514 | |||
1515 | if (triCount > 0) |
||
1516 | { |
||
1517 | if (avModelTriangles == null || avModelTriangles.Length != triCount) |
||
1518 | { |
||
1519 | avModelTriangles = new int[triCount]; |
||
1520 | } |
||
1521 | |||
1522 | for (int i = 0; i < triCount && iLength >= (iIndex + 1); i++) |
||
1523 | { |
||
1524 | int v = 0; |
||
1525 | |||
1526 | int.TryParse(alCsvParts[iIndex], out v); |
||
1527 | iIndex++; |
||
1528 | |||
1529 | avModelTriangles[i] = v; |
||
1530 | } |
||
1531 | |||
1532 | bGotModelTriangles = true; |
||
1533 | bGotModelTrianglesFromDC = true; |
||
1534 | } |
||
1535 | |||
1536 | return true; |
||
1537 | } |
||
1538 | |||
1539 | |||
1540 | } |