Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Split CSG Mesh

Discussion in 'World Building' started by Plummers, Apr 12, 2020.

  1. Plummers

    Plummers

    Joined:
    Oct 29, 2015
    Posts:
    35
    Hi,
    I have a mesh that is cut into two parts by subtraction using the CSG tool. Is there a way to split this "cut" mesh into two different meshes?

    Thanks in advance
     
  2. Plummers

    Plummers

    Joined:
    Oct 29, 2015
    Posts:
    35
    Solved.

    Found a way looping through the vertices of the whole mesh to get the "cut" parts out and then create a new gameobject for each of them. Seems to work well.
     
  3. Vsion-Studio

    Vsion-Studio

    Joined:
    Oct 7, 2019
    Posts:
    4
    Hi Plummers
    I'm interested in the same thing. I've used the CSG tool from this repo: https://github.com/karl-/pb_CSG
    and I also want to separate the meshes when are split with substraction.

    Can you please detail a little bit more the solution you found?
    Thanks!
     
    Plummers likes this.
  4. Plummers

    Plummers

    Joined:
    Oct 29, 2015
    Posts:
    35
    Hi,

    It's been a while since I was playing around with this, it's pretty cool when it works. Here's my code I found for splitting the mesh. Let me know if this makes sense, I can help further if I put my brain to it! Cheers

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using UnityEngine.ProBuilder.MeshOperations;
    4. using UnityEngine.ProBuilder;
    5.  
    6. public class splitMesh : MonoBehaviour
    7. {
    8.     public Material invisible;
    9.     public List<GameObject> SplitMesh(GameObject whole)
    10.     {
    11.         List<GameObject> results = new List<GameObject>();
    12.  
    13.         MeshRenderer meshRenderer = whole.GetComponent<MeshRenderer>();
    14.         Mesh mesh = whole.GetComponent<MeshFilter>().mesh;
    15.         bool destroy = false;
    16.         int[] indices = mesh.triangles;
    17.         Vector3[] verts = mesh.vertices;
    18.         List<Vector3> newVerts = new List<Vector3>();
    19.         List<Vector3> vertList = new List<Vector3>(verts);
    20.  
    21.         int count = 0;
    22.         while (vertList.Count > 0)
    23.         {
    24.             count++;
    25.             newVerts.Clear();
    26.             newVerts.Add(vertList[0]);
    27.             newVerts.Add(vertList[1]);
    28.             newVerts.Add(vertList[2]);
    29.             for (int i = 3; i < vertList.Count; i += 3)
    30.             {
    31.                 bool check = false;
    32.                 for (int j = 0; j < 3 && !check; j++)
    33.                 {
    34.                    for (int v = 0; v < newVerts.Count && !check;v++)
    35.                     {
    36.                         if (newVerts[v] == vertList[i + j])
    37.                         {
    38.                             check = true;
    39.                         }
    40.                     }
    41.                 }
    42.                 if (check)
    43.                 {
    44.                     for (int k = 0; k < 3; k++)
    45.                     {
    46.                         newVerts.Add(vertList[i + k]);
    47.                     }
    48.                     for (int k = 0; k < 3; k++)
    49.                     {
    50.                         vertList.RemoveAt(i + 2 - k);
    51.                     }
    52.                     i = 0;
    53.                 }
    54.             }
    55.             vertList.RemoveAt(0);
    56.             vertList.RemoveAt(0);
    57.             vertList.RemoveAt(0);
    58.             Vector3[] vertsR = new Vector3[newVerts.Count];
    59.             List<int> indR = new List<int>();
    60.             for (int i = 0; i < newVerts.Count; i++)
    61.             {
    62.                 vertsR[i] = newVerts[i];
    63.                 indR.Add(indices[i]);
    64.             }
    65.             Mesh newMeshGG = new Mesh();
    66.             newMeshGG.vertices = vertsR;
    67.             newMeshGG.triangles = indR.ToArray();
    68.  
    69.             newMeshGG.RecalculateNormals();
    70.             if (vertList.Count == 0 && count == 1)
    71.             {
    72.                 results.Add(whole);
    73.             }
    74.             else
    75.             {
    76.                 GameObject gg = new GameObject("newGameObject");
    77.                 gg.transform.SetParent(whole.transform.parent);
    78.                 gg.AddComponent<MeshRenderer>().material = invisible;
    79.                 gg.GetComponent<MeshRenderer>().enabled = false;
    80.                 gg.AddComponent<MeshFilter>().mesh = newMeshGG;
    81.                 ProBuilderizeShape(gg);
    82.                 results.Add(gg);
    83.                 destroy = true;
    84.             }
    85.  
    86.         }
    87.  
    88.         if (destroy)
    89.         {
    90.             Destroy(whole);
    91.         }
    92.  
    93.         return results;
    94.     }
    95.  
    96.     public void ProBuilderizeShape(GameObject shape)
    97.     {
    98.         var filter = shape.GetComponent<MeshFilter>();
    99.         // Add a new uninitialized pb_Object
    100.         var mesh2 = shape.AddComponent<ProBuilderMesh>();
    101.         // Create a new MeshImporter
    102.         var importer = new MeshImporter(mesh2);
    103.         // Import from a GameObject. In this case we're loading and assigning to the same GameObject, but you may
    104.         // load and apply to different Objects as well.
    105.         importer.Import(filter.sharedMesh);
    106.         // Since we're loading and setting from the same object, it is necessary to create a new mesh to avoid
    107.         // overwriting the mesh that is being read from.
    108.         filter.sharedMesh = new Mesh();
    109.         // Apply the imported geometry to the pb_Object
    110.         mesh2.ToMesh();
    111.         // Rebuild UVs, Collisions, Tangents, etc.
    112.         mesh2.Refresh();
    113.         mesh2.CenterPivot(null);
    114.     }
    115. }
     
    Vsion-Studio likes this.
  5. Vsion-Studio

    Vsion-Studio

    Joined:
    Oct 7, 2019
    Posts:
    4
    Hi!
    I've been trying your code and it works fine for my needs. Thank you very much!
     
    Plummers likes this.
  6. Spectra_7

    Spectra_7

    Joined:
    Oct 17, 2017
    Posts:
    33
    Hello Plummers.

    Thanks a lot for the code. It works pretty good.
    One problem I am facing is that, the CPU freezes in between.

    Is there any way to improve performance like using Compute Shaders, etc?
     
    Last edited: Mar 10, 2021
  7. Plummers

    Plummers

    Joined:
    Oct 29, 2015
    Posts:
    35
    Hi Spectra_7,
    Cool, happy you got it working. As for performance I'm not sure, I remember that the ProBuilder guys were maybe working on improving their split function because it was in early testing.

    Good luck