Can't find Translation component in Unity.Transforms

Hey folks. Every content I read or watch mentions a allusive Translation and Rotation components in the Unity.Transforms package.

Ultimately, I’m trying to find the world position of one object and convert that to local position of another object (one object following another). But I can’t find any of these components anywhere and I can’t find a deprecation notice or documentation about how to make these translations between world and local spaces.

Can someone clarify what am I missing? Is this a package? A deprecation notice? A documentation I didn’t find?

I’m using Unity 2022.3.1f1 and Entities and Entities Graphics 1.0.11.

Thank you all.

Surprised you’re not asking about TransformAspect. It sounds like you were only looking at resources written for 0.51 and earlier.
https://docs.unity3d.com/Packages/com.unity.entities@1.0/manual/upgrade-guide.html#update-transforms-in-your-project

Objects only have immediately reliable information on their local space transformation. LocalToWorld stores a local-to-world matrix, but is mostly meant to be used for rendering, and the value will lag behind what it should be given the object hierarchy until the appropriate transform system runs. A more correct and general solution is to get the local-to-world of an object with TransformHelpers.ComputeWorldTransformMatrix and the world space position value from matrix.c3.xyz. Another object’s computed local-to-world can be inverted into a world-to-local, and the world position value can be transformed into a local position. This is an accurate solution but is slow due to random lookups. You should consider adding constraints to your design like only directly working with root objects when interaction between separate hierarchies is needed, to avoid needing to compute transformation matrices or rely on an updated LocalToWorld.

Thank you @Spy-Master , I couldn’t find any of the references you shared, and it’s really useful.

I’m not sure I follow your recommendation on the design. Can you be a bit more clear?

I have a Subscebe like so:

  • Subscene

  • Enemies

  • enemy1

  • enemy2

  • Allies

  • Ally1

  • Ally2

The player moves the whole group of Allies and each enemy has a reference for an ally to follow. I am using LocalToWorld somewhat like:

var allyPositionInWorld = allyLocalToWorld.TransformPoint(allyLocalTransform.Position);
var allyLocationOnEnemyLocal = enemyLocalToWorld.InverseTransformPoint(allyPositionInWorld)
var distance = allyLocationOnEnemyLocal - enemyLocalTransform.Position

would you approach any different?

thanks!

Moving around the world in Entity (Local To World) uses float4x4 to define position, rotation and scale.

public struct Teste : IComponentData{
    public Entity player;
    public LocalToWorld local;
}
public partial struct Teste2 : ISystem{

    void OnUpdate(ref SystemState systemState){
        foreach(Teste teste in SystemAPI.Query<Teste>()){
            Entity entity = systemState.EntityManager.Instantiate(teste.player);
            var position = float4x4.Translate(teste.local.Position);
            LocalToWorld localToWorld = teste.local;
            systemState.EntityManager.SetComponentData(entity, localToWorld);
        }
    }
}

9165554--1275482--upload_2023-7-23_8-24-34.png

The float4x4.Translate() also accepts the vector3 position of the transform.

         var position = new Vector3(0f,0f,0f);
         var newPosition = float4x4.Translate(position);

If you’re dead set on using a nested hierarchy (you seem to structure units to be hierarchy children of ally / root “container” or “batch” entities), the code you provided could work, depending on what things mean. If allyLocalToWorld and enemyLocalToWorld correspond to the parent entities for all allies and all enemies, that code seems correct.

If they instead correspond to the individual unit entity LocalToWorld values, allyLocalToWorld would just provide the (potentially stale from last frame if the entity’s LocalTransform was changed this frame) position of that entity directly through the .Position property. Also, once you get the allyLocationOnEnemyLocal value, the distance to the ally is just the length of that vector.

If you always keep the LocalToWorld of the parent entities in sync with their LocalTransform and you don’t use PostTransformMatrix (or you account for that when computing the true LocalToWorld), that design seems alright. If you implement it and see no problems with it, then you should do well with that, I see no major reason to change what works.

Alternatively, you can add a component (like “AllyTag”) that specifically identifies ally units, and instead of relying on the transform system to perform updates (which again causes LocalToWorld on the unit entities to be incorrect until the next transform system update, under the assumption that you only touch the root “batch” entity to move multiple things at once), you can switch to an IJobEntity that filters by the component that only allies have, and pass in the transformation that you want to apply. If multiple players exist and / or players can control multiple sets of allies at once, you could modify the ally-identifying component or add a new component, and store what group the ally is currently selected in. You’d use a NativeHashMap of group ID to transformation to apply, reset and add in the transformation that needs to occur for each group on every frame, and run a job which applies the correct transformation for that group on that entity, or perform no transformation if the group did not have a transformation that frame (no player input). Alternatively, if there are relatively few groups that could exist at any given time, you could use shared components to differentiate between different ally groups, and use a query that filters by a shared component value, used to schedule one job per group that needs a transformation. This might be better than trying a lookup per entity, but then you would need structural changes whenever an ally is switched to belong to a different active group. This means that you’re in charge of updating the unit LocalTransform values, but then you can always trust that you have a correct world space transformation because the entity does not need to depend on a parent to dynamically compute world transform with TransformHelpers or use the parent’s possibly stale LocalToWorld value. This line of thinking is most useful when any of the following are true:
-You need to get world space transform values fairly often, and you are not 100% sure your LocalToWorld for the parent has been updated with any transformations that occurred that frame (and using TransformHelpers to help with that is slow)
-You use Unity Physics, which doesn’t support nested transforms for physics bodies
-You want to just generally simplify how you manage transforms

To be clear, this is very dependent on use case, and solutions always depend on things like the number of entities and groupings, how often a piece of data is needed (and therefore whether you want it cached or just quickly recomputed each time), adjusting job dependencies / execution order / inputs and outputs to maximize parallelization.

Thanks for your reply here @Spy-Master . I’m still trying to wrap up my head around your suggestion. I group the entities mostly for easy of authoring and for moving the group.

If I got your restructuring suggestion right, you’re recommending I leave the parent “Allies” entity on 0,0 and instead move each individual entity on user input with the same transformation vector. Then I just use LocalTransform on the Enemies to follow their target, leaving local to world and vice versa out of the equation. Is this what you’re recommending?

Yes, either completely un-parented ally / enemy units or designing the parent to always have the identity transformation matrix (i.e. no special translation, rotation, scale). This means an extra job to apply a new transformation across all the moved entities if you move things in a group, but that can be a parallel operation and not cost too much to perform. Then, if you need the units’ world-space values later on, especially for things like target-follow behaviour, that could be worth it since you’d have quick access with LocalTransform.Position etc.

Right, thanks, I understand your recommendation.

It’s difficult for me to not to want to organize things hierarchically when you have units with limbs and want to raycast from a limb or position effects in specific cue points within a prefab, which means I’m bound to deal with all this complexity of translating between spaces.

I wonder if I’m too stuck to OO paradigm, but it sounds like too common of a need to me

Do you have any complex-ish game source code or video tutorial to point me to? I would love to see how they get away from constantly calling CalculateTransformMatrix on V Rising or any complex game, for example.