Search Unity

help decreasing CPU hungry function

Discussion in 'Scripting' started by EliJNemer, Feb 14, 2020 at 12:03 AM.

  1. EliJNemer

    EliJNemer

    Joined:
    Aug 3, 2019
    Posts:
    94
    hello,

    i have a function in my game which is very cpu hungry. it decreases my fps from 120 to 20 when i use it..

    do any of you know a good method of decreaseing the cpu usage of this function? other that the usual methods of run function every 2nd or 3rd frame and such?

    it is a trajectory simulation code..

    here is the code for anyone intrested

    Code (CSharp):
    1. void Update()
    2. {
    3. //if mouse pressed and somevariable changed =>
    4. simulate();
    5. }
    6.  
    7. void Simulate()
    8.     {
    9.         if (!simulationStarted)
    10.         {
    11.             simulationStarted = true;
    12.  
    13.             //first simulation ==============================
    14.             ballPositionsOfflineSim = OfflineBallSimulationForGame.SimulateBall(ballRB[0], force, positionToHit, numberOfSimulationSteps, false);
    15. }
    //new script

    Code (CSharp):
    1. public static class OfflineBallSimulationForGame {
    2.     public static DiscreteDynamicsWorld World;
    3.  
    4.  
    5.     //IMPORTANT Time.fixedTime must match the timestep being used here.
    6.     public static List<UnityEngine.Vector3> SimulateBall(BRigidBody ballRb, UnityEngine.Vector3 ballThrowForce, UnityEngine.Vector3 positionToHit,int numberOfSimulationSteps, bool reverseOrder)
    7.     {
    8.  
    9.         var ballPositions = new List<UnityEngine.Vector3>(numberOfSimulationSteps);
    10.  
    11.         //Create a World
    12.         //Debug.Log("Initialize physics");
    13.      
    14.         CollisionConfiguration CollisionConf;
    15.         CollisionDispatcher Dispatcher;
    16.         BroadphaseInterface Broadphase;
    17.         CollisionWorld cw;
    18.         ConstraintSolver Solver;
    19.         BulletSharp.SoftBody.SoftBodyWorldInfo softBodyWorldInfo;
    20.  
    21.         //This should create a copy of the BPhysicsWorld with the same settings
    22.         BPhysicsWorld bw = BPhysicsWorld.Get();
    23.         bw.CreatePhysicsWorld(out cw, out CollisionConf, out Dispatcher, out Broadphase, out Solver, out softBodyWorldInfo);
    24.         World = (DiscreteDynamicsWorld) cw;
    25.  
    26.         //Copy all existing rigidbodies in scene
    27.         // IMPORTANT rigidbodies must be added to the offline world in the same order that they are in the source world
    28.         // this is because collisions must be resolved in the same order for the sim to be deterministic
    29.         DiscreteDynamicsWorld sourceWorld = (DiscreteDynamicsWorld) bw.world;
    30.         BulletSharp.RigidBody bulletBallRb = null;
    31.         BulletSharp.Math.Matrix mm = BulletSharp.Math.Matrix.Identity;
    32.         for(int i = 0; i < sourceWorld.NumCollisionObjects; i++)
    33.         {
    34.             //here we add the RigidBodies from the source World
    35.             CollisionObject co = sourceWorld.CollisionObjectArray[i];
    36.            
    37.            
    38.             //Debug.Log(sourceWorld);
    39.            
    40.             if (co != null && co.UserObject is BRigidBody)
    41.             {
    42.                 BRigidBody rb = (BRigidBody) co.UserObject;
    43.                 float mass = rb.isDynamic() ? rb.mass : 0f;
    44.                 BCollisionShape existingShape = rb.GetComponent<BCollisionShape>();
    45.                 CollisionShape shape = null;
    46.                 if (existingShape is BSphereShape)
    47.                 {
    48.                     shape = ((BSphereShape)existingShape).CopyCollisionShape();
    49.                 }
    50.                 else if (existingShape is BBoxShape)
    51.                 {
    52.                     shape = ((BBoxShape)existingShape).CopyCollisionShape();
    53.                 }
    54.                 else if (existingShape is BConvexHullShape)
    55.                 {
    56.                     shape = ((BConvexHullShape)existingShape).CopyCollisionShape();
    57.                 }
    58.            
    59.  
    60.                 RigidBody bulletRB = null;
    61.                 BulletSharp.Math.Vector3 localInertia = new BulletSharp.Math.Vector3();
    62.                 rb.CreateOrConfigureRigidBody(ref bulletRB, ref localInertia, shape, null);
    63.                 BulletSharp.Math.Vector3 pos = rb.GetCollisionObject().WorldTransform.Origin;
    64.                 BulletSharp.Math.Quaternion rot = rb.GetCollisionObject().WorldTransform.GetOrientation();
    65.                 BulletSharp.Math.Matrix.AffineTransformation(1f, ref rot, ref pos, out mm);
    66.                 bulletRB.WorldTransform = mm;
    67.                 World.AddRigidBody(bulletRB, rb.groupsIBelongTo, rb.collisionMask);
    68.                 if (rb == ballRb)
    69.                 {
    70.                     bulletBallRb = bulletRB;
    71.                     bulletRB.ApplyImpulse(ballThrowForce.ToBullet(), positionToHit.ToBullet());
    72.                 }
    73.             }
    74.         }
    75.  
    76.         //Step the simulation numberOfSimulationSteps times
    77.         for (int i = 0; i < numberOfSimulationSteps; i++)
    78.         {  
    79.                 int numSteps = World.StepSimulation(1f / 100f, 10, 1f / 100f);
    80.                 ballPositions.Add(bulletBallRb.WorldTransform.Origin.ToUnity());
    81.  
    82.             //BallThrowTestForGame.lineStrips_0.LineVertices[i] = bulletBallRb.WorldTransform.Origin.ToUnity();
    83.         }
    84.        
    85.  
    86.         if (World != null)
    87.         {
    88.             //remove/dispose constraints
    89.             int i;
    90.             for (i = World.NumConstraints - 1; i >= 0; i--)
    91.             {
    92.                 TypedConstraint constraint = World.GetConstraint(i);
    93.                 World.RemoveConstraint(constraint);
    94.                 constraint.Dispose();
    95.             }
    96.  
    97.             //remove the rigidbodies from the dynamics world and delete them
    98.             for (i = World.NumCollisionObjects - 1; i >= 0; i--)
    99.             {
    100.                 CollisionObject obj = World.CollisionObjectArray[i];
    101.                 RigidBody body = obj as RigidBody;
    102.                 if (body != null && body.MotionState != null)
    103.                 {
    104.                     body.MotionState.Dispose();
    105.                 }
    106.                 World.RemoveCollisionObject(obj);
    107.                 obj.Dispose();
    108.             }
    109.  
    110.             World.Dispose();
    111.             Broadphase.Dispose();
    112.             Dispatcher.Dispose();
    113.             CollisionConf.Dispose();
    114.         }
    115.  
    116.         if (Broadphase != null)
    117.         {
    118.             Broadphase.Dispose();
    119.         }
    120.         if (Dispatcher != null)
    121.         {
    122.             Dispatcher.Dispose();
    123.         }
    124.         if (CollisionConf != null)
    125.         {
    126.             CollisionConf.Dispose();
    127.         }
    128.  
    129.         return ballPositions;
    130.     }
    131. }
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    4,984
    Before you optimize or adjust anything, get some more baseline numbers. Getting the FPS is a great start, but also track some of the obvious parametrics, such as the current values of
    World.NumCollisionObjects
    and
    World.NumConstraints
    and
    numberOfSimulationSteps
    .

    From the looks of the above code I am gonna guess you are pumping a metric buttload of things through the CPU. Try to identify what each of those loop count loops is doing. Are all of them necessary every frame? Can you get away with fewer of them? Can you pool them spatially and only do the ones near the player? Can you do 1/10th of some step each frame round-robin?

    Also, if in doubt about what exactly is dogging you, the Profiler is your friend. Hit Window->Analysis->Profiler and run your code a bit, learn how to use that and identify where your hotspots are.
     
    EliJNemer and All_American like this.
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    6,876
    Do a deep profile, find out what parts of that function are the slowest.

    I have a strong feeling this:
    Code (csharp):
    1. bw.CreatePhysicsWorld(out cw, out CollisionConf, out Dispatcher, out Broadphase, out Solver, out softBodyWorldInfo);
    Is going to be slow.

    I can't see how 'creating a physics world' is going to at all fast. Especially the result contains lots of collision objects (you get the World from bw later and loop 'NumCollisionObjects').

    A lot of this creation code where you create a world, get various output objects, use them for simulation, and then dispose them. Is there a reason you can't create it once and recycle it over and over?

    Mind you, I and many others of us may not be familiar with the library you're using. So knowing the overheads and implications of these various objects is an unknown to us. But just from the names/looks of it... yeah, just the creation of these disposable objects every time you call this seems a bit much.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    4,984
    Nice spot lord. I agree; that's likely a thing that should happen less than once a frame.

    OP: see if you can find a project that uses this lib, if it's not yours, and try to suss out what they do once, and what they run every frame. It's likely very performant when used correctly, and that's just a matter of slotting it into Unity's lifecycle properly.
     
    EliJNemer likes this.
  5. All_American

    All_American

    Joined:
    Oct 14, 2011
    Posts:
    1,277
    Or get a better cpu.
     
    Joe-Censored likes this.
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    4,984
    I love that your username is All_American and that's the suggestion! MORE POWER!!!!!!
     
  7. All_American

    All_American

    Joined:
    Oct 14, 2011
    Posts:
    1,277
    I was joking...

    but I would upgrade...Lololol
     
    EliJNemer and Kurt-Dekker like this.
unityunity