For a given Translation component that could be in a hierarchy with arbitrary other rotations, scales and translations on its parents, how do I set the Translation.Value so LocalToWorld.Position will be at a given world position?
Multiplying by the inverse of the localToWorld matrix doesn’t compile.
float3 worldPosition = new float3(1, 2, 3);
float4x4 worldToLocal = math.inverse(localToWorld.Value);
translation.Value = math.mul(worldPosition, worldToLocal); // this will not compile, what is the correct notation or solution?
While that does seem to compile it does not seem to provide a valid local position that can be applied to Translation to effectively set it to a given world position =/
Cause you doing it wrong You mul to LTW and setting Translation directly, but Translation is in parent relation space. You should add your new local pos to current translation value. Example:
public class TransformSystemTest : JobComponentSystem
{
private EntityQuery _query;
protected override void OnCreate()
{
_query = GetEntityQuery(typeof(LocalToWorld), typeof(Translation));
}
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
if (Input.GetKeyDown(KeyCode.Space))
{
Debug.Log("Move last child to (1,1,1) in world space");
var ltw = _query.ToComponentDataArray<LocalToWorld>(Allocator.TempJob);
var t = _query.ToComponentDataArray<Translation>(Allocator.TempJob);
float4 newWorldPosition = new float4(1, 1, 1, 1);
float4x4 worldToLocal = math.inverse(ltw[2].Value);
float3 newLocalPos = t[2].Value + math.mul(worldToLocal, newWorldPosition).xyz;
var tmp = t[2];
tmp.Value = newLocalPos;
t[2] = tmp;
_query.CopyFromComponentDataArray(t);
ltw.Dispose();
t.Dispose();
}
return inputDeps;
}
}
You, sir, are a lifesaver. Thanks so much for taking the time to write that out
I suppose that for the less mathematically inclined it would be nice to have some utility methods.
I’ll leave the one for position here for posterity:
I don’t suppose I could bother you for a similar method to set the world rotation? I’ve been at it for a while but keep getting cubes jumping around my screen.
Rotation is not so easy like that. This is why Unity have complex rotation stuff in current system. Look at Mike (If I remember right it was his talk) talk about transform system and how they work with rotation, composite rotation etc. And read this docs for better understanding https://docs.unity3d.com/Packages/com.unity.entities@0.1/manual/transform_system.html
Just an FYI for people who come here looking for a way to sync a non-ECS transform position / rotation to an entity; there is a much easier way of doing it:
EntityManager.AddComponentObject(entity, gameObject.transform);
EntityManager.AddComponentData(entity, new CopyTransformFromGameObject { });
// OR
EntityManager.AddComponentData(entity, new CopyTransformToGameObject { });
There are 3 things to note with this method:
You can remove the transform using RemoveComponent.
It is possible to assign another non-null transform by calling AddComponentObject() again.
The syncing of the transform from the gameObject to the entity seems to be applied directly to the LocalToWorld matrix and the Rotation value is not set as you would expect. Could be a bug they’ll fix but for now it may lead to confusion. You should use the LocalToWorld matrix to get the world position and world rotation from the entity if needed (just use Quaternion.LookRotation(localToWorld.Forward, localToWorld.Up) to get the world rotation)
Apparently setting the rotation to a global rotation for a nested entity also requires you to update the LocalToWorld and LocalToParent, but it’s actually pretty straight forward.
I’ve created a solution that seems to work. Simply add a FollowComponent to an entity and define the entity to follow and the following entity’s position / rotation will be set to follow.
Disclaimer: Use at your own peril, have yet to extensively test this. It does not include anything to handle scaling in the hierarchy.
What about one for scale? Say I have entity (A) and (B), and I want to parent (B) to (A), but (A) and/or it’s parents might have non-uniform and non-default scales, which automatically skews (B) the moment its parented. Is there a way to use LTW Values to compensate for scale? So that if (B) was 1, 2, 1 in world scale, it would remain so after parented but with new local to parent scale?