- Home /
How can I optimize this burst compiled job for better performance than regular method on main thread?
I have converted one of my AI functions to a burst compiled job. However, the performance is slightly worse than regular method running on main thread. I have 200 agents using this when testing, so not a lot but more than a few.
First, I have an interface that simulates an "EarlyFixedupdate". This is achieved using script execution order and a simple component that I can add to any GameObject.. I use this same method to provide an "EarlyOnAnimatorIKUpdate". I use this to batch a bunch of sphere casts I need in the animator to place feet and works great. Noticeable performance gains and simple to implement.
public interface IEarlyFixedUpdate
{
void EarlyFixedUpdate();
}
public class EarlyFixedUpdateHandler : MonoBehaviour
{
IEarlyFixedUpdate earlyFixedUpdate;
private void Awake()
{
earlyFixedUpdate = GetComponent<IEarlyFixedUpdate>();
}
public void FixedUpdate()
{
earlyFixedUpdate.EarlyFixedUpdate();
}
}
This is the job:
[BurstCompile]
public struct AIMoveJob : IJob
{
public float3 myPosition;
public float fixedDeltaTime;
public float3 transformForward;
public float3 usingSlopeNormal;
public bool walkBackwards;
public float3 globalVelocity;
public float acceleration;
public bool leadTargetWhenClose;
public bool validTarget;
public bool targetIsClose;
public bool targetPathClear;
public bool moveAwayFromTarget;
public float targetIsCloseDistance;
public float targetDistance;
public float rotateForce;
public float torqueClamp;
public float speedDampingLowerLimit;
public float rotationDampingLowerLimit;
public float rotationDampingFromSpeed;
public float speedDampingFromRotation;
public float originalMaxSpeed;
public quaternion dotRot90;
// Results
public NativeArray<float3> resultSimulatedVelocity;
public NativeArray<float3> resultNextPosition;
public NativeArray<float> resultTorqueDelta;
public NativeArray<float> resultMaxSpeed;
public void Execute()
{
float moveSpeed;
float3 moveVelocity;
// Position
moveSpeed = math.min(math.length(myPosition - resultNextPosition[0]) / fixedDeltaTime,
resultMaxSpeed[0]);
moveVelocity = Util.ProjectOnPlane(transformForward * moveSpeed, usingSlopeNormal);
if (walkBackwards) moveVelocity = -moveVelocity;
resultSimulatedVelocity[0] = moveVelocity - globalVelocity;
// Clamp the velocity
if (math.length(resultSimulatedVelocity[0]) > acceleration * fixedDeltaTime) {
resultSimulatedVelocity[0] = math.normalize(resultSimulatedVelocity[0]) * acceleration * fixedDeltaTime;
}
// Lead the target one frame
if (leadTargetWhenClose && validTarget && targetIsClose && targetPathClear && !moveAwayFromTarget) {
float leadStrength = math.sqrt((targetIsCloseDistance - targetDistance) / targetIsCloseDistance);
resultNextPosition[0] += (globalVelocity * fixedDeltaTime * leadStrength);
}
// Rotation
float dotProduct = math.dot(math.mul(dotRot90, math.normalize(resultNextPosition[0] - myPosition)), transformForward);
if (walkBackwards) dotProduct = -dotProduct;
resultTorqueDelta[0] = math.clamp(dotProduct * rotateForce * fixedDeltaTime, -torqueClamp, torqueClamp);
float torqueModifier = math.max(moveSpeed * rotationDampingLowerLimit, moveSpeed / (1 + rotationDampingFromSpeed));
resultTorqueDelta[0] *= torqueModifier;
// Slow down if turning sharply
resultMaxSpeed[0] = math.max(speedDampingLowerLimit * originalMaxSpeed, originalMaxSpeed - (math.abs(resultTorqueDelta[0] * speedDampingFromRotation)));
}
}
This is the code used to prepare the job. This happens in the "EarlyFixedupdate".
void PrepareAIMoveJob()
{
resultSimulatedVelocity = new NativeArray<float3>(1, Allocator.TempJob);
resultNextPosition = new NativeArray<float3>(1, Allocator.TempJob);
resultTorqueDelta = new NativeArray<float>(1, Allocator.TempJob);
resultMaxSpeed = new NativeArray<float>(1, Allocator.TempJob);
//// Results
resultSimulatedVelocity[0] = groundManager.simulatedVelocity;
resultNextPosition[0] = nextPosition;
resultTorqueDelta[0] = groundManager.torqueDelta;
resultMaxSpeed[0] = richAI.maxSpeed;
AIMoveJob job = new AIMoveJob()
{
myPosition = root.myTransform.position,
fixedDeltaTime = Time.fixedDeltaTime,
transformForward = root.myTransform.forward,
usingSlopeNormal = groundManager.usingSlopeNormal,
walkBackwards = walkBackwards,
globalVelocity = groundManager.GlobalVelocity,
acceleration = richAI.acceleration,
leadTargetWhenClose = agentData.leadTargetWhenClose,
validTarget = ValidTarget,
targetIsClose = targetHandler ? targetHandler.TargetIsClose : false,
targetPathClear = targetPathClear,
moveAwayFromTarget = moveAwayFromTarget,
targetIsCloseDistance = agentData.targetIsCloseDistance,
targetDistance = targetHandler ? targetHandler.targetDistance : 0,
rotateForce = agentData.rotateForce,
torqueClamp = agentData.torqueClamp,
speedDampingLowerLimit = agentData.speedDampingLowerLimit,
rotationDampingLowerLimit = agentData.rotationDampingLowerLimit,
rotationDampingFromSpeed = agentData.rotationDampingFromSpeed,
speedDampingFromRotation = agentData.speedDampingFromRotation,
originalMaxSpeed = originalMaxSpeed,
dotRot90 = Util.dotRot90,
// Results
resultSimulatedVelocity = resultSimulatedVelocity,
resultNextPosition = resultNextPosition,
resultTorqueDelta = resultTorqueDelta,
resultMaxSpeed = resultMaxSpeed
};
aiMoveJobHandle = job.Schedule();
aiMoveJobPrepared = true;
}
So in "EarlyFixedUpodate" all the jobs are prepared and scheduled. Then in regular FixedUpdate I complete the jobs and process the results. I take care to dispose of the NativeArrays wherever needed.
The results in gameplay are the same as regular method but the performance is about 2 percent worse. I am only using the Mathematics library (including the ProjectOnPlane which is a static function that uses Unity mathematics). Any Vector3 are converted to float3.
Is there something I can do to actually increase the performance like batching or some scheduling option? It might just be that my required sample size is too small or the math is just too simple to achieve any benefits.
Your answer
![](https://koobas.hobune.stream/wayback/20220613005019im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Getter and Setter in C# 2 Answers
How do you bring your ideas to real code? 1 Answer
Unity after fixing build with error kept getting error until I changed build name 0 Answers
Unity Ads Quesition 0 Answers