# Mesh Manipulation

Hey Unity folks. I’ve been experimenting with some vertex manipulation recently to try to make some sort of “destructable environment,” as seen in Red Faction. The way I am doing this is below: that script moves the vertices, and the firing script merely SendMessages Destruct to play. I’m shooting at a cube with a mesh collider attached (in the hopes that it will change with the vertices).

So far I haven’t had much luck. Any ideas?

``````//the resistant quality of the material (more resistance = less movement)
var resistance = 1.0;
//how much the impact spreads - does it go into one point or spread over the full surface?
//will the thing shoot out dust or blood or anything?
var particles : GameObject;

function Destruct(hitPos) {
//the force of impact
force = 10;
//range over which the impact spreads
impactRange = 1;

var mesh : Mesh = GetComponent(MeshFilter).mesh;
var vertices = mesh.vertices;
var normals = mesh.normals;

for(i = 0; i < vertices.length; i++) {
distance = Vector3.Distance(hitPos, vertices[i]);
//force depends on distance from hit
force = force * ((impactRange - distance) / impactRange) - resistance;
if(distance <= impactRange  force > 0) {
vertices[i].x -= normals[i].x * force;
if(particles)
Instantiate(particles, vertices[i], Quaternion.FromToRotation(Vector3.up, normals[i]));
}
}
mesh.vertices = vertices;
mesh.RecalculateNormals();
mesh.RecalculateBounds();
}
``````

Later, I will add a line or two that make it so that if the line from the point of impact to the vertex being tested is intersected, the vertex will not move.

Sounds like a good approach (to me, a newbie!) - what is it doing wrong when you run it?

It won’t do anything to the mesh when I run it. I tried making it so that when Destruct gets called it just moves all the vertices away (so I can tell if it works at all), and it did that fine, so now I’m completely puzzled as to what the problem is. The code inside Destruct for that above approach was simple:

1. for loop to go through vertices
2. vertex += 2 times its normal

When I did this, the sides of the cube moved outwards when I shot it as expected. For some reason, the extra math must screw something up (maybe). If anyone has any ideas, I would be very appreciative to hear them.

I can barely wrap my brain around my OWN code, but for that it’s worth…

You declare force = 10 before cycling through the verts, but then after the first vert, force is not reset to 10. Should force= 10 be inside the start of the for loop? Or use a variable like maxforce = 10, an then inside the loop, force = maxforce *…?

Otherwise I’m thinking only one vert would be fully affected, especially once resistance is subtracted.

you might be on to something there… one second.

Ok - I just got the script working on the mesh surroundings in the FPS example. It works like I thought it should, and is very nice. Unfortunately, the box that I was shooting earlier will still not destruct, even though the only thing missing from it that the surroundings have is an empty “Animation” component, and I don’t think that’s the reason it wouldn’t work. Anyways, when it does work, the vertices move away great, but the mesh collider does not change, making it so that I can be standing over a big gap, which is not what I want. How can I reset the mesh collider so that it matches my newly changed mesh?

The scripts I am using are as follows:

Replace the Machine Gun script with this:

``````var range = 100.0;
var fireRate = 0.05;
var force = 10.0;
var damage = 5.0;
var bulletsPerClip = 40;
var clips = 20;
var hitParticles : ParticleEmitter;
var muzzleFlash : Renderer;

private var bulletsLeft : int = 0;
private var nextFireTime = 0.0;
private var m_LastFrameShot = -1;

var impactRange = .1;
var hitPos = Vector3.zero;

function Start ()
{
// We don't want to emit particles all the time, only when we hit something.
if (hitParticles)
hitParticles.emit = false;
bulletsLeft = bulletsPerClip;
}

function LateUpdate()
{
if (muzzleFlash)
{
// We shot this frame, enable the muzzle flash
if (m_LastFrameShot == Time.frameCount)
{
muzzleFlash.transform.localRotation = Quaternion.AxisAngle(Vector3.forward, Random.value);
muzzleFlash.enabled = true;

if (audio)
{
if (!audio.isPlaying)
audio.Play();
audio.loop = true;
}
}
// We didn't, disable the muzzle flash
else
{
muzzleFlash.enabled = false;
enabled = false;

// Play sound
if (audio)
{
audio.loop = false;
}
}
}
}

function Fire ()
{
if (bulletsLeft == 0)
return;

// If there is more than one bullet between the last and this frame
// Reset the nextFireTime
if (Time.time - fireRate > nextFireTime)
nextFireTime = Time.time - Time.deltaTime;

// Keep firing until we used up the fire time
while( nextFireTime < Time.time  bulletsLeft != 0)
{
FireOneShot();
nextFireTime += fireRate;
}
}

function FireOneShot ()
{
var direction = transform.TransformDirection(Vector3.forward);
var hit : RaycastHit;

// Did we hit anything?
if (Physics.Raycast (transform.position, direction, hit, range))
{
// Apply a force to the rigidbody we hit
if (hit.rigidbody)

// Place the particle system for spawing out of place where we hit the surface!
// And spawn a couple of particles
/*if (hitParticles)
{
hitParticles.transform.position = hit.point;
hitParticles.transform.rotation = Quaternion.FromToRotation(Vector3.up, hit.normal);
hitParticles.Emit();
}*/

// Send a damage message to the hit object
hitPos = hit.point;
}

bulletsLeft--;

// Register that we shot this frame,
// so that the LateUpdate function enabled the muzzleflash renderer for one frame
m_LastFrameShot = Time.frameCount;
enabled = true;

if (bulletsLeft == 0)
}

// We have a clip left reload
if (clips > 0)
{
clips--;
bulletsLeft = bulletsPerClip;
}
}

function GetBulletsLeft () {
return bulletsLeft;
}
``````

and put this script on what you want to destroy:

``````//the resistant quality of the material (more resistance = less movement)
var resistance = 1.0;
//how much the impact spreads - does it go into one point or spread over the full surface?
//will the thing shoot out dust or blood or anything?
var particles : GameObject;

function Destruct(destructorScript) {
//range over which the impact spreads
impactRange = 1;//destructorScript.impactRange;
hitPos = destructorScript.hitPos;
destructorScriptForce = 10;//destructorScript.force;

var mesh : Mesh = GetComponent(MeshFilter).mesh;
var vertices = mesh.vertices;
var normals = mesh.normals;
isChanged = false;
for(i = 0; i < vertices.length; i++) {
//the force of impact
force = destructorScriptForce;
distance = Vector3.Distance(hitPos, vertices[i]);
//force depends on distance from hit and resistance of material
force = force * ((impactRange - distance) / impactRange) - resistance;
if(distance <= impactRange  force > 0) {
vertices[i] -= normals[i] * force;
if(particles) {
instantiatedParticles = Instantiate(particles, vertices[i], Quaternion.FromToRotation(Vector3.up, normals[i]));
//instantiatedParticles.particles.max = ((impactRange - distance) / impactRange);
}
isChanged = true;
}
}
if(isChanged) {
mesh.vertices = vertices;
mesh.RecalculateBounds();
GetComponent(MeshCollider).sharedMesh = mesh;
}
}
``````

Does anyone know how to get a mesh collider to reset itself from a script to work on a newly shaped mesh?

Also - how can I make it so that a mesh will “break” apart"? For instance, let’s say I blow a hole in the wall - how can I attach the vertices that are on each side of the wall at the breaking points to each other so that the wall is now in two seperate pieces, and then add a box collider to the unattached piece that replaces the mesh collider? This is very specific, so you can just give me ideas about how to do the wall breaking, and not code.

Thanks for any help!

What you’re trying to code here is a little over my head, but the one thing I noticed is you’re not reassigning the mesh collider after you’ve deformed the mesh so the old collider is still there…

``````GetComponent(MeshCollider).sharedMesh = mesh;
``````

Try putting that in there at the end of your script. I’d like to see this deformation in action since I built the FPS tutorial scene and it would be neat to see it blown apart like this.

Good luck, hopefully someone with some real coding skills can help out with this if my suggestion doesn’t do the trick.

I’m very flattered to have my code used by the creater of the scene (wowie!) Anyways - it only works on walls and the ground at the moment, so don’t get TOO excited. When you hit a light, the effect is kind of cool, but obviously not desired.

Just set the “resistance” variable to something around 4 or 5 to make it work reasonably. You can tweak that number, too, if you want different effects.

Sweet!

That line did exactly what I wanted. It slowed down the framerate a lot though… I’ll work on it a little to make it pretty again.

I still can’t figure out how to make holes in a wall. If anyone has any ideas, I would be very much obliged.

[EDIT] the code above has been changed to incorporate something that slightly speeds it up.

Can anyone think of a way to simply say “get all the vertices in this area and do this to them” without testing each vertex? I’m thinking of something like the explosion script where it looks within a sphere surrounding the explosion for any rigidbodies to move.

Did the added code to reassign the mesh collider do the trick? I haven’t tried your scripts yet.

 Yeah, recalculating the mesh collider is CPU intensive (or so Joe told me)… each section of the FPS tut is around 5,000 polys so recalculating all that info in one frame might bring everything to a halt?

I’m curious to see what the textures do when deformed. If you need a place to host an example scene let me know, I’ll put it up on my server.

Here’s a picture.

The amount of the damage done can easily be modified by tweaking the “resistance” variable on the destruct script. For that picture, I think I had it set to 5, but you could easily set it higher, making the depressions in the ground shallower.

I want to add the same kind of thing to the explosion script, so it works with that too, but haven’t gotten around to it yet.

That’s awesome that both the regular texture and the secondary UV lightmap seems to conform to the new geometry… very cool. Post the updated code (unless it’s just adding the mesh collider line), I want to try it out

I already updated the code above - so just copy-paste that to a javascript file.

I still can’t get it to work right on meshes with more vertices that are close together. As soon as I figure it out, though, I’ll start making my habitats seriously fall to their knees.

The code above is fully updated I think. I edited it after you gave me that line of code.

It still runs really slow, but I’m working on making it managably fast. If anyone has any ideas on this, I would be happy to hear them.

Also, if you brilliant Unity folks could help me think up a method for making a surface “break” (and get two completed meshes out of the breaking) that would be very helpful as well.

[EDIT] Whoops - sorry for the repost: second page gets me every time.

Random, uninformed idea on the breaking: create two NEW meshes, each copying some verts from the original, and then destroy the original?

There are two performance bottlenecks.

1. You are using too much dynamic typing. By forcing javascript to use more static typing you get more speed. Eg. the type of hitpos is not known, because the type of destructor script is not known. So just statically type hitPos and you get a performance boost. The important part is to make sure that all variables used in the inner loop are statically typed. In the inner loop you can do a lot more early outs, eg. Just calculate the sqrDistance to the vertex and exit if it’s too far away.

I attached the script optimized and with some fixes.

• transforming the hitpos into local space of the mesh.
1. Don’t spawn particles per vertex. I can’t really see why it should be per vertex anyway. Just spawn at the impact location.

2. Assigning the mesh collider is slow for large meshes. PhysX does some heavy preprocessing of meshes so it can do collision detection at fast speeds.

The problem here is that the level geometry was joined in slightly suboptimal ways. Eg. every mesh has multiple materials. (Now that doesn’t give the performance benefit of combining meshes but you pay for it in this case. Because you need to process and recalculate collision meshes for more vertices)

If you split all the geometry so that all those combined meshes that don’t share the same material anyway are seperate meshes it would be run a lot faster.

So optimizing the geometry will probably make things run fast enough.

14427–489–\$destructable_750.js (1.3 KB)

Sure - I knew about the size of the mesh slowing it down and that particles per vertex would be slower than possible (on second thought I don’t know why I did that at all). Thanks for the typing one though - I assumed that would be taken care of during the compiling.

On another note, that two new meshes idea would probably run slow during the split, but would be much faster once they are broken. Plus, it makes more sense. The main problem I’m having trouble with is this:

1. There are two sides to a wall, each of which has vertices and triangles
2. When a piece breaks or a hole is formed, triangles must be broken.
3. To make the pieces still be solid (and not two unconnected walls), triangles must be formed between the two walls to cover the holes left over.

Number 3 is the one I’m having trouble with - I can break things and I can split meshes up, but I can’t figure out how to identify the connecting point on the opposite wall.