I am having some problems with rotation conversions between local/world in a system. I am curious if anyone is able to identify what mistakes I am making.
I have a simple system that I am iterating through a few points at a very basic level. I can’t seem to get the rotation to convert properly back into a local space and create the intended result even though I have a few conversion equations that seem to be working. So I must assume it is an inconsistency in my knowledge of quaternion notation and/or operation.
I’ve tested the sequence of calculations in non-ecs and it is working fine. At a high level it is:
Vector3 pos = worldPoints[j].transform.position;
Vector3 toLastPoint = worldPoints[worldPoints.Length - 1].transform.position - pos;
Vector3 toTarget = target- pos;
Quaternion rotation= worldPoints[j].transform.rotation;
Quaternion targetRotation = Quaternion.FromToRotation(toLastPoint, toTarget) * pointRotation;
if (w >= 1) worldPoints[j].transform.rotation = targetRotation;
else worldPoints[j].transform.rotation = Quaternion.Lerp(pointRotation, targetRotation, w);
Of course it is worth noting that these positions and rotations are in world space.
When doing this with entities, the quaternion from the Rotation component and the float3 from the Translation are given in localSpace. I have tried both converting them to world (preferred solution) as well as converting everything to local. Neither seem to have the same result and again, I assume it is something wrong with the way I am handling the quaternions.
with ECS I am doing the following, with the translation and rotation taken from the input for the job they are in.
float3 ePos= EntityManager.GetComponentData<Translation>(e).Value;
LocalToWorld e1LTW = EntityManager.GetComponentData<LocalToWorld>(e);
float3 ePosWorld = GetEntityWorldPosition(e1LTW, ePos);
float3 toLastPoint = ePos2 - ePos;
float3 toTarget = localTarget - ePosWorld;
quaternion eRot = EntityManager.GetComponentData<Rotation>(e).Value;
quaternion eRotWorld = GetWorldRotation(e1LTW, eRot);
quaternion targetRotation = math.mul(FromToRotation(toLastPoint, toTarget), eRotWorld);
quaternion targetRotationLocal = GetLocalRotation(e1LTW, eRotations[j]);
entityManager.SetComponentData<Rotation>(e, new Rotation { Value = targetRotationLocal });
with the conversion as:
private static float3 GetEntityWorldPosition(LocalToWorld ltw, float3 t)
{
float4 pos = new float4(t, 1);
float3 worldPos= math.mul(ltw.Value, pos).xyz;
return worldPos;
}
private static float3 GetEntityLocalPosition(LocalToWorld ltw, float3 worldPosition)
{
float4 pos = new float4(worldPosition, 1);
float4x4 worldToLocal = math.inverse(ltw.Value);
float3 localPos = math.mul(worldToLocal, pos).xyz;
return localPos;
}
public static quaternion GetWorldRotation(LocalToWorld ltw, quaternion q)
{
return math.mul(quaternion.LookRotationSafe(ltw.Forward, ltw.Up), q.value);
}
public static quaternion GetLocalRotation(LocalToWorld ltw, quaternion q)
{
var invWorld = math.inverse(quaternion.LookRotationSafe(ltw.Forward, ltw.Up));
var result = math.mul(invWorld, q.value);
return result;
}
For the non-ecs portion the points line up as intended, and for the ecs, it keeps moving every frame and it is recalculating every frame.
Is there any issues with the quaternion conversions between world and local? Is there something wrong with my process of taking local position/rotation, converting to world, calculating and adding a new rotation, converting back to local, and assigning the new quaternion to the rotation?
Any help is greatly appreciated. Thank you.