/** * \brief Triangulates userPoints and sets mesh data. * @param m Mesh to be used for graphics. * @param c Mesh to be used for collisions. * @param convexity The #PolygonType. Necessary for producing the correct face orientation. */ public static bool MeshWithPoints(List <Vector2> _points, DrawSettings drawSettings, out Mesh m, out Mesh c, out Draw.PolygonType convexity) { // Assumes local space. Returns graphics mesh in the following submesh order: // 0 - Front face / back face (optional) // 1 - Sides (optional) List <Vector2> points = new List <Vector2>(_points); m = new Mesh(); c = new Mesh(); m.name = "Graphics"; c.name = "Collisions"; convexity = Convexity(points); if (convexity == Draw.PolygonType.ConcaveClockwise || convexity == Draw.PolygonType.ConvexClockwise) { points.Reverse(); } // Run a self-intersect test if (SelfIntersectTest(points)) { #if DEBUG Debug.LogWarning("Polydraw: Mesh generation failed on self-intersect test."); #endif return(false); } float zOrigin = 0f; float collisionOrigin = 0f; float halfSideLength = drawSettings.sideLength / 2f; float colHalfSideLength = drawSettings.colDepth / 2f; if (drawSettings.axis != Axis.Forward) { halfSideLength = -halfSideLength; colHalfSideLength = -colHalfSideLength; } switch (drawSettings.anchor) { case Draw.Anchor.Front: zOrigin = drawSettings.zPosition + drawSettings.faceOffset + halfSideLength; break; case Draw.Anchor.Back: zOrigin = drawSettings.zPosition + drawSettings.faceOffset - halfSideLength; break; case Draw.Anchor.Center: default: zOrigin = drawSettings.zPosition + drawSettings.faceOffset; break; } switch (drawSettings.colAnchor) { case Draw.Anchor.Front: collisionOrigin = drawSettings.zPosition + drawSettings.faceOffset + colHalfSideLength; break; case Draw.Anchor.Back: collisionOrigin = drawSettings.zPosition + drawSettings.faceOffset - colHalfSideLength; break; case Draw.Anchor.Center: default: collisionOrigin = drawSettings.zPosition + drawSettings.faceOffset; break; } /*** Generate Front Face ***/ Triangulator tr = new Triangulator(points); int[] front_indices = tr.Triangulate(); // Create the Vector3 vertices List <Vector3> front_vertices = points.ToVector3(drawSettings.axis, zOrigin - halfSideLength); Vector2 avg = Vector3.zero; for (int i = 0; i < points.Count; i++) { avg += points[i]; } avg /= (float)points.Count; avg -= drawSettings.uvOffset; List <Vector2> front_uv = new List <Vector2>(points.ToArray()); for (int i = 0; i < points.Count; i++) { front_uv[i] -= drawSettings.uvOffset; front_uv[i] = front_uv[i].RotateAroundPoint(avg, drawSettings.uvRotation); front_uv[i] = Vector2.Scale(front_uv[i], drawSettings.uvScale); } /*** Finish Front Face ***/ /*** Generate Sides ***/ // For use with graphics mesh List <Vector3> side_vertices = new List <Vector3>(); // For use with collision mesh List <Vector3> collison_vertices = new List <Vector3>(); for (int i = 0; i < points.Count; i++) { int next = i >= points.Count - 1 ? 0 : i + 1; Vector2 cur = points[i]; Vector2 nex = points[next]; side_vertices.Add(cur.ToVector3(drawSettings.axis, zOrigin + halfSideLength)); side_vertices.Add(cur.ToVector3(drawSettings.axis, zOrigin - halfSideLength)); side_vertices.Add(nex.ToVector3(drawSettings.axis, zOrigin + halfSideLength)); side_vertices.Add(nex.ToVector3(drawSettings.axis, zOrigin - halfSideLength)); collison_vertices.Add(cur.ToVector3(drawSettings.axis, collisionOrigin + colHalfSideLength)); collison_vertices.Add(cur.ToVector3(drawSettings.axis, collisionOrigin - colHalfSideLength)); collison_vertices.Add(nex.ToVector3(drawSettings.axis, collisionOrigin + colHalfSideLength)); collison_vertices.Add(nex.ToVector3(drawSettings.axis, collisionOrigin - colHalfSideLength)); } collison_vertices.Add(points[0].ToVector3(drawSettings.axis, collisionOrigin + colHalfSideLength)); collison_vertices.Add(points[0].ToVector3(drawSettings.axis, collisionOrigin - colHalfSideLength)); // +6 connects it to the first 2 verts int[] side_indices = new int[(points.Count * 6)]; int windingOrder = 1; // assume counter-clockwise, cause y'know, we set it that way int v = 0; for (int i = 0; i < side_indices.Length; i += 6) { // 0 is for clockwise winding order, anything else is CC if (i % 2 != windingOrder) { side_indices[i + 0] = v; side_indices[i + 1] = v + 1; side_indices[i + 2] = v + 2; side_indices[i + 3] = v + 1; side_indices[i + 4] = v + 3; side_indices[i + 5] = v + 2; } else { side_indices[i + 2] = v + 0; side_indices[i + 1] = v + 1; side_indices[i + 0] = v + 2; side_indices[i + 5] = v + 1; side_indices[i + 4] = v + 3; side_indices[i + 3] = v + 2; } v += 4; } /*** Finish Generating Sides ***/ Vector2[] side_uv = CalcSideUVs(side_vertices.ToVector2(drawSettings.axis), drawSettings); m.Clear(); List <Vector3> full_vertices = new List <Vector3>(drawSettings.generateSide ? front_vertices.Concat(side_vertices).ToArray() : front_vertices.ToArray()); if (drawSettings.generateBackFace) { List <Vector3> backVerts = points.ToVector3(drawSettings.axis, zOrigin + halfSideLength); full_vertices.AddRange(backVerts); } m.vertices = full_vertices.ToArray(); if (drawSettings.generateSide && drawSettings.generateBackFace) { m.subMeshCount = 2; int len = front_indices.Length, sideVertexCount = side_vertices.Count; int full = len * 2; int[] frontBack = new int[full]; System.Array.Copy(front_indices, frontBack, len); for (int i = 0; i < len; i++) { frontBack[(full - 1) - i] = front_indices[i] + sideVertexCount + front_vertices.Count; } m.SetTriangles(frontBack, 0); m.SetTriangles(ShiftTriangles(side_indices, front_vertices.Count), 1); } else if (drawSettings.generateSide || drawSettings.generateBackFace) { if (drawSettings.generateSide) { m.subMeshCount = 2; m.SetTriangles(front_indices, 0); m.SetTriangles(ShiftTriangles(side_indices, front_vertices.Count), 1); } else { m.subMeshCount = 1; int len = front_indices.Length; int full = len * 2; int[] frontBack = new int[full]; System.Array.Copy(front_indices, frontBack, len); for (int i = 0; i < len; i++) { frontBack[(full - 1) - i] = front_indices[i] + front_vertices.Count; } m.SetTriangles(frontBack, 0); } } else { m.triangles = front_indices; } List <Vector2> full_uvs = new List <Vector2>(drawSettings.generateSide ? front_uv.Concat(side_uv).ToArray() : front_uv.ToArray()); if (drawSettings.generateBackFace) { full_uvs.AddRange(front_uv); } m.uv = full_uvs.ToArray(); m.RecalculateNormals(); m.RecalculateBounds(); ; // Smooth edge normals if (drawSettings.generateSide) { int front = front_vertices.Count; Vector3[] nrm = m.normals; int len = side_vertices.Count; for (int i = 2; i < len; i += 4) //side_vertices.Count; i+=2) { int curr = front + i; int next = i >= len - 2 ? front : front + i + 2; float angle = Vector3.Angle(nrm[curr], nrm[next]); if (angle > drawSettings.smoothAngle) { continue; } Vector3 nrmAvg = ((nrm[curr] + nrm[next]) / 2f).normalized; nrm[curr] = nrmAvg; nrm[next] = nrmAvg; nrm[curr + 1] = nrmAvg; nrm[next + 1] = nrmAvg; } m.normals = nrm; } c.Clear(); c.vertices = collison_vertices.ToArray(); c.triangles = side_indices; c.uv = new Vector2[0];//side_uv.ToArray(); c.RecalculateNormals(); c.RecalculateBounds(); return(true); }
/** * \brief Triangulates userPoints and sets mesh data. * This method should not be called directly unless you absolutely need to. Use DrawPreviewMesh() or DrawFinalMesh() instead. * @param m Mesh to be used for graphics. * @param c Mesh to be used for collisions. * @param convexity The #PolygonType. Necessary for producing the correct face orientation. */ public static bool MeshWithPoints(List <Vector2> _points, DrawSettings drawSettings, out Mesh m, out Mesh c, out Draw.PolygonType convexity) { // Assumes local space. Returns graphics mesh in the following submesh order: // 0 - Front face // 1 - Sides (optional) // 2 - Back face (planned) List <Vector2> points = new List <Vector2>(_points); // Debug.Log(drawSettings.ToString()); m = new Mesh(); c = new Mesh(); m.name = "Graphics"; c.name = "Collisions"; convexity = Convexity(points); if (convexity == Draw.PolygonType.ConcaveClockwise || convexity == Draw.PolygonType.ConvexClockwise) { points.Reverse(); } // Run a self-intersect test if (SelfIntersectTest(points)) { #if DEBUG Debug.LogWarning("Polydraw: Mesh generation failed on self-intersect test."); #endif return(false); } float zOrigin = 0f; float collisionOrigin = 0f; float halfSideLength = drawSettings.sideLength / 2f; float colHalfSideLength = drawSettings.colDepth / 2f; switch (drawSettings.anchor) { case Draw.Anchor.Front: zOrigin = drawSettings.zPosition + drawSettings.faceOffset + halfSideLength; break; case Draw.Anchor.Back: zOrigin = drawSettings.zPosition + drawSettings.faceOffset - halfSideLength; break; case Draw.Anchor.Center: default: zOrigin = drawSettings.zPosition + drawSettings.faceOffset; break; } switch (drawSettings.colAnchor) { case Draw.Anchor.Front: collisionOrigin = drawSettings.zPosition + drawSettings.faceOffset + colHalfSideLength; break; case Draw.Anchor.Back: collisionOrigin = drawSettings.zPosition + drawSettings.faceOffset - colHalfSideLength; break; case Draw.Anchor.Center: default: collisionOrigin = drawSettings.zPosition + drawSettings.faceOffset; break; } /*** Generate Front Face ***/ Triangulator tr = new Triangulator(points); int[] front_indices = tr.Triangulate(); // Create the Vector3 vertices List <Vector3> front_vertices = VerticesWithPoints(points, zOrigin - halfSideLength); Vector2 avg = Vector3.zero; for (int i = 0; i < points.Count; i++) { avg += points[i]; } avg /= (float)points.Count; avg -= drawSettings.uvOffset; List <Vector2> front_uv = new List <Vector2>(points.ToArray()); for (int i = 0; i < points.Count; i++) { front_uv[i] -= drawSettings.uvOffset; front_uv[i] = front_uv[i].RotateAroundPoint(avg, drawSettings.uvRotation); front_uv[i] = Vector2.Scale(front_uv[i], drawSettings.uvScale); } /*** Finish Front Face ***/ /*** Generate Sides ***/ // For use with graphics mesh List <Vector3> side_vertices = new List <Vector3>(); // For use with collision mesh List <Vector3> collison_vertices = new List <Vector3>(); for (int i = 0; i < points.Count; i++) { int next = i >= points.Count - 1 ? 0 : i + 1; side_vertices.Add(new Vector3(points[i].x, points[i].y, zOrigin + halfSideLength)); side_vertices.Add(new Vector3(points[i].x, points[i].y, zOrigin - halfSideLength)); side_vertices.Add(new Vector3(points[next].x, points[next].y, zOrigin + halfSideLength)); side_vertices.Add(new Vector3(points[next].x, points[next].y, zOrigin - halfSideLength)); collison_vertices.Add(new Vector3(points[i].x, points[i].y, collisionOrigin + colHalfSideLength)); collison_vertices.Add(new Vector3(points[i].x, points[i].y, collisionOrigin - colHalfSideLength)); collison_vertices.Add(new Vector3(points[next].x, points[next].y, collisionOrigin + colHalfSideLength)); collison_vertices.Add(new Vector3(points[next].x, points[next].y, collisionOrigin - colHalfSideLength)); } collison_vertices.Add(new Vector3(points[0].x, points[0].y, collisionOrigin + colHalfSideLength)); collison_vertices.Add(new Vector3(points[0].x, points[0].y, collisionOrigin - colHalfSideLength)); // +6 connects it to the first 2 verts int[] side_indices = new int[(points.Count * 6)]; int windingOrder = 1; // assume counter-clockwise, cause y'know, we set it that way int v = 0; for (int i = 0; i < side_indices.Length; i += 6) { // 0 is for clockwise winding order, anything else is CC if (i % 2 != windingOrder) { side_indices[i + 0] = v; side_indices[i + 1] = v + 1; side_indices[i + 2] = v + 2; side_indices[i + 3] = v + 1; side_indices[i + 4] = v + 3; side_indices[i + 5] = v + 2; } else { side_indices[i + 2] = v + 0; side_indices[i + 1] = v + 1; side_indices[i + 0] = v + 2; side_indices[i + 5] = v + 1; side_indices[i + 4] = v + 3; side_indices[i + 3] = v + 2; } v += 4; } /*** Finish Generating Sides ***/ Vector2[] side_uv = CalcSideUVs(side_vertices, drawSettings); m.Clear(); m.vertices = drawSettings.generateSide ? front_vertices.Concat(side_vertices).ToArray() : front_vertices.ToArray(); if (drawSettings.generateSide) { m.subMeshCount = 2; m.SetTriangles(front_indices, 0); m.SetTriangles(ShiftTriangles(side_indices, front_vertices.Count), 1); } else { m.triangles = front_indices; } m.uv = drawSettings.generateSide ? front_uv.Concat(side_uv).ToArray() : front_uv.ToArray(); m.RecalculateNormals(); m.RecalculateBounds(); m.Optimize(); c.Clear(); c.vertices = collison_vertices.ToArray(); c.triangles = side_indices; c.uv = new Vector2[0];//side_uv.ToArray(); c.RecalculateNormals(); c.RecalculateBounds(); return(true); }