- Home /
Mesh deformation with collisions
Ok, this is my case:
I have this script to make a mesh react with collisions and deform the vertices of the mesh depending on the contact points and the force of the collision. The problem is the script, it's not working at all. When I search the index of the vertex that it's equal to the contact point it doesn't found anything. Can you guys help me a bit?
Edit: I think the getNearestVertex it's not needed at this time. The collider it's based on the mesh.
This is my script:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class HitDeformation : MonoBehaviour {
public MeshFilter meshFilter;
public float forceDetectionThreshold = 5;
private Mesh mesh;
private Material mat;
private List<Vector3> Points;
private List<Vector3> Verts;
void Start(){
Verts = new List<Vector3>();
}
void OnCollisionEnter(Collision col){
if(col.relativeVelocity.magnitude > forceDetectionThreshold)
deformMesh(col);
}
void deformMesh(Collision collision){
mesh = meshFilter.mesh;
ContactPoint[] contacts = collision.contacts;
float force = collision.relativeVelocity.magnitude;
Verts.Clear ();
Verts.AddRange(mesh.vertices);
Debug.Log("Colision and mesh data stored in deformMesh function variables. Comparing Contact points with mesh");
foreach(ContactPoint c in contacts){
int i = Verts.IndexOf(c.point);
if(i != -1){
Debug.Log("vertex found. Index nº "+i);
Verts[i] = Verts[i] + (-transform.forward*force);
}
}
Debug.Log("dumping new verts to mesh vertices");
mesh.vertices = Verts.ToArray();
Debug.Log("dumping new mesh to MeshFilter mesh");
meshFilter.mesh = mesh;
//meshFilter.mesh.Optimize (); I don't know if this it's really neccesary
}
/*Vector3 getNearestVertex(Vector3 point){
float minDistanceSqr = Mathf.Infinity;
Vector3 nearestVertex = Vector3.zero;
Debug.Log("Finding nearestVertex of given point");
// scan all vertices to find nearest
foreach (Vector3 vertex in Verts){
Vector3 diff = point-vertex;
float distSqr = diff.sqrMagnitude;
if (distSqr < minDistanceSqr){
minDistanceSqr = distSqr;
nearestVertex = vertex;
}
}
// convert nearest vertex back to world space
return transform.TransformPoint(nearestVertex);
}*/
/* get collision
* Get the contact points
* Push the points where the contact points are
* update the mesh
* voila?
*/
}
Sorry for this, I don't know if bumping a question it's allowed but I really need an answer
The contact point is NOT the vertex of your collider, it's just the contacting position on your collider. Nearest vertex is needed this time.
But deformating like this is not a good idea at ALL, you should just resizing the whole object
That's why it doesn't find the contact point? I tried with finding the nearest point but still not working
Answer by EvilTak · Dec 06, 2014 at 09:20 AM
Try this: http://forum.unity3d.com/threads/now-with-source-mesh-deformation-on-impact.50214/ You can also add some noise to the deformation to add realism.
I've been searching this everywhere. How I didn't see that thread?
Thank you very much. Works like a charm.
Answer by KingDolphin · Dec 06, 2014 at 08:52 AM
I'm not entirely sure what the problem is, but here is a probably really messy script that I made awhile back that deforms another mesh.
this goes on the object hitting the deformable object
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class deformer : MonoBehaviour {
public float speed = 2f;
public Mesh mesh;
public Vector3[] verts;
public float maxDistance;
public GameObject explosion;
void Start() {
mesh = this.GetComponent<MeshFilter>().mesh;
verts = mesh.vertices;
this.GetComponent<MeshFilter>().mesh = mesh;
}
void OnCollisionEnter(Collision other) {
Debug.Log("Collided with " + other.gameObject.name);
if (other.gameObject.GetComponent<deformable>() != null) {
Vector3 colPosition = transform.InverseTransformPoint(other.contacts[0].point);
movePoints(other.gameObject);
}
}
public void movePoints(GameObject other) {
Vector3[] otherVerts = other.GetComponent<deformable>().verts;
float distance;
for (int i=0; i<otherVerts.Length; i+=1) {
distance = GetDistance((rigidbody.position), other.transform.TransformPoint(otherVerts[i]));
if (distance <= maxDistance) {
//edit the vertices
}
}
other.GetComponent<deformable>().UpdateMesh(otherVerts);
}
}
this goes on the object being deformed
using UnityEngine; using System.Collections;
public class deformable : MonoBehaviour {
public Mesh mesh;
public Vector3[] verts;
public Mesh oldMesh;
void Start () {
if (mesh == null) {
oldMesh = mesh = this.GetComponent<MeshFilter>().mesh;
}
verts = mesh.vertices;
this.GetComponent<MeshFilter>().mesh = mesh;
}
public void UpdateMesh() {
mesh.vertices = verts;
this.GetComponent<MeshFilter>().mesh.vertices = mesh.vertices;
}
public void UpdateMesh(Vector3[] points) {
mesh.vertices = points;
this.GetComponent<MeshFilter>().mesh.vertices = mesh.vertices;
this.GetComponent<MeshCollider>().sharedMesh = null;
this.GetComponent<MeshCollider>().sharedMesh = mesh;
}
void OnApplicationQuit() {
this.GetComponent<MeshFilter>().mesh.vertices = oldMesh.vertices;
this.GetComponent<MeshCollider>().sharedMesh = null;
this.GetComponent<MeshCollider>().sharedMesh = oldMesh;
}
}
I'll give it a try and I'll let you know if this works for me.
Another question: Why you are using the shared$$anonymous$$esh? I've readed that it's recommended to use the shared$$anonymous$$esh only for reading the mesh data.
Oh, when I first made this, it was my first time ever doing anything with meshes and I was doing it for a hackathon, so when $$anonymous$$onodevelop recommended things when I put the '.' after get component, I didn't see just mesh only shared mesh and it worked for my scenario so yeah, probably shouldn't use that if you have multiple objects being deformed.