3DSelfie  Hansjoerg Hofer (1026632), Sebastian Metzler (0927550)
ControlPoints.cs
Go to the documentation of this file.
1 using UnityEngine;
2 using System.Collections;
3 using System.Collections.Generic;
4 
10 public class ControlPoints : MonoBehaviour {
11 
12  private Mesh _mesh;
13  private float _epsilon = 0.01f;
14 
15  private float _maxDistance = 1.5f;
16  private float _scale = 0.8f;
17 
18  private List<int>[] _vertexIdentities;
19  private List<Vector3>[] _vertexOffsets;
20 
21  /*
22  * Hand picked Control Points from male_head_obj_MAYA.obj
23  */
24  /*
25  * Left Eye
26  */
27  private List<int>[] _lEyeF2v;
28  private Vector3[] _lEyeF2world;
29  private Vector3[] _lEyeFCP = new Vector3[] {
30  new Vector3(0.167f, 1.993f, 0.680f),
31  new Vector3(0.241f, 2.049f, 0.704f),
32  new Vector3(0.304f, 2.039f, 0.701f),
33  new Vector3(0.394f, 2.006f, 0.638f),
34  new Vector3(0.328f, 1.967f, 0.684f),
35  new Vector3(0.233f, 1.983f, 0.680f)
36  };
37  public Vector3[] LEyeFCP {
38  get { return _lEyeF2world; }
39  }
40  /*
41  * Left Eyebrow
42  */
43  private List<int>[] _lEyebrow2v;
44  private Vector3[] _lEyebrow2world;
45  private Vector3[] _lEyebrowCP = new Vector3[] {
46  new Vector3(0.152f, 2.111f, 0.834f),
47  new Vector3(0.184f, 2.202f, 0.832f),
48  new Vector3(0.298f, 2.234f, 0.776f),
49  new Vector3(0.389f, 2.240f, 0.699f),
50  new Vector3(0.464f, 2.184f, 0.601f),
51  new Vector3(0.438f, 2.121f, 0.668f),
52  new Vector3(0.438f, 2.121f, 0.668f),
53  new Vector3(0.354f, 2.162f, 0.745f),
54  new Vector3(0.271f, 2.147f, 0.796f),
55  };
56  public Vector3[] LEyebrowCP {
57  get { return _lEyebrow2world; }
58  }
59  /*
60  * Right Eye
61  */
62  private List<int>[] _rEyeF2v;
63  private Vector3[] _rEyeF2world;
64  private Vector3[] _rEyeFCP = new Vector3[] {
65  new Vector3(-0.167f, 1.993f, 0.680f),
66  new Vector3(-0.241f, 2.049f, 0.704f),
67  new Vector3(-0.304f, 2.039f, 0.701f),
68  new Vector3(-0.394f, 2.006f, 0.638f),
69  new Vector3(-0.328f, 1.967f, 0.684f),
70  new Vector3(-0.233f, 1.983f, 0.689f)
71  };
72  public Vector3[] REyeFCP {
73  get { return _rEyeF2world; }
74  }
75  /*
76  * Right Eyebrow
77  */
78  private List<int>[] _rEyebrow2v;
79  private Vector3[] _rEyebrow2world;
80  private Vector3[] _rEyebrowCP = new Vector3[] {
81  new Vector3(-0.152f, 2.111f, 0.834f),
82  new Vector3(-0.184f, 2.202f, 0.832f),
83  new Vector3(-0.298f, 2.234f, 0.776f),
84  new Vector3(-0.389f, 2.240f, 0.699f),
85  new Vector3(-0.464f, 2.184f, 0.601f),
86  new Vector3(-0.438f, 2.121f, 0.668f),
87  new Vector3(-0.438f, 2.121f, 0.668f),
88  new Vector3(-0.354f, 2.162f, 0.745f),
89  new Vector3(-0.271f, 2.147f, 0.796f),
90  };
91  public Vector3[] REyebrowCP {
92  get { return _rEyebrow2world; }
93  }
94 
95  /*
96  * Eye Side
97  */
98  private List<int>[] _eyeS2v;
99  private Vector3[] _eyeS2world;
100  private Vector3[] _eyeSCP = new Vector3[] {
101  new Vector3(0.241f, 2.049f, 0.704f),
102  new Vector3(0.286f, 1.968f, 0.693f),
103  new Vector3(0.394f, 2.006f, 0.638f)
104  };
105  public Vector3[] EyeSCP {
106  get { return _eyeS2world; }
107  }
108 
109  /*
110  * Mouth
111  */
112  private List<int>[] _mouthF2v;
113  private Vector3[] _mouthF2world;
114  private Vector3[] _mouthFCP = new Vector3[] {
115 // new Vector3(0.000f, 1.490f, 0.949f),
116  new Vector3(0.052f, 1.508f, 0.943f),
117 // new Vector3(0.141f, 1.494f, 0.901f),
118  new Vector3(0.245f, 1.426f, 0.763f),
119  new Vector3(0.145f, 1.494f, 0.901f),
120  new Vector3(0.068f, 1.356f, 0.901f),
121 // new Vector3(0.068f, 1.356f, 0.901f),
122 // new Vector3(-0.068f, 1.356f, 0.901f),
123  new Vector3(-0.068f, 1.356f, 0.901f),
124  new Vector3(-0.145f, 1.494f, 0.901f),
125  new Vector3(-0.245f, 1.426f, 0.763f),
126 // new Vector3(-0.141f, 1.494f, 0.901f),
127  new Vector3(-0.052f, 1.508f, 0.943f)
128  };
129  public Vector3[] MouthFCP {
130  get { return _mouthF2world; }
131  }
132 
133  /*
134  * Mouth Side
135  */
136  private List<int>[] _mouthS2v;
137  private Vector3[] _mouthS2world;
138  private Vector3[] _mouthSCP = new Vector3[] {
139  new Vector3(0.245f, 1.426f, 0.763f),
140  new Vector3(0.068f, 1.356f, 0.901f),
141  new Vector3(0.000f, 1.490f, 0.949f)
142  };
143  public Vector3[] MouthSCP {
144  get { return _mouthS2world; }
145  }
146 
147  /*
148  * Contour
149  */
150  private List<int>[] _contourF2v;
151  private Vector3[] _contourF2world;
152  private Vector3[] _contourFCP = new Vector3[] {
153  new Vector3(0.000f, 2.944f, -0.038f),
154  new Vector3(0.406f, 2.837f, -0.082f),
155  new Vector3(0.618f, 2.290f, 0.075f),
156  new Vector3(0.542f, 1.742f, 0.256f),
157  new Vector3(0.368f, 1.253f, 0.457f),
158  new Vector3(0.000f, 1.084f, 0.855f),
159  new Vector3(-0.368f, 1.253f, 0.457f),
160  new Vector3(-0.542f, 1.742f, 0.256f),
161  new Vector3(-0.618f, 2.290f, 0.075f),
162  new Vector3(-0.406f, 2.837f, -0.082f)
163  };
164  public Vector3[] ContourFCP {
165  get { return _contourF2world; }
166  }
167 
168  /*
169  * Contour Side
170  */
171  private List<int>[] _contourS2v;
172  private Vector3[] _contourS2world;
173  private Vector3[] _contourSCP = new Vector3[] {
174  new Vector3(0.000f, 1.084f, 0.855f),
175  new Vector3(0.000f, 1.745f, 1.083f),
176  new Vector3(0.000f, 2.382f, 0.815f),
177  new Vector3(0.000f, 2.944f, -0.038f),
178  new Vector3(0.000f, 2.499f, -0.841f),
179  new Vector3(0.000f, 1.587f, -0.799f)
180  };
181  public Vector3[] ContourSCP {
182  get { return _contourS2world; }
183  }
184 
185  private bool _enableRotation;
186  public bool EnableRotation {
187  set { _enableRotation = value; }
188  get { return _enableRotation; }
189  }
190  private float _sensitivity;
191  private Vector3 _mouseReference;
192  private Vector3 _mouseOffset;
193  private Vector3 _rotation;
194  private bool _isRotating;
195 
202  void Start () {
203  _mesh = GetComponent<MeshFilter>().mesh;
204 
205  Vector3[] vertices = _mesh.vertices;
206  /*Color[] colors = new Color[vertices.Length];
207  for (int i = 0; i < vertices.Length; i++) {
208  colors[i] = Color.white;
209  }
210  _mesh.colors = colors;*/
211 
212  _vertexOffsets = new List<Vector3>[vertices.Length];
213 
214  //search for duplicate vertices
215  _vertexIdentities = new List<int>[vertices.Length];
216  for (int i = 0; i < vertices.Length; i++) {
217  for (int j = 0; j < vertices.Length; j++) {
218 
219  if (vertices [i].x == vertices [j].x
220  && vertices [i].y == vertices [j].y
221  && vertices [i].z == vertices [j].z) {
222 
223  if (_vertexIdentities [i] == null) {
224  _vertexIdentities [i] = new List<int> ();
225  }
226  _vertexIdentities [i].Add (j);
227  }
228  }
229  }
230 
231  FindControlPoints (_lEyeFCP, out _lEyeF2v, out _lEyeF2world);
232  FindControlPoints (_rEyeFCP, out _rEyeF2v, out _rEyeF2world);
233 
234  FindControlPoints (_lEyebrowCP, out _lEyebrow2v, out _lEyebrow2world);
235  FindControlPoints (_rEyebrowCP, out _rEyebrow2v, out _rEyebrow2world);
236 
237  FindControlPoints (_mouthFCP, out _mouthF2v, out _mouthF2world);
238  FindControlPoints (_contourFCP, out _contourF2v, out _contourF2world);
239 
240  /*
241  * Find Side CP
242  */
243  RotateToProfile ();
244 
245  FindControlPoints (_lEyebrowCP, out _lEyebrow2v, out _lEyebrow2world);
246  FindControlPoints (_rEyebrowCP, out _rEyebrow2v, out _rEyebrow2world);
247  FindControlPoints (_mouthSCP, out _mouthS2v, out _mouthS2world);
248  FindControlPoints (_eyeSCP, out _eyeS2v, out _eyeS2world);
249  FindControlPoints (_contourSCP, out _contourS2v, out _contourS2world);
250 
251  RotateToFront ();
252 
253  _sensitivity = 0.2f;
254  _rotation = Vector3.zero;
255  }
256 
262  void Update() {
263  if(_enableRotation && Input.GetMouseButtonDown(0)) {
264  // rotating flag
265  _isRotating = true;
266  // store mouse
267  _mouseReference = Input.mousePosition;
268  }
269 
270  if(Input.GetMouseButtonUp(0))
271  _isRotating = false;
272 
273  if(_isRotating)
274  {
275  // offset
276  _mouseOffset = (Input.mousePosition - _mouseReference);
277 
278  _rotation.y = -(_mouseOffset.x) * _sensitivity;
279  _rotation.x = -(_mouseOffset.y) * _sensitivity;
280 
281  // rotate
282  transform.eulerAngles += _rotation;
283  // store mouse
284  _mouseReference = Input.mousePosition;
285  }
286  }
287 
298  public Vector3[] CalculateOffset(Vector3[] startPoints, Vector3[] endPoints, bool side = false) {
299 
300  if(side) RotateToProfile ();
301 
302  Vector3[] offsets = new Vector3[startPoints.Length];
303  for (int i = 0; i < startPoints.Length; i++) {
304 
305  Vector3 startM = transform.InverseTransformPoint(startPoints[i]);
306  Vector3 endM = transform.InverseTransformPoint(endPoints[i]);
307  offsets[i] = endM - startM;
308  }
309 
310  if(side) RotateToFront ();
311 
312  return offsets;
313  }
314 
324  public void DeformContour(Vector3[] offsets) {
325  DeformModel(offsets, _contourF2v, new List<int>() { 4, 5, 6 } );
326  }
327 
337  public void DeformLEye(Vector3[] offsets) {
338  DeformModel(offsets, _lEyeF2v);
339  }
340 
350  public void DeformREye(Vector3[] offsets) {
351  DeformModel(offsets, _rEyeF2v);
352  }
353 
363  public void DeformLEyeBrow(Vector3[] offsets) {
364  DeformModel(offsets, _lEyebrow2v);
365  }
366 
376  public void DeformREyeBrow(Vector3[] offsets) {
377  DeformModel(offsets, _rEyebrow2v);
378  }
379 
389  public void DeformMouth(Vector3[] offsets) {
390  DeformModel(offsets, _mouthF2v);
391  }
392 
403  private void DeformModel(Vector3[] offsets, List<int>[] idxCP) {
404  DeformModel(offsets, idxCP, new List<int>());
405  }
406 
417  private void DeformModel(Vector3[] offsets, List<int>[] idxCP, List<int> ignore) {
418  for(int i = 0; i < offsets.Length; i++) {
419 
420  if(ignore.IndexOf(i) != -1) continue;
421 
422  MoveVertex (idxCP [i], offsets[i]);
423  }
424  }
425 
432  public void ApplyDeformation() {
433 
434  Vector3[] vertices = _mesh.vertices;
435  Vector2[] uvs = _mesh.uv;
436 
437  for(int i = 0; i < vertices.Length; i++) {
438  List<Vector3> offsets = _vertexOffsets[i];
439 
440  //Calculate new UV coordinates
441  Vector3 origin = transform.TransformPoint(vertices[i]);
442  Vector3 direction = new Vector3(vertices[i].x, 0.0f, vertices[i].z);
443  direction.Normalize();
444 
445  //Hit with cylinder;
446  Ray r = new Ray(origin, direction);
447  RaycastHit hit;
448  if (Physics.Raycast (r, out hit))
449  uvs[i] = hit.textureCoord;
450 
451  if(offsets == null) continue;
452 
453  Vector3 sum = Vector3.zero;
454 
455  foreach(Vector3 offset in offsets) {
456  sum += offset * 2.0f;
457  }
458 
459  //Apply average deformation
460  vertices[i] += sum / offsets.Count;
461  }
462 
463  _mesh.vertices = vertices;
464  _mesh.uv = uvs;
465  }
466 
476  void MoveVertex(List<int> vertexIndices, Vector3 transpose) {
477 
478  //Move all Control Points (on same pos)
479  for (int i = 0; i < vertexIndices.Count; i++) {
480  if(_vertexOffsets[vertexIndices[i]] == null)
481  _vertexOffsets[vertexIndices[i]] = new List<Vector3>();
482 
483  _vertexOffsets[vertexIndices[i]].Add (transpose);
484  }
485  //Take first index as reference control point
486  int controlPointIndex = vertexIndices [0];
487 
488  List<int> neighbours = GetNeighbors (controlPointIndex);
489  //Create list of indices that should not be tested again
490  List<int> ignore = new List<int> (neighbours);
491  ignore.AddRange (vertexIndices);
492 
493  //Move all neighbours
494  for (int i = 0; i < neighbours.Count; i++) {
495  int neighbourIndex = neighbours[i];
496 
497  //all neighbour identities should not be tested again
498  ignore.AddRange (_vertexIdentities[neighbourIndex]);
499 
500  float distance = Vector3.Distance (_mesh.vertices[neighbourIndex], _mesh.vertices[controlPointIndex]);
501 
502  //Debug.Log ("Distance " + vertexIndices[0] + " to " + neighbours[i] + " is " + distance);
503 
504  if(distance > _maxDistance) continue;
505 
506  float distProb = Gauss(0);
507 
508  //Move the neighbor
509  MoveVertexRec(controlPointIndex, neighbourIndex, transpose * distProb, ref ignore);
510  }
511  }
512 
524  void MoveVertexRec(int controlPointIndex, int currentVertexIndex, Vector3 transpose, ref List<int> ignore) {
525 
526  //Save offset for all Vertex identities
527  for (int i = 0; i < _vertexIdentities[currentVertexIndex].Count; i++) {
528  if(_vertexOffsets[_vertexIdentities[currentVertexIndex][i]] == null)
529  _vertexOffsets[_vertexIdentities[currentVertexIndex][i]] = new List<Vector3>();
530 
531  _vertexOffsets[_vertexIdentities[currentVertexIndex][i]].Add (transpose);
532  }
533  List<int> neighbours = GetNeighbors (currentVertexIndex);
534  List<int> oldIgnore = new List<int> (ignore);
535  ignore.AddRange(neighbours);
536 
537  //Save offset for all neighbours
538  for (int i = 0; i < neighbours.Count; i++) {
539  int neighborIndex = neighbours[i];
540 
541  if(oldIgnore.IndexOf(neighborIndex) != -1) continue;
542 
543  //all neighbor identities should not be tested again
544  ignore.AddRange (_vertexIdentities[neighborIndex]);
545 
546  float distance = Vector3.Distance (_mesh.vertices[neighborIndex], _mesh.vertices[controlPointIndex]);
547 
548  //Debug.Log ("Distance " + controlPointIndex + " to " + neighborIndex + " is " + distance);
549 
550  if(distance > _maxDistance) continue;
551 
552  float distProb = Gauss(distance * _scale);
553 
554  //Move the neighbor
555  MoveVertexRec(controlPointIndex, neighborIndex, transpose * distProb, ref ignore);
556  }
557  }
558 
570  void FindControlPoints(Vector3[] cp, out List<int>[] cp2v, out Vector3[] cp2world) {
571  cp2v = new List<int>[cp.Length];
572  cp2world = new Vector3[cp.Length];
573  Vector3[] vertices = _mesh.vertices;
574 
575  int found = 0;
576 
577  for (int i = 0; i < vertices.Length; i++) {
578  //search for control points
579  for (int j = 0; j < cp.Length; j++) {
580 
581  if(_epsilon > Mathf.Abs(vertices[i].x - cp[j].x)
582  && _epsilon > Mathf.Abs(vertices[i].y - cp[j].y)
583  && _epsilon > Mathf.Abs(vertices[i].z - cp[j].z)) {
584 
585  //Debug.Log (cp[j] + " " + vertices[i]);
586 
587  if(cp2v[j] == null) {
588  cp2v[j] = new List<int>();
589 
590  //Save WordPoint just once!
591  cp2world[j] = transform.TransformPoint(vertices[i]);
592  }
593  cp2v[j].Add(i);
594 
595  found++;
596  }
597  }
598  }
599 
600  if (found < cp.Length) {
601  throw new MissingComponentException ("Could not find all control points (" + found + "/" + cp.Length + ")");
602  }
603  }
604 
613  float Gauss(float x)
614  {
615  float sigma = 0.5f;
616  float a = 1.0f / (sigma * Mathf.Sqrt (2.0f * Mathf.PI));
617  return a * Mathf.Exp ( - Mathf.Pow(x, 2.0f) / (2.0f * Mathf.Pow(sigma, 2.0f)) );
618 
619  //paper
620  //return Mathf.Exp ( - Mathf.Pow(x, 2.0f) / (sigma) );
621  }
622 
632  List<int> GetNeighbors(int index) {
633  int[] triangles = _mesh.triangles;
634 
635  List<int> verts = new List<int>();
636  for(int i = 0; i < triangles.Length / 3; i++){
637  // see if the triangle contains the index
638  bool found = false;
639  for(int j = 0; j < 3; j++){
640  int cur = triangles[i * 3 + j];
641  if(cur == index) found = true;
642  }
643  // if we found the index in the triangle, append the others.
644  if(found){
645  for(int j = 0; j < 3 ; j++){
646  int cur = triangles[i * 3 + j];
647  if(verts.IndexOf(cur) == -1 && cur != index){
648  verts.Add(cur);
649  }
650  }
651  }
652  }
653  return verts;
654  }
655 
659  public void RotateToProfile() {
660  transform.Rotate (Vector3.up * 90.0f);
661  }
665  void RotateToFront() {
666  transform.Rotate (Vector3.up * -90.0f);
667  }
668 }
void DeformMouth(Vector3[] offsets)
Deforms the mouth.
Vector3[] LEyeFCP
ControlPoints script on mesh.
void DeformREye(Vector3[] offsets)
Deforms the right eye.
void DeformLEyeBrow(Vector3[] offsets)
Deforms the left eyebrow.
void ApplyDeformation()
Applies the average of the calculated weighted offsets to every vertex in the mesh.
Vector3[] MouthSCP
Vector3[] EyeSCP
Vector3[] REyebrowCP
void DeformLEye(Vector3[] offsets)
Deforms the left eye.
Vector3[] REyeFCP
void DeformContour(Vector3[] offsets)
Deforms the face contour.
void DeformREyeBrow(Vector3[] offsets)
Deforms the right eyebrow.
Vector3[] LEyebrowCP
Vector3[] ContourFCP
Vector3[] ContourSCP
Vector3[] MouthFCP
Vector3[] CalculateOffset(Vector3[] startPoints, Vector3[] endPoints, bool side=false)
Calculates the offset of two contours in world coordinates.
void RotateToProfile()
Rotates the mesh by 90 degrees around the y axis.