- Home /
Bad rotation performance vs. crazy joints vs. rigidbodies
Hi,
I've run into a nasty chain of problems involving rotations, rigidbodies and joints, and I can't see any good way out.
I have a spaceship that is a rigidbody, in zero gravity, working fine. As child objects of that ship, I have cannons, which are made up of a body that rotates left-right, and cannon barrels that rotate up-down (children of the body). All parts of the cannons have colliders but no rigidbodies, because I want them to get hit by incoming fire, but I don't want them to affect the movement of the ship. Body and barrel are rotated by script - at this point everything is working fine...
Initial problem: Rotation performance
.. until I realize the performance of the rotations is extremely bad. Calling Rotate() on a Transform for around 10 cannons every frame drops the framerate from 60 to 20. After some research I find out that objects with colliders but no rigidbodies are not supposed to be rotated, since they're assumed to be static by the engine. So I add a rigidbody to my cannon body, performance is fixed, but of course that opens the gate to new physics problems.
Complication #1: a rigidbody cannot be a child of a rigidbody
I try it anyway. If the cannon is kinematic, it affects the ship physics and moves it around - not good, but the cannon stays stuck to the ship properly. If the cannon is non-kinematic, and collisions with the ship are disabled, then the ship doesn't move, but the cannon does not follow it. So I try fixed joints instead.
Complication #2: not-so-fixed joints
I had never used them before, but my understanding of fixed joints is that they should make a rigidbody stick to another with 0 tolerance - otherwise it shouldn't be called "fixed", right?
I moved a cannon out of the ship hierarchy, gave it a fixed joint, and set the ship as the "connected body". That almost works, except that when the ship moves, the cannon jitters, as if the fixed joint position was updated a frame too late or something like that. My ship is moved only by AddForce(), so I know of anything in my scripts that could be causing this jitter. Physics engine bug?
I also tried setting the cannon to kinematic mode, but that seems to propagate to the connected body, and stops my ship from moving in any way.
What is the question?**
I have several, I hope somebody can help:
Is there any way to solve the rotation performance problem without involving rigid bodies?
What could be causing the fixed joint jitter? If it's a known engine problem, is there a workaround?
If fixed joints are not the way to go, and I can't parent a rigidbody to another, and I have to have cannons as rigidbodies because of the performance issue, is there anything else I can do besides writing my own parenting system?
Thanks for reading this far :)
Answer by Nimred · Jan 05, 2015 at 08:28 PM
Solved it, kinda. It looks like I had several mesh colliders on the same game object instead of one. That must have made the rotation performance problem much worse, because now that I removed the extra ones, performance seems fine. Even with 3 times as many cannons the framerate stays stable.
Answer by GameVortex · Jan 05, 2015 at 04:28 PM
I think you can solve this issue without the use of rigidbodies or joints because the performance issue is not the rotation. Rotating a object is cheap, it does nothing else than change some values of the transform. The performance issue comes from the call to the transform itself. The inherited variable transform of your Monobehaviour is actually an expensive GetComponent() function. Having multiple of these each frame would result in performance issues. To solve this you can cache the transforms instead, meaning you get the Transform component once, store it in a variable and then use that variable for accessing the Transform.
Example:
private Transform cachedTransform;
private void Start()
{
cachedTransform = transform;
}
private void Update()
{
cachedTransform.Rotate(Vector3.up * Time.deltaTime);
}
The same goes for anywhere you might be moving objects by using transform.position or scaling or any other uses of transform. Of course if you are only going to use the transform rarely you do not have to cache it as a call to transform once in a while is not a problem.
That's very good to know, I thought the transform variable was cached just as you coded it. However that's not the cause of the performance issue here, it really is the rotation. As it so happens I was already caching the transform, by coincidence (myBody is a Transform):
myBody.Rotate(Vector3.up, deltaAngle); // Commenting this line alone removes the performance issue.
There's several mentions of the rotation performance problem in UnityAnswers, and the manual talks about it as well:
Static Collider
This is a GameObject that has a Collider but no Rigidbody. Static colliders are used for level geometry which always stays at the same place and never moves around. Inco$$anonymous$$g rigidbody objects will collide with the static collider but will not move it.
The physics engine assumes that static colliders never move or change and can make useful optimizations based on this assumption. Consequently, static colliders should not be disabled/enabled, moved or scaled during gameplay. If you do change a static collider then this will result in extra internal recomputation by the physics engine which causes a major drop in performance. Worse still, the changes can sometimes leave the collider in an undefined state that produces erroneous physics calculations.