UnityMol  0.9.6-875
UnityMol viewer / In developement
SmoothFilter.cs
Go to the documentation of this file.
1 using UnityEngine;
2 using System.Collections;
3 using System.Collections.Generic;
4 
5 /*
6  MeshSmoothTest
7 
8  Laplacian Smooth Filter, HC-Smooth Filter
9 
10  MarkGX, Jan 2011
11 */
12 public class SmoothFilter : MonoBehaviour {
13  private static float NUDGE_COEF = 0.05f;
14  private static float BETA = 0.85f;
15  private static float ONE_MINUS_BETA = 1f - BETA;
16 
17  // The HCSmoothing algorithm tries to compensate for the shrinking induced by the Laplacian
18  // algorithm. The extent to which it does this is governed by this variable. If it is very small,
19  // e.g. in [0;2], the algorithm will produce results similar to the Laplacian filter. If it is around
20  // 0.5 or higher, the compensation will be more noticeable, but the smoothing effect will not be as good.
21  private static float HC_CORRECT = 0.2f;
22 
23 
24  /*
25  Standard Laplacian Smooth Filter
26  */
27  /*
28  public static Vector3[] laplacianFilter(Vector3[] sv, int[] t, AdjacencySets adjacencySets) {
29  Vector3[] wv = new Vector3[sv.Length];
30  List<Vector3> adjacentVertices = new List<Vector3>();
31 
32  float dx = 0.0f;
33  float dy = 0.0f;
34  float dz = 0.0f;
35 
36  for (int vi=0; vi< sv.Length; vi++) {
37  // Find the sv neighboring vertices
38  //adjacentVertices = MeshUtils.findAdjacentNeighbors (sv, t, sv[vi]);
39  adjacentVertices.Clear();
40  BuildNeighborsLists(adjacencySets, adjacentVertices, vi, sv);
41 
42  if (adjacentVertices.Count != 0) {
43  dx = 0.0f;
44  dy = 0.0f;
45  dz = 0.0f;
46 
47  //Debug.Log("Vertex Index Length = "+vertexIndexes.Length);
48  // Add the vertices and divide by the number of vertices
49  for (int j=0; j<adjacentVertices.Count; j++) {
50  dx += adjacentVertices[j].x;
51  dy += adjacentVertices[j].y;
52  dz += adjacentVertices[j].z;
53  }
54 
55  wv[vi].x = dx / adjacentVertices.Count;
56  wv[vi].y = dy / adjacentVertices.Count;
57  wv[vi].z = dz / adjacentVertices.Count;
58  }
59  }
60  return wv;
61  }
62  */
63 
64  // Assuming "neighbors" only includes actual neighbors, not the vertex itself
65  private static Vector3 TrueAverageVertex(List<Vector3> neighbors, Vector3 v) {
66  /* // Not supposed to happen anyway!
67  if(neighbors.Count < 1)
68  return v;
69  */
70 
71  foreach(Vector3 vert in neighbors)
72  v += vert;
73 
74  float denominator = ( (float)neighbors.Count + 1f);
75  float factor = 1f/denominator;
76  if(factor == 0f)
77  Debug.Log("HERE IS THE PROBLEM!!!!!!!!!!!!!");
78  v = v * factor; // awkward, but you can't divide a vector by a float
79  return v;
80  }
81 
82  private static Vector3 AverageOfNeighbors(List<Vector3> neighbors) {
83  Vector3 average = Vector3.zero;
84  foreach(Vector3 v in neighbors)
85  average += v;
86 
87  float denominator = (float)neighbors.Count;
88  float factor = 1f/denominator;
89  if(factor == 0f)
90  Debug.Log("HERE IS THE PROBLEM!!!!!!!!!!!!!");
91  average *= factor;
92  return average;
93  }
94 
95  private static Vector3 NudgeVertex(List<Vector3> neighbors, Vector3 v) {
96  if(neighbors.Count == 0)
97  return v;
98 
99  Vector3 nudgeVector;
100  foreach(Vector3 vert in neighbors) {
101  nudgeVector = vert - v;
102  v += NUDGE_COEF * nudgeVector;
103  }
104  return v;
105  }
106 
107  private static void BuildNeighborsLists(AdjacencySets adjSets, List<Vector3> neighbors,
108  List<int> neighborIndices, int i, Vector3[] vertices) {
109  HashSet<int> aSet = adjSets.GetAdjacencySet(i);
110  foreach(int index in aSet) {
111  if(i != index) {
112  neighbors.Add(vertices[index]);
113  neighborIndices.Add(index);
114  }
115  }
116  }
117 
118 
119  private static bool IsInsideVertex(List<Vector3> neighbors,
120  List<int> nIndices, AdjacencySets aSets) {
121  int nbNeighbors; // number of neighbors that each neighbor possesses
122  HashSet<int> aSet;
123 
124  // First we iterate over every neighbor of the "central" vertex we consider
125  for(int nIndex=0; nIndex<neighbors.Count; nIndex++) {
126 
127  // We then get the adjacency set containing *its* neighbors
128  aSet = aSets.GetAdjacencySet(nIndices[nIndex]);
129  nbNeighbors = 0;
130 
131  // We now iterate over this set. If any value in it is also in the nIndices list,
132  // i.e. in the list of neighbors of our "central" vertex, we increment the number
133  // of neighbors.
134  foreach(int a in aSet) {
135  if(nIndices.Contains(a))
136  nbNeighbors++;
137  }
138 
139  // If this number is less than two, this means one of the neighbors of the central
140  // vertex has less than two neighbors that are also a neighbor of the central vertex.
141  // In other words, the central vertex is on an edge of the mesh.
142  if(nbNeighbors < 2)
143  return false;
144  }
145 
146  // If the function has never returned false, then the vertex is not on an edge.
147  // It can be moved.
148  return true;
149  }
150 
151 
152 
153  public static void AdjSetsSmoother(MeshData mData, AdjacencySets adjacencySets) {
154  Vector3[] vertices = mData.vertices;
155  Vector3[] ov = mData.vertices; // original vertices
156  List<Vector3> neighbors = new List<Vector3>();
157  List<int> neighborIndices = new List<int>();
158  for(int i=0; i<vertices.Length; i++) {
159  neighbors.Clear(); // must exist but be empty for each new vertex
160  neighborIndices.Clear();
161  BuildNeighborsLists(adjacencySets, neighbors, neighborIndices, i, ov);
162  vertices[i] = TrueAverageVertex(neighbors, ov[i]);
163  }
164  mData.vertices = vertices;
165  }
166 
167  // Not really necessary in UnityMol's current state.
168  // Could be useful to keep around for imported meshes.
169  public static void ConditionalAdjSetsSmoother(MeshData mData, AdjacencySets adjacencySets) {
170  Vector3[] vertices = mData.vertices;
171  Vector3[] ov = mData.vertices; // original vertices
172  List<Vector3> neighbors = new List<Vector3>();
173  List<int> neighborIndices = new List<int>();
174  for(int i=0; i<vertices.Length; i++) {
175  neighbors.Clear(); // must exist but be empty for each new vertex
176  neighborIndices.Clear();
177  BuildNeighborsLists(adjacencySets, neighbors, neighborIndices, i, ov);
178 
179  // True if the vertex is not on the edge of the mesh.
180  if(IsInsideVertex(neighbors, neighborIndices, adjacencySets))
181  vertices[i] = TrueAverageVertex(neighbors, ov[i]);
182  }
183  mData.vertices = vertices;
184  }
185 
186 
187 
188  public static void AdjSetsHCSmoother(Mesh mesh, AdjacencySets adjacencySets) {
189  Vector3[] ov = mesh.vertices; // original vertices
190  Vector3[] wv = mesh.vertices; // will contain the Laplacian smoothing
191  Vector3[] bv = new Vector3[mesh.vertices.Length];
192  bool[] canBeMoved = new bool[mesh.vertices.Length];
193 
194  List<Vector3> neighbors = new List<Vector3>();
195  List<int> neighborIndices = new List<int>();
196  for(int i=0; i<wv.Length; i++) {
197  neighbors.Clear(); // must exist but be empty for each new vertex
198  neighborIndices.Clear();
199  BuildNeighborsLists(adjacencySets, neighbors, neighborIndices, i, ov);
200 
201  // True if the vertex is not on the edge of the mesh.
202  canBeMoved[i] = IsInsideVertex(neighbors, neighborIndices, adjacencySets);
203  if(canBeMoved[i])
204  wv[i] = TrueAverageVertex(neighbors, ov[i]);
205 
206  // Compute the differences
207  bv[i] = wv[i] - ov[i];
208  }
209 
210  // We let the first loop complete because bv must be filled for the next step
211  Vector3 average;
212  Vector3 move;
213  for(int i=0; i<bv.Length; i++) {
214  // We can't reuse the same neighbor list, because we get it from bv this time
215  neighbors.Clear();
216  neighborIndices.Clear();
217  BuildNeighborsLists(adjacencySets, neighbors, neighborIndices, i, bv);
218  average = AverageOfNeighbors(neighbors);
219 
220  // Final computation
221  if(canBeMoved[i]) {
222  move = BETA*bv[i] + ONE_MINUS_BETA*average;
223  wv[i] += HC_CORRECT*move;
224  }
225  }
226  mesh.vertices = wv;
227  }
228 
229 
230  /* // Doesn't really work
231  public static void OcSmoother(Mesh mesh, VertexTree vertexTree) {
232  Vector3[] vertices = mesh.vertices;
233  List<Vector3> neighbors = new List<Vector3>();
234  for(int i=0; i<vertices.Length; i++) {
235  neighbors.Clear(); // must exist but be empty for each new vertex
236  neighbors = vertexTree.GetNeighbors(neighbors, null, vertices[i]);
237  //vertices[i] = AverageVertex(neighbors, vertices[i]);
238  vertices[i] = NudgeVertex(neighbors, vertices[i]);
239  }
240  mesh.vertices = vertices;
241  }
242  */
243 
244 
245 }
static float BETA
Definition: SmoothFilter.cs:14
static void ConditionalAdjSetsSmoother(MeshData mData, AdjacencySets adjacencySets)
static void AdjSetsSmoother(MeshData mData, AdjacencySets adjacencySets)
Vector3[] vertices
Definition: MeshData.cs:6
static bool IsInsideVertex(List< Vector3 > neighbors, List< int > nIndices, AdjacencySets aSets)
static Vector3 AverageOfNeighbors(List< Vector3 > neighbors)
Definition: SmoothFilter.cs:82
HashSet< int > GetAdjacencySet(int vIndex)
static void AdjSetsHCSmoother(Mesh mesh, AdjacencySets adjacencySets)
static float ONE_MINUS_BETA
Definition: SmoothFilter.cs:15
static Vector3 NudgeVertex(List< Vector3 > neighbors, Vector3 v)
Definition: SmoothFilter.cs:95
static void BuildNeighborsLists(AdjacencySets adjSets, List< Vector3 > neighbors, List< int > neighborIndices, int i, Vector3[] vertices)
static float HC_CORRECT
Definition: SmoothFilter.cs:21
static float NUDGE_COEF
Definition: SmoothFilter.cs:13
static Vector3 TrueAverageVertex(List< Vector3 > neighbors, Vector3 v)
Definition: SmoothFilter.cs:65