private GameObject Boolean(BoolOp operation) { Reset(main_object, operating_object); current_operation = TransfOp.Spectate; UpdateTransformationButtons(); Mesh m; if (CSG_operation_history.Count == 0) { StoreCurrentState("start", main_object); } switch (operation) { case BoolOp.Union: StoreCurrentState("transformation", main_object); StoreCurrentState("union", operating_object); m = CSG.Union(main_object, operating_object); break; case BoolOp.Subtract: StoreCurrentState("transformation", main_object); StoreCurrentState("subtract", operating_object); m = CSG.Subtract(main_object, operating_object); break; case BoolOp.Intersect: default: StoreCurrentState("transformation", main_object); StoreCurrentState("intersect", operating_object); m = CSG.Intersect(main_object, operating_object); break; } composite = new GameObject(); composite.name = "Constructed CSG"; composite.AddComponent <MeshFilter>().sharedMesh = m; composite.AddComponent <MeshRenderer>().sharedMaterial = materials[material_ID]; // Generate new mesh Mesh mesh = ConstructMesh(composite); // Generate new meshcollider composite.AddComponent <MeshCollider>(); composite.GetComponent <MeshCollider>().sharedMesh = mesh; // Change tag composite.tag = "csg"; Destroy(main_object); Destroy(operating_object); main_object = null; operating_object = null; // Switch new composited object to main object return(composite); }
void Boolean(BoolOp operation) { Mesh m = new Mesh(); switch (operation) { case BoolOp.Union: m = CSG.Union(first, second); break; case BoolOp.Subtract: m = CSG.Subtract(first, second); break; case BoolOp.Intersect: m = CSG.Intersect(first, second); break; } composite = new GameObject(); composite.AddComponent <MeshFilter>().mesh = m; composite.AddComponent <MeshRenderer>().material = first.GetComponent <MeshRenderer>().material; GenerateBarycentric(composite); }
// Use this for initialization void Start() { /* * // Create new GameObject * GameObject newObject = new GameObject(); * newObject.transform.localScale*=2f; * MeshFilter meshFilter = newObject.AddComponent<MeshFilter>(); * MeshRenderer meshRenderer = newObject.AddComponent<MeshRenderer>(); * meshRenderer.materials = new Material[2]{meshColliderA.transform.GetComponent<Renderer>().materials[0],meshColliderB.transform.GetComponent<Renderer>().materials[0]}; * * // Assign booleanMesh * BooleanMesh booleanMesh = new BooleanMesh(meshColliderA,meshColliderB); * //meshFilter.mesh = booleanMesh.Difference(); * //meshFilter.mesh = booleanMesh.Union(); * meshFilter.mesh = booleanMesh.Intersection(); */ GameObject newObject = new GameObject(); var meshFilter = newObject.AddComponent <MeshFilter>(); var meshRenderer = newObject.AddComponent <MeshRenderer>(); meshRenderer.materials = new Material[2] { meshColliderA.transform.GetComponent <Renderer>().materials[0], meshColliderB.transform.GetComponent <Renderer>().materials[0] }; meshFilter.mesh = CSG.Intersect(meshColliderA, meshColliderB); }
public void T06_IntersectingARayWithACSGObjectMiss() { CSG c = new CSG(CSG.Operation.Union, new Sphere(), new Cube()); Ray r = new Ray(new Point(0, 2, -5), new Vector(0, 0, 1)); List <Intersection> xs = c.Intersect(r); Assert.IsEmpty(xs); }
public void TestCsgRayMisses() { var c = new CSG(CsgOperation.Union, new Sphere(), new Cube()); var r = new Ray(new Point(0, 2, -5), Vector.VectorZ); var xs = c.Intersect(r); Assert.AreEqual(xs.Count, 0); }
public static GameObject GetIntersection(GameObject obj, GameObject hemisphere, Material truncatedMaterial, bool disableHemispheres) { GameObject cube = hemisphere.transform.Find("GuideCube").gameObject; Vector3 size = cube.transform.lossyScale; size.x -= 0.01F; size.y -= 0.01F; size.z -= 0.01F; //check if there is indeed area that is overlapping between the two objects Collider[] hitColliders = Physics.OverlapBox(cube.transform.position, size / 2, cube.transform.rotation); bool isColliding = false; foreach (Collider col in hitColliders) { if (col.gameObject == obj) { isColliding = true; } } if (!isColliding) { hemisphere.gameObject.SetActive(false); obj.gameObject.SetActive(false); return(null); } Vector3 position; position = obj.transform.position; obj.transform.position = new Vector3(0, 0, 0); hemisphere.transform.position = obj.transform.position; Mesh n = CSG.Intersect(cube, obj); n.name = "Truncated Sphere"; GameObject final = new GameObject("Final"); final.AddComponent <MeshFilter>().sharedMesh = n; final.AddComponent <MeshRenderer>().sharedMaterial = truncatedMaterial; final.AddComponent <MeshCollider>(); final.GetComponent <MeshCollider>().sharedMesh = n; obj.transform.position = position; hemisphere.transform.position = position; final.transform.position = position; final.layer = LayerMask.NameToLayer("final"); final.tag = "Final"; //GameObject VectorLineObj = DrawHemisphereLines(final, "final"); //VectorLineObj.transform.parent = final.transform; //VectorLineObj.name = "HemiLine"; if (disableHemispheres) { obj.GetComponent <MeshRenderer>().enabled = false; hemisphere.GetComponent <MeshRenderer>().enabled = false; } return(final); }
public GameObject Intersect(GameObject s0, GameObject s1) { Mesh m = CSG.Intersect(s0, s1); GameObject composite = new GameObject(); composite.transform.parent = mainObj.transform; composite.AddComponent <MeshFilter>().sharedMesh = m; composite.AddComponent <MeshRenderer>().sharedMaterial = s0.GetComponent <MeshRenderer>().sharedMaterial; return(composite); }
public void TestCsgBBIntersectHit() { var left = new TestShape(); var right = new TestShape(); var shape = new CSG(CsgOperation.Difference, left, right); var r = new Ray(new Point(0, 0, -5), new Vector(0, 0, 1)); var xs = shape.Intersect(r); Assert.IsNotNull(left.SavedRay); Assert.IsNotNull(right.SavedRay); }
// Use this for initialization void Start() { // Initialize two new meshes in the scene GameObject numbers = GameObject.Find("twoNum"); GameObject ring = GameObject.Find("ring"); // Perform boolean operation Mesh m = CSG.Intersect(ring, numbers); // Create a gameObject to render the result composite = new GameObject(); composite.AddComponent <MeshFilter>().mesh = m; composite.AddComponent <MeshRenderer>().sharedMaterial = ring.GetComponent <MeshRenderer>().sharedMaterial; }
public static void CreateHemisphereMesh() { GameObject Sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); GameObject Cube = GameObject.CreatePrimitive(PrimitiveType.Cube); Cube.transform.localScale = new Vector3(2, 2, 2); Sphere.transform.position = new Vector3(0, 0, 0); Cube.transform.position = new Vector3(1, 0, 0); GameObject.Destroy(Sphere); GameObject.Destroy(Cube); Mesh m = CSG.Intersect(Sphere, Cube); m.name = "Hemisphere Mesh"; hemisphereMesh = m; }
public void TestCsgRayHits() { var s1 = new Sphere(); var s2 = new Sphere(); s2.Transform = Matrix.Translation(0, 0, 0.5); var c = new CSG(CsgOperation.Union, s1, s2); var r = new Ray(new Point(0, 0, -5), Vector.VectorZ); var xs = c.Intersect(r); Assert.AreEqual(xs.Count, 2); Assert.AreEqual(xs[0].t, 4, epsilon); Assert.AreEqual(xs[0].Object, s1); Assert.AreEqual(xs[1].t, 6.5, epsilon); Assert.AreEqual(xs[1].Object, s2); }
public void T07_IntersectingARayWithACSGObjectHit() { Sphere s1 = new Sphere(); Sphere s2 = new Sphere(); s2.SetMatrix(Mat4.TranslateMatrix(0, 0, 0.5)); CSG c = new CSG(CSG.Operation.Union, s1, s2); Ray r = new Ray(new Point(0, 0, -5), new Vector(0, 0, 1)); List <Intersection> xs = c.Intersect(r); Assert.AreEqual(2, xs.Count); Assert.IsTrue(Utility.FE(4, xs[0].t)); Assert.AreEqual(s1, xs[0].rayObject); Assert.IsTrue(Utility.FE(6.5, xs[1].t)); Assert.AreEqual(s2, xs[1].rayObject); }
static ActionResult MenuBooleanOperation(BooleanOperation operation, ProBuilderMesh lhs, ProBuilderMesh rhs) { if (lhs == null || rhs == null) { return(new ActionResult(ActionResult.Status.Failure, "Must Select 2 Objects")); } string op_string = operation == BooleanOperation.Union ? "Union" : (operation == BooleanOperation.Subtract ? "Subtract" : "Intersect"); ProBuilderMesh[] sel = new ProBuilderMesh[] { lhs, rhs }; UndoUtility.RecordSelection(sel, op_string); UnityEngine.ProBuilder.Csg.Model result; switch (operation) { case BooleanOperation.Union: result = CSG.Union(lhs.gameObject, rhs.gameObject); break; case BooleanOperation.Subtract: result = CSG.Subtract(lhs.gameObject, rhs.gameObject); break; default: result = CSG.Intersect(lhs.gameObject, rhs.gameObject); break; } var materials = result.materials.ToArray(); ProBuilderMesh pb = ProBuilderMesh.Create(); pb.GetComponent <MeshFilter>().sharedMesh = (Mesh)result; pb.GetComponent <MeshRenderer>().sharedMaterials = materials; MeshImporter importer = new MeshImporter(pb.gameObject); importer.Import(new MeshImportSettings() { quads = true, smoothing = true, smoothingAngle = 1f }); pb.Rebuild(); pb.CenterPivot(null); Selection.objects = new Object[] { pb.gameObject }; return(new ActionResult(ActionResult.Status.Success, op_string)); }
static ActionResult MenuBooleanOperation(BooleanOperation operation, ProBuilderMesh lhs, ProBuilderMesh rhs) { if (lhs == null || rhs == null) { return(new ActionResult(ActionResult.Status.Failure, "Must Select 2 Objects")); } string op_string = operation == BooleanOperation.Union ? "Union" : (operation == BooleanOperation.Subtract ? "Subtract" : "Intersect"); ProBuilderMesh[] sel = new ProBuilderMesh[] { lhs, rhs }; UndoUtility.RecordSelection(sel, op_string); Mesh c; switch (operation) { case BooleanOperation.Union: c = CSG.Union(lhs.gameObject, rhs.gameObject); break; case BooleanOperation.Subtract: c = CSG.Subtract(lhs.gameObject, rhs.gameObject); break; default: c = CSG.Intersect(lhs.gameObject, rhs.gameObject); break; } GameObject go = new GameObject(); go.AddComponent <MeshRenderer>().sharedMaterial = EditorMaterialUtility.GetUserMaterial(); go.AddComponent <MeshFilter>().sharedMesh = c; ProBuilderMesh pb = InternalMeshUtility.CreateMeshWithTransform(go.transform, false); DestroyImmediate(go); Selection.objects = new Object[] { pb.gameObject }; return(new ActionResult(ActionResult.Status.Success, op_string)); }
void Boolean(BoolOp operation) { Mesh m; /** * All boolean operations accept two gameobjects and return a new mesh. * Order matters - left, right vs. right, left will yield different * results in some cases. */ switch (operation) { case BoolOp.Union: m = CSG.Union(left, right); break; case BoolOp.SubtractLR: m = CSG.Subtract(left, right); break; case BoolOp.SubtractRL: m = CSG.Subtract(right, left); break; case BoolOp.Intersect: default: m = CSG.Intersect(right, left); break; } composite = new GameObject(); composite.AddComponent <MeshFilter>().sharedMesh = m; composite.AddComponent <MeshRenderer>().sharedMaterial = left.GetComponent <MeshRenderer>().sharedMaterial; GenerateBarycentric(composite); GameObject.Destroy(left); GameObject.Destroy(right); }
public void BooleanOp_WithReallySmallEpsilon_DoesNotCrash([ValueSource(nameof(BooleanOps))] CSG.BooleanOp op) { CSG.epsilon = 0.00000001f; Assert.DoesNotThrow(() => { CSG.Intersect(m_InputA, m_InputA); }); }
public void Rebuild() { // If there's an existing MeshGroup object, get rid of it if (transform.FindChild("MeshGroup") != null) { DestroyImmediate(transform.FindChild("MeshGroup").gameObject); } if (brushes != null && brushes.Count > 0) { // Ensure any brush objects that have been deleted by the user are removed from the brush sequence for (int i = 0; i < brushes.Count; i++) { if (brushes[i] == null) { brushes.RemoveAt(i); i--; } } CSG current = null; // Iterate through each brush in sequence for (int i = 0; i < brushes.Count; i++) { Brush.CSGMode mode = brushes[i].Mode; // Generate the CSG geometry for the brush CSG brushGeometry = brushes[i].GenerateCSG(); brushGeometry.SetShared(brushes[i].SharedBrushData); if (i == 0) { // The first brush is always added to the space (rather than subtracted) current = brushGeometry; } else { // For every brush after the first one, carry out the correct operation if (mode == Brush.CSGMode.Subtract) { current = current.Subtract(brushGeometry); } else if (mode == Brush.CSGMode.Union) { current = current.Union(brushGeometry); } else if (mode == Brush.CSGMode.Intersect) { current = current.Intersect(brushGeometry); } } } // Now that the final CSG has been calculated, fetch the polygons (mixture of triangles and quads) Polygon[] polygons = current.Polygons; // Create polygon subsets for each material Dictionary <Material, List <Polygon> > polygonMaterialTable = new Dictionary <Material, List <Polygon> >(); // Iterate through every polygon adding it to the appropiate material list foreach (Polygon polygon in current.Polygons) { Material material = ((SharedBrushData)polygon.Shared).Material; if (!polygonMaterialTable.ContainsKey(material)) { polygonMaterialTable.Add(material, new List <Polygon>()); } polygonMaterialTable[material].Add(polygon); } // Create a grouping object which will act as a parent for all the per material meshes meshGroup = new GameObject("MeshGroup"); meshGroup.transform.parent = this.transform; // Create a separate mesh for polygons of each material so that we batch by material foreach (KeyValuePair <Material, List <Polygon> > polygonMaterialGroup in polygonMaterialTable) { Mesh mesh = new Mesh(); List <Vector3> vertices = new List <Vector3>(); List <Vector3> normals = new List <Vector3>(); List <Vector2> uvs = new List <Vector2>(); List <Color> colors = new List <Color>(); List <int> triangles = new List <int>(); // Setup an indexer that tracks unique vertices, so that we reuse vertex data appropiately Indexer indexer = new Indexer(); // Iterate through every polygon and triangulate foreach (Polygon polygon in polygonMaterialGroup.Value) { List <int> indices = new List <int>(); for (int i = 0; i < polygon.Vertices.Length; i++) { // Each vertex must know about its shared data for geometry tinting polygon.Vertices[i].Shared = polygon.Shared; // If the vertex is already in the indexer, fetch the index otherwise add it and get the added index int index = indexer.Add(polygon.Vertices[i]); // Put each vertex index in an array for use in the triangle generation indices.Add(index); } // Triangulate the n-sided polygon and allow vertex reuse by using indexed geometry for (int i = 2; i < indices.Count; i++) { triangles.Add(indices[0]); triangles.Add(indices[i - 1]); triangles.Add(indices[i]); } } // Create the relevant buffers from the vertex array for (int i = 0; i < indexer.Vertices.Count; i++) { vertices.Add(indexer.Vertices[i].Position); normals.Add(indexer.Vertices[i].Normal); uvs.Add(indexer.Vertices[i].UV); colors.Add(((SharedBrushData)indexer.Vertices[i].Shared).BrushTintColor); } // Set the mesh buffers mesh.vertices = vertices.ToArray(); mesh.normals = normals.ToArray(); mesh.colors = colors.ToArray(); mesh.uv = uvs.ToArray(); mesh.triangles = triangles.ToArray(); // Optionally you can turn these on to ensure normals are correct and also generate tangents // mesh.RecalculateNormals(); // GenerateTangents(mesh); GameObject materialMesh = new GameObject("MaterialMesh", typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider)); materialMesh.transform.parent = meshGroup.transform; // Set the mesh to be rendered materialMesh.GetComponent <MeshFilter>().mesh = mesh; // Set the collision mesh materialMesh.GetComponent <MeshCollider>().sharedMesh = mesh; materialMesh.renderer.material = polygonMaterialGroup.Key; } } }