t1 / TFDContents / Assets / KinectDemos / FaceTrackingDemo / Scripts / ModelFaceController.cs @ 3
이력 | 보기 | 이력해설 | 다운로드 (15.2 KB)
1 | 3 | KTH | using UnityEngine; |
---|---|---|---|
2 | using System.Collections; |
||
3 | using System.Collections.Generic; |
||
4 | |||
5 | public class ModelFaceController : MonoBehaviour |
||
6 | { |
||
7 | public enum AxisEnum { X, Y, Z }; |
||
8 | |||
9 | [Tooltip("Transform of the joint, used to move and rotate the head.")] |
||
10 | public Transform HeadTransform; |
||
11 | |||
12 | [Tooltip("Whether the model's head is facing the player or not.")] |
||
13 | public bool mirroredHeadMovement = true; |
||
14 | |||
15 | [Tooltip("Camera used to estimate the overlay position of the head over the background.")] |
||
16 | public Camera foregroundCamera; |
||
17 | |||
18 | // for testing purposes |
||
19 | //public Transform overlayObj; |
||
20 | |||
21 | [Tooltip("Vertical offset of the model above the head position.")] |
||
22 | public float verticalOffset = 0f; |
||
23 | |||
24 | [Tooltip("Scale factor for the head model.")] |
||
25 | [Range(0.1f, 2.0f)] |
||
26 | public float modelScaleFactor = 1f; |
||
27 | |||
28 | [Tooltip("Smooth factor used for head movement and head-joint rotations.")] |
||
29 | public float smoothFactor = 10f; |
||
30 | |||
31 | // Upper Lip Left |
||
32 | [Tooltip("Left upper lip transform.")] |
||
33 | public Transform UpperLipLeft; |
||
34 | [Tooltip("Left upper lip axis of rotation.")] |
||
35 | public AxisEnum UpperLipLeftAxis; |
||
36 | [Tooltip("Maximum up-value for the left upper lip, down-value is the opposite one.")] |
||
37 | public float UpperLipLeftUp; |
||
38 | |||
39 | // Upper Lip Right |
||
40 | [Tooltip("Right upper lip transform.")] |
||
41 | public Transform UpperLipRight; |
||
42 | [Tooltip("Right upper lip axis of rotation.")] |
||
43 | public AxisEnum UpperLipRightAxis; |
||
44 | [Tooltip("Maximum up-value for the right upper lip, down-value is the opposite one.")] |
||
45 | public float UpperLipRightUp; |
||
46 | |||
47 | // Jaw |
||
48 | [Tooltip("Jaw (mouth) transform.")] |
||
49 | public Transform Jaw; |
||
50 | [Tooltip("Jaw axis of rotation.")] |
||
51 | public AxisEnum JawAxis; |
||
52 | [Tooltip("Maximum down-value for the jaw, up-value is the opposite one.")] |
||
53 | public float JawDown; |
||
54 | |||
55 | // Lip Left |
||
56 | [Tooltip("Left lip transform.")] |
||
57 | public Transform LipLeft; |
||
58 | [Tooltip("Left lip axis of rotation.")] |
||
59 | public AxisEnum LipLeftAxis; |
||
60 | [Tooltip("Maximum stretched-value for the left lip, rounded-value is the opposite one.")] |
||
61 | public float LipLeftStretched; |
||
62 | |||
63 | // Lip Right |
||
64 | [Tooltip("Right lip transform.")] |
||
65 | public Transform LipRight; |
||
66 | [Tooltip("Right lip axis of rotation.")] |
||
67 | public AxisEnum LipRightAxis; |
||
68 | [Tooltip("Maximum stretched-value for the right lip, rounded-value is the opposite one.")] |
||
69 | public float LipRightStretched; |
||
70 | |||
71 | // Eyebrow Left |
||
72 | [Tooltip("Left eyebrow transform.")] |
||
73 | public Transform EyebrowLeft; |
||
74 | [Tooltip("Left eyebrow axis of rotation.")] |
||
75 | public AxisEnum EyebrowLeftAxis; |
||
76 | [Tooltip("Maximum lowered-value for the left eyebrow, raised-value is the opposite one.")] |
||
77 | public float EyebrowLeftLowered; |
||
78 | |||
79 | // Eyebrow Right |
||
80 | [Tooltip("Right eyebrow transform.")] |
||
81 | public Transform EyebrowRight; |
||
82 | [Tooltip("Right eyebrow axis of rotation.")] |
||
83 | public AxisEnum EyebrowRightAxis; |
||
84 | [Tooltip("Maximum lowered-value for the right eyebrow, raised-value is the opposite one.")] |
||
85 | public float EyebrowRightLowered; |
||
86 | |||
87 | // Lip Corner Left |
||
88 | [Tooltip("Left lip-corner transform.")] |
||
89 | public Transform LipCornerLeft; |
||
90 | [Tooltip("Left lip-corner axis of rotation.")] |
||
91 | public AxisEnum LipCornerLeftAxis; |
||
92 | [Tooltip("Maximum depressed-value for the left lip-corner, smile-value is the opposite one.")] |
||
93 | public float LipCornerLeftDepressed; |
||
94 | |||
95 | // Lip Corner Right |
||
96 | [Tooltip("Right lip-corner transform.")] |
||
97 | public Transform LipCornerRight; |
||
98 | [Tooltip("Right lip-corner axis of rotation.")] |
||
99 | public AxisEnum LipCornerRightAxis; |
||
100 | [Tooltip("Maximum depressed-value for the right lip-corner, smile-value is the opposite one.")] |
||
101 | public float LipCornerRightDepressed; |
||
102 | |||
103 | // Upper Eyelid Left |
||
104 | [Tooltip("Left upper eyelid transform.")] |
||
105 | public Transform UpperEyelidLeft; |
||
106 | [Tooltip("Left upper eyelid axis of rotation.")] |
||
107 | public AxisEnum UpperEyelidLeftAxis; |
||
108 | [Tooltip("Maximum lowered-value for the left upper eyelid, raised-value is the opposite one.")] |
||
109 | public float UpperEyelidLeftLowered; |
||
110 | |||
111 | // Upper Eyelid Right |
||
112 | [Tooltip("Right upper eyelid transform.")] |
||
113 | public Transform UpperEyelidRight; |
||
114 | [Tooltip("Right upper eyelid axis of rotation.")] |
||
115 | public AxisEnum UpperEyelidRightAxis; |
||
116 | [Tooltip("Maximum lowered-value for the right upper eyelid, raised-value is the opposite one.")] |
||
117 | public float UpperEyelidRightLowered; |
||
118 | |||
119 | // Lower Eyelid Left |
||
120 | [Tooltip("Left lower eyelid transform.")] |
||
121 | public Transform LowerEyelidLeft; |
||
122 | [Tooltip("Left lower eyelid axis of rotation.")] |
||
123 | public AxisEnum LowerEyelidLeftAxis; |
||
124 | [Tooltip("Maximum raised-value for the left lower eyelid, lowered-value is the opposite one.")] |
||
125 | public float LowerEyelidLeftRaised; |
||
126 | |||
127 | // Lower Eyelid Right |
||
128 | [Tooltip("Right lower eyelid transform.")] |
||
129 | public Transform LowerEyelidRight; |
||
130 | [Tooltip("Right lower eyelid axis of rotation.")] |
||
131 | public AxisEnum LowerEyelidRightAxis; |
||
132 | [Tooltip("Maximum raised-value for the right lower eyelid, lowered-value is the opposite one.")] |
||
133 | public float LowerEyelidRightRaised; |
||
134 | |||
135 | |||
136 | private FacetrackingManager manager; |
||
137 | private KinectInterop.DepthSensorPlatform platform; |
||
138 | |||
139 | private Vector3 HeadInitialPosition; |
||
140 | private Quaternion HeadInitialRotation; |
||
141 | |||
142 | private float UpperLipLeftNeutral; |
||
143 | private float UpperLipRightNeutral; |
||
144 | private float JawNeutral; |
||
145 | private float LipLeftNeutral; |
||
146 | private float LipRightNeutral; |
||
147 | private float EyebrowLeftNeutral; |
||
148 | private float EyebrowRightNeutral; |
||
149 | private float LipCornerLeftNeutral; |
||
150 | private float LipCornerRightNeutral; |
||
151 | private float UpperEyelidLeftNeutral; |
||
152 | private float UpperEyelidRightNeutral; |
||
153 | private float LowerEyelidLeftNeutral; |
||
154 | private float LowerEyelidRightNeutral; |
||
155 | |||
156 | |||
157 | void Start() |
||
158 | { |
||
159 | if(HeadTransform != null) |
||
160 | { |
||
161 | HeadInitialPosition = HeadTransform.position; |
||
162 | //HeadInitialPosition.z = 0; |
||
163 | HeadInitialRotation = HeadTransform.rotation; |
||
164 | } |
||
165 | |||
166 | UpperLipLeftNeutral = GetJointRotation(UpperLipLeft, UpperLipLeftAxis); |
||
167 | UpperLipRightNeutral = GetJointRotation(UpperLipRight, UpperLipRightAxis); |
||
168 | |||
169 | JawNeutral = GetJointRotation(Jaw, JawAxis); |
||
170 | |||
171 | LipLeftNeutral = GetJointRotation(LipLeft, LipLeftAxis); |
||
172 | LipRightNeutral = GetJointRotation(LipRight, LipRightAxis); |
||
173 | |||
174 | EyebrowLeftNeutral = GetJointRotation(EyebrowLeft, EyebrowLeftAxis); |
||
175 | EyebrowRightNeutral = GetJointRotation(EyebrowRight, EyebrowRightAxis); |
||
176 | |||
177 | LipCornerLeftNeutral = GetJointRotation(LipCornerLeft, LipCornerLeftAxis); |
||
178 | LipCornerRightNeutral = GetJointRotation(LipCornerRight, LipCornerRightAxis); |
||
179 | |||
180 | UpperEyelidLeftNeutral = GetJointRotation(UpperEyelidLeft, UpperEyelidLeftAxis); |
||
181 | UpperEyelidRightNeutral = GetJointRotation(UpperEyelidRight, UpperEyelidRightAxis); |
||
182 | |||
183 | LowerEyelidLeftNeutral = GetJointRotation(LowerEyelidLeft, LowerEyelidLeftAxis); |
||
184 | LowerEyelidRightNeutral = GetJointRotation(LowerEyelidRight, LowerEyelidRightAxis); |
||
185 | |||
186 | KinectManager kinectManager = KinectManager.Instance; |
||
187 | if(kinectManager && kinectManager.IsInitialized()) |
||
188 | { |
||
189 | platform = kinectManager.GetSensorPlatform(); |
||
190 | } |
||
191 | } |
||
192 | |||
193 | void Update() |
||
194 | { |
||
195 | // get the face-tracking manager instance |
||
196 | if(manager == null) |
||
197 | { |
||
198 | manager = FacetrackingManager.Instance; |
||
199 | } |
||
200 | |||
201 | if(manager && manager.GetFaceTrackingID() != 0) |
||
202 | { |
||
203 | // set head position & rotation |
||
204 | if(HeadTransform != null) |
||
205 | { |
||
206 | // head position |
||
207 | Vector3 newPosition = manager.GetHeadPosition(mirroredHeadMovement); |
||
208 | |||
209 | // head rotation |
||
210 | Quaternion newRotation = HeadInitialRotation * manager.GetHeadRotation(mirroredHeadMovement); |
||
211 | |||
212 | // rotational fix, provided by Richard Borys: |
||
213 | // The added rotation fixes rotational error that occurs when person is not centered in the middle of the kinect |
||
214 | Vector3 addedRotation = newPosition.z != 0f ? new Vector3(Mathf.Rad2Deg * (Mathf.Tan(newPosition.y) / newPosition.z), |
||
215 | Mathf.Rad2Deg * (Mathf.Tan(newPosition.x) / newPosition.z), 0) : Vector3.zero; |
||
216 | |||
217 | addedRotation.x = newRotation.eulerAngles.x + addedRotation.x; |
||
218 | addedRotation.y = newRotation.eulerAngles.y + addedRotation.y; |
||
219 | addedRotation.z = newRotation.eulerAngles.z + addedRotation.z; |
||
220 | |||
221 | newRotation = Quaternion.Euler(addedRotation.x, addedRotation.y, addedRotation.z); |
||
222 | // end of rotational fix |
||
223 | |||
224 | if(smoothFactor != 0f) |
||
225 | HeadTransform.rotation = Quaternion.Slerp(HeadTransform.rotation, newRotation, smoothFactor * Time.deltaTime); |
||
226 | else |
||
227 | HeadTransform.rotation = newRotation; |
||
228 | |||
229 | // check for head pos overlay |
||
230 | if(foregroundCamera) |
||
231 | { |
||
232 | // get the background rectangle (use the portrait background, if available) |
||
233 | Rect backgroundRect = foregroundCamera.pixelRect; |
||
234 | PortraitBackground portraitBack = PortraitBackground.Instance; |
||
235 | |||
236 | if(portraitBack && portraitBack.enabled) |
||
237 | { |
||
238 | backgroundRect = portraitBack.GetBackgroundRect(); |
||
239 | } |
||
240 | |||
241 | KinectManager kinectManager = KinectManager.Instance; |
||
242 | |||
243 | if(kinectManager) |
||
244 | { |
||
245 | long userId = kinectManager.GetUserIdByIndex(manager.playerIndex); |
||
246 | Vector3 posColorOverlay = kinectManager.GetJointPosColorOverlay(userId, (int)KinectInterop.JointType.Head, foregroundCamera, backgroundRect); |
||
247 | |||
248 | if(posColorOverlay != Vector3.zero) |
||
249 | { |
||
250 | newPosition = posColorOverlay; |
||
251 | |||
252 | // if(overlayObj) |
||
253 | // { |
||
254 | // overlayObj.position = newPosition; |
||
255 | // } |
||
256 | } |
||
257 | } |
||
258 | } |
||
259 | else |
||
260 | { |
||
261 | // move around the initial position |
||
262 | newPosition += HeadInitialPosition; |
||
263 | } |
||
264 | |||
265 | // vertical offet |
||
266 | if(verticalOffset != 0f) |
||
267 | { |
||
268 | // add the vertical offset |
||
269 | Vector3 dirHead = new Vector3(0, verticalOffset, 0); |
||
270 | dirHead = HeadTransform.InverseTransformDirection(dirHead); |
||
271 | newPosition += dirHead; |
||
272 | } |
||
273 | |||
274 | // set the position |
||
275 | if(smoothFactor != 0f) |
||
276 | HeadTransform.position = Vector3.Lerp(HeadTransform.position, newPosition, smoothFactor * Time.deltaTime); |
||
277 | else |
||
278 | HeadTransform.position = newPosition; |
||
279 | |||
280 | // scale factor |
||
281 | if(HeadTransform.localScale.x != modelScaleFactor) |
||
282 | { |
||
283 | HeadTransform.localScale = new Vector3(modelScaleFactor, modelScaleFactor, modelScaleFactor); |
||
284 | } |
||
285 | } |
||
286 | |||
287 | // apply animation units |
||
288 | |||
289 | // AU0 - Upper Lip Raiser |
||
290 | // 0=neutral, covering teeth; 1=showing teeth fully; -1=maximal possible pushed down lip |
||
291 | float fAU0 = manager.GetAnimUnit(KinectInterop.FaceShapeAnimations.LipPucker); |
||
292 | SetJointRotation(UpperLipLeft, UpperLipLeftAxis, fAU0, UpperLipLeftNeutral, UpperLipLeftUp); |
||
293 | SetJointRotation(UpperLipRight, UpperLipRightAxis, fAU0, UpperLipRightNeutral, UpperLipRightUp); |
||
294 | |||
295 | // AU1 - Jaw Lowerer |
||
296 | // 0=closed; 1=fully open; -1= closed, like 0 |
||
297 | float fAU1 = manager.GetAnimUnit(KinectInterop.FaceShapeAnimations.JawOpen); |
||
298 | SetJointRotation(Jaw, JawAxis, fAU1, JawNeutral, JawDown); |
||
299 | |||
300 | // AU2 – Lip Stretcher |
||
301 | // 0=neutral; 1=fully stretched (joker’s smile); -1=fully rounded (kissing mouth) |
||
302 | float fAU2_left = manager.GetAnimUnit(KinectInterop.FaceShapeAnimations.LipStretcherLeft); |
||
303 | fAU2_left = (platform == KinectInterop.DepthSensorPlatform.KinectSDKv2) ? (fAU2_left * 2 - 1) : fAU2_left; |
||
304 | SetJointRotation(LipLeft, LipLeftAxis, fAU2_left, LipLeftNeutral, LipLeftStretched); |
||
305 | |||
306 | float fAU2_right = manager.GetAnimUnit(KinectInterop.FaceShapeAnimations.LipStretcherRight); |
||
307 | fAU2_right = (platform == KinectInterop.DepthSensorPlatform.KinectSDKv2) ? (fAU2_right * 2 - 1) : fAU2_right; |
||
308 | SetJointRotation(LipRight, LipRightAxis, fAU2_right, LipRightNeutral, LipRightStretched); |
||
309 | |||
310 | // AU3 – Brow Lowerer |
||
311 | // 0=neutral; -1=raised almost all the way; +1=fully lowered (to the limit of the eyes) |
||
312 | float fAU3_left = manager.GetAnimUnit(KinectInterop.FaceShapeAnimations.LefteyebrowLowerer); |
||
313 | fAU3_left = (platform == KinectInterop.DepthSensorPlatform.KinectSDKv2) ? (fAU3_left * 2 - 1) : fAU3_left; |
||
314 | SetJointRotation(EyebrowLeft, EyebrowLeftAxis, fAU3_left, EyebrowLeftNeutral, EyebrowLeftLowered); |
||
315 | |||
316 | float fAU3_right = manager.GetAnimUnit(KinectInterop.FaceShapeAnimations.RighteyebrowLowerer); |
||
317 | fAU3_right = (platform == KinectInterop.DepthSensorPlatform.KinectSDKv2) ? (fAU3_right * 2 - 1) : fAU3_right; |
||
318 | SetJointRotation(EyebrowRight, EyebrowRightAxis, fAU3_right, EyebrowRightNeutral, EyebrowRightLowered); |
||
319 | |||
320 | // AU4 – Lip Corner Depressor |
||
321 | // 0=neutral; -1=very happy smile; +1=very sad frown |
||
322 | float fAU4_left = manager.GetAnimUnit(KinectInterop.FaceShapeAnimations.LipCornerDepressorLeft); |
||
323 | fAU4_left = (platform == KinectInterop.DepthSensorPlatform.KinectSDKv2) ? (fAU4_left * 2) : fAU4_left; |
||
324 | SetJointRotation(LipCornerLeft, LipCornerLeftAxis, fAU4_left, LipCornerLeftNeutral, LipCornerLeftDepressed); |
||
325 | |||
326 | float fAU4_right = manager.GetAnimUnit(KinectInterop.FaceShapeAnimations.LipCornerDepressorRight); |
||
327 | fAU4_right = (platform == KinectInterop.DepthSensorPlatform.KinectSDKv2) ? (fAU4_right * 2) : fAU4_right; |
||
328 | SetJointRotation(LipCornerRight, LipCornerRightAxis, fAU4_right, LipCornerRightNeutral, LipCornerRightDepressed); |
||
329 | |||
330 | // AU6, AU7 – Eyelid closed |
||
331 | // 0=neutral; -1=raised; +1=fully lowered |
||
332 | float fAU6_left = manager.GetAnimUnit(KinectInterop.FaceShapeAnimations.LefteyeClosed); |
||
333 | fAU6_left = (platform == KinectInterop.DepthSensorPlatform.KinectSDKv2) ? (fAU6_left * 2 - 1) : fAU6_left; |
||
334 | SetJointRotation(UpperEyelidLeft, UpperEyelidLeftAxis, fAU6_left, UpperEyelidLeftNeutral, UpperEyelidLeftLowered); |
||
335 | SetJointRotation(LowerEyelidLeft, LowerEyelidLeftAxis, fAU6_left, LowerEyelidLeftNeutral, LowerEyelidLeftRaised); |
||
336 | |||
337 | float fAU6_right = manager.GetAnimUnit(KinectInterop.FaceShapeAnimations.RighteyeClosed); |
||
338 | fAU6_right = (platform == KinectInterop.DepthSensorPlatform.KinectSDKv2) ? (fAU6_right * 2 - 1) : fAU6_right; |
||
339 | SetJointRotation(UpperEyelidRight, UpperEyelidRightAxis, fAU6_right, UpperEyelidRightNeutral, UpperEyelidRightLowered); |
||
340 | SetJointRotation(LowerEyelidRight, LowerEyelidRightAxis, fAU6_right, LowerEyelidRightNeutral, LowerEyelidRightRaised); |
||
341 | } |
||
342 | else |
||
343 | { |
||
344 | // hide the model behind the camera |
||
345 | if(HeadTransform && HeadTransform.position.z >= 0f) |
||
346 | { |
||
347 | HeadTransform.position = new Vector3(0f, 0f, -10f); |
||
348 | } |
||
349 | } |
||
350 | } |
||
351 | |||
352 | private float GetJointRotation(Transform joint, AxisEnum axis) |
||
353 | { |
||
354 | float fJointRot = 0.0f; |
||
355 | |||
356 | if(joint == null) |
||
357 | return fJointRot; |
||
358 | |||
359 | Vector3 jointRot = joint.localRotation.eulerAngles; |
||
360 | |||
361 | switch(axis) |
||
362 | { |
||
363 | case AxisEnum.X: |
||
364 | fJointRot = jointRot.x; |
||
365 | break; |
||
366 | |||
367 | case AxisEnum.Y: |
||
368 | fJointRot = jointRot.y; |
||
369 | break; |
||
370 | |||
371 | case AxisEnum.Z: |
||
372 | fJointRot = jointRot.z; |
||
373 | break; |
||
374 | } |
||
375 | |||
376 | return fJointRot; |
||
377 | } |
||
378 | |||
379 | private void SetJointRotation(Transform joint, AxisEnum axis, float fAU, float fMin, float fMax) |
||
380 | { |
||
381 | if(joint == null) |
||
382 | return; |
||
383 | |||
384 | // float fSign = 1.0f; |
||
385 | // if(fMax < fMin) |
||
386 | // fSign = -1.0f; |
||
387 | |||
388 | // [-1, +1] -> [0, 1] |
||
389 | //fAUnorm = (fAU + 1f) / 2f; |
||
390 | float fValue = fMin + (fMax - fMin) * fAU; |
||
391 | |||
392 | Vector3 jointRot = joint.localRotation.eulerAngles; |
||
393 | |||
394 | switch(axis) |
||
395 | { |
||
396 | case AxisEnum.X: |
||
397 | jointRot.x = fValue; |
||
398 | break; |
||
399 | |||
400 | case AxisEnum.Y: |
||
401 | jointRot.y = fValue; |
||
402 | break; |
||
403 | |||
404 | case AxisEnum.Z: |
||
405 | jointRot.z = fValue; |
||
406 | break; |
||
407 | } |
||
408 | |||
409 | if(smoothFactor != 0f) |
||
410 | joint.localRotation = Quaternion.Slerp(joint.localRotation, Quaternion.Euler(jointRot), smoothFactor * Time.deltaTime); |
||
411 | else |
||
412 | joint.localRotation = Quaternion.Euler(jointRot); |
||
413 | } |
||
414 | |||
415 | |||
416 | } |