Open Henry00IS opened 1 year ago
This is a functional prototype / proof of concept of Bounty.cs written by me. But it's not perfect, it will fail when the front or back scale of a "scaled extrude" is zero (a pyramid shape). It's also pretty hacky with LINQ.
using AeternumGames.ShapeEditor;
using InternalRealtimeCSG;
using RealtimeCSG.Components;
using RealtimeCSG.Legacy;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Shape = RealtimeCSG.Legacy.Shape;
namespace RealtimeCSG
{
public static class Bounty
{
public static CSGBrush CreateBrushFromPolygonMesh(Transform parent, string brushName, PolygonMesh mesh)
{
foreach (var polygon in mesh)
{
polygon.Reverse();
}
var controlMesh = new ControlMesh();
//// control mesh polygons:
int edgeIndex = 0;
controlMesh.Polygons = new Legacy.Polygon[mesh.Count];
for (int i = 0; i < mesh.Count; i++)
{
controlMesh.Polygons[i] = new Legacy.Polygon(new int[mesh[i].Count], i);
for (int j = 0; j < mesh[i].Count; j++)
{
controlMesh.Polygons[i].EdgeIndices[j] = edgeIndex;
edgeIndex++;
}
}
//// control mesh vertices:
var vertices = new List<Vector3>();
foreach (var polygon in mesh)
{
foreach (var vertex in polygon)
{
vertices.Add(vertex.position);
}
}
controlMesh.Vertices = vertices.Distinct().ToArray();
//// control mesh half edges:
var edges = new List<HalfEdge>();
for (short i = 0; i < mesh.Count; i++)
{
var polygon = mesh[i];
for (int j = 0; j < polygon.Count; j++)
{
var vertex = polygon[j];
var vertexIndex = (short)vertices.FindIndex(v => v.EqualsWithEpsilon5(vertex.position));
edges.Add(new HalfEdge { PolygonIndex = i, VertexIndex = vertexIndex, TwinIndex = -1 });
}
}
controlMesh.Edges = edges.ToArray();
//// control mesh half edge twin association:
var twn = 0;
for (short i = 0; i < mesh.Count; i++)
{
var polygon = mesh[i];
for (int j = 0; j < polygon.Count; j++)
{
var previous = polygon.PreviousVertex(j);
var current = polygon[j];
var cnt = 0;
for (short z = 0; z < mesh.Count; z++)
{
var polygon2 = mesh[z];
for (int k = 0; k < polygon2.Count; k++)
{
cnt++;
if (i == z) continue;
var previous2 = polygon2.PreviousVertex(k);
var current2 = polygon2[k];
if (previous2.position.EqualsWithEpsilon5(current.position) && current2.position.EqualsWithEpsilon5(previous.position))
{
controlMesh.Edges[twn].TwinIndex = cnt - 1;
}
}
}
twn++;
}
}
//// shape:
var shape = new Shape();
var material = CSGSettings.DefaultMaterial;
var polygonCount = mesh.Count;
shape.Surfaces = new Surface[polygonCount];
shape.TexGens = new TexGen[polygonCount];
shape.TexGenFlags = new TexGenFlags[polygonCount];
for (int i = 0; i < polygonCount; i++)
{
shape.Surfaces[i].TexGenIndex = i;
shape.Surfaces[i].Plane = GeometryUtility.CalcPolygonPlane(controlMesh, (short)i);
GeometryUtility.CalculateTangents(shape.Surfaces[i].Plane.normal, out shape.Surfaces[i].Tangent, out shape.Surfaces[i].BiNormal);
shape.TexGens[i].RenderMaterial = material;
shape.TexGens[i].Scale = MathConstants.oneVector3;
shape.TexGenFlags[i] = CSGSettings.DefaultTexGenFlags;
}
ShapeUtility.EnsureInitialized(shape);
controlMesh.Valid = ControlMeshUtility.Validate(controlMesh, shape);
if (controlMesh.Valid)
{
Debug.Log("The control mesh is valid!");
}
return BrushFactory.CreateBrush(parent, brushName, controlMesh, shape);
}
}
}
Background
In RealtimeCSG, brushes (convex meshes) are represented using the half-edge data structure (see here).
At the moment we convert all of the polygons of a generated convex mesh into planes and then feed those into a RealtimeCSG function that converts a set of planes into a brush. But converting planes (finding the intersection point of 3 planes, where sometimes there are infinite intersections) into a convex mesh is a difficult problem. That's why it often fails and has stability problems.
Your task
Build a function that can take a
PolygonMesh
(see here) and build a brush in the scene, by callingBrushFactory.CreateBrush
(see here). This requires generating the half-edge connectivity data.Files
The C# function has been prepared and only needs contents. Here is a special version of the 2D Shape Editor that you can add as a package:
com.aeternumgames.shapeeditor.zip
Here is the Bounty.cs file, place this file in your RealtimeCSG installation (in your Assets directory):
RealtimeCSGBounty.zip
Try extruding using "RealtimeCSG -> Create Bevel" and you will get a notification in the console window that leads you to the function that needs to be written.
Tips
PolygonMesh
is just aList
ofPolygon
. They are convex n-gons (no triangulation) without duplicate normals.