Unity - How to set the color of an individual face when clicking a mesh? - unity3d

Yesterday others on Stack Overflow helped me determine how to recolor a mesh triangle to red by clicking on it, it works great, the only problem is that the 3 vertices that get recolored are shared between triangles. This results in coloration that looks rather smeared. I'm really hoping there's a way to color only a single face (or normal if you will).
I've attached the following script to my mesh that uses a raycast to determine the surface coordinate and translate a green cube there. The gif below will better illustrate this problem.
Once again, any help or insight into this would be greatly appreciated. Thanks!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyRayDraw : MonoBehaviour
{
public GameObject cube;
private MeshRenderer meshRenderer;
Mesh mesh;
Vector3[] vertices;
Color[] colorArray;
private void Start()
{
mesh = transform.GetComponent<MeshFilter>().mesh;
vertices = mesh.vertices;
colorArray = new Color[vertices.Length];
for (int k = 0; k < vertices.Length; k++)
{
colorArray[k] = Color.white;
}
mesh.colors = colorArray;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit))
{
Snap(hit.point); // Moves the green cube
int[] triangles = mesh.triangles;
var vertIndex1 = triangles[hit.triangleIndex * 3 + 0];
var vertIndex2 = triangles[hit.triangleIndex * 3 + 1];
var vertIndex3 = triangles[hit.triangleIndex * 3 + 2];
colorArray[vertIndex1] = Color.red;
colorArray[vertIndex2] = Color.red;
colorArray[vertIndex3] = Color.red;
mesh.colors = colorArray;
}
else
{
Debug.Log("no hit");
}
}
}
}

As you say the issue is that the vertices are shared between triangles but coloring is always vertex based.
The idea for a solution is:
for each vertex of the hit triangle check if it is used by other triangles
if so copy its position to create a new separated vertex
update the triangle to use the newly created vertex indices
(evtl.) use RecalculateNormals to make the triangles face outside without having to care about the order of provided vertices
using System.Linq;
using UnityEngine;
public class MyRayDraw : MonoBehaviour
{
public GameObject cube;
// Better to reference those already in the Inspector
[SerializeField] private MeshFilter meshFilter;
[SerializeField] private MeshRenderer meshRenderer;
[SerializeField] private MeshCollider meshCollider;
private Mesh _mesh;
private void Awake()
{
if (!meshFilter) meshFilter = GetComponent<MeshFilter>();
if (!meshRenderer) meshRenderer = GetComponent<MeshRenderer>();
if (!meshCollider) meshCollider = GetComponent<MeshCollider>();
_mesh = meshFilter.mesh;
// create new colors array where the colors will be created
var colors = new Color[_mesh.vertices.Length];
for (var k = 0; k < colors.Length; k++)
{
colors[k] = Color.white;
}
_mesh.colors = colors;
}
private void Update()
{
if (!Input.GetMouseButtonDown(0)) return;
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out var hit))
{
Debug.Log(hit.triangleIndex);
//cube.transform.position = hit.point;
// Get current vertices, triangles and colors
var vertices = _mesh.vertices;
var triangles = _mesh.triangles;
var colors = _mesh.colors;
// Get the vert indices for this triangle
var vert1Index = triangles[hit.triangleIndex * 3 + 0];
var vert2Index = triangles[hit.triangleIndex * 3 + 1];
var vert3Index = triangles[hit.triangleIndex * 3 + 2];
// Get the positions for the vertices
var vert1Pos = vertices[vert1Index];
var vert2Pos = vertices[vert2Index];
var vert3Pos = vertices[vert3Index];
// Now for all three vertices we first check if any other triangle if using it
// by simply count how often the indices are used in the triangles list
var vert1Occurrences = 0;
var vert2Occurrences = 0;
var vert3Occurrences = 0;
foreach (var index in triangles)
{
if (index == vert1Index) vert1Occurrences++;
else if (index == vert2Index) vert2Occurrences++;
else if (index == vert3Index) vert3Occurrences++;
}
// Create copied Lists so we can dynamically add entries
var newVertices = vertices.ToList();
var newColors = colors.ToList();
// Now if a vertex is shared we need to add a new individual vertex
// and also an according entry for the color array
// and update the vertex index
// otherwise we will simply use the vertex we already have
if (vert1Occurrences > 1)
{
newVertices.Add(vert1Pos);
newColors.Add(new Color());
vert1Index = newVertices.Count - 1;
}
if (vert2Occurrences > 1)
{
newVertices.Add(vert2Pos);
newColors.Add(new Color());
vert2Index = newVertices.Count - 1;
}
if (vert3Occurrences > 1)
{
newVertices.Add(vert3Pos);
newColors.Add(new Color());
vert3Index = newVertices.Count - 1;
}
// Update the indices of the hit triangle to use the (eventually) new
// vertices instead
triangles[hit.triangleIndex * 3 + 0] = vert1Index;
triangles[hit.triangleIndex * 3 + 1] = vert2Index;
triangles[hit.triangleIndex * 3 + 2] = vert3Index;
// color these vertices
newColors[vert1Index] = Color.red;
newColors[vert2Index] = Color.red;
newColors[vert3Index] = Color.red;
// write everything back
_mesh.vertices = newVertices.ToArray();
_mesh.triangles = triangles;
_mesh.colors = newColors.ToArray();
_mesh.RecalculateNormals();
}
else
{
Debug.Log("no hit");
}
}
}
Note, however, that this works with simple coloring but might not for complex textures with UV mapping. You would have to also update the mesh.uv if using UV mapped textures.

Related

Sewing up two meshes

Good afternoon! I'm trying to sew up two meshes. I do this as follows: first I convert the sprite into a mesh, then I duplicate the resulting mesh, shift it along the "z" axis, invert it, and then sew it up. But I faced such a problem: he sews rectangular meshes well, but in circular meshes there are some defects on the sides. So, how can you sew up these sides? (Materials and code)
public class ConvertSpriteInMesh : MonoBehaviour
{
public Sprite sprite;
private MeshDraft meshDraft = new MeshDraft();
private Mesh mesh;
void Start()
{
GetComponent<MeshFilter>().mesh = SpriteToMesh(sprite);
SewingUp();
}
/// <summary>
/// Sewing up nets
/// </summary>
private void SewingUp()
{
mesh = GetComponent<MeshFilter>().mesh;
meshDraft = new MeshDraft(mesh);
int leftVertical = mesh.vertices.Length / 2; // getting the beginning of the left vertical of the mesh
int index = mesh.vertices.Length;
for (int i = 0; i < leftVertical - 1; i++)
{
meshDraft.AddQuad(mesh.vertices[i], mesh.vertices[i+1], mesh.vertices[i + leftVertical + 1],mesh.vertices[i+leftVertical],
index);
index += 4;
}
GetComponent<MeshFilter>().mesh = meshDraft.ToMesh(); // assign the resulting mesh
}
/// <summary>
/// Convert Sprite to Mesh
/// </summary>
/// <param name="_sprite"></param>
/// <returns></returns>
private Mesh SpriteToMesh(Sprite _sprite)
{
// declaring variables
Mesh mesh = new Mesh();
Vector3[] _verticles;
int[] _triangle;
// assigning values
_verticles = Array.ConvertAll(_sprite.vertices, i => (Vector3)i);
_triangle = Array.ConvertAll(_sprite.triangles, i => (int)i);
// changing the size of the array
Array.Resize(ref _verticles, _verticles.Length * 2);
Array.Resize(ref _triangle, _triangle.Length * 2);
// adding another side
for (int i = 0; i < _verticles.Length / 2; i++)
{
_verticles[_verticles.Length / 2 + i] = new Vector3(_verticles[i].x, _verticles[i].y, 0.5f);
}
for (int i = 0; i < _triangle.Length / 2; i++)
{
_triangle[_triangle.Length / 2 + i] = _triangle[i] + (_verticles.Length / 2);
}
// invert the second side
for(int i = _triangle.Length / 2; i < _triangle.Length; i += 3) {
var temp = _triangle[i];
_triangle[i] = _triangle[i + 1];
_triangle[i + 1] = temp;
}
// assigning the mesh
mesh.vertices = _verticles;
mesh.triangles = _triangle;
mesh.RecalculateBounds();
mesh.RecalculateNormals();
return mesh;
}
}
public partial class MeshDraft {
public string name = "";
public List<Vector3> vertices = new List<Vector3>();
public List<int> triangles = new List<int>();
public List<Vector3> normals = new List<Vector3>();
public List<Vector4> tangents = new List<Vector4>();
public List<Vector2> uv = new List<Vector2>();
public List<Vector2> uv2 = new List<Vector2>();
public List<Vector2> uv3 = new List<Vector2>();
public List<Vector2> uv4 = new List<Vector2>();
public List<Color> colors = new List<Color>();
public MeshDraft(Mesh mesh) {
name = mesh.name;
vertices.AddRange(mesh.vertices);
triangles.AddRange(mesh.triangles);
normals.AddRange(mesh.normals);
tangents.AddRange(mesh.tangents);
uv.AddRange(mesh.uv);
uv2.AddRange(mesh.uv2);
uv3.AddRange(mesh.uv3);
uv4.AddRange(mesh.uv4);
colors.AddRange(mesh.colors);
}
public void AddQuad(Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3, int index, Color color = default(Color)) {
vertices.Add(v0);
vertices.Add(v1);
vertices.Add(v2);
vertices.Add(v3);
Vector3 normal0 = Vector3.Cross(v2 - v1, v3 - v1).normalized;
Vector3 normal1 = Vector3.Cross(v1 - v0, v2 - v0).normalized;
normals.Add(normal0);
normals.Add(normal0);
normals.Add(normal1);
normals.Add(normal1);
colors.Add(color);
colors.Add(color);
colors.Add(color);
colors.Add(color);
triangles.Add(index);
triangles.Add(index + 1);
triangles.Add(index + 2);
triangles.Add(index);
triangles.Add(index + 2);
triangles.Add(index + 3);
}
public Mesh ToMesh() {
var mesh = new Mesh { name = name };
mesh.SetVertices(vertices);
mesh.SetTriangles(triangles, 0);
mesh.SetNormals(normals);
mesh.SetTangents(tangents);
mesh.SetUVs(0, uv);
mesh.SetUVs(1, uv2);
mesh.SetUVs(2, uv3);
mesh.SetUVs(3, uv4);
mesh.SetColors(colors);
return mesh;
}
Successful stitching (screen)
Bad stitching (screen)
I was given an answer on another forum, who is interested, I will leave a link here - https://www.cyberforum.ru/unity/thread2823987.html

Mesh is getting black on change

I have written a small code, which is mooving vertices down on mouse click. The problem is in that mesh on change is getting black (only in some places).
Here's the code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MinerScript : MonoBehaviour
{
public MeshFilter filter;
public MeshCollider col;
public GameObject Player;
public float mineSpeed = 200;
Mesh mesh;
Vector3[] vertices;
void Update()
{
filter = transform.parent.GetComponent<PlayerGravity>().mesh;
mesh = filter.GetComponent<MeshFilter>().sharedMesh;
vertices = mesh.vertices;
Ray ray = new Ray(transform.position, transform.forward * 2);
if (Physics.Raycast(ray))
{
if (Input.GetMouseButton(1))
{
int index = Mathf.RoundToInt(ClosestIndexToPoint(ray));
vertices[index] += (-Player.transform.eulerAngles) * Time.deltaTime * mineSpeed;
mesh.vertices = vertices;
mesh.RecalculateBounds();
mesh.RecalculateNormals();
Color[] colors = new Color[mesh.vertices.Length];
colors[index] = Color.red;
mesh.SetColors(colors);
//col.sharedMesh = mesh;
}
}
}
public float ClosestIndexToPoint(Ray ray)
{
if (Physics.Raycast(ray, out RaycastHit hit))
{
Mesh m = hit.transform.GetComponent<MeshFilter>().sharedMesh;
col = hit.transform.GetComponent<MeshCollider>();
int[] tri = new int[3] {
m.triangles[hit.triangleIndex * 3 + 0],
m.triangles[hit.triangleIndex * 3 + 1],
m.triangles[hit.triangleIndex * 3 + 2],
};
float closestDistance = Vector3.Distance(m.vertices[tri[0]], hit.point);
int closestVertexIndex = tri[0];
for (int i = 0; i < tri.Length; i++)
{
float dist = Vector3.Distance(m.vertices[tri[i]], hit.point);
if (dist < closestDistance)
{
closestDistance = dist;
closestVertexIndex = tri[i];
}
}
return closestVertexIndex;
}
else
return -1;
}
I don't think the problem is in color, as i've tried to apply the teture on it.
About code:
It throws a ray, and if it hits any mesh, it is calling func "ClosestIndexToPoint". It returns value of type float. This function gets the triangle a ray hits, and then finds the closest vertecs to it. Then it just mooves it down (or the rotation of our Player object, cause a have a non - flat mesh).

MeshRenderer has wrong bounds when rotated

When I try to get the bounds of my models (created in Blender) and show them in Inspector:
As you can see the bounds are correct when the objects are not rotated. But when they are (left-most object) bounds start getting totally wrong.
Here is a script that shows / gets the bounds:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GetBounds : MonoBehaviour
{
public MeshRenderer mesh_renderer = null;
public bool show_bounds = false;
private void OnDrawGizmos()
{
if (!show_bounds) return;
Gizmos.DrawWireCube(mesh_renderer.bounds.center, mesh_renderer.bounds.size);
Gizmos.DrawWireSphere(mesh_renderer.bounds.center, 0.3f);
}
}
How can I fix this?
In this thread I have come across this image which explains it pretty much
Unity dos not recalculate the Mesh.bounds all the time except when you add a mesh for the first time or "manually" invoke Mesh.RecalculateBounds.
It then uses this local space Mesh.bounds in order to calculate the translated, scaled and rotated Renderer.bounds in global space based on the Mesh.bounds. This way it always has to iterate a fixed amount of 8 vertices of the bounding box.
There was also a solution provided if you want to get the exact bounds calculated directly from the vertices. I adopted and cleaned it up a bit
public class GetBounds : MonoBehaviour
{
public MeshRenderer mesh_renderer;
public bool show_bounds;
public MeshFilter meshFilter;
public Mesh mesh;
private void OnDrawGizmos()
{
if (!mesh_renderer) return;
if (!show_bounds) return;
if (!meshFilter) meshFilter = mesh_renderer.GetComponent<MeshFilter>();
if (!meshFilter) return;
if (!mesh) mesh = meshFilter.mesh;
if (!mesh) return;
var vertices = mesh.vertices;
if (vertices.Length <= 0) return;
// TransformPoint converts the local mesh vertice dependent on the transform
// position, scale and orientation into a global position
var min = transform.TransformPoint(vertices[0]);
var max = min;
// Iterate through all vertices
// except first one
for (var i = 1; i < vertices.Length; i++)
{
var V = transform.TransformPoint(vertices[i]);
// Go through X,Y and Z of the Vector3
for (var n = 0; n < 3; n++)
{
max = Vector3.Max(V, max);
min = Vector3.Min(V, min);
}
}
var bounds = new Bounds();
bounds.SetMinMax(min, max);
// ust to compare it to the original bounds
Gizmos.DrawWireCube(mesh_renderer.bounds.center, mesh_renderer.bounds.size);
Gizmos.DrawWireSphere(mesh_renderer.bounds.center, 0.3f);
Gizmos.color = Color.green;
Gizmos.DrawWireCube(bounds.center, bounds.size);
Gizmos.DrawWireSphere(bounds.center, 0.3f);
}
}
Result:
In WHITE: The MeshRenderer.bounds
In GREEN: The "correct" calculated vertex bounds

Unity game - generate circuit with line drawing

I'm not a very beginer in unity, but not so far ;).
Today, I want to make a game which is a mix pool pinball.
The game physic is quite ok for me, but my big challenge is :
what i want to do
Allow the player to draw his own circuit and then place the different item : bumper, sticky wall ...
I make it in 3D, but with the camera position, it will be like 2D.
First of all, I don't know how to make curvy gameobject. I know about bezier curve generator, but not how generate shape with.
Ideally, it would be great if I could : draw a line (with the mouse or finder position) like a line renderer component and then unity extrude in one direction the field circuit. And that' it I have my circuit.
The second challenge will be to place (whit mouse or finger) the different component : bumper, players... with some rules : A sticky wall have to be on a simple wall from the circuit, not in the middle, you have to alway keep some space for the balls etc...
Then we create a game circuit, then we could play :):)
I work with the last unity version.
Obviously, I don't expect a full solution:rolleyes:, but according to you, is it possible ? And which way, which technic I should learn to do that? Which could be the big issu ? ... any remark advice is good to take.
I already begin to look at https://unity3d.com/fr/learn/tutori...ation-tutorial/creating-meshes?playlist=17153, I d'ont know if it's completly too much or not ?
Many thanks for your help,
Axel
Here my solution
using System.IO;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEngine.Networking;
public class scri : MonoBehaviour
{
// For saving the mesh------------------------
public KeyCode saveKey = KeyCode.F12;
public string saveName = "SavedMesh";
// Concerning mesher--------------------------
public GameObject mesher; //require
public List<Vector3> vertices;
public List<int> triangles;
public Vector3 point0;
public Vector3 point1;
public Vector3 point2;
public Vector3 point3;
public int loop;
public float size;
public Mesh meshFilterMesh;
public Mesh meshColliderMesh;
// Sprite work
public Color[] pixels;
public Texture2D newTexture;
public Texture2D oldTexture; //require
private Sprite mySprite;
private SpriteRenderer spriteRenderer;
public int pathCount;
public GameObject displayerComponent; //require
public PolygonCollider2D polygonColliderAdded; //require
void Start()
{
// Mesher
vertices = new List<Vector3> ();
triangles = new List<int> ();
meshFilterMesh= mesher.GetComponent<MeshFilter>().mesh;
meshColliderMesh= mesher.GetComponent<MeshCollider>().sharedMesh;
size = 10; // lenght of the mesh in Z direction
loop=0;
// Sprite
pixels = oldTexture.GetPixels();
newTexture =new Texture2D(oldTexture.width,oldTexture.height,TextureFormat.ARGB32, false);
spriteRenderer = gameObject.AddComponent<SpriteRenderer>();
ConvertSpriteAndCreateCollider (pixels);
BrowseColliderToCreateMesh (polygonColliderAdded);
}
void Update()
{
// Save if F12 press
if (Input.GetKeyDown(saveKey)){SaveAsset();}
}
public void ConvertSpriteAndCreateCollider (Color[] pixels) {
for (int i = 0 ; i < pixels.Length ; i++ )
{
// delete all black pixel (black is the circuit, white is the walls)
if ((pixels[i].r==0 && pixels[i].g==0 && pixels[i].b==0 && pixels[i].a==1)) {
pixels[i] = Color.clear;
}
}
// Set a new texture with this pixel list
newTexture.SetPixels(pixels);
newTexture.Apply();
// Create a sprite from this texture
mySprite = Sprite.Create(newTexture, new Rect(0, 0, newTexture.width, newTexture.height), new Vector2(10.0f,10.0f), 10.0f, 0, SpriteMeshType.Tight,new Vector4(0,0,0,0),false);
// Add it to our displayerComponent
displayerComponent.GetComponent<SpriteRenderer>().sprite=mySprite;
// Add the polygon collider to our displayer Component and get his path count
polygonColliderAdded = displayerComponent.AddComponent<PolygonCollider2D>();
}
// Method to browse the collider and launch makemesh
public void BrowseColliderToCreateMesh (PolygonCollider2D polygonColliderAdded){
//browse all path from collider
pathCount=polygonColliderAdded.pathCount;
for (int i = 0; i < pathCount; i++)
{
Vector2[] path = polygonColliderAdded.GetPath(i);
// browse all path point
for (int j = 1; j < path.Length; j++)
{
if (j != (path.Length - 1)) // if we aren't at the last point
{
point0 = new Vector3(path[j-1].x ,path[j-1].y ,0);
point1 = new Vector3(path[j-1].x ,path[j-1].y ,size);
point2 = new Vector3(path[j].x ,path[j].y ,size);
point3 = new Vector3(path[j].x ,path[j].y ,0);
MakeMesh(point0,point1,point2,point3);
}
else if(j == (path.Length - 1))// if we are at the last point, we need to close the loop with the first point
{
point0 = new Vector3(path[j-1].x ,path[j-1].y ,0);
point1 = new Vector3(path[j-1].x ,path[j-1].y ,size);
point2 = new Vector3(path[j].x ,path[j].y ,size);
point3 = new Vector3(path[j].x ,path[j].y ,0);
MakeMesh(point0,point1,point2,point3);
point0 = new Vector3(path[j].x ,path[j].y ,0);
point1 = new Vector3(path[j].x ,path[j].y ,size);
point2 = new Vector3(path[0].x ,path[0].y ,size); // First point
point3 = new Vector3(path[0].x ,path[0].y ,0); // First point
MakeMesh(point0,point1,point2,point3);
}
}
}
}
//Method to generate 2 triangles mesh from the 4 points 0 1 2 3 and add it to the collider
public void MakeMesh (Vector3 point0,Vector3 point1,Vector3 point2, Vector3 point3){
// Vertice add
vertices.Add(point0);
vertices.Add(point1);
vertices.Add(point2);
vertices.Add(point3);
//Triangle order
triangles.Add(0+loop*4);
triangles.Add(2+loop*4);
triangles.Add(1+loop*4);
triangles.Add(0+loop*4);
triangles.Add(3+loop*4);
triangles.Add(2+loop*4);
loop = loop + 1;
// create mesh
meshFilterMesh.vertices=vertices.ToArray();
meshFilterMesh.triangles=triangles.ToArray();
// add this mesh to the MeshCollider
mesher.GetComponent<MeshCollider>().sharedMesh=meshFilterMesh;
}
// Save if F12 press
public void SaveAsset()
{
var mf = mesher.GetComponent<MeshFilter>();
if (mf)
{
var savePath = "Assets/" + saveName + ".asset";
Debug.Log("Saved Mesh to:" + savePath);
AssetDatabase.CreateAsset(mf.mesh, savePath);
}
}
}

How to cut a mesh by plane in Unity3d

I want to cut meshes by plane.
try this code, but get only one of parts of cutting mesh.
Screenshot 1
Screenshot 2
public void SliceIt()
{
Vector3[] vertices = mesh.vertices;
Transform clone = clone = ((Transform)Instantiate(transform, transform.position + new Vector3(0, 0.25f, 0), transform.rotation));
Mesh meshSlice = clone.GetComponent<MeshFilter>().sharedMesh;
Vector3[] verticesSlice = meshSlice.vertices;
List<Vector3> verticesSlice2 = new List<Vector3>();
Mesh cutplanemesh = cutplane.GetComponent<MeshFilter>().sharedMesh;
Vector3[] cutplanevertices = cutplanemesh.vertices;
p1 = cutplane.TransformPoint(cutplanevertices[40]);
p2 = cutplane.TransformPoint(cutplanevertices[20]);
p3 = cutplane.TransformPoint(cutplanevertices[0]);
var myplane = new Plane(p1, p2, p3);
for (var i = 0; i < vertices.Length; i++)
{
var tmpverts = transform.TransformPoint(vertices[i]); // original object vertices
if (myplane.GetSide(tmpverts))
{
vertices[i] = transform.InverseTransformPoint(new Vector3(tmpverts.x, tmpverts.y - (myplane.GetDistanceToPoint(tmpverts)), tmpverts.z));
verticesSlice[i] = transform.InverseTransformPoint(new Vector3(tmpverts.x, tmpverts.y, tmpverts.z));
var v = transform.InverseTransformPoint(new Vector3(tmpverts.x, tmpverts.y, tmpverts.z));
verticesSlice2.Add(v);
}
else
{
var v = transform.InverseTransformPoint(new Vector3(tmpverts.x, tmpverts.y - (myplane.GetDistanceToPoint(tmpverts)), tmpverts.z));
verticesSlice2.Add(v);
}
}
mesh.vertices = verticesSlice;
mesh.RecalculateBounds();
meshSlice.vertices = verticesSlice2.ToArray();
meshSlice.RecalculateBounds();
}
I got this code from here.
I also read this question, but I couldn't figure how to split triangles which belong to positive and negative sides of plane.
You can use already existing assets on asset store:
https://www.assetstore.unity3d.com/#!/content/59618
It is not only cut a mesh, it also cut colliders, do some optimizations and it is extandable.