/// <summary> /// Applies a clip or split operation to a brush by supplying a plane local to the brush. Clipping allows you to cut away and discard parts of the brush, while splitting allows you to split a brush in two. /// </summary> /// <returns>If keepBothSides is <c>true</c>, this returns the second brush if one was created.</returns> /// <param name="brush">Brush to clip/split</param> /// <param name="localPlane">Local plane to clip/split against</param> /// <param name="keepBothSides">If set to <c>true</c> split the brush and keep both sides.</param> /// <param name="resetPivots">If set to <c>true</c> make sure the pivot clipped brush and any new brush are at their center.</param> public static GameObject ApplyClipPlane(PrimitiveBrush brush, Plane localPlane, bool keepBothSides, bool resetPivots = true) { // Clip the polygons against the plane List <Polygon> polygonsFront; List <Polygon> polygonsBack; List <Polygon> polygonList = new List <Polygon>(brush.GetPolygons()); if (PolygonFactory.SplitPolygonsByPlane(polygonList, localPlane, false, out polygonsFront, out polygonsBack)) { // Update the brush with the new polygons brush.SetPolygons(polygonsFront.ToArray(), true); GameObject newObject = null; // If they have decided to split instead of clip, create a second brush with the other side if (keepBothSides) { newObject = brush.Duplicate(); // Finally give the new brush the other set of polygons newObject.GetComponent <PrimitiveBrush>().SetPolygons(polygonsBack.ToArray(), true); newObject.transform.SetSiblingIndex(brush.transform.GetSiblingIndex()); // Reset the new brush's pivot if (resetPivots) { newObject.GetComponent <PrimitiveBrush>().ResetPivot(); } } // Can't reset the first brush pivot until after the second brush is made, otherwise the second // brush is effectively translated twice, ending up in the wrong position if (resetPivots) { brush.ResetPivot(); } return(newObject); } else { return(null); } }
public static void SplitIntersecting(PrimitiveBrush[] brushes) { List <Brush> intersections = new List <Brush>(); foreach (PrimitiveBrush brush in brushes) { intersections.AddRange(brush.BrushCache.IntersectingVisualBrushes); } foreach (PrimitiveBrush brush in brushes) { List <PrimitiveBrush> newBrushes = new List <PrimitiveBrush>(); foreach (Brush intersectingBrush in intersections) { PrimitiveBrush brushToClip = (PrimitiveBrush)intersectingBrush; Polygon[] polygons = brush.GetPolygons(); // A brush may have several polygons that share a plane, find all the distinct polygon planes List <Plane> distinctPlanes = new List <Plane>(); for (int polygonIndex = 0; polygonIndex < polygons.Length; polygonIndex++) { Polygon polygon = polygons[polygonIndex]; Vertex vertex1, vertex2, vertex3; SurfaceUtility.GetPrimaryPolygonDescribers(polygon, out vertex1, out vertex2, out vertex3); Vector3 position1 = vertex1.Position; Vector3 position2 = vertex2.Position; Vector3 position3 = vertex3.Position; // Transform from local to brush to local to intersectingBrush position1 = intersectingBrush.transform.InverseTransformPoint(brush.transform.TransformPoint(position1)); position2 = intersectingBrush.transform.InverseTransformPoint(brush.transform.TransformPoint(position2)); position3 = intersectingBrush.transform.InverseTransformPoint(brush.transform.TransformPoint(position3)); // Calculate plane in intersectingBrush's local space Plane polygonPlane = new Plane(position1, position2, position3); bool found = false; // See if it already exists for (int i = 0; i < distinctPlanes.Count; i++) { if (MathHelper.PlaneEqualsLooser(distinctPlanes[i], polygonPlane)) { found = true; break; } } // Not added to an existing group, so add new if (!found) { // Add a new group for the polygon distinctPlanes.Add(polygonPlane); } } foreach (Plane clipPlane in distinctPlanes) { #if UNITY_EDITOR UnityEditor.Undo.RecordObject(brushToClip, "Split Intersecting Brushes"); UnityEditor.Undo.RecordObject(brushToClip.transform, "Split Intersecting Brushes"); #endif GameObject newObject = ClipUtility.ApplyClipPlane(brushToClip, clipPlane, true, false); if (newObject != null) { #if UNITY_EDITOR UnityEditor.Undo.RegisterCreatedObjectUndo(newObject, "Split Intersecting Brushes"); #endif newBrushes.Add(newObject.GetComponent <PrimitiveBrush>()); } } brushToClip.ResetPivot(); } foreach (PrimitiveBrush newBrush in newBrushes) { newBrush.ResetPivot(); } intersections.AddRange(newBrushes.ConvertAll <Brush>(item => (Brush)item)); } }
private void CreateBrush(List <Vector3> positions) { Polygon sourcePolygon = PolygonFactory.ConstructPolygon(positions, true); // Early out if it wasn't possible to create the polygon if (sourcePolygon == null) { return; } if (activePolygon != null) { for (int i = 0; i < sourcePolygon.Vertices.Length; i++) { Vector2 newUV = GeometryHelper.GetUVForPosition(activePolygon, sourcePolygon.Vertices[i].Position); sourcePolygon.Vertices[i].UV = newUV; } } Vector3 planeNormal = GetActivePlane().normal; // Debug.Log(Vector3.Dot(sourcePolygon.Plane.normal, planeNormal)); // Flip the polygon if the winding order is wrong if (Vector3.Dot(sourcePolygon.Plane.normal, planeNormal) < 0) { sourcePolygon.Flip(); // Need to flip the UVs across the U (X) direction for (int i = 0; i < sourcePolygon.Vertices.Length; i++) { Vector2 uv = sourcePolygon.Vertices[i].UV; uv.x = 1 - uv.x; sourcePolygon.Vertices[i].UV = uv; } } float extrusionDistance = 1; Vector3 positionOffset = Vector3.zero; if (selectingHeight) { extrusionDistance = prismHeight; } else { if (activePolygon != null && activeBrush != null) { extrusionDistance = activeBrush.CalculateExtentsInAxis(planeNormal); } else { Brush lastSelectedBrush = csgModel.LastSelectedBrush; if (lastSelectedBrush != null) { Bounds lastSelectedBrushBounds = lastSelectedBrush.GetBoundsTransformed(); for (int i = 0; i < 3; i++) { if (!planeNormal[i].EqualsWithEpsilon(0)) { if (lastSelectedBrushBounds.size[i] != 0) { extrusionDistance = lastSelectedBrushBounds.size[i]; if (planeNormal[i] > 0) { positionOffset[i] = lastSelectedBrushBounds.center[i] - lastSelectedBrushBounds.extents[i]; } else { positionOffset[i] = lastSelectedBrushBounds.center[i] + lastSelectedBrushBounds.extents[i]; } } } } } } // Subtractions should go through if (csgMode == CSGMode.Subtract) { sourcePolygon.Flip(); } } Quaternion rotation; Polygon[] polygons; SurfaceUtility.ExtrudePolygon(sourcePolygon, extrusionDistance, out polygons, out rotation); GameObject newObject = csgModel.CreateCustomBrush(polygons); PrimitiveBrush newBrush = newObject.GetComponent <PrimitiveBrush>(); newObject.transform.rotation = rotation; newObject.transform.position += positionOffset; if (activePolygon != null && activePolygon.Material != csgModel.GetDefaultMaterial()) { for (int i = 0; i < polygons.Length; i++) { polygons[i].Material = activePolygon.Material; } } // Finally give the new brush the other set of polygons newBrush.SetPolygons(polygons, true); newBrush.Mode = csgMode; newBrush.ResetPivot(); // Use this brush as the basis for drawing the next brush csgModel.SetLastSelectedBrush(newBrush); Undo.RegisterCreatedObjectUndo(newObject, "Draw Brush"); }