- Home /
OnCollisionStay perfomance
Hi,
I have a large scene with many collisions and OnCollisionStay is consuming too much resources. I'd like this event to be fired every seconds. Is somebody have a tip for this? I have tried "yield return new WaitForSeconds(1.0f);" but it doesn't prevent from firing.
Is there another way to get existing collision information without OnCollisionStay?
Thanks Harold
EDITED: Thanks for your answer.
But the problem is that my collision is changing each frame and I need more than the existence of the contact.
Vector3 GetContactsBarycenter(ContactPoint[] points, GameObject target)
{
Vector3 bar = Vector3.zero;
foreach (ContactPoint pt in points)
bar += pt.point;
return target.transform.InverseTransformPoint(bar / (float)points.Length);
}
IEnumerator OnCollisionStay(Collision collision)
{
Debug.DrawRay(collision.gameObject.transform.TransformPoint(
GetContactsBarycenter(collision.contacts, collision.gameObject)),
collision.gameObject.transform.TransformDirection(Vector3.up),
Color.green);
yield return 0;
}
@HPx, I edited your question and added the script to it (the Your answer box must be used only to post answers - UA is different from forums)
Answer by aldonaletto · Dec 22, 2011 at 10:06 AM
Why do you need to use OnCollisionStay? Saving a copy of contacts during OnCollisionEnter could be enough, depending on what you need to do:
var myContacts: ContactPoint[];
function OnCollisionEnter(coll: Collision){ myContacts = coll.contacts; } You should edit your question an post your script - we could check it and have more ideas on how to reduce the CPU load.
EDITED:
OnCollisionStay is called each physics cycle while the rigidbody is awake - even if you disable the script - but maybe you could reduce the load by calling the barycenter calculation routine only at some interval, like this:
public float baryInterval = 1; // report barycenter each second float baryTime = 0;
Vector3 GetContactsBarycenter(ContactPoint[] points, GameObject target) { Vector3 bar = Vector3.zero; foreach (ContactPoint pt in points) bar += pt.point; return target.transform.InverseTransformPoint(bar / (float)points.Length); }
void OnCollisionStay(Collision collision) { if (Time.time > baryTime){ // report only when the time has come baryTime = Time.time + baryInterval; // calculate new baryTime Debug.DrawRay(collision.gameObject.transform.TransformPoint( GetContactsBarycenter(collision.contacts, collision.gameObject)), collision.gameObject.transform.TransformDirection(Vector3.up), Color.green); } } Physx will still have to calculate the contact points each time, but at least your code will only execute at the defined interval.
I don't think my code influence anything.
What is time-consu$$anonymous$$g is the computing of Collision structure. What's why I'd like to execute it once a second or if it's not possible to store collisions in a list with Enter and Exit and calculate Collision struct in a co-routine, but I'm not sure it's possible.
I think it's rather a problem of physX than Unity. I think I've reached the joint number limitations. It would be better if PhysX was multithreaded.
Thanks anyway.
Physx and Unity functions run much faster than our code: they are created in C++ or other high level languages and compiled to native machine code, while our scripts are compiled to CIL, an interpreted language that has a lot of overhead. Generating the Collision structure takes time, for sure, but maybe reducing the script part you get some appreciable speed improvement. I once had a script that used Debug.DrawRay to show the contact normals of 8 blocks, and it reduced the frame rate to ridiculous levels; when I removed the Debug instructions, the frame rate returned to the regular speed.