I was trying to calculate angular acceleration times needed to rotate an object (say a ship for example), but they spin out of control when WithBurst() was used, WithoutBurst() works just fine.
Trying to find the cause, I discovered the following:
- Debug.Log itself changes the outcome of the calculation.
- Moving private static readonly fields into the job changes the outcome too.
The following was gutted out from a larger system.
using Unity.Entities;
using Unity.Jobs;
using UnityEngine;
using Unity.Physics.Systems;
using Unity.Physics;
using Unity.Mathematics;
using Unity.Collections;
/// <summary>
/// Azmi ~ 20210825
/// </summary>
[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
[UpdateBefore(typeof(BuildPhysicsWorld))]
[AlwaysUpdateSystem]
public class BuggedThrusterSystem : SystemBase
{
private static readonly quaternion PitchCW;
private static readonly quaternion PitchCCW;
private static readonly quaternion YawCW;
private static readonly quaternion YawCCW;
private static readonly quaternion RollCW;
private static readonly quaternion RollCCW;
static BuggedThrusterSystem()
{
PitchCW = quaternion.EulerZXY(0, 0, 0);
PitchCCW = quaternion.EulerZXY(math.PI, 0, 0);
RollCW = quaternion.EulerZXY(0, -math.PI / 2f, 0);
RollCCW = quaternion.EulerZXY(0, +math.PI / 2f, 0);
YawCW = quaternion.EulerZXY(-math.PI / 2f, 0, 0);
YawCCW = quaternion.EulerZXY(+math.PI / 2f, 0, 0);
}
protected override void OnUpdate()
{
NativeArray<float> result = new NativeArray<float>(1, Allocator.TempJob); // Dummy array, without this Burst optimizes the job to blank
// Calculate without burst
var vector = new float3(-1, 0, 0); // any vector
var velocity = new float3(10, 20, 0); // any vector
result[0] = BuggedCalculateAngularBurnSolution(vector, velocity, 5f);
Job
.WithBurst()
.WithCode(() =>
{
var vector = new float3(-1, 0, 0);
var velocity = new float3(10, 20, 0);
result[0] = BuggedCalculateAngularBurnSolution(vector, velocity, 5f);
})
.WithDisposeOnCompletion(result)
.Schedule();
}
static float BuggedCalculateAngularThrustBurnTime(quaternion inverse, float3 required, float3 angularVelocity, float angularAcceleration)
{
float3 localAdjust = math.mul(inverse, required + angularVelocity);
float3 localVelocity = math.mul(inverse, angularVelocity);
float I = localAdjust.z; // Angular distance to travel
float Vi = localVelocity.z; // Initial angular velocity per second
float a = angularAcceleration; // Acceleration
float Vm2 = ((2 * I * a) + (Vi * Vi)) / 2;
//Debug.Log($"Sample: {I} {Vi} {a} {Vm2}");
if (Vm2 < 0)
return 0;
float Vm = math.sqrt(Vm2);
return (Vm - Vi) / a;
}
static void BuggedCalculateAngularThrustBurnTime2(quaternion cwInverse, quaternion ccwInverse, float3 required, float3 angularVelocity, float angularAcceleration, out float burnTime, out bool burnCW)
{
float cwTime = BuggedCalculateAngularThrustBurnTime(cwInverse, required, angularVelocity, angularAcceleration);
float ccwTime = BuggedCalculateAngularThrustBurnTime(ccwInverse, required, angularVelocity, angularAcceleration);
if (cwTime > ccwTime)
{
burnTime = cwTime;
burnCW = true;
}
else
{
burnTime = ccwTime;
burnCW = false;
}
}
static float BuggedCalculateAngularBurnSolution(float3 vector, float3 angularVelocity, float acceleration)
{
// Calculate thruster burn times
float pitchBurnTime;
bool pitchBurnCW;
float rollBurnTime;
bool rollBurnCW;
float yawBurnTime;
bool yawBurnCW;
BuggedCalculateAngularThrustBurnTime2(PitchCCW, PitchCW, vector, angularVelocity, acceleration, out pitchBurnTime, out pitchBurnCW);
BuggedCalculateAngularThrustBurnTime2(RollCCW, RollCW, vector, angularVelocity, acceleration, out rollBurnTime, out rollBurnCW);
BuggedCalculateAngularThrustBurnTime2(YawCCW, YawCW, vector, angularVelocity, acceleration, out yawBurnTime, out yawBurnCW);
Debug.Log($"Calc: {vector} {pitchBurnCW} {pitchBurnTime} {rollBurnCW} {rollBurnTime} {yawBurnCW} {yawBurnTime}");
return pitchBurnTime + rollBurnTime + yawBurnTime;
}
}
Here is the result of the calculation as read by Debug.Log:
Calc: float3(-1f, 0f, 0f) False 0 True 2.447214 False 6
Calc: float3(-1f, 0f, 0f) True 5.969601E-07 True 3.414214 False 6.810694
The first line is without burst run from the main thread, the second line is from the bursted job, I think the discrepancy is way to large to attribute it to float precision?
Uncommenting the first Debug.Log fixes the issue?!
Reproduceable in Burst 1.4.1 and the latest 1.4.11 too.