Some Optimization Questions (Loops and Distance Calculations)

I’m hoping to optimize some of the scripting in my game. For my first problem, I noticed the profiler reveals 6.4% CPU from one type of script. It’s a custom LOD script that runs in FixedUpdate().

(LOD_Simple.FixedUpdate is the subject in question) The intent of the LOD script was to cut down on the Camera.Render percentage, but it seems my distance calculations are starting to take up a lot of CPU. (There’s a lot of instances of this script on many objects, and I’m not even done with the objects in the scene) The script is fairly simple, it is basically this but with a few more boolean checks (that are cached at startup)

function FixedUpdate ()
{
    isAngle = Vector3.Angle(t.position - cam.position, cam.forward) <= cam2.fieldOfView + 20;
    var curDist = Vector3.Distance(cam.position, t.position);
   
    if (curDist > dist1 || (!isAngle && curDist > dist1 * .5))
        {
            myRenderer.enabled = false;
        }
        else
        {
            myRenderer.enabled = true;
        }
}

As you can see, I’ve cached every Type I could ever need for this script. The Renderer, Transforms, and Camera are all local variables. All it does is check Distance and Angle and disables the renderer. (In some cases it also changes out the Mesh for a simpler version) Thinking through this, I know that the most efficient calculations are the ones that don’t happen at all. But it’s not like I can just stop calculating distance. The camera could be anywhere at any time.

Another solution could be to use collision data and triggers instead, but I’m worried about whether that’ll really be more efficient. As the profiler noted, Physics and Collision data is taking a big chunk out of CPU already. And using a Trigger system would result in a lot of instances of dynamic Colliders. So there must be a more efficient way to calculate Distance and Angle, right? Or is there a more complex solution I’m not seeing here? Is there something else that will allow me to switch the renderer with a lower cost?

Problem 2: AI scripts use Raycasts to detect their targets. So I store a list of targets and loop through each one with the Raycast. (Distance is done first so it gives up if targets are out of range) Something like this:

function FixedUpdate () {
   
    for (var i = 0; i < elen; i++)
    {
        var curEnemy = enemies[i];
        var curDist = Vector3.Distance(transform.position, curEnemy.transform.position);
        var curAware = enemyAwareness[i];
        if (curDist <= maxDist)
        {
            //raycasts and junk
        }
        else
        curAware = 0;
       
    }
   
}

I could do this easily with culling (distance from player) and by limiting the targets to a few for each enemy. I only had to do specific targets. But now a new enemy type requires me to do these checks for all characters! Which means a LOT of looping, I’m worried the same thing will happen as the LOD script. Except instead of just checking one transform, it has to check over 30! I thought I might get around it by only looping through closest characters, but that still requires a distance check to see who is close! There must be a more efficient way to get the closest couple of characters without checking against everyone for every FixedUpdate right??

Note: I’m using the fastest type of loop (to my knowledge) which is the for i = 0 etc. And I’m caching array length (i < elen) so I don’t have to reference it every time. But there must be more I can do to improve the performance of looping, even if looping ends up being the wrong choice for optimization, I would like to know in general if there’s a better way. :stuck_out_tongue:

Thanks in advance! Lastly, I was wondering exactly what “Overhead” is? It’s taking up 7% and I have no clue what it even does!

Hi SomeGuy22!
I can’t contribute too much; I just can help you a little.

Fixed update is executed several times per seconds; if I were you, I would try using Invoke method calling the function which handles the calculation once per second.
You will find out that the result will be (almost) the same, but you will be saving resources (play with distances and delay of Invoke method until you get what you want).

I guess this approach will be good enough to improve the performance.

Let me suppose you have 10 enemies and running the game at 60 fps.

  • Using fixed update you are performing 600 iteration (10 x 60).
  • But with the other approach, only 10 iteration (10 x 1 = 10).

Try it :smile:

For the first one, instead of using Vector3.Distance, use the square magnitude instead. This will save you a square root call per distance check (potentially 100-1000s?).

So your code would end up like this:

  var curDist = (cam.position - t.position).sqrMaginitude;
   
  if (curDist > dist1 * dist1 || (!isAngle && curDist > (dist1 * .5) * (dist1 * .5)))

You also might consider moving the code out of FixedUpdate and into LateUpdate so it’s only called once per frame, rather than multiple times per frame which the player couldn’t possibly see.

For the second one, consider putting a large sphere trigger collider around your character and adding anything that touches it to the potential target list. This will save you from having to loop through every single object in the game.

2 Likes

Distance performs a minus operation (I don’t know if it is said “minus” :P)… so, there is no problem using Distance:

As GroZZleR said, Distance uses two square root calls. magnitude is the square root of (xx+yy+z*z). Using Distance is just vectorA.magnitude-vectorB.magnitude. So that means, as I said, it calls two square root calls. Which is slow. So any time you can, it’s better to use .sqrMagnitude

1 Like

Thanks for the reply!

However the documentation clearly states FixedUpdate() is on a fixed framerate. Which means so long as the actual framerate is higher than the fixed rate, which it should be most of the time, as FixedUpdate() handles physics not every frame, but several times per second. Hence why I chose Fixed Update instead of Update(). By this, its not 10 x 60, but 10 x FixedTimeStep / Second

LateUpdate() however, is called every frame, which would actually be worse than FixedUpdate. Invoke Repeating can be customized however, so I guess I could try that to get even slower updates than fixed update. Also Regarding Distance, it’s true both use minus operations, but I’ve heard that sqrDistance performs better than the regular (a-b).magnitude (Which is what Vector3.Distance claims to do)

But I suggest to use Invoke method, not update either fixed :smile:

Yes! my bad!.. distance is not a vector!.
Correct, avoid using distance :smile:

Using .sqrMagnitude instead of Vector3.Distance brought down CPU usage by 2 or 3%!

As for the AI list, I was able to come up with a system that used exactly the code above, but now the list is controlled by Collision Triggers. For this, I had to use a dynamic List. that updates whenever objects meet certain conditions (tags and components). From there it can dynamically add and remove targets and the distance/angle code only applies to those on the list :slight_smile: Thanks a lot guys!

Also it seems Overhead might have something to do with vsync/inspector editor data. After completing that enemy script I’ll start nailing Rendering optimizations!