'Splitting' a Mesh

Hi

Is it possible to ‘break’ a Mesh down into its individual polygons and place them into an array? What I would like to do with a basic mesh is ‘explode’ its polygons off at random velocity in the direction of the polygon faces.

I had a brief look at Mesh.GetTriangles but I’m a little confused as this returns int[ ]! - so I think this is a non starter.

Then I had a look at Mesh.vertices which makes a little more sense as it returns Vector3[ ] (which I assume is the coordinates of the vertices). Would I be correct to suggest that vertices[0], vertices[1] and vertices[2] would be the first poly/face?

Do I then need to Normalize the Cross Product on the Vectors to get the face direction?

This turns me to my final question which is 3D in general (I am very new to this area…) When I export my Model from Cheetah3D a lot of the polygons have 4 vertices. When they are imported into Unity are they converted to triangle meshes?

A lot of questions I know - any help would be much appreciated. :slight_smile:

Ta

JT

That’s not how the array is organized, no. The vertices can be in any order at all.

Triangles is an int[ ] which is a long list of triplets (its length is always a multiple of 3). So the first 3 numbers there (triangles[0], triangles[1], triangles[2]) represent the first triangle. they’re integers because they refer back to the vertex array. In other words, the first triangle is vertices[triangles[0]], vertices[triangles[1]], vertices[triangles[2]].

The challenge with “blowing apart” a mesh is that every vertex is shared by multiple triangles. So to blow it apart, you would need to rebuild the array of vertices as well as the array of triangles. So to do that, try something like this:

var newVertices : Vector3[] = new Vector3[triangles.length];
var newTriangles : int[] = new int[triangles.length];
ver newUV : Vector2[] = new Vector2[triangles.length];

for (v=0;v<triangles.length;v++) {
newVertices[v] = vertices[triangles[v]];
newTriangles[v] = v;
newUV[v] = uv[triangles[v]];
}

I think that’ll work.

1 Like

It’s actually a random speed that you want, not a random velocity (‘velocity’ includes both speed and direction, and the direction is already determined by the normal of the polygon).

I believe GetTriangles() returns the triangles for a submesh. To access all the triangles in the mesh, just use the ‘triangles’ property/member variable.

Actually it would be vertices[triangles[0]], vertices[triangles[1]], vertices[triangles[2]].

I’m fairly certain that Unity converts all polygons with more than 3 sides into triangles on import.

As for ‘exploding a mesh’, I haven’t actually done this in Unity, but I’ve written similar code in other projects. Here’s how I would most likely proceed:

  1. For each triangle in the mesh…

  2. Create a new game object

  3. Create a mesh for the game object (you’ll need a filter and a renderer)

  4. Assign the mesh data for the triangle in question to the new mesh

  5. Compute the face direction as the cross product of two of its edges (there are normals stored with the mesh, but they’re vertex normals rather than face normals)

  6. Assign the new object an initial velocity of normal * initialSpeed

Note that this will break coplanar triangles apart (that is, faces that had more than 3 vertices in the original mesh will not break apart in one piece). If you want to keep the original faces together, you’ll need to preprocess the mesh to identify coplanar triangles, and then keep these together when exploding the mesh.

Another issue is that the newly created triangles will most likely not be centered at the origin, which may or may not cause problems, depending on how you want the spawned pieces to behave. To be safe though, I would probably translate each triangle to the origin, and then position the spawned game object at the triangle’s original world-space center.

Also keep in mind that you’ll need to transform the mesh vertices into world space as you go, using the transform of the exploding object.

Now, this was very cursory - there are a lot of details that I glossed over. It’s not trivial, but it should be do-able with some effort.

If you get stuck on anything specific, post back here and I or someone else will probably be able to help.

I’m not sure I’d create a new game object for each triangle. For a large mesh that would probably slow things down quite a bit. I’d just create a single new mesh of triangles with no shared vertices, then move each triplet in the direction of the normal each frame based on a randomly assigned velocity. With this method you’ll have to keep track of everything manually, but I assume the object is being destroyed, so the mesh will be Destroyed() in short time.

A couple quick comments on this…

First, from the OP’s mention of a ‘basic’ mesh, and from the fact that he intends to break it into individual triangles/polygons, I’m assuming that the mesh if fairly simple and has a low poly count. (If this is not correct, perhaps the OP could clarify this point.)

The purpose of creating a separate object for each face is to take advantage of the functionality already available to Unity game objects. Things you might want the spawned fragments to do might include:

  1. Spin as they move, rather than only moving linearly
  2. Be affected by gravity
  3. Bounce off other objects (with the help of, say, a box collider approximating the shape of the triangle)
  4. Make a sound when they bounce
  5. Cause damage when they hit other game entities

The OP may or may not want to do any of these things, but nevertheless creating the fragments as proper game objects will afford much, much greater flexibility than scripting the behavior manually.

This does assume, of course, that the original mesh has a fairly low poly count (if the original mesh has 10,000 triangles, then neither method is liable to meet with much success).

I agree, if you want to use physics and things then GOs make it simple. If going that route for a complex mesh instead of breaking it into triangle it could be divided into some larger pieces and each piece assigned to a GO. Also, if doing this then you could just create the pieces in the modeling app and swap out the models when the “break” event occurs.

Another approach: use a mesh particle system. This would look better anyway, since objects in real life aren’t actually made out of triangles. :wink: (Unless you specifically wanted the “mesh breaking into triangles” effect, of course.)

–Eric

Hi

Thanks for all the posts. It is a very basic mesh and in honesty just an ‘exercise’ to solidify my understanding of how the meshes are constructed.

I knew as soon as I posted this I would get a correct definition of a Vector! Thanks now you made me look stupid! hehe :sweat_smile:

Thanks everyone

JT

If you haven’t already figured the mesh stuff out, it seemed like a fun little exercise, so:

private var amount : float = 0.0;
private var surfaceNormals : Vector3[];
private var newVertices : Vector3[];
var maxDist : float = 20;

function Start () {
	// Get mesh info from attached mesh
	var myMesh = GetComponent(MeshFilter).mesh;
	var myVertices = myMesh.vertices;
	var myTriangles = myMesh.triangles;
	var myUV = myMesh.uv;
	var myNormals = myMesh.normals;
	// Set up new arrays to use with rebuilt mesh
	newVertices = new Vector3[myTriangles.Length];
	var newUV = new Vector2[myTriangles.Length];
	var newNormals = new Vector3[myTriangles.Length];
	var newTriangles = new int[myTriangles.Length];

	// Rebuild mesh so that every triangle has unique vertices
	for (i = 0; i < myTriangles.Length; i++) {
		newVertices[i] = myVertices[myTriangles[i]];
		newUV[i] = myUV[myTriangles[i]];
		newNormals[i] = myNormals[myTriangles[i]];
		newTriangles[i] = i;
	}
	
	// Assign new mesh
	myMesh.vertices = newVertices;
	myMesh.uv = newUV;
	myMesh.normals = newNormals;
	myMesh.triangles = newTriangles;
	
	// Get array of surface normals for each triangle
	surfaceNormals = new Vector3[myTriangles.Length/3];
	var idx = 0;
	for (i = 0; i < surfaceNormals.Length; i++) {
		var v0 = newVertices[idx++];
		surfaceNormals[i] = Vector3.Cross(newVertices[idx++]-v0, newVertices[idx++]-v0).normalized;
	}
}

function OnGUI () {
	amount = GUI.VerticalSlider(Rect(10, 10, 20, Screen.height-20), amount, maxDist, 0.0);
	if (GUI.changed) {
		ExplodeMesh(amount);
	}
}

function ExplodeMesh (amount : float) {
	var idx = 0;
	var myMesh = GetComponent(MeshFilter).mesh;
	var thisVertices = myMesh.vertices;
	for (i = 0; i < surfaceNormals.Length; i++) {
		thisVertices[idx] = newVertices[idx++] + surfaceNormals[i] * amount;
		thisVertices[idx] = newVertices[idx++] + surfaceNormals[i] * amount;
		thisVertices[idx] = newVertices[idx++] + surfaceNormals[i] * amount;
	}
	myMesh.vertices = thisVertices;
}

Put that on an object with a mesh renderer, and then you can drag the slider to make the triangles go apart (up to maxDist units away) and back together. Thanks to StarManta for the rebuilding bit…I might have overthought that and done something more complicated. :wink:

–Eric

2 Likes

Brilliant!

I’ll give that a go when I get a chance. Then I’ll convert it to my language of choice, C#.

Ta

JT

I understood the code above except of this:

surfaceNormals = new Vector3[myTriangles.Length/3];

Why should we divide the total triangles by 3?Shouldn’t we have a normal per triangle?

I will be happy to get an explanation on this /

Thanks

Right, that’s why it’s divided by 3. It takes 3 entries in the triangles array to describe 1 triangle.

–Eric

math wise it should be myTriangles.Length and to feed it you have to calculate it which is easy if we assume vertex to be the xth vertex in the tri, the normal is:

±Cross( vertex1 - vertex0, vertex2 - vertex0) (the sign depends on the winding order)

Here is an object-based one:

//DestructibleObject - provides functionality to destroy whatever GameObject the script is attached to
//the attached object must have a MeshFilter in its children, and its shrapnel objects must have a renderer in the root.
//by Eli

using UnityEngine;
using System.Collections;

public class DestructibleObject : MonoBehaviour
{
	public GameObject shrapnelPrefab;
	public AudioClip breakSound;
	public float lifespan = 10.0f;
	public float fadeTime = 0.5f;
	
	protected bool destroyed = false;
	protected float lifetime;
	protected GameObject[] pieces;
	
	public virtual void Update()
	{
		if (destroyed)
		{
			lifetime -= Time.deltaTime;
			
			//out of time, destroy this object
			if (lifetime <= 0.0f)
			{
				Object.Destroy(gameObject);
			}
			//fade out before destroying
			else if (lifetime <= fadeTime)
			{
				for (int i = 0; i < pieces.Length; i++)
				{
					Color c = pieces[i].renderer.material.color;
					c.a = 1.0f - ((fadeTime - lifetime) / fadeTime);
					pieces[i].renderer.material.color = c;
				}
			}
		}
	}
	
	public virtual void Explode()
	{
		if (destroyed)
		{
			return;
		}
		destroyed = true;
		lifetime = lifespan + fadeTime;
		
		//construct all the individual destructible pieces from our mesh
		MeshFilter filter = GetComponentInChildren(typeof(MeshFilter)) as MeshFilter;
		Mesh mesh = filter.mesh;
		pieces = new GameObject[mesh.triangles.Length/3];
		//a sneaky easy way to get the children to be sized correctly is to have a unit scale when spawning them, then restore it later
		Vector3 oldScale = transform.localScale;
		transform.localScale = new Vector3(1,1,1);
		
	    for (int i = 0; i < mesh.triangles.Length; i+=3)
		{	
			GameObject go = GameObject.Instantiate(shrapnelPrefab) as GameObject;
			Mesh newMesh = (go.GetComponent(typeof(MeshFilter)) as MeshFilter).mesh;
			newMesh.vertices 	= new Vector3[]
			{
				mesh.vertices[mesh.triangles[i+0]],
				mesh.vertices[mesh.triangles[i+1]],
				mesh.vertices[mesh.triangles[i+2]],
				mesh.vertices[mesh.triangles[i+0]] - mesh.normals[mesh.triangles[i+0]] * 0.15f, //need to turn this plane 3D
				mesh.vertices[mesh.triangles[i+1]] - mesh.normals[mesh.triangles[i+1]] * 0.15f,
				mesh.vertices[mesh.triangles[i+2]] - mesh.normals[mesh.triangles[i+2]] * 0.15f
			};
			newMesh.uv 			= new Vector2[]
			{
				mesh.uv[mesh.triangles[i+0]],
				mesh.uv[mesh.triangles[i+1]],
				mesh.uv[mesh.triangles[i+2]],
				mesh.uv[mesh.triangles[i+0]],
				mesh.uv[mesh.triangles[i+1]],
				mesh.uv[mesh.triangles[i+2]]
			};
			newMesh.triangles 	= new int[]
			{
				0, 2, 3,
				2, 5, 3,
				0, 3, 1,
				1, 3, 4,
				1, 4, 2,
				2, 4, 5,
				2, 0, 1,
				5, 4, 3
			};
			newMesh.RecalculateNormals();
			(go.collider as MeshCollider).sharedMesh = newMesh;
			go.transform.parent = filter.transform;
			go.transform.localPosition = Vector3.zero;
			go.transform.localRotation = Quaternion.identity;
			pieces[i/3] = go;
	    }
		mesh.triangles = new int[0];
		mesh.vertices = new Vector3[0];
		mesh.uv = new Vector2[0];
		mesh.normals = new Vector3[0];
		transform.localScale = oldScale;
		Object.Destroy(collider);
		audio.PlayOneShot(breakSound);
	}
	
	public GameObject[] GetPieces()
	{
		return pieces;
	}
}

It works best if you make the MeshFilter object a child of the parent object, and you do all transformations to the parent. That way the locations of each piece will be accurate.

Hey)
I was trying to understand the code above and I’ve got a few questions:

  1. Why is the newMesh.triangles array so weird? I mean you have 8 triangles in it:
newMesh.triangles   = new int[]
{
          0, 2, 3,
          2, 5, 3,
          0, 3, 1,
          1, 3, 4,
          1, 4, 2,
          2, 4, 5,
          2, 0, 1,
          5, 4, 3
};

I can’t get it(
2) Why do those 2 arrays(vertices and uv) have 6 members??? Not 3 - like 3 vertices in a triangle or 8(like in a new triangles array)??

newMesh.vertices    = new Vector3[]
{
               mesh.vertices[mesh.triangles[i+0]],
               mesh.vertices[mesh.triangles[i+1]],
               mesh.vertices[mesh.triangles[i+2]],
               mesh.vertices[mesh.triangles[i+0]] - mesh.normals[mesh.triangles[i+0]] * 0.15f, //need to turn this plane 3D
               mesh.vertices[mesh.triangles[i+1]] - mesh.normals[mesh.triangles[i+1]] * 0.15f,
               mesh.vertices[mesh.triangles[i+2]] - mesh.normals[mesh.triangles[i+2]] * 0.15f
};

newMesh.uv          = new Vector2[]
{
               mesh.uv[mesh.triangles[i+0]],
               mesh.uv[mesh.triangles[i+1]],
               mesh.uv[mesh.triangles[i+2]],
               mesh.uv[mesh.triangles[i+0]],
               mesh.uv[mesh.triangles[i+1]],
               mesh.uv[mesh.triangles[i+2]]
};

I really need your help, I wanna get this code and then modify it to make random pieces out of a mesh(not always the same pieces). I want to control pieces distribution.

Thanks in advance for the replies)

As far as I understand it, the eight triangles constitute the six faces of the 3D plane (2 triangles for each quad face), which is essentially a triangular plate with the thickness 0.15f. If you catch what I mean, then both your questions should be solved.