public static CSGMesh Combine(Vector3 offset, IDictionary<CSGNode, CSGMesh> brushMeshes) { var planeLookup = new Dictionary<Plane, short>(); var vertexLookup = new Dictionary<Vector3, short>(); var planes = new List<Plane>(); var polygons = new List<Polygon>(); var edges = new List<HalfEdge>(); var vertices = new List<Vector3>(); var bounds = new AABB(); bounds.Clear(); int edgeIndex = 0; int polygonIndex = 0; foreach (var item in brushMeshes) { var node = item.Key; var translation = Vector3.Subtract(node.Translation, offset); var mesh = item.Value; foreach (var edge in mesh.Edges) { short vertexIndex; var vertex = Vector3.Add(mesh.Vertices[edge.VertexIndex], translation); if (!vertexLookup.TryGetValue(vertex, out vertexIndex)) { vertexIndex = (short)vertices.Count; vertices.Add(vertex); vertexLookup.Add(vertex, vertexIndex); } var newEdge = new HalfEdge(); newEdge.VertexIndex = vertexIndex; newEdge.NextIndex = (short)(edge.NextIndex + edgeIndex); newEdge.TwinIndex = (short)(edge.TwinIndex + edgeIndex); newEdge.PolygonIndex = (short)(edge.PolygonIndex + polygonIndex); edges.Add(newEdge); } foreach (var polygon in mesh.Polygons) { if (polygon.FirstIndex == -1) continue; short planeIndex; var plane = mesh.Planes[polygon.PlaneIndex]; if (!planeLookup.TryGetValue(plane, out planeIndex)) { planeIndex = (short)planes.Count; planes.Add(plane); planeLookup.Add(plane, planeIndex); } var newPolygon = new Polygon(); newPolygon.PlaneIndex = planeIndex; newPolygon.FirstIndex = (short)(polygon.FirstIndex + edgeIndex); newPolygon.Category = polygon.Category; newPolygon.Visible = polygon.Visible; newPolygon.Bounds.Set(polygon.Bounds, translation); polygons.Add(newPolygon); if (newPolygon.Visible) { var first = edges[newPolygon.FirstIndex]; var iterator = first; do { bounds.Add(vertices[iterator.VertexIndex]); iterator = edges[iterator.NextIndex]; } while (iterator != first); } } edgeIndex = edges.Count; polygonIndex = polygons.Count; } return new CSGMesh(planes.ToArray(), polygons, edges, vertices, bounds); }
// Note: This method is not optimized! Code is simplified for clarity! // for example: Plane.Distance / Plane.OnSide should be inlined manually and shouldn't use enums, but floating point values directly! public PolygonSplitResult PolygonSplit(Plane cuttingPlane, Vector3 translation, ref Polygon inputPolygon, out Polygon outsidePolygon) { HalfEdge prev = Edges[inputPolygon.FirstIndex]; HalfEdge current = Edges[prev.NextIndex]; HalfEdge next = Edges[current.NextIndex]; HalfEdge last = next; HalfEdge enterEdge = null; HalfEdge exitEdge = null; var prevVertex = Vertices[prev.VertexIndex]; var prevDistance = cuttingPlane.Distance(prevVertex); // distance to previous vertex var prevSide = Plane.OnSide(prevDistance); // side of plane of previous vertex var currentVertex = Vertices[current.VertexIndex]; var currentDistance = cuttingPlane.Distance(currentVertex); // distance to current vertex var currentSide = Plane.OnSide(currentDistance); // side of plane of current vertex do { var nextVertex = Vertices[next.VertexIndex]; var nextDistance = cuttingPlane.Distance(nextVertex); // distance to next vertex var nextSide = Plane.OnSide(nextDistance); // side of plane of next vertex if (prevSide != currentSide) // check if edge crossed the plane ... { if (currentSide != PlaneSideResult.Intersects) // prev:inside/outside - current:inside/outside - next:?? { if (prevSide != PlaneSideResult.Intersects) // prev:inside/outside - current:outside - next:?? { // Calculate intersection of edge with plane split the edge into two, inserting the new vertex var newVertex = Plane.Intersection(prevVertex, currentVertex, prevDistance, currentDistance); var newEdge = EdgeSplit(current, newVertex); if (prevSide == PlaneSideResult.Inside) // prev:inside - current:outside - next:?? { //edge01 exits: // // outside // 1 // * // ......./........ intersect // / // 0 // inside exitEdge = current; } else if (prevSide == PlaneSideResult.Outside) // prev:outside - current:inside - next:?? { //edge01 enters: // // outside // 0 // \ // .......\........ intersect // * // 1 // inside enterEdge = current; } prevDistance = 0; prev = Edges[prev.NextIndex]; prevSide = PlaneSideResult.Intersects; if (exitEdge != null && enterEdge != null) break; current = Edges[prev.NextIndex]; currentVertex = Vertices[current.VertexIndex]; next = Edges[current.NextIndex]; nextVertex = Vertices[next.VertexIndex]; } } else // prev:?? - current:intersects - next:?? { if (prevSide == PlaneSideResult.Intersects || // prev:intersects - current:intersects - next:?? nextSide == PlaneSideResult.Intersects || // prev:?? - current:intersects - next:intersects prevSide == nextSide) // prev:inside/outde - current:intersects - next:inside/outde { if (prevSide == PlaneSideResult.Inside || // prev:inside - current:intersects - next:intersects/inside nextSide == PlaneSideResult.Inside) // prev:intersects/inside - current:intersects - next:inside { // outside // 0 1 // --------*....... intersect // \ // 2 // inside // // outside // 1 2 // ........*------- intersect // / // 0 // inside // // outside // 1 //........*....... intersect // / \ // 0 2 // inside // prevSide = PlaneSideResult.Inside; enterEdge = exitEdge = null; break; } else if (prevSide == PlaneSideResult.Outside || // prev:outside - current:intersects - next:intersects/outside nextSide == PlaneSideResult.Outside) // prev:intersects/outside - current:intersects - next:outside { // outside // 2 // / //..------*....... intersect // 0 1 // inside // // outside // 0 // \ //........*------- intersect // 1 2 // inside // // outside // 0 2 // \ / //........*....... intersect // 1 // inside // prevSide = PlaneSideResult.Outside; enterEdge = exitEdge = null; break; } } else // prev:inside/outside - current:intersects - next:inside/outside { if (prevSide == PlaneSideResult.Inside) // prev:inside - current:intersects - next:outside { //find exit edge: // // outside // 2 // 1 / // ........*....... intersect // / // 0 // inside exitEdge = current; if (enterEdge != null) break; } else // prev:outside - current:intersects - next:inside { //find enter edge: // // outside // 0 // \ 1 // ........*....... intersect // \ // 2 // inside enterEdge = current; if (exitEdge != null) break; } } } } prev = current; current = next; next = Edges[next.NextIndex]; prevDistance = currentDistance; currentDistance = nextDistance; prevSide = currentSide; currentSide = nextSide; prevVertex = currentVertex; currentVertex = nextVertex; } while (next != last); // We should never have only one edge crossing the plane .. //Debug.Assert((enterEdge == null) == (exitEdge == null)); // Check if we have an edge that exits and an edge that enters the plane and split the polygon into two if we do if (enterEdge != null && exitEdge != null) { //enter . // . // =====>*-----> // . // //outside . inside // . // <-----*<===== // . // . exit outsidePolygon = new Polygon(); var outsidePolygonIndex = (short)this.Polygons.Count; this.Polygons.Add(outsidePolygon); var outsideEdge = new HalfEdge(); var outsideEdgeIndex = (short)Edges.Count; var insideEdge = new HalfEdge(); var insideEdgeIndex = (short)(outsideEdgeIndex + 1); outsideEdge.TwinIndex = insideEdgeIndex; insideEdge.TwinIndex = outsideEdgeIndex; //insideEdge.PolygonIndex = inputPolygonIndex;// index does not change outsideEdge.PolygonIndex = outsidePolygonIndex; outsideEdge.VertexIndex = exitEdge.VertexIndex; insideEdge.VertexIndex = enterEdge.VertexIndex; outsideEdge.NextIndex = exitEdge.NextIndex; insideEdge.NextIndex = enterEdge.NextIndex; exitEdge.NextIndex = insideEdgeIndex; enterEdge.NextIndex = outsideEdgeIndex; outsidePolygon.FirstIndex = outsideEdgeIndex; inputPolygon.FirstIndex = insideEdgeIndex; outsidePolygon.Visible = inputPolygon.Visible; outsidePolygon.Category = inputPolygon.Category; outsidePolygon.PlaneIndex = inputPolygon.PlaneIndex; Edges.Add(outsideEdge); Edges.Add(insideEdge); // calculate the bounds of the polygons outsidePolygon.Bounds.Clear(); var first = Edges[outsidePolygon.FirstIndex]; var iterator = first; do { outsidePolygon.Bounds.Add(Vertices[iterator.VertexIndex]); iterator.PolygonIndex = outsidePolygonIndex; iterator = Edges[iterator.NextIndex]; } while (iterator != first); inputPolygon.Bounds.Clear(); first = Edges[inputPolygon.FirstIndex]; iterator = first; do { inputPolygon.Bounds.Add(Vertices[iterator.VertexIndex]); iterator = Edges[iterator.NextIndex]; } while (iterator != first); return PolygonSplitResult.Split; } else { outsidePolygon = null; switch (prevSide) { case PlaneSideResult.Inside: return PolygonSplitResult.CompletelyInside; case PlaneSideResult.Outside: return PolygonSplitResult.CompletelyOutside; default: case PlaneSideResult.Intersects: { var polygonPlane = Planes[inputPolygon.PlaneIndex]; var result = Vector3.DotProduct(polygonPlane.Normal, cuttingPlane.Normal); if (result > 0) return PolygonSplitResult.PlaneAligned; else return PolygonSplitResult.PlaneOppositeAligned; } } } }
public static CSGMesh CreateFromPlanes(Plane[] brushPlanes) { var planes = new Plane[brushPlanes.Length]; for (int i = 0; i < brushPlanes.Length; i++) { var plane = brushPlanes[i]; planes[i] = new Plane(plane.A, plane.B, plane.C, plane.D); } var pointIntersections = new List<PointIntersection>(planes.Length * planes.Length); var intersectingPlanes = new List<short>(); var vertices = new List<Vector3>(); var edges = new List<HalfEdge>(); // Find all point intersections where 3 (or more planes) intersect for (short planeIndex1 = 0; planeIndex1 < planes.Length - 2; planeIndex1++) { var plane1 = planes[planeIndex1]; for (short planeIndex2 = (short)(planeIndex1 + 1); planeIndex2 < planes.Length - 1; planeIndex2++) { var plane2 = planes[planeIndex2]; for (short planeIndex3 = (short)(planeIndex2 + 1); planeIndex3 < planes.Length; planeIndex3++) { var plane3 = planes[planeIndex3]; // Calculate the intersection var vertex = Plane.Intersection(plane1, plane2, plane3); // Check if the intersection is valid if (float.IsNaN(vertex.X) || float.IsNaN(vertex.Y) || float.IsNaN(vertex.Z) || float.IsInfinity(vertex.X) || float.IsInfinity(vertex.Y) || float.IsInfinity(vertex.Z)) continue; intersectingPlanes.Clear(); intersectingPlanes.Add(planeIndex1); intersectingPlanes.Add(planeIndex2); intersectingPlanes.Add(planeIndex3); for (short planeIndex4 = 0; planeIndex4 < planes.Length; planeIndex4++) { if (planeIndex4 == planeIndex1 || planeIndex4 == planeIndex2 || planeIndex4 == planeIndex3) continue; var plane4 = planes[planeIndex4]; var side = plane4.OnSide(vertex); if (side == PlaneSideResult.Intersects) { if (planeIndex4 < planeIndex3) // Already found this vertex goto SkipIntersection; // We've found another plane which goes trough our found intersection point intersectingPlanes.Add(planeIndex4); } else if (side == PlaneSideResult.Outside) // Intersection is outside of brush goto SkipIntersection; } var vertexIndex = (short)vertices.Count; vertices.Add(vertex); // Add intersection point to our list pointIntersections.Add(new PointIntersection(vertexIndex, intersectingPlanes)); SkipIntersection: ; } } } var foundPlanes = new short[2]; // Find all our intersection edges which are formed by a pair of planes // (this could probably be done inside the previous loop) for (int i = 0; i < pointIntersections.Count; i++) { var pointIntersectionA = pointIntersections[i]; for (int j = i + 1; j < pointIntersections.Count; j++) { var pointIntersectionB = pointIntersections[j]; var planesIndicesA = pointIntersectionA.PlaneIndices; var planesIndicesB = pointIntersectionB.PlaneIndices; short foundPlaneIndex = 0; foreach (var currentPlaneIndex in planesIndicesA) { if (!planesIndicesB.Contains(currentPlaneIndex)) continue; foundPlanes[foundPlaneIndex] = currentPlaneIndex; foundPlaneIndex++; if (foundPlaneIndex == 2) break; } // If foundPlaneIndex is 0 or 1 then either this combination does not exist, // or only goes trough one point if (foundPlaneIndex < 2) continue; // Create our found intersection edge var halfEdgeA = new HalfEdge(); var halfEdgeAIndex = (short)edges.Count; edges.Add(halfEdgeA); var halfEdgeB = new HalfEdge(); var halfEdgeBIndex = (short)edges.Count; edges.Add(halfEdgeB); halfEdgeA.TwinIndex = halfEdgeBIndex; halfEdgeB.TwinIndex = halfEdgeAIndex; halfEdgeA.VertexIndex = pointIntersectionA.VertexIndex; halfEdgeB.VertexIndex = pointIntersectionB.VertexIndex; // Add it to our points pointIntersectionA.Edges.Add(new EdgeIntersection( halfEdgeA, foundPlanes[0], foundPlanes[1])); pointIntersectionB.Edges.Add(new EdgeIntersection( halfEdgeB, foundPlanes[0], foundPlanes[1])); } } var polygons = new List<Polygon>(); for (short i = 0; i < (short)planes.Length; i++) { var polygon = new Polygon(); polygon.PlaneIndex = i; polygons.Add(polygon); } var bounds = new AABB(); var direction = new Vector3(); for (int i = pointIntersections.Count - 1; i >= 0; i--) { var pointIntersection = pointIntersections[i]; var pointEdges = pointIntersection.Edges; // Make sure that we have at least 2 edges ... // This may happen when a plane only intersects at a single edge. if (pointEdges.Count <= 2) { pointIntersections.RemoveAt(i); continue; } var vertexIndex = pointIntersection.VertexIndex; var vertex = vertices[vertexIndex]; for (int j = 0; j < pointEdges.Count - 1; j++) { var edge1 = pointEdges[j]; for (int k = j + 1; k < pointEdges.Count; k++) { var edge2 = pointEdges[k]; int planeIndex1 = -1; int planeIndex2 = -1; // Determine if and which of our 2 planes are identical if (edge1.PlaneIndices[0] == edge2.PlaneIndices[0]) { planeIndex1 = 0; planeIndex2 = 0; } else if (edge1.PlaneIndices[0] == edge2.PlaneIndices[1]) { planeIndex1 = 0; planeIndex2 = 1; } else if (edge1.PlaneIndices[1] == edge2.PlaneIndices[0]) { planeIndex1 = 1; planeIndex2 = 0; } else if (edge1.PlaneIndices[1] == edge2.PlaneIndices[1]) { planeIndex1 = 1; planeIndex2 = 1; } else continue; HalfEdge ingoing; HalfEdge outgoing; short outgoingIndex; var shared_plane = planes[edge1.PlaneIndices[planeIndex1]]; var edge1_plane = planes[edge1.PlaneIndices[1 - planeIndex1]]; var edge2_plane = planes[edge2.PlaneIndices[1 - planeIndex2]]; direction = Vector3.CrossProduct(shared_plane.Normal, edge1_plane.Normal); // Determine the orientation of our two edges to determine // which edge is in-going, and which one is out-going if (Vector3.DotProduct(direction, edge2_plane.Normal) < 0) { ingoing = edge2.Edge; outgoingIndex = edge1.Edge.TwinIndex; outgoing = edges[outgoingIndex]; } else { ingoing = edge1.Edge; outgoingIndex = edge2.Edge.TwinIndex; outgoing = edges[outgoingIndex]; } // Link the out-going half-edge to the in-going half-edge ingoing.NextIndex = outgoingIndex; // Add reference to polygon to half-edge, and make sure our // polygon has a reference to a half-edge // Since a half-edge, in this case, serves as a circular // linked list this just works. var polygonIndex = edge1.PlaneIndices[planeIndex1]; ingoing.PolygonIndex = polygonIndex; outgoing.PolygonIndex = polygonIndex; var polygon = polygons[polygonIndex]; polygon.FirstIndex = outgoingIndex; polygon.Bounds.Add(vertex); } } // Add the intersection point to the area of our bounding box bounds.Add(vertex); } return new CSGMesh(planes, polygons, edges, vertices, bounds); }
public CSGMesh Clone() { var newPlanes = new Plane[Planes.Length]; for (int i = 0; i < Planes.Length; i++) { var plane = Planes[i]; newPlanes[i] = new Plane(plane.A, plane.B, plane.C, plane.D); } var newPolygons = new List<Polygon>(Polygons.Count); foreach (var polygon in Polygons) { var newPolygon = new Polygon(); newPolygon.FirstIndex = polygon.FirstIndex; newPolygon.Visible = polygon.Visible; newPolygon.Category = polygon.Category; newPolygon.PlaneIndex = polygon.PlaneIndex; newPolygon.Bounds.Set(polygon.Bounds); newPolygons.Add(newPolygon); } var newEdges = new List<HalfEdge>(Edges.Count); foreach (var edge in Edges) { var newEdge = new HalfEdge(); newEdge.NextIndex = edge.NextIndex; newEdge.PolygonIndex = edge.PolygonIndex; newEdge.TwinIndex = edge.TwinIndex; newEdge.VertexIndex = edge.VertexIndex; newEdges.Add(newEdge); } var newVertices = new List<Vector3>(Vertices.Count); foreach (var vertex in Vertices) { var newVertex = new Vector3(vertex.X, vertex.Y, vertex.Z); newVertices.Add(newVertex); } var newBounds = new AABB(Bounds); var newMesh = new CSGMesh( newPlanes, newPolygons, newEdges, newVertices, newBounds); return newMesh; }
public static bool GenerateControlMeshFromVertices(ShapePolygon shape2DPolygon, Matrix4x4 localToWorld, Vector3 direction, float height, Material capMaterial, TexGen capTexgen, bool?smooth, bool singleSurfaceEnds, //Plane buildPlane, out ControlMesh controlMesh, out Shape shape) { if (shape2DPolygon == null) { controlMesh = null; shape = null; return(false); } var vertices = shape2DPolygon.Vertices; if (vertices.Length < 3) { controlMesh = null; shape = null; return(false); } if (height == 0.0f) { controlMesh = null; shape = null; return(false); } Vector3 from; Vector3 to; if (height > 0) { @from = direction * height; // buildPlane.normal * height; to = MathConstants.zeroVector3; } else { @from = MathConstants.zeroVector3; to = direction * height; //buildPlane.normal * height; } var count = vertices.Length; var doubleCount = (count * 2); var extraPoints = 0; var extraEdges = 0; var endsPolygons = 2; var startEdgeOffset = doubleCount; if (!singleSurfaceEnds) { extraPoints = 2; extraEdges = (4 * count); endsPolygons = doubleCount; startEdgeOffset += extraEdges; } var dstPoints = new Vector3 [doubleCount + extraPoints]; var dstEdges = new HalfEdge[(count * 6) + extraEdges]; var dstPolygons = new Polygon [count + endsPolygons]; var center1 = MathConstants.zeroVector3; var center2 = MathConstants.zeroVector3; for (int i = 0; i < count; i++) { var point1 = vertices[i]; var point2 = vertices[(count + i - 1) % count]; point1 += @from; point2 += to; // swap y/z to solve texgen issues dstPoints[i].x = point1.x; dstPoints[i].y = point1.y; dstPoints[i].z = point1.z; center1 += dstPoints[i]; dstEdges [i].VertexIndex = (short)i; dstEdges [i].HardEdge = true; // swap y/z to solve texgen issues dstPoints[i + count].x = point2.x; dstPoints[i + count].y = point2.y; dstPoints[i + count].z = point2.z; center2 += dstPoints[i + count]; dstEdges [i + count].VertexIndex = (short)(i + count); dstEdges [i + count].HardEdge = true; } if (!singleSurfaceEnds) { dstPoints[doubleCount] = center1 / count; dstPoints[doubleCount + 1] = center2 / count; int edge_offset = doubleCount; short polygon_index = (short)count; // 'top' for (int i = 0, j = count - 1; i < count; j = i, i++) { var jm = (j) % count; var im = (i) % count; var edgeOut0 = edge_offset + (jm * 2) + 1; var edgeIn0 = edge_offset + (im * 2) + 0; var edgeOut1 = edge_offset + (im * 2) + 1; dstEdges[edgeIn0].VertexIndex = (short)(doubleCount); dstEdges[edgeIn0].HardEdge = true; dstEdges[edgeIn0].TwinIndex = edgeOut1; dstEdges[edgeOut1].VertexIndex = (short)im; dstEdges[edgeOut1].HardEdge = true; dstEdges[edgeOut1].TwinIndex = edgeIn0; dstEdges[im].PolygonIndex = polygon_index; dstEdges[edgeIn0].PolygonIndex = polygon_index; dstEdges[edgeOut0].PolygonIndex = polygon_index; dstPolygons[polygon_index] = new Polygon(new int[] { im, edgeIn0, edgeOut0 }, polygon_index); polygon_index++; } edge_offset = doubleCount * 2; // 'bottom' for (int i = 0, j = count - 1; j >= 0; i = j, j--) { var jm = (count + count - j) % count; var im = (count + count - i) % count; var edgeOut0 = edge_offset + (jm * 2) + 1; var edgeIn0 = edge_offset + (im * 2) + 0; var edgeOut1 = edge_offset + (im * 2) + 1; dstEdges[edgeIn0].VertexIndex = (short)(doubleCount + 1); dstEdges[edgeIn0].HardEdge = true; dstEdges[edgeIn0].TwinIndex = edgeOut1; dstEdges[edgeOut1].VertexIndex = (short)(im + count); dstEdges[edgeOut1].HardEdge = true; dstEdges[edgeOut1].TwinIndex = edgeIn0; dstEdges[im + count].PolygonIndex = polygon_index; dstEdges[edgeIn0].PolygonIndex = polygon_index; dstEdges[edgeOut0].PolygonIndex = polygon_index; dstPolygons[polygon_index] = new Polygon(new int[] { im + count, edgeIn0, edgeOut0 }, polygon_index); polygon_index++; } } else { var polygon0Edges = new int[count]; var polygon1Edges = new int[count]; for (var i = 0; i < count; i++) { dstEdges [i].PolygonIndex = (short)(count + 0); dstEdges [i + count].PolygonIndex = (short)(count + 1); polygon0Edges[i] = i; polygon1Edges[count - (i + 1)] = i + count; } dstPolygons[count + 0] = new Polygon(polygon0Edges, count + 0); dstPolygons[count + 1] = new Polygon(polygon1Edges, count + 1); } for (int v0 = count - 1, v1 = 0; v1 < count; v0 = v1, v1++) { var polygonIndex = (short)(v1); var nextOffset = startEdgeOffset + (((v1 + 1) % count) * 4); var currOffset = startEdgeOffset + (((v1)) * 4); var prevOffset = startEdgeOffset + (((v1 + count - 1) % count) * 4); var nextTwin = nextOffset + 1; var prevTwin = prevOffset + 3; dstEdges[v1].TwinIndex = currOffset + 0; dstEdges[v1 + count].TwinIndex = currOffset + 2; dstEdges[currOffset + 0].PolygonIndex = polygonIndex; dstEdges[currOffset + 1].PolygonIndex = polygonIndex; dstEdges[currOffset + 2].PolygonIndex = polygonIndex; dstEdges[currOffset + 3].PolygonIndex = polygonIndex; dstEdges[currOffset + 0].TwinIndex = (v1); dstEdges[currOffset + 1].TwinIndex = prevTwin; dstEdges[currOffset + 2].TwinIndex = (v1 + count); dstEdges[currOffset + 3].TwinIndex = nextTwin; dstEdges[currOffset + 0].VertexIndex = (short)(v0); dstEdges[currOffset + 1].VertexIndex = (short)(v1 + count); dstEdges[currOffset + 2].VertexIndex = (short)(((v1 + 1) % count) + count); dstEdges[currOffset + 3].VertexIndex = (short)(v1); dstEdges[currOffset + 0].HardEdge = true; dstEdges[currOffset + 1].HardEdge = true; dstEdges[currOffset + 2].HardEdge = true; dstEdges[currOffset + 3].HardEdge = true; dstPolygons[polygonIndex] = new Polygon(new [] { currOffset + 0, currOffset + 1, currOffset + 2, currOffset + 3 }, polygonIndex); } for (int i = 0; i < dstPoints.Length; i++) { dstPoints[i] = localToWorld.MultiplyPoint(dstPoints[i]); } controlMesh = new ControlMesh { Vertices = dstPoints, Edges = dstEdges, Polygons = dstPolygons }; controlMesh.SetDirty(); shape = new Shape { Materials = new Material[dstPolygons.Length], Surfaces = new Surface[dstPolygons.Length], TexGenFlags = new TexGenFlags[dstPolygons.Length], TexGens = new TexGen[dstPolygons.Length] }; var smoothinggroup = (smooth.HasValue && smooth.Value) ? SurfaceUtility.FindUnusedSmoothingGroupIndex() : 0; var containedMaterialCount = 0; if (shape2DPolygon.EdgeMaterials != null && shape2DPolygon.EdgeTexgens != null /* && * shape2DPolygon.edgeTexgenFlags != null*/) { containedMaterialCount = Mathf.Min(shape2DPolygon.EdgeMaterials.Length, shape2DPolygon.EdgeTexgens.Length /*, * shape2DPolygon.edgeTexgenFlags.Length*/); } if (!capMaterial) { capMaterial = CSGSettings.DefaultMaterial; capTexgen = new TexGen(-1); } for (var i = 0; i < dstPolygons.Length; i++) { if (i < containedMaterialCount) { //shape.TexGenFlags[i] = shape2DPolygon.edgeTexgenFlags[i]; shape.Materials [i] = shape2DPolygon.EdgeMaterials[i]; shape.TexGens [i] = shape2DPolygon.EdgeTexgens[i]; shape.Surfaces [i].TexGenIndex = i; shape.TexGens[i].MaterialIndex = -1; } else { shape.Materials[i] = capMaterial; shape.TexGens[i] = capTexgen; //shape.TexGenFlags[i] = TexGenFlags.None; shape.Surfaces[i].TexGenIndex = i; shape.TexGens[i].MaterialIndex = -1; } if (smooth.HasValue) { if (i < count) { shape.TexGens[i].SmoothingGroup = smoothinggroup; } else { shape.TexGens[i].SmoothingGroup = 0; } } } for (var s = 0; s < dstPolygons.Length; s++) { var normal = shape.Surfaces[s].Plane.normal; shape.Surfaces[s].Plane = GeometryUtility.CalcPolygonPlane(controlMesh, (short)s); Vector3 tangent, binormal; GeometryUtility.CalculateTangents(normal, out tangent, out binormal); //var tangent = Vector3.Cross(GeometryUtility.CalculateTangent(normal), normal).normalized; //var binormal = Vector3.Cross(normal, tangent); shape.Surfaces[s].Tangent = tangent; shape.Surfaces[s].BiNormal = binormal; shape.Surfaces[s].TexGenIndex = s; } controlMesh.IsValid = ControlMeshUtility.Validate(controlMesh, shape); if (controlMesh.IsValid) { return(true); } controlMesh = null; shape = null; return(false); }