From my own experience trying to update a mesh collider frame by frame is terribly slow, instead I found a work around by simply updating the mesh collider when I need it per theANMATOR2b suggestion. I tweaked the script I found [here][1] and added it to each game object with a mesh collider I would like to update.
using UnityEngine;
using System.Collections;
public class SkinnedCollisionHelper : MonoBehaviour
{
// Public variables
// Instance variables
private CWeightList[] nodeWeights; // array of node weights (one per node)
private Vector3[] newVert; // array for the regular update of the collision mesh
private Mesh mesh; // the dynamically-updated collision mesh
private MeshCollider collide; // quick pointer to the mesh collider that we're updating
// Function: Start
// This basically translates the information about the skinned mesh into
// data that we can internally use to quickly update the collision mesh.
void Start()
{
SkinnedMeshRenderer rend = GetComponent(typeof(SkinnedMeshRenderer)) as SkinnedMeshRenderer;
collide = GetComponent(typeof(MeshCollider)) as MeshCollider;
if (collide != null && rend != null)
{
Mesh baseMesh = rend.sharedMesh;
mesh = new Mesh();
mesh.vertices = baseMesh.vertices;
mesh.uv = baseMesh.uv;
mesh.triangles = baseMesh.triangles;
newVert = new Vector3[baseMesh.vertices.Length];
short i;
// Make a CWeightList for each bone in the skinned mesh
nodeWeights = new CWeightList[rend.bones.Length];
for (i = 0; i < rend.bones.Length; i++)
{
nodeWeights *= new CWeightList();*
nodeWeights_.transform = rend.bones*;
}*_
// Create a bone weight list for each bone, ready for quick calculation during an update…
Vector3 localPt;
for (i = 0; i < baseMesh.vertices.Length; i++)
{
BoneWeight bw = baseMesh.boneWeights*;*
if (bw.weight0 != 0.0f)
{
localPt = baseMesh.bindposes[bw.boneIndex0].MultiplyPoint3x4(baseMesh.vertices*);*
nodeWeights[bw.boneIndex0].weights.Add(new CVertexWeight(i, localPt, bw.weight0));
}
if (bw.weight1 != 0.0f)
{
localPt = baseMesh.bindposes[bw.boneIndex1].MultiplyPoint3x4(baseMesh.vertices*);*
nodeWeights[bw.boneIndex1].weights.Add(new CVertexWeight(i, localPt, bw.weight1));
}
if (bw.weight2 != 0.0f)
{
localPt = baseMesh.bindposes[bw.boneIndex2].MultiplyPoint3x4(baseMesh.vertices*);*
nodeWeights[bw.boneIndex2].weights.Add(new CVertexWeight(i, localPt, bw.weight2));
}
if (bw.weight3 != 0.0f)
{
localPt = baseMesh.bindposes[bw.boneIndex3].MultiplyPoint3x4(baseMesh.vertices*);*
nodeWeights[bw.boneIndex3].weights.Add(new CVertexWeight(i, localPt, bw.weight3));
}
}
UpdateCollisionMesh();
}
else
{
Debug.LogError(gameObject.name + “: SkinnedCollisionHelper: this object either has no SkinnedMeshRenderer or has no MeshCollider!”);
}
}
// Function: UpdateCollisionMesh
// Manually recalculates the collision mesh of the skinned mesh on this
// object.
public void UpdateCollisionMesh()
{
if (mesh != null)
{
// Start by initializing all vertices to ‘empty’
for (int i = 0; i < newVert.Length; i++)
{
newVert = new Vector3(0, 0, 0);
}
// Now get the local positions of all weighted indices…
foreach (CWeightList wList in nodeWeights)
{
foreach (CVertexWeight vw in wList.weights)
{
newVert[vw.index] += wList.transform.localToWorldMatrix.MultiplyPoint3x4(vw.localPosition) * vw.weight;
}
}
// Now convert each point into local coordinates of this object.
for (int i = 0; i < newVert.Length; i++)
{
newVert = transform.InverseTransformPoint(newVert*);*
}
// Update the mesh (& collider) with the updated vertices
mesh.vertices = newVert;
mesh.RecalculateBounds();
collide.sharedMesh = mesh;
}
}
}
class CVertexWeight
{
public int index;
public Vector3 localPosition;
public float weight;
public CVertexWeight(int i, Vector3 p, float w)
{
index = i;
localPosition = p;
weight = w;
}
}
class CWeightList
{
public Transform transform;
public ArrayList weights;
public CWeightList()
{
weights = new ArrayList();
}
}
I called the update collision mesh function from another script and implemented it into another function like this
SkinnedCollisionHelper[] items = FindObjectsOfType();
foreach (SkinnedCollisionHelper item in items)
{
item.UpdateCollisionMesh();
}
I use a play animation, and a pause animation function in my game. I simply add the previous short script into my pause function and whenever in the game I click pause, the mesh updates to fit. This is how I implement that into my Play and Pause Animation script.
using UnityEngine;
using System.Collections;
using System;
public class Play_Pause : MonoBehaviour
{
public Animation anim;
public void Play()
{
GetComponent().Play();
anim = GetComponent();
foreach (AnimationState state in anim)
{
state.speed = 1F;
}
}
public void Pause()
{
SkinnedCollisionHelper[] items = FindObjectsOfType();
foreach (SkinnedCollisionHelper item in items)
{
item.UpdateCollisionMesh();
}
anim = GetComponent();
foreach (AnimationState state in anim)
{
state.speed = 0F;
}
}
}
This does require you to have a Pause feature in your game. At least for my situation this works great. Hopefully it can be useful for anyone else who may have something similar
_*[1]: http://forum.unity3d.com/threads/raycast-without-colliders.14378/*_
I'm was tried that, work slower than SkinnedMeshRenderer.bakeMesh(); But, thanks. :)
– leodluzGreat! Thank you. You provided very clear and excellent solution. I solved my challenges with your code. Thanks again.
– Byol