diff --git a/Source/Game/MeshSimplifier.cs b/Source/Game/MeshSimplifier.cs deleted file mode 100644 index 2ddec5c..0000000 --- a/Source/Game/MeshSimplifier.cs +++ /dev/null @@ -1,681 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using FlaxEngine; -using Console = Cabrito.Console; - -namespace Game -{ - [Flags] - public enum TriangleAttributes - { - NONE, - NORMAL = 2, - TEXCOORD = 4, - COLOR = 8 - }; - - public class Triangle - { - public Int3 v; - public Vector3 n; - //public Vector3[3] uvs; - public Vector4 err; - public bool dirty; - public bool deleted; - public TriangleAttributes attr; - public int material; - } - - public class Vertex - { - public Vector3 p; - public int tstart,tcount; - public SymetricMatrix q; - public bool border; - }; - - public class Ref - { - public int tid, tvertex; - - /*public Ref() - { - tid = 0; - tvertex = 0; - }*/ - } - - public class SymetricMatrix - { - // Constructor - - public SymetricMatrix(double c = 0) - { - m = new double[10]; - for (int i=0; i<10; i++) m[i] = c; - } - - public SymetricMatrix( double m11, double m12, double m13, double m14, - double m22, double m23, double m24, - double m33, double m34, - double m44) - { - m = new double[10]; - m[0] = m11; m[1] = m12; m[2] = m13; m[3] = m14; - m[4] = m22; m[5] = m23; m[6] = m24; - m[7] = m33; m[8] = m34; - m[9] = m44; - } - - // Make plane - - public SymetricMatrix(double a,double b,double c,double d) - { - m = new double[10]; - m[0] = a*a; m[1] = a*b; m[2] = a*c; m[3] = a*d; - m[4] = b*b; m[5] = b*c; m[6] = b*d; - m[7 ] =c*c; m[8 ] = c*d; - m[9 ] = d*d; - } - - public double this[int index] - { - get { return m[index]; } - set - { - m[index] = value; - } - } - // Determinant - - public double det( int a11, int a12, int a13, - int a21, int a22, int a23, - int a31, int a32, int a33) - { - double det = m[a11]*m[a22]*m[a33] + m[a13]*m[a21]*m[a32] + m[a12]*m[a23]*m[a31] - - m[a13]*m[a22]*m[a31] - m[a11]*m[a23]*m[a32]- m[a12]*m[a21]*m[a33]; - return det; - } - - - - public static SymetricMatrix operator+(SymetricMatrix o, SymetricMatrix n) - { - return new SymetricMatrix( o.m[0]+n[0], o.m[1]+n[1], o.m[2]+n[2], o.m[3]+n[3], - o.m[4]+n[4], o.m[5]+n[5], o.m[6]+n[6], - o.m[ 7]+n[ 7], o.m[ 8]+n[8 ], - o.m[ 9]+n[9 ]); - } - - - /*public static SymetricMatrix operator+=(SymetricMatrix o, SymetricMatrix n) - { - m[0]+=n[0]; m[1]+=n[1]; m[2]+=n[2]; m[3]+=n[3]; - m[4]+=n[4]; m[5]+=n[5]; m[6]+=n[6]; m[7]+=n[7]; - m[8]+=n[8]; m[9]+=n[9]; - return *this; - }*/ - - double[] m; - }; - - public static class ListExtras - { - // list: List to resize - // size: desired new size - // element: default value to insert - - public static void Resize(this List list, int size, T element = default(T)) where T : new() - { - int count = list.Count; - - if (size < count) - { - list.RemoveRange(size, count - size); - } - else if (size > count) - { - if (size > list.Capacity) // Optimization - list.Capacity = size; - - list.AddRange(Enumerable.Repeat(element, size - count)); - for (int i = count; i < size; i++) - list[i] = new T(); - } - - - - } - } - - // Fast Quadratic Mesh Simplification - public class MeshSimplifier - { - private float ratio; - private float agressiveness; - - private List triangles; - private List vertices; - private List refs = new List(); - - public MeshSimplifier(float ratio = 1.0f, float agressiveness = 7.0f) - { - this.ratio = ratio; - this.agressiveness = agressiveness; - } - - public List Simplify(Vector3[] input) - { - triangles = new List(input.Length / 3); - vertices = new List(); - - // TODO: no overlapping vertices, vertices must be unique - - - { - - Dictionary verticeMap = new Dictionary(); - for (int i = 0; i < input.Length; i++) - { - if (!verticeMap.ContainsKey(input[i])) - verticeMap[input[i]] = verticeMap.Count; - } - - for (int i = 0; i < input.Length; i += 3) - { - int i1 = i + 0; - int i2 = i + 1; - int i3 = i + 2; - Vector3 v1 = input[i1]; - Vector3 v2 = input[i2]; - Vector3 v3 = input[i3]; - - if (verticeMap.ContainsKey(v1)) - i1 = verticeMap[v1]; - else - verticeMap.Add(v1, i1); - - if (verticeMap.ContainsKey(v2)) - i2 = verticeMap[v2]; - else - verticeMap.Add(v2, i2); - - if (verticeMap.ContainsKey(v3)) - i3 = verticeMap[v3]; - else - verticeMap.Add(v3, i3); - - triangles.Add(new Triangle() - { - v = new Int3(i1, i2, i3), - }); - } - - foreach (KeyValuePair kvp in verticeMap) - { - vertices.Add(new Vertex() - { - p = kvp.Key, - q = new SymetricMatrix(), - }); - } - - - /*foreach (var vec in input) - { - vertices.Add(new Vertex() - { - p = vec, - q = new SymetricMatrix(), - }); - }*/ - } - return Simplify(); - } - - public List Simplify(Vector3[] verts, int[] indices) - { - triangles = new List(indices.Length / 3); - vertices = new List(verts.Length); - - { - foreach (var vec in verts) - { - vertices.Add(new Vertex() - { - p = vec, - q = new SymetricMatrix(), - }); - } - - for (int i = 0; i < indices.Length; i += 3) - { - triangles.Add(new Triangle() - { - v = new Int3(indices[i]-1, indices[i+1]-1, indices[i+2]-1), - }); - } - } - return Simplify(); - } - - private List Simplify() - { - - // main iteration loop - int deleted_triangles=0; - List deleted0 = new List(); - List deleted1 = new List(); - int triangle_start_count = triangles.Count; - - int target_count = (int)(ratio * (float)triangle_start_count); - - //int iteration = 0; - //loop(iteration,0,100) - int iteration; - for (iteration = 0; iteration < 9999; iteration++) - { - if (ratio < 1.0f && triangle_start_count-deleted_triangles<=target_count) - break; - - if (ratio >= 1.0f || iteration % 5 == 0) - update_mesh(iteration); - // clear dirty flag - for (int i = 0; i < triangles.Count; i++) - triangles[i].dirty=false; - // - // All triangles with edges below the threshold will be removed - // - // The following numbers works well for most models. - // If it does not, try to adjust the 3 parameters - // - //double threshold = 0.001; //1.0E-3 EPS; - double threshold = 1.0E-3;//1.0E-9; - if (ratio < 1.0f) - threshold = 0.000000001 * Math.Pow((double)(iteration+3),agressiveness); - //if (verbose) { - // printf("lossless iteration %d\n", iteration); - //} - - // remove vertices & mark deleted triangles - for (int i = 0; i < triangles.Count; i++) - { - Triangle t = triangles[i]; - if (t.err[3] > threshold) - { - t = t; - continue; - } - - if(t.deleted) - continue; - if(t.dirty) - continue; - - for (int j = 0; j < 3; j++) - { - if (t.err[j] > threshold) - continue; - - int i0=t.v[ j ]; - Vertex v0 = vertices[i0]; - int i1=t.v[(j+1)%3]; - Vertex v1 = vertices[i1]; - - // Border check - if(v0.border != v1.border) - continue; - - // Compute vertex to collapse to - Vector3 p = new Vector3(); - calculate_error(i0,i1,ref p); - - deleted0.Resize(v0.tcount); // normals temporarily - deleted1.Resize(v1.tcount); // normals temporarily - - // don't remove if flipped - if( flipped(ref p,i0,i1,ref v0,deleted0) ) - continue; - if( flipped(ref p,i1,i0,ref v1,deleted1) ) - continue; - - if ( (t.attr & TriangleAttributes.TEXCOORD) == TriangleAttributes.TEXCOORD ) - { - update_uvs(i0,ref v0,ref p,deleted0); - update_uvs(i0,ref v1,ref p,deleted1); - } - - // not flipped, so remove edge - v0.p=p; - v0.q=v1.q+v0.q; - int tstart=refs.Count; - - update_triangles(i0,ref v0,deleted0,ref deleted_triangles); - update_triangles(i0,ref v1,deleted1,ref deleted_triangles); - - int tcount=refs.Count-tstart; - - if(tcount<=v0.tcount) - { - // save ram - if (tcount != 0) - { - for (int m = 0; m < tcount; m++) - refs[v0.tstart] = refs[tstart]; - } - } - else - // append - v0.tstart=tstart; - - v0.tcount=tcount; - break; - } - if (ratio < 1.0f && triangle_start_count-deleted_triangles<=target_count) - break; - } - - if (ratio >= 1.0f) - { - if (deleted_triangles <= 0) - break; - deleted_triangles = 0; - } - } //for each iteration - // clean up mesh - compact_mesh(); - - if (triangles.Count == 0) - return null; - - List finalVerts = new List(); - foreach (var t in triangles) - { - finalVerts.Add(vertices[t.v[0]].p); - finalVerts.Add(vertices[t.v[1]].p); - finalVerts.Add(vertices[t.v[2]].p); - } - - return finalVerts; - } - - // Check if a triangle flips when this edge is removed - - private bool flipped(ref Vector3 p,int i0,int i1,ref Vertex v0, List deleted) - { - for (int k = 0; k < v0.tcount; k++) - { - Triangle t = triangles[refs[v0.tstart+k].tid]; - if(t.deleted) - continue; - - int s=refs[v0.tstart+k].tvertex; - int id1=t.v[(s+1)%3]; - int id2=t.v[(s+2)%3]; - - if(id1==i1 || id2==i1) // delete ? - { - deleted[k]=true; - continue; - } - Vector3 d1 = vertices[id1].p-p; d1.Normalize(); - Vector3 d2 = vertices[id2].p-p; d2.Normalize(); - if(Mathf.Abs(Vector3.Dot(d1, d2))>0.999) return true; - Vector3 n = Vector3.Cross(d1, d2); - n.Normalize(); - deleted[k]=false; - if(Vector3.Dot(n, t.n)<0.2) return true; - } - return false; - } - - // update_uvs - - private void update_uvs(int i0, ref Vertex v, ref Vector3 p, List deleted) - { - for (int k = 0; k < v.tcount; k++) - { - Ref r=refs[v.tstart+k]; - Triangle t=triangles[r.tid]; - if(t.deleted)continue; - if(deleted[k])continue; - Vector3 p1=vertices[t.v[0]].p; - Vector3 p2=vertices[t.v[1]].p; - Vector3 p3=vertices[t.v[2]].p; - //t.uvs[r.tvertex] = interpolate(p,p1,p2,p3,t.uvs); - } - } - - // Update triangle connections and edge error after a edge is collapsed - - private void update_triangles(int i0,ref Vertex v,List deleted,ref int deleted_triangles) - { - Vector3 p = new Vector3(); - for (int k = 0; k < v.tcount; k++) - { - Ref r=refs[v.tstart+k]; - Triangle t=triangles[r.tid]; - if(t.deleted)continue; - if(deleted[k]) - { - t.deleted=true; - deleted_triangles++; - continue; - } - t.v[r.tvertex]=i0; - t.dirty=true; - t.err[0]=calculate_error(t.v[0],t.v[1],ref p); - t.err[1]=calculate_error(t.v[1],t.v[2],ref p); - t.err[2]=calculate_error(t.v[2],t.v[0],ref p); - t.err[3]=Math.Min(t.err[0],Math.Min(t.err[1],t.err[2])); - triangles[r.tid] = t; - refs.Add(r); - } - } - - // compact triangles, compute edge error and build reference list - - private void update_mesh(int iteration) - { - if(iteration>0) // compact triangles - { - int dst=0; - for (int i = 0; i < triangles.Count; i++) - if(!triangles[i].deleted) - { - triangles[dst++]=triangles[i]; - } - triangles.Resize(dst); - } - // - // Init Quadrics by Plane & Edge Errors - // - // required at the beginning ( iteration == 0 ) - // recomputing during the simplification is not required, - // but mostly improves the result for closed meshes - // - if( iteration == 0 ) - { - //for (int i = 0; i < vertices.Count; i++) - // vertices[i].q=new SymetricMatrix();//vertices[i].q=Matrix(0.0); - - for (int i = 0; i < triangles.Count; i++) - { - Triangle t=triangles[i]; - - Vector3[] p = new Vector3[3]; - for (int j = 0; j<3; j++) - p[j]=vertices[t.v[j]].p; - - Vector3 n = Vector3.Cross(p[1]-p[0],p[2]-p[0]); - n.Normalize(); - t.n=n; - for (int j = 0; j<3; j++) - vertices[t.v[j]].q = vertices[t.v[j]].q + new SymetricMatrix(n.X,n.Y,n.Z,Vector3.Dot(-n, p[0])); - } - for (int i = 0; i < triangles.Count; i++) - { - // Calc Edge Error - Triangle t=triangles[i]; - Vector3 p = new Vector3(); - for (int j = 0; j<3; j++) t.err[j]=calculate_error(t.v[j],t.v[(j+1)%3], ref p); - t.err[3]=Math.Min(t.err[0],Math.Min(t.err[1],t.err[2])); - } - } - - // Init Reference ID list - for (int i = 0; i < vertices.Count; i++) - { - vertices[i].tstart=0; - vertices[i].tcount=0; - } - for (int i = 0; i < triangles.Count; i++) - { - Triangle t=triangles[i]; - for (int j = 0; j<3; j++) - vertices[t.v[j]].tcount++; - } - int tstart=0; - for (int i = 0; i < vertices.Count; i++) - { - Vertex v=vertices[i]; - v.tstart=tstart; - tstart+=v.tcount; - v.tcount=0; - } - - // Write References - refs.Resize(triangles.Count*3); - for (int i = 0; i < triangles.Count; i++) - { - Triangle t=triangles[i]; - for (int j = 0; j<3; j++) - { - Vertex v=vertices[t.v[j]]; - refs[v.tstart+v.tcount].tid=i; - refs[v.tstart+v.tcount].tvertex=j; - v.tcount++; - } - } - - // Identify boundary : vertices[].border=0,1 - if( iteration == 0 ) - { - List vcount = new List(); - List vids = new List(); - - for (int i = 0; i < vertices.Count; i++) - vertices[i].border=false; - - for (int i = 0; i < vertices.Count; i++) - { - Vertex v=vertices[i]; - vcount.Clear(); - vids.Clear(); - for (int j = 0; j < v.tcount; j++) - { - int kk=refs[v.tstart+j].tid; - Triangle t=triangles[kk]; - for (int k = 0; k<3; k++) - { - int ofs=0,id=t.v[k]; - while(ofs try to find best result - Vector3 p1=vertices[id_v1].p; - Vector3 p2=vertices[id_v2].p; - Vector3 p3=(p1+p2)*0.5f; - double error1 = vertex_error(ref q, p1.X,p1.Y,p1.Z); - double error2 = vertex_error(ref q, p2.X,p2.Y,p2.Z); - double error3 = vertex_error(ref q, p3.X,p3.Y,p3.Z); - error = Math.Min(error1, Math.Min(error2, error3)); - if (error1 == error) p_result=p1; - if (error2 == error) p_result=p2; - if (error3 == error) p_result=p3; - } - return (float)error; - } - } -} \ No newline at end of file diff --git a/Source/Game/Q3MapImporter.cs b/Source/Game/Q3MapImporter.cs index 1c8cc0e..371706a 100644 --- a/Source/Game/Q3MapImporter.cs +++ b/Source/Game/Q3MapImporter.cs @@ -4,15 +4,9 @@ using System.Diagnostics; using FlaxEngine; using System.IO; using System.Linq; -using System.Runtime.CompilerServices; -using System.Threading; using FlaxEngine.Assertions; -using FlaxEngine.Utilities; using Console = Cabrito.Console; -// TODO: remove coplanar/degenerate faces from the final mesh -// It seems the original algorithm is working but removing degenerate faces does not work - namespace Game { public class BrushGeometry @@ -26,7 +20,6 @@ namespace Game public MaterialBase brushMaterial = null; // FIXME: brush can have multiple textures } - public class Q3MapImporter : Script { //private string mapPath = @"C:\dev\GoakeFlax\Assets\Maps\cube_q1.map"; @@ -40,13 +33,6 @@ namespace Game Model model; public MaterialBase material; - const float epsilon = 0.01f; - - - - - - static void QuickHull(Vector3[] points, out Vector3[] outVertices) { var verts = new List(); @@ -66,81 +52,6 @@ namespace Game outVertices = finalPoints.ToArray(); } - private Color[] planeColors = new Color[] - { - Color.Red, - Color.Orange, - Color.Yellow, - Color.Green, - Color.Cyan, - Color.Blue, - Color.Purple, - Color.Magenta, - }; - - private int skipPlanes = 0; - private int takePlanes = 5; - - private List debugPoints = new List(); - - private List> debugNormals = new List>(); - - public override void OnDebugDraw() - { - foreach (var cn in debugNormals) - { - DebugDraw.DrawLine(cn.Item1, cn.Item1 + cn.Item2 * 50f, Color.Red, 0f, false); - } - return; - if (root == null) - return; - - //foreach (var p in debugPoints) - // DebugDraw.DrawSphere(new BoundingSphere(p, 30f), Color.LightBlue, 0f, false); - - foreach (var brush in root.entities[0].brushes.Skip(1).Take(1)) - { - int planeI = skipPlanes; - foreach (var plane in brush.planes.Take(takePlanes)) - //foreach (var plane in brush.planes) - { - Plane p = new Plane(plane.v1, plane.v2, plane.v3); - Vector3 planeNormal = -p.Normal; - - const float w = 300f; - - Vector3 p1 = new Vector3(-w, -w, 0f); - Vector3 p2 = new Vector3(w, -w, 0f); - Vector3 p3 = new Vector3(-w, w, 0f); - Vector3 p4 = new Vector3(w, w, 0f); - - Vector3 uu = Vector3.Up; - if (Mathf.Abs(Vector3.Dot(planeNormal, uu)) > 0.9999f) - uu = Vector3.Forward; - - var q = Quaternion.LookAt(Vector3.Zero, planeNormal, -uu); - - p1 = p1 * q; - p2 = p2 * q; - p3 = p3 * q; - p4 = p4 * q; - - p1 += p.D * planeNormal; - p2 += p.D * planeNormal; - p3 += p.D * planeNormal; - p4 += p.D * planeNormal; - - var color = planeColors[planeI%planeColors.Length] * 0.5f; - DebugDraw.DrawTriangle(p1, p2, p3, color); - DebugDraw.DrawTriangle(p2, p3, p4, color); - - - - planeI++; - } - } - } - private MapEntity root; private static IEnumerable> DifferentCombinations(IEnumerable elements, int k) @@ -246,513 +157,6 @@ namespace Game vertices = new Vector3[0]; } - static public void TriangulateBrush2(MapBrush brush, out Vector3[] vertices) - { - const float cs = 3000f; - - Vector3[] cubePoints = new[] - { - new Vector3(-cs, -cs, -cs), - new Vector3(cs, -cs, -cs), - new Vector3(-cs, cs, -cs), - new Vector3(cs, cs, -cs), - new Vector3(-cs, -cs, cs), - new Vector3(cs, -cs, cs), - new Vector3(-cs, cs, cs), - new Vector3(cs, cs, cs), - }; - Vector3[] cubeVerts; - QuickHull(cubePoints, out cubeVerts); - List brushVertices = new List(cubeVerts); - - foreach (var brushPlane in brush.planes) - { - Plane plane = brushPlane.plane; - List faceVertices = new List(); - List clippedVertices = new List(); - - Func isFront = (f) => f > epsilon; - Func isBack = (f) => f < epsilon; - - for (int i = 0; i < brushVertices.Count; i++) - { - int i2 = ((i + 1) % 3 == 0) ? (i - 2) : (i + 1); - Vector3 start = brushVertices[i]; - Vector3 end = brushVertices[i2]; - - var d1 = Plane.DotCoordinate(plane, start); - var d2 = Plane.DotCoordinate(plane, end); - - if (isBack(d1)) - { - // include the point behind the clipping plane - faceVertices.Add(start); - } - - if (isBack(d1) && isFront(d2) || isFront(d1) && isBack(d2)) - { - // the cutting plane clips the edge - //if (isFront(d2)) - { - Ray ray = new Ray(start, (end - start).Normalized); - Ray ray2 = new Ray(end, (start - end).Normalized); - if (plane.Intersects(ref ray, out Vector3 point) || plane.Intersects(ref ray2, out point)) - { - - //faceVertices.Add(point); - //clippedVertices.Add(point); - - /* - intersect - start __._ (end) - | |/ - | / - |/ - next - */ - if (isBack(d1) && isFront(d2)) - { - // finish the current triangle and start the next one - // [start, intersect, next], [intersect, ...] - - faceVertices.Add(point); - - if ((faceVertices.Count % 3) == 2) - { - int i3 = ((i2 + 1) % 3 == 0) ? (i2 - 2) : (i2 + 1); - Vector3 next = brushVertices[i3]; - faceVertices.Add(next); - } - else - ray = ray; - - faceVertices.Add(point); - } - - /* - - ____ (start) - | |/ - | * intersect2 - |/ - end - */ - else if (isFront(d1) && isBack(d2)) - { - // continue where we left off - // [intersect, intersect2, ...] - - faceVertices.Add(point); - - if ((i % 3) == 2) - { - int i3 = ((i2 + 1) % 3 == 0) ? (i2 - 2) : (i2 + 1); - Vector3 next = brushVertices[i3]; - faceVertices.Add(next); - } - else - ray = ray; - } - else - ray = ray; - } - else - d1 = d1; - } - } - } - - brushVertices.Clear(); - brushVertices.AddRange(faceVertices); - - Assert.IsTrue(faceVertices.Count % 3 == 0); - - /*var newMeshPoints = new List(); - int duplis = 0; - foreach (var v in faceVertices) - { - bool found = false; - foreach (var vo in newMeshPoints) - { - if ((v - vo).Length < epsilon) - { - found = true; - duplis++; - break; - } - } - - //if (!newMeshPoints.Contains(v)) - if (!found) - newMeshPoints.Add(v); - } - if (duplis > 0) - Console.Print("duplicates: " + duplis); - - if (newMeshPoints.Count > 0) - { - var tempPoints = newMeshPoints; - newMeshPoints = new List(tempPoints.Count); - foreach (var tp in tempPoints) - { - // Flip Y and Z - newMeshPoints.Add(new Vector3(tp.X, tp.Z, tp.Y)); - } - - var hullPoints = QuickHull(newMeshPoints.ToArray()); - var ms = new MeshSimplifier(); - var optimizedVerts = ms.Simplify(hullPoints); - brushVertices.Clear(); - brushVertices.AddRange(hullPoints); - } - else - brushVertices.Clear(); - */ - - } - - vertices = brushVertices.ToArray(); - } - - static public void TriangulateBrush3(MapBrush brush, out Vector3[] vertices) - { - float cs = 4000f; - - float maxD = 0f; - float minD = 0f; - foreach (var brushPlane in brush.planes) - { - var p = brushPlane.plane; - minD = Mathf.Min(p.D); - maxD = Mathf.Max(p.D); - } - - //cs = maxD*2; - - - Vector3[] cubePoints = new[] - { - new Vector3(-1, -1, -1) * cs, - new Vector3(1, -1, -1) * cs, - new Vector3(-1, 1, -1) * cs, - new Vector3(1, 1, -1) * cs, - new Vector3(-1, -1, 1) * cs, - new Vector3(1, -1, 1) * cs, - new Vector3(-1, 1, 1) * cs, - new Vector3(1, 1, 1) * cs, - }; - Vector3[] cubeVerts; - QuickHull(cubePoints, out cubeVerts); - List brushVertices = new List(cubeVerts); - - //foreach (var brushPlane in brush.planes.Skip(skipPlanes).Take(takePlanes)) - foreach (var brushPlane in brush.planes) - { - Plane plane = brushPlane.plane; - - List faceVertices = new List(); - List clippedVertices = new List(); - - Func isFront = (f) => f > epsilon; - Func isBack = (f) => f < epsilon; - - List> planeEdges = new List>(); - var faceEdges = new List>(); - - void ProcessEdges() - { - if (planeEdges.Count > 0) - { - // heal discontinued edges - for (int j = 0; j < planeEdges.Count; j++) - { - var edgePrev = planeEdges[j]; - var edgeNext = planeEdges[(j + 1) % planeEdges.Count]; - - //if (edgePrev.Item2 != edgeNext.Item1) - if ((edgePrev.Item2 - edgeNext.Item1).Length > 0.0001f) - { - var newEdge = new Tuple(edgePrev.Item2, edgeNext.Item1); - planeEdges.Insert(j + 1, newEdge); - j--; - } - } - - // triangulate edges - /*for (int j = 0; j < edges.Count - 1; j++) - { - var edgePrev = edges[j]; - var edgeNext = edges[(j + 1) % edges.Count]; - - Vector3 v0 = edges[0].Item1; - Vector3 v1 = edgePrev.Item2; - Vector3 v2 = edgeNext.Item2; - - faceVertices.Add(v0); - faceVertices.Add(v1); - faceVertices.Add(v2); - }*/ - - // triangulate clipped face - /*for (int j = 0; j < clippedVertices.Count-1; j++) - { - Vector3 v0 = clippedVertices[0]; - Vector3 v1 = edgePrev.Item2; - Vector3 v2 = edgeNext.Item2; - }*/ - // TODO: maybe optimize the triangles here instead of using QuickHull - } - else - plane = plane; - - - faceEdges.AddRange(planeEdges); - planeEdges = new List>(); - //edges.Clear(); - } - - for (int i = 0; i < brushVertices.Count; i++) - { - if (i > 0 && i % 3 == 0) - ProcessEdges(); - - int i2 = ((i + 1) % 3 == 0) ? (i - 2) : (i + 1); - Vector3 start = brushVertices[i]; - Vector3 end = brushVertices[i2]; - - var d1 = Plane.DotCoordinate(plane, start); - var d2 = Plane.DotCoordinate(plane, end); - - Vector3 edgeStart = start; - Vector3 edgeEnd = end; - - - if (isBack(d1)) - { - edgeStart = start; - } - - if (isBack(d1) && isFront(d2) || isFront(d1) && isBack(d2)) - { - Ray ray = new Ray(start, (end - start).Normalized); - Ray ray2 = new Ray(end, (start - end).Normalized); - if (plane.Intersects(ref ray, out Vector3 point) || plane.Intersects(ref ray2, out point)) - { - edgeEnd = point; - clippedVertices.Add(point); - - if (isFront(d1)) - { - edgeStart = edgeEnd; - edgeEnd = end; - } - } - } - - if (isFront(d1) && isFront(d2)) - continue; - - var abs = Mathf.Abs((edgeEnd-edgeStart).Length); - if (abs < 0.000001f) - { - abs = abs; - //continue; - } - Tuple edge = new Tuple(edgeStart, edgeEnd); - planeEdges.Add(edge); - } - ProcessEdges(); - - if (true) - { - // triangulate edges - - faceVertices.Clear(); - //foreach (var edges in faceEdges) - { - // merge same points in edges - for (int j = 0; j < faceEdges.Count; j++) - { - Vector3 v0 = faceEdges[j].Item1; - Vector3 v1 = faceEdges[j].Item2; - - var edgeNext = faceEdges[(j + 1) % faceEdges.Count]; - Vector3 v2 = edgeNext.Item1; - Vector3 v3 = edgeNext.Item2; - - var dot = Vector3.Dot(v1.Normalized, v2.Normalized); - if (v1 != v2 && dot > 0.9999999f) - { - v1 = v1; - //faceEdges[(j + 1) % faceEdges.Count] = new Tuple(v1, v3); - } - } - - List> newEdges = new List>(); - for (int j = 0; j < faceEdges.Count; j++) - { - Vector3 v0 = faceEdges[j].Item1; - Vector3 v1 = faceEdges[j].Item2; - - var abs = Mathf.Abs((v1-v0).Length); - if (abs < 0.000001f) - { - v1 = v1; - //continue; - } - - Tuple newEdge = new Tuple(v0, v1); - while (true) - { - var edgeNext = faceEdges[(j + 1) % faceEdges.Count]; - Vector3 v2 = edgeNext.Item1; - Vector3 v3 = edgeNext.Item2; - - //var dot = Vector3.Dot((v3 - v0).Normalized, (v1 - v0).Normalized); - /*var dot = Vector3.Dot((v3 - v2).Normalized, (v1 - v0).Normalized); - if (dot > 0.9f) - { - newEdge = new Tuple(v0, v3); - j++; - } - else*/ - break; - - /*var dot = Vector3.Dot((v3 - v2).Normalized, (v1 - v0).Normalized); - if (dot > 0.9f) - { - newEdge = new Tuple(v0, v3); - j++; - } - else - break;*/ - } - - newEdges.Add(newEdge); - } - - for (int j = 0; j < newEdges.Count - 1; j++) - { - var edgePrev = newEdges[j]; - var edgeNext = newEdges[(j + 1) % newEdges.Count]; - - Vector3 v0 = newEdges[0].Item1; - Vector3 v1 = edgePrev.Item2; - Vector3 v2 = edgeNext.Item2; - - faceVertices.Add(v0); - faceVertices.Add(v1); - faceVertices.Add(v2); - } - } - - } - - List uniqPoints = new List(); - foreach (var v in faceVertices) - { - bool found = false; - foreach (var v2 in uniqPoints) - { - if ((v - v2).Length < 0.01f) - { - found = true; - break; - } - } - - if (!found) - uniqPoints.Add(v); - //uniqPoints.Add(new Vector3((float)Math.Round(v.X, 3), (float)Math.Round(v.Y, 3), (float)Math.Round(v.Z, 3))); - } - - //debugPoints = new List(uniqPoints); - - - Vector3[] hullPoints; - QuickHull(uniqPoints.ToArray(), out hullPoints); - var hullVerts = new MeshSimplifier().Simplify(hullPoints); - - if (false) - { - // create edges from clipped points - var clippedEdges = new List>(); - - //foreach (var e in edges) - // newEdges.Add(new Tuple(e.Item1, e.Item2)); - - for (int i = 0; i < clippedVertices.Count; i++) - { - int i2 = (i + 1) % clippedVertices.Count; - Vector3 start = clippedVertices[i]; - Vector3 end = clippedVertices[i2]; - - while (i < clippedVertices.Count) - { - int i3 = (i + 2) % clippedVertices.Count; - Vector3 end2 = clippedVertices[i3]; - - var edgeDirection = (end - start).Normalized; - var edgeDirection2 = (end2 - start).Normalized; - - if ((edgeDirection2 - edgeDirection).Length < 0.0001f) - { - end = end2; - i++; - } - else - break; - } - - clippedEdges.Add(new Tuple(start, end)); - } - - // triangulate edges - for (int j = 0; j < clippedEdges.Count; j++) - { - var edgePrev = clippedEdges[j]; - var edgeNext = clippedEdges[(j + 1) % clippedEdges.Count]; - - Vector3 v0 = clippedEdges[0].Item1; - Vector3 v1 = edgePrev.Item2; - Vector3 v2 = edgeNext.Item2; - - faceVertices.Add(v0); - faceVertices.Add(v1); - faceVertices.Add(v2); - } - } - - if (true) - { - - uniqPoints = uniqPoints; - hullVerts = hullVerts; - hullPoints = hullPoints; - faceVertices = faceVertices; - - var optimizedVerts = hullVerts;//new MeshSimplifier().Simplify(faceVertices.ToArray()); - - brushVertices.Clear(); - brushVertices.AddRange(optimizedVerts); - } - else - { - //debugPoints = new List(faceVertices); - - //var hullPoints = faceVertices; - - var ms = new MeshSimplifier(); - var optimizedVerts = hullPoints; //ms.Simplify(hullPoints); - - brushVertices.Clear(); - brushVertices.AddRange(optimizedVerts); - } - } - - vertices = brushVertices.ToArray(); - } - public override void OnStart() { byte[] mapChars = File.ReadAllBytes(mapPath); @@ -766,7 +170,6 @@ namespace Game bool oneMesh = false; bool convexMesh = true; - if (!oneMesh) { Dictionary materials = null; @@ -775,7 +178,6 @@ namespace Game List brushGeometries = new List(root.entities[0].brushes.Count); - // pass 1: triangulation sw.Restart(); int brushIndex = 0; @@ -947,40 +349,7 @@ namespace Game geom.model.SetupLODs(new int[] { 1 }); geom.model.LODs[0].Meshes[0].UpdateMesh(geom.vertices, geom.indices, geom.normals, null, geom.uvs); - - /* - StaticModel childModel = Actor.AddChild(); - childModel.Name = "Brush_" + brushIndex; - childModel.Model = geom.model; - childModel.SetMaterial(0, geom.brushMaterial); - childModel.Parent = mapRootActor; - - CollisionData collisionData = Content.CreateVirtualAsset(); - if (collisionData.CookCollision(convexMesh ? CollisionDataType.ConvexMesh : CollisionDataType.TriangleMesh, geom.vertices.ToArray(), - geom.indices.ToArray())) - { - bool failed = true; - if (convexMesh) - { - // fallback to triangle mesh - failed = collisionData.CookCollision(CollisionDataType.TriangleMesh, - geom.vertices.ToArray(), - geom.indices.ToArray()); - if (!failed) - Console.PrintWarning("Hull brush " + brushIndex.ToString() + " is not convex"); - } - if (failed) - throw new Exception("failed to cook final collision"); - } - - var meshCollider = childModel.AddChild(); - meshCollider.CollisionData = collisionData; - */ } - - //brushGeometries.Add(geom); - - } sw.Stop(); Console.Print("Pass 2: texturing: " + sw.Elapsed.TotalMilliseconds + "ms"); @@ -1032,7 +401,7 @@ namespace Game { try { - TriangulateBrush3(brush, out Vector3[] brushVertices); + TriangulateBrush(brush, out Vector3[] brushVertices); Vector2[] brushUvs = new Vector2[brushVertices.Length]; Vector3[] brushNormals = new Vector3[brushVertices.Length]; @@ -1159,20 +528,6 @@ namespace Game } } - public override void OnEnable() - { - // Here you can add code that needs to be called when script is enabled (eg. register for events) - } - - public override void OnDisable() - { - // Here you can add code that needs to be called when script is disabled (eg. unregister from events) - } - - public override void OnUpdate() - { - } - public override void OnDestroy() { Destroy(ref model); diff --git a/Source/Game/QBrush.cs b/Source/Game/QBrush.cs deleted file mode 100644 index 17f9750..0000000 --- a/Source/Game/QBrush.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Collections.Generic; -using FlaxEngine; - -namespace Game -{ - [ExecuteInEditMode] - public class QBrush : Script - { - Model model; - - public MaterialBase material; - - public override void OnAwake() - { - model = Content.CreateVirtualAsset(); - model.SetupLODs(new int[] {1}); - - { - var mesh = model.LODs[0].Meshes[0]; - - const float X = 0.525731112119133606f * 100f; - const float Z = 0.850650808352039932f * 100f; - const float N = 0.0f; - var vertices = new[] - { - new Vector3(-X, N, Z), - new Vector3(X, N, Z), - new Vector3(-X, N, -Z), - new Vector3(X, N, -Z), - new Vector3(N, Z, X), - new Vector3(N, Z, -X), - new Vector3(N, -Z, X), - new Vector3(N, -Z, -X), - new Vector3(Z, X, N), - new Vector3(-Z, X, N), - new Vector3(Z, -X, N), - new Vector3(-Z, -X, N) - }; - var triangles = new[] - { - 1, 4, 0, 4, 9, 0, 4, 5, 9, 8, 5, 4, - 1, 8, 4, 1, 10, 8, 10, 3, 8, 8, 3, 5, - 3, 2, 5, 3, 7, 2, 3, 10, 7, 10, 6, 7, - 6, 11, 7, 6, 0, 11, 6, 1, 0, 10, 1, 6, - 11, 0, 9, 2, 11, 9, 5, 2, 9, 11, 2, 7 - }; - mesh.UpdateMesh(vertices, triangles, vertices); - } - - StaticModel childModel = Actor.GetOrAddChild(); - childModel.Model = model; - childModel.SetMaterial(0, material); - } - - public override void OnDestroy() - { - Destroy(ref model); - } - } -} \ No newline at end of file diff --git a/Tests/MapParser/MapParserTests.cs b/Tests/MapParser/MapParserTests.cs index 265a2a7..ca42bab 100644 --- a/Tests/MapParser/MapParserTests.cs +++ b/Tests/MapParser/MapParserTests.cs @@ -19,7 +19,6 @@ namespace GoakeTests.MapParser [SetUp] public void Setup() { - dm4Bytes = File.ReadAllBytes(@"C:\dev\GoakeFlax\Assets\Maps\dm4.map"); aerowalkBytes = File.ReadAllBytes(@"C:\dev\Goake\maps\aerowalk\aerowalk.map"); @@ -99,33 +98,6 @@ namespace GoakeTests.MapParser // warmup? //var roott = Game.MapParser.Parse(aerowalkBytes); - List mapEntities = new List(100); - aerowalkRoot = Game.MapParser.Parse(aerowalkBytes); - - Stopwatch sw = Stopwatch.StartNew(); - - for (int i = 0; i < 1; i++) - { - foreach (var ent in aerowalkRoot.entities) - foreach (var brush in ent.brushes) - { - Q3MapImporter.TriangulateBrush3(brush, out Vector3[] verts); - Assert.IsTrue(verts.Length > 0); - } - } - - sw.Stop(); - - var elapsedMs = sw.Elapsed.TotalMilliseconds; - TestContext.Out.WriteLine("Triangulation time: " + elapsedMs + "ms"); - } - - [Test] - public void Perf_TriangulateAerowalk2() - { - // warmup? - //var roott = Game.MapParser.Parse(aerowalkBytes); - List mapEntities = new List(100); aerowalkRoot = Game.MapParser.Parse(aerowalkBytes); /*for (int i = 0; i < 1; i++) @@ -172,7 +144,7 @@ namespace GoakeTests.MapParser foreach (var ent in root.entities) foreach (var brush in ent.brushes) { - Q3MapImporter.TriangulateBrush3(brush, out Vector3[] verts); + Q3MapImporter.TriangulateBrush(brush, out Vector3[] verts); Assert.IsTrue(verts.Length > 0); } }