- Home /
Vertex Mesh Optimization Question
Hey thanks for checking out my question! I currently have a grenade script that will pass in variables to my terrain mesh deformation script and loop through all the vertices in the terrain mesh and modify those that are within a certain radius. However, I was wondering if there was a way to avoid looping through all the vertices and just grab the vertices within the grenade radius? I noticed that with a raycasthit, you can retrieve the index for the triangle, but I cannot seem to find something like that for overlapshpere. Any help is appreciated, thanks.
public class Grenade : MonoBehaviour {
public float explosionDelay;
public float explosionRadius;
public float explosionPower;
public LayerMask effectLayer;
void Start () {
StartCoroutine(Explode());
}
IEnumerator Explode() {
yield return new WaitForSeconds(explosionDelay);
Collider[] _hit = Physics.OverlapSphere(transform.position, explosionRadius, effectLayer);
for (int i = 0; i < _hit.Length; i++) {
if (_hit[i].GetComponent<DeformTerrain>())
_hit[i].GetComponent<DeformTerrain>().DeformMesh(transform.position, explosionRadius, explosionPower);
}
Destroy(gameObject);
}
}
public class DeformTerrain : MonoBehaviour {
private MeshFilter meshf;
private Vector3[] verts;
public void DeformMesh(Vector3 _Position, float _radius, float _power) {
meshf = GetComponent<MeshFilter>();
verts = meshf.mesh.vertices;
for (int i = 0; i < verts.Length; i++) {
Vector3 worldVert = transform.TransformPoint(verts[i]);
float _dist = Vector3.Distance(worldVert, _Position);
if (_dist < _radius) {
verts[i].y -= _power * (_dist/2); //This makes it a bit more rounded
}
}
Destroy(GetComponent<MeshCollider>());
meshf.mesh.vertices = verts;
gameObject.AddComponent<MeshCollider>();
}
}
Answer by Bunny83 · Mar 17, 2018 at 02:58 AM
Well, it depends on how your vertices are arranged in the array. If it follows some logic you could work out a sub region of your vertices array. However if you have no idea how the vertices a distributed in the array you have no other way than iteration over all. Though there is a major improvement to your code: Do not transform ever single vertex into worldspace. Instead just transform your "_Position" into the local space of the terrain object. That way you can work with local space coordinates. Also you may want to check the squared distance for slightly better performance.
public void DeformMesh(Vector3 _Position, float _radius, float _power)
{
meshf = GetComponent<MeshFilter>();
verts = meshf.mesh.vertices;
Vector3 pos = transform.InverseTransformPoint(_Position);
float r2 = _radius * _radius;
for (int i = 0; i < verts.Length; i++)
{
float _dist = (verts[i] - pos).sqrMagnitude;
if (_dist < r2)
verts[i].y -= _power * (Mathf.Sqrt(_dist)/2);
}
Destroy(GetComponent<MeshCollider>());
meshf.mesh.vertices = verts;
gameObject.AddComponent<MeshCollider>();
}
Note that the biggest performance killer is your $$anonymous$$eshCollider. However to further improve your script you may want to pull those two lines into the Start method of your "DeformTerrain " class:
meshf = GetComponent<$$anonymous$$eshFilter>();
verts = meshf.mesh.vertices;
Of course this would only work when this is the only script that is manipulating the terrain mesh because in this case we don't need to read the vertices back every time we deform the mesh.