/// <summary> /// Updates vertex normals and face planes. /// </summary> public void Invalidate(IProgressListener listener = null, InvalidateFlags invalidate = InvalidateFlags.All) { if (invalidate.HasFlag(InvalidateFlags.Faces)) { if (listener != null) { listener.OnStarted("Invalidating mesh faces"); } foreach (var face in m_Faces) { var v0 = m_Vertices[face[0]].Position; var v1 = m_Vertices[face[1]].Position; var v2 = m_Vertices[face[2]].Position; face.Plane = new Plane(v0, v1, v2); } if (listener != null) { listener.OnComplete("Invalidating mesh faces"); } } if (invalidate.HasFlag(InvalidateFlags.Vertices)) { if (listener != null) { listener.OnStarted("Invalidating mesh vertices"); } int i = 0; foreach (var vertex in m_Vertices) { foreach (var face in m_Faces) { if (face.HasVertex(vertex.Key)) { vertex.Value.Normal += face.Plane.Normal; } } if (listener != null) { listener.OnStep(++i, m_Vertices.Count); } vertex.Value.Normal.Normalize(); } if (listener != null) { listener.OnComplete("Invalidating mesh vertices"); } } }
public void WriteMesh(ref Mesh mesh, IProgressListener listener = null) { long current = 0; long total = mesh.Vertices.Count + mesh.Faces.Count; listener.OnStarted("Mesh write"); foreach (var vertex in mesh.Vertices) { m_Writer.WriteLine(string.Format( CultureInfo.InvariantCulture, "v {0} {1} {2}", vertex.Value.Position.X.ToString("0.000000", CultureInfo.InvariantCulture), vertex.Value.Position.Y.ToString("0.000000", CultureInfo.InvariantCulture), vertex.Value.Position.Z.ToString("0.000000", CultureInfo.InvariantCulture))); ++current; if (listener != null) { listener.OnStep(current, total); } } int count = 0; foreach (var face in mesh.Faces) { m_Writer.WriteLine(string.Format(CultureInfo.InvariantCulture, "f {0} {1} {2}", face[0], face[1], face[2])); ++count; ++current; if (listener != null) { listener.OnStep(current, total); } } if (listener != null) { listener.OnComplete("Mesh write"); } m_Writer.Close(); }
public virtual void Read(out Mesh mesh, IProgressListener listener = null) { mesh = new Mesh(); Regex r = new Regex(@" |//"); NumberStyles numberStyle = NumberStyles.Float; IFormatProvider numberFormatProvider = CultureInfo.InvariantCulture; if (listener != null) { listener.OnStarted("Load mesh"); } int indicesCount = 0; while (m_Reader.Peek() >= 0) { string line = m_Reader.ReadLine(); String[] elements = r.Split(line); // List<Vertex> normals; switch (elements[0]) { case "v": { float x, y, z; if ( float.TryParse(elements[1], numberStyle, numberFormatProvider, out x) && float.TryParse(elements[2], numberStyle, numberFormatProvider, out y) && float.TryParse(elements[3], numberStyle, numberFormatProvider, out z) ) { mesh.Vertices.Add(++indicesCount, new Vertex(new Vector3(x, y, z))); } else { Trace.WriteLine(line); } break; } case "f": { int f1, f2, f3; int f1Index = 1; int f2Index = 2; int f3Index = 3; switch (elements.Length) { case 7: { //normal indexes in elements[2],elements[4] and elements[6] are ignored; f1Index = 1; f2Index = 3; f3Index = 5; goto case 4; } case 4: { if ( int.TryParse(elements[f1Index], numberStyle, numberFormatProvider, out f1) && int.TryParse(elements[f2Index], numberStyle, numberFormatProvider, out f2) && int.TryParse(elements[f3Index], numberStyle, numberFormatProvider, out f3) ) { mesh.Faces.Add(new Triangle(f1, f2, f3)); } else { Trace.WriteLine(line); throw new NotImplementedException("Only triangles are Implemented. Faces in file are not a triangles.That is bad:("); } } break; default: Trace.WriteLine("Invalid number of components"); break; } break; } case "vn": { break; } default: Trace.WriteLine("Unknown obj specifier."); break; } if (listener != null) { listener.OnStep( m_Reader.BaseStream.Position, m_Reader.BaseStream.Length); } } if (listener != null) { listener.OnComplete("Mesh loaded successfully"); } mesh.Invalidate(listener, Mesh.InvalidateFlags.Faces); }
private void Contract(int targetTriangles, IProgressListener listener = null) { SelectValidPairs(); if (listener != null) { listener.OnStarted("Compacting"); } int totalTriangles = m_Faces.Count - targetTriangles; int currentTriangle = 0; while (m_Faces.Count > targetTriangles) { if (listener != null) { listener.OnStep(currentTriangle, totalTriangles); } ++currentTriangle; double minError = (double)int.MaxValue; //KeyValuePair<VertexPair, double> min; VertexPair minPair = new VertexPair() { First = 0, Second = 0 }; foreach (KeyValuePair<VertexPair, double> e in m_Errors) { if (e.Value < minError) { minError = e.Value; minPair = e.Key; } } Vector3 error; ComputeError(minPair.First, minPair.Second, out error); #if false VertexSplit split = new VertexSplit(); //var fv split.First.Position = m_Vertices[minPair.First].Position; split.Second.Position = m_Vertices[minPair.Second].Position; split.Target.Position = error; m_Splits.Add(split); #endif var vertex = m_Vertices[minPair.First]; vertex.Position = error; m_Quadrics[minPair.First] = m_Quadrics[minPair.First] + m_Quadrics[minPair.Second]; for (int i = m_Faces.Count - 1; i != 0; ) { var face = m_Faces[i]; for (int j = 0; j < 3; ++j) { if (face[j] == minPair.Second) { if (face[0] == minPair.First || face[1] == minPair.First || face[2] == minPair.First) { m_Faces.Remove(face); } else { face[j] = minPair.First; } --i; break; } else if (j == 2) { --i; } } } m_Vertices.Remove(minPair.Second); KeyValuePair<VertexPair, double> pair; #if false for (int iter = m_Errors.Count - 1; iter != 0; ) { pair = m_Errors.ElementAt(iter); if (pair.Key.First == minPair.Second && pair.Key.Second != minPair.First) { m_Errors.Remove(m_Errors.ElementAt(iter).Key); m_Errors.Add( new VertexPair() { First = Math.Min(minPair.First, pair.Key.Second), Second = Math.Max(minPair.First, pair.Key.Second) }, 0.0); --iter; } else if (pair.Key.Second == minPair.Second && pair.Key.First != minPair.First) { m_Errors.Remove(m_Errors.ElementAt(iter).Key); m_Errors.Add( new VertexPair() { First = Math.Min(minPair.First, pair.Key.First), Second = Math.Max(minPair.First, pair.Key.First) }, 0.0); --iter; } else { --iter; } } #else for (int it = 0; it < m_Errors.Count; ++it) { pair = m_Errors.ElementAt(it); if (pair.Key.First == minPair.Second && pair.Key.Second != minPair.First) { m_Errors.Remove(m_Errors.ElementAt(it).Key); var key = new VertexPair() { First = Math.Min(minPair.First, pair.Key.Second), Second = Math.Max(minPair.First, pair.Key.Second) }; if (!m_Errors.ContainsKey(key)) { m_Errors.Add( key, 0.0); } } else if (pair.Key.Second == minPair.Second && pair.Key.First != minPair.First) { m_Errors.Remove(m_Errors.ElementAt(it).Key); var key = new VertexPair() { First = Math.Min(minPair.First, pair.Key.First), Second = Math.Max(minPair.First, pair.Key.First) }; if (!m_Errors.ContainsKey(key)) { m_Errors.Add( key, 0.0); } } } #endif m_Errors.Remove(minPair); for (int it = 0; it < m_Errors.Count; ++it) { var key = m_Errors.ElementAt(it).Key; if (key.First == minPair.First) { m_Errors[key] = ComputeError(minPair.First, key.Second); } if (key.Second == minPair.First) { m_Errors[key] = ComputeError(minPair.First, key.First); } } /*foreach (var e in m_Errors) { var p = e.Key; if (p.First == minPair.First) { m_Errors[p] = ComputeError(minPair.First, p.Second); } if (p.Second == minPair.First) { m_Errors[p] = ComputeError(minPair.First, p.First); } }*/ } if (listener != null) { listener.OnComplete("Compacting"); } }
private void Contract(int targetTriangles, IProgressListener listener = null) { SelectValidPairs(); if (listener != null) { listener.OnStarted("Compacting"); } int totalTriangles = m_Faces.Count - targetTriangles; int currentTriangle = 0; while (m_Faces.Count > targetTriangles) { if (listener != null) { listener.OnStep(currentTriangle, totalTriangles); } ++currentTriangle; double minError = (double)int.MaxValue; //KeyValuePair<VertexPair, double> min; VertexPair minPair = new VertexPair() { First = 0, Second = 0 }; foreach (KeyValuePair <VertexPair, double> e in m_Errors) { if (e.Value < minError) { minError = e.Value; minPair = e.Key; } } Vector3 error; ComputeError(minPair.First, minPair.Second, out error); #if false VertexSplit split = new VertexSplit(); //var fv split.First.Position = m_Vertices[minPair.First].Position; split.Second.Position = m_Vertices[minPair.Second].Position; split.Target.Position = error; m_Splits.Add(split); #endif var vertex = m_Vertices[minPair.First]; vertex.Position = error; m_Quadrics[minPair.First] = m_Quadrics[minPair.First] + m_Quadrics[minPair.Second]; for (int i = m_Faces.Count - 1; i != 0;) { var face = m_Faces[i]; for (int j = 0; j < 3; ++j) { if (face[j] == minPair.Second) { if (face[0] == minPair.First || face[1] == minPair.First || face[2] == minPair.First) { m_Faces.Remove(face); } else { face[j] = minPair.First; } --i; break; } else if (j == 2) { --i; } } } m_Vertices.Remove(minPair.Second); KeyValuePair <VertexPair, double> pair; #if false for (int iter = m_Errors.Count - 1; iter != 0;) { pair = m_Errors.ElementAt(iter); if (pair.Key.First == minPair.Second && pair.Key.Second != minPair.First) { m_Errors.Remove(m_Errors.ElementAt(iter).Key); m_Errors.Add( new VertexPair() { First = Math.Min(minPair.First, pair.Key.Second), Second = Math.Max(minPair.First, pair.Key.Second) }, 0.0); --iter; } else if (pair.Key.Second == minPair.Second && pair.Key.First != minPair.First) { m_Errors.Remove(m_Errors.ElementAt(iter).Key); m_Errors.Add( new VertexPair() { First = Math.Min(minPair.First, pair.Key.First), Second = Math.Max(minPair.First, pair.Key.First) }, 0.0); --iter; } else { --iter; } } #else for (int it = 0; it < m_Errors.Count; ++it) { pair = m_Errors.ElementAt(it); if (pair.Key.First == minPair.Second && pair.Key.Second != minPair.First) { m_Errors.Remove(m_Errors.ElementAt(it).Key); var key = new VertexPair() { First = Math.Min(minPair.First, pair.Key.Second), Second = Math.Max(minPair.First, pair.Key.Second) }; if (!m_Errors.ContainsKey(key)) { m_Errors.Add( key, 0.0); } } else if (pair.Key.Second == minPair.Second && pair.Key.First != minPair.First) { m_Errors.Remove(m_Errors.ElementAt(it).Key); var key = new VertexPair() { First = Math.Min(minPair.First, pair.Key.First), Second = Math.Max(minPair.First, pair.Key.First) }; if (!m_Errors.ContainsKey(key)) { m_Errors.Add( key, 0.0); } } } #endif m_Errors.Remove(minPair); for (int it = 0; it < m_Errors.Count; ++it) { var key = m_Errors.ElementAt(it).Key; if (key.First == minPair.First) { m_Errors[key] = ComputeError(minPair.First, key.Second); } if (key.Second == minPair.First) { m_Errors[key] = ComputeError(minPair.First, key.First); } } /*foreach (var e in m_Errors) * { * var p = e.Key; * if (p.First == minPair.First) * { * m_Errors[p] = ComputeError(minPair.First, p.Second); * } * * if (p.Second == minPair.First) * { * m_Errors[p] = ComputeError(minPair.First, p.First); * } * }*/ } if (listener != null) { listener.OnComplete("Compacting"); } }