Skip to content
This repository has been archived by the owner on Feb 11, 2024. It is now read-only.

Commit

Permalink
Merge pull request #110 from Henry00IS/2DSEConcave
Browse files Browse the repository at this point in the history
2DSE: Extrude anything into a single concave NoCSG brush.
  • Loading branch information
Henry00IS authored May 12, 2018
2 parents b2e072b + 84d3c5b commit e2e2fa0
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 43 deletions.
33 changes: 23 additions & 10 deletions Scripts/Brushes/CompoundBrushes/Editor/ShapeEditorWindowPopup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public enum PopupMode
public int revolveSteps = 4;
public bool revolveSpiralSloped = false;
public Vector2Int GlobalPivotPosition_Position;
public bool convexBrushes = true;

private Action<ShapeEditorWindowPopup> onApply;

Expand All @@ -50,6 +51,7 @@ public ShapeEditorWindowPopup(PopupMode popupMode, ShapeEditor.Project project,
revolve360 = project.revolve360;
revolveSteps = project.revolveSteps;
revolveSpiralSloped = project.revolveSpiralSloped;
convexBrushes = project.convexBrushes;
GlobalPivotPosition_Position = project.globalPivot.position;

this.onApply = (self) =>
Expand All @@ -59,27 +61,32 @@ public ShapeEditorWindowPopup(PopupMode popupMode, ShapeEditor.Project project,
{
case PopupMode.CreatePolygon:
project.extrudeScale = extrudeScale;
project.convexBrushes = convexBrushes;
break;

case PopupMode.RevolveShape:
project.extrudeScale = extrudeScale;
project.convexBrushes = convexBrushes;
project.revolve360 = revolve360;
project.revolveSteps = revolveSteps;
project.revolveSpiralSloped = revolveSpiralSloped;
break;

case PopupMode.ExtrudeShape:
project.extrudeScale = extrudeScale;
project.convexBrushes = convexBrushes;
project.extrudeDepth = extrudeDepth;
break;

case PopupMode.ExtrudePoint:
project.extrudeScale = extrudeScale;
project.convexBrushes = convexBrushes;
project.extrudeDepth = extrudeDepth;
break;

case PopupMode.ExtrudeBevel:
project.extrudeScale = extrudeScale;
project.convexBrushes = convexBrushes;
project.extrudeDepth = extrudeDepth;
project.extrudeClipDepth = extrudeClipDepth;
break;
Expand All @@ -93,28 +100,29 @@ public ShapeEditorWindowPopup(PopupMode popupMode, ShapeEditor.Project project,

public override Vector2 GetWindowSize()
{
// + 18 for every element
switch (popupMode)
{
case PopupMode.BezierDetailLevel:
return new Vector2(205, 140);

case PopupMode.GlobalPivotPosition:
return new Vector2(300, 50 + 18);
return new Vector2(300, 68);

case PopupMode.CreatePolygon:
return new Vector2(300, 50 + 18);
return new Vector2(300, 50 + 36);

case PopupMode.RevolveShape:
return new Vector2(300, 86 + 18 + 18);
return new Vector2(300, 104 + 36);

case PopupMode.ExtrudeShape:
return new Vector2(300, 68 + 18);
return new Vector2(300, 68 + 36);

case PopupMode.ExtrudePoint:
return new Vector2(300, 68 + 18);
return new Vector2(300, 68 + 36);

case PopupMode.ExtrudeBevel:
return new Vector2(300, 86 + 18);
return new Vector2(300, 86 + 36);

default:
return new Vector2(300, 150);
Expand All @@ -124,12 +132,14 @@ public override Vector2 GetWindowSize()
public override void OnGUI(Rect rect)
{
bool hasScale = true;
bool hasConvexBrushes = true;
string accept = "";
switch (popupMode)
{
case PopupMode.BezierDetailLevel:
GUILayout.Label("Bezier Detail Level", EditorStyles.boldLabel);
hasScale = false;
hasConvexBrushes = false;
accept = "Apply";

GUILayout.BeginHorizontal(EditorStyles.toolbar);
Expand Down Expand Up @@ -184,6 +194,7 @@ public override void OnGUI(Rect rect)
case PopupMode.GlobalPivotPosition:
GUILayout.Label("Global Pivot Position", EditorStyles.boldLabel);
hasScale = false;
hasConvexBrushes = false;
accept = "Set Position";

#if !UNITY_2017_2_OR_NEWER
Expand Down Expand Up @@ -211,10 +222,7 @@ public override void OnGUI(Rect rect)
revolveSteps = EditorGUILayout.IntField("Steps", revolveSteps);
if (revolveSteps < 1) revolveSteps = 1;

EditorGUILayout.BeginHorizontal();
GUILayout.Label("NoCSG Only");
revolveSpiralSloped = GUILayout.Toggle(revolveSpiralSloped, "Sloped Spiral", EditorStyles.toolbarButton);
EditorGUILayout.EndHorizontal();
revolveSpiralSloped = EditorGUILayout.Toggle("Sloped Spiral", revolveSpiralSloped);

// steps can't be more than 360.
if (revolveSteps > revolve360) revolveSteps = revolve360;
Expand Down Expand Up @@ -248,6 +256,11 @@ public override void OnGUI(Rect rect)
break;
}

if (hasConvexBrushes)
{
convexBrushes = EditorGUILayout.Toggle("Convex Brushes", convexBrushes);
}

if (hasScale)
{
EditorGUIUtility.wideMode = true;
Expand Down
6 changes: 6 additions & 0 deletions Scripts/Brushes/CompoundBrushes/ShapeEditor/Project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ public class Project
[SerializeField]
public bool revolveSpiralSloped = false;

/// <summary>
/// Whether the shape uses Convex Decomposition or Concave Shapes.
/// </summary>
[SerializeField]
public bool convexBrushes = true;

/// <summary>
/// Clones this project and returns the copy.
/// </summary>
Expand Down
137 changes: 104 additions & 33 deletions Scripts/Brushes/CompoundBrushes/ShapeEditor/ShapeEditorBrush.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ public override int BrushCount
{
get
{
// if the user desires a single concave brush we return 1.
if (!project.convexBrushes)
return 1;

// we already know the amount of brushes we need.
if (!isDirty)
return desiredBrushCount;
Expand Down Expand Up @@ -149,10 +153,14 @@ public override void Invalidate(bool polygonsChanged)
if (extrudeMode == ExtrudeMode.RevolveShape && project.revolveSpiralSloped && project.globalPivot.position.y != 0)
this.IsNoCSG = true;

// force nocsg when using concave brushes as sabrecsg doesn't support it.
if (!project.convexBrushes)
this.IsNoCSG = true;

// nothing to do except copy csg information to our child brushes.
if (!isDirty)
{
for (int i = 0; i < BrushCount; i++)
for (int i = 0; i < (project.convexBrushes ? desiredBrushCount : 1); i++)
{
generatedBrushes[i].Mode = this.Mode;
generatedBrushes[i].IsNoCSG = this.IsNoCSG;
Expand All @@ -175,16 +183,22 @@ public override void Invalidate(bool polygonsChanged)
if (m_LastBuiltPolygons == null)
m_LastBuiltPolygons = BuildConvexPolygons();

// prepare a list of polygons for concave brushes.
List<Polygon> concavePolygons = null;
if (!project.convexBrushes)
concavePolygons = new List<Polygon>();

// iterate through the brushes we received:
int brushCount = BrushCount;
int brushCount = desiredBrushCount;

// iterate through the brushes we received:
for (int i = 0; i < brushCount; i++)
{
// copy our csg information to our child brushes.
generatedBrushes[i].Mode = this.Mode;
generatedBrushes[i].IsNoCSG = this.IsNoCSG;
generatedBrushes[i].IsVisible = this.IsVisible;
generatedBrushes[i].HasCollision = this.HasCollision;
generatedBrushes[project.convexBrushes ? i : 0].Mode = this.Mode;
generatedBrushes[project.convexBrushes ? i : 0].IsNoCSG = this.IsNoCSG;
generatedBrushes[project.convexBrushes ? i : 0].IsVisible = this.IsVisible;
generatedBrushes[project.convexBrushes ? i : 0].HasCollision = this.HasCollision;

// local variables.
Quaternion rot;
Expand All @@ -198,7 +212,11 @@ public override void Invalidate(bool polygonsChanged)
GenerateUvCoordinates(m_LastBuiltPolygons[i], false);
Polygon poly1 = m_LastBuiltPolygons[i].DeepCopy();
poly1.Flip();
generatedBrushes[i].SetPolygons(new Polygon[] { poly1 });

if (project.convexBrushes)
generatedBrushes[i].SetPolygons(new Polygon[] { poly1 });
else
concavePolygons.Add(poly1);
break;

// generate 3d cube-ish shapes that revolve around the pivot and spirals up or down.
Expand Down Expand Up @@ -254,7 +272,10 @@ public override void Invalidate(bool polygonsChanged)
GenerateUvCoordinates(backPoly, false);
polygons.Add(backPoly);

generatedBrushes[i].SetPolygons(polygons.ToArray());
if (project.convexBrushes)
generatedBrushes[i].SetPolygons(polygons.ToArray());
else
concavePolygons.AddRange(polygons);
break;

// generate a 3d cube-ish shape.
Expand All @@ -263,7 +284,10 @@ public override void Invalidate(bool polygonsChanged)
SurfaceUtility.ExtrudePolygon(m_LastBuiltPolygons[i], project.extrudeDepth, out outputPolygons, out rot);
foreach (Polygon poly in outputPolygons)
GenerateUvCoordinates(poly, false);
generatedBrushes[i].SetPolygons(outputPolygons);
if (project.convexBrushes)
generatedBrushes[i].SetPolygons(outputPolygons);
else
concavePolygons.AddRange(outputPolygons);
break;

// generate a 3d cone-ish shape.
Expand All @@ -272,7 +296,10 @@ public override void Invalidate(bool polygonsChanged)
ExtrudePolygonToPoint(m_LastBuiltPolygons[i], project.extrudeDepth, new Vector2((project.globalPivot.position.x * project.extrudeScale.x) / 8.0f, -(project.globalPivot.position.y * project.extrudeScale.y) / 8.0f), out outputPolygons, out rot);
foreach (Polygon poly in outputPolygons)
GenerateUvCoordinates(poly, false);
generatedBrushes[i].SetPolygons(outputPolygons);
if (project.convexBrushes)
generatedBrushes[i].SetPolygons(outputPolygons);
else
concavePolygons.AddRange(outputPolygons);
break;

// generate a 3d trapezoid-ish shape.
Expand All @@ -281,7 +308,10 @@ public override void Invalidate(bool polygonsChanged)
ExtrudePolygonBevel(m_LastBuiltPolygons[i], project.extrudeDepth, project.extrudeClipDepth / project.extrudeDepth, new Vector2((project.globalPivot.position.x * project.extrudeScale.x) / 8.0f, -(project.globalPivot.position.y * project.extrudeScale.y) / 8.0f), out outputPolygons, out rot);
foreach (Polygon poly in outputPolygons)
GenerateUvCoordinates(poly, false);
generatedBrushes[i].SetPolygons(outputPolygons);
if (project.convexBrushes)
generatedBrushes[i].SetPolygons(outputPolygons);
else
concavePolygons.AddRange(outputPolygons);
break;
}

Expand All @@ -293,42 +323,83 @@ public override void Invalidate(bool polygonsChanged)
// it also excludes a couple faces that CSG doesn't exclude due to floating point precision errors.
// the latter is especially noticable with complex revolved shapes.

// compare each brush to another brush:
for (int i = 0; i < brushCount; i++)
// hidden surface removal for convex brushes.
if (project.convexBrushes)
{
for (int j = 0; j < brushCount; j++)
// compare each brush to another brush:
for (int i = 0; i < brushCount; i++)
{
// can't check for hidden faces on the same brush.
if (i == j) continue;

// compare each polygon on brush i to each polygon on brush j:
foreach (Polygon pa in generatedBrushes[i].GetPolygons())
for (int j = 0; j < brushCount; j++)
{
foreach (Polygon pb in generatedBrushes[j].GetPolygons())
// can't check for hidden faces on the same brush.
if (i == j) continue;

// compare each polygon on brush i to each polygon on brush j:
foreach (Polygon pa in generatedBrushes[i].GetPolygons())
{
// check they both have this polygon:
bool identical = true;
foreach (Vertex va in pa.Vertices)
foreach (Polygon pb in generatedBrushes[j].GetPolygons())
{
if (!pb.Vertices.Any(vb => vb.Position == va.Position))
// check they both have this polygon:
bool identical = true;
foreach (Vertex va in pa.Vertices)
{
if (!pb.Vertices.Any(vb => vb.Position == va.Position))
{
identical = false;
break;
}
}
// identical polygons on both brushes means it can be excluded:
if (identical)
{
identical = false;
break;
pa.UserExcludeFromFinal = true;
pb.UserExcludeFromFinal = true;
}
}
// identical polygons on both brushes means it can be excluded:
if (identical)
}
}

// invalidate every brush.
generatedBrushes[i].Invalidate(true);
csgBounds.Encapsulate(generatedBrushes[i].GetBounds());
}
}

// hidden surface removal for a concave brush.
else
{
List<Polygon> concavePolygonsCopy = concavePolygons.ToList();

// compare each polygon and find duplicates:
foreach (Polygon pa in concavePolygonsCopy)
{
foreach (Polygon pb in concavePolygonsCopy)
{
// can't be the same polygon.
if (pa == pb) continue;

// check they both have this polygon:
bool identical = true;
foreach (Vertex va in pa.Vertices)
{
if (!pb.Vertices.Any(vb => vb.Position == va.Position))
{
pa.UserExcludeFromFinal = true;
pb.UserExcludeFromFinal = true;
identical = false;
break;
}
}
// identical polygons on both brushes means it can be excluded:
if (identical)
{
concavePolygons.Remove(pa);
concavePolygons.Remove(pb);
}
}
}

// invalidate every brush.
generatedBrushes[i].Invalidate(true);
csgBounds.Encapsulate(generatedBrushes[i].GetBounds());
// invalidate the brush.
generatedBrushes[0].SetPolygons(concavePolygons.ToArray());
csgBounds.Encapsulate(generatedBrushes[0].GetBounds());
}

// apply the generated csg bounds.
Expand Down

0 comments on commit e2e2fa0

Please sign in to comment.