TransformSystem is responsible for updating the LocalToWorld transformation matrices used by other systems (including rendering).
By default, Unity updates a single TransformSystem instance each frame. EndFrameTransformSystem is updated before EndFrameBarrier and requires no additional work.
In cases where transform data is required to be updated at additional points in the frame, the suggested methods are:
- Create additional instance(s) of
TransformSystemand useUpdateBefore/UpdateAfterattributes to control where they are updated.
For example:
[UpdateBefore(typeof(EndFrameBarrier))]
public class EndFrameTransformSystem : TransformSystem<EndFrameBarrier>
{
}
- Create additional instance of
TransformSystemand update after everyComponentSystem(includes barriers, excludesJobComponentSystem) by using[ComponentSystemPatch]attribute. Be aware that the overhead for updating theTransformSystemafter everyComponentSystemcan be very high when the number ofComponentSystemclasses is large.
For example:
[ComponentSystemPatch]
public class PatchTransformSystem : TransformSystem<UserSystem>
{
}
- Manually update your systems. This is the expected method for more complex applications.
The only requirement for TransfromSystem is that one of the following components is associated with an Entity:
public struct Position : IComponentData
{
public float3 Value;
}
public struct Rotation : IComponentData
{
public quaternion Value;
}
public struct Scale : IComponentData
{
public float3 Value;
}
TransformSystem will add the LocalToWorld component and update the matrix based on the values in your selected associated components (Position, Rotation, and Scale). LocalToWorld does not need to be added by the user or other systems.
public struct LocalToWorld : ISystemStateComponentData
{
public float4x4 Value;
}
LocalToWorld is expected to be [ReadOnly] by other systems. Be aware that anything written to this component will be overwritten and its behavior during update is undefined if written to.
In many cases, individual transforms are never expected to change at runtime. For these types of objects, if a Static component is added:
public struct Static : IComponentData
{
}
They will cease to be updated after the LocalToWorld matrix has been created and updated for the first time. Any changes to associated Position, Rotation, or Scale components will be ignored. Marking Static transforms can substantially reduce the amount of work a TransformSystem needs to do which will improve performance.
The process of freezing is:
TransformSystemupdate queries forStaticcomponents.TransformSystemaddsFrozenPendingcomponent.TransformSystemupdates theLocalToWorldcomponent normally.- On the next
TransformSystemupdate, queries forFrozenPendingcomponents and addsFrozencomponent. TransformSystemignores Position, Rotation, or Scale components if there is an associatedFrozencomponent.
If necessary, users can detect if LocalToWorld matrix is frozen by existence of a Frozen component. Generally however, identifying static objects by the existence of the Static component is sufficient.
In cases where user systems require custom transformation matrices and updates, the TransformSystem will ignore components associated with a CustomLocalToWorld component.
public struct CustomLocalToWorld : IComponentData
{
public float4x4 Value;
}
If a CustomLocalToWorld component exists, it is expected that a user system will write the appropriate data. Position, Rotation, Scale, Static, and any other TransformSystem components are ignored.
Attaching transformations (transformation hierarchies) is controlled by separate "event" or "side-channel" entities associated with an Attach component.
public struct Attach : IComponentData
{
public Entity Parent;
public Entity Child;
}
To attach a Child Entity to a Parent Entity, create a new Entity with an associated Attach component, assigning the respective values.
For example:
var parent = m_Manager.CreateEntity(typeof(Position), typeof(Rotation));
var child = m_Manager.CreateEntity(typeof(Position));
var attach = m_Manager.CreateEntity(typeof(Attach));
m_Manager.SetComponentData(parent, new Position {Value = new float3(0, 2, 0)});
m_Manager.SetComponentData(parent, new Rotation {Value = quaternion.lookRotation(new float3(1.0f, 0.0f, 0.0f), math.up())});
m_Manager.SetComponentData(child, new Position {Value = new float3(0, 0, 1)});
m_Manager.SetComponentData(attach, new Attach {Parent = parent, Child = child});
- The
Attachcomponent, and associatedEntity, will be destroyed by theTransformSystemon update. - Values in Position, Rotation, and Scale components will be interpreted as relative to parent space.`
- Attached, Parent, and LocalToParent components will be associated with the Child
Entity.
public struct Attached : IComponentData
{
}
public struct Parent : ISystemStateComponentData
{
public Entity Value;
}
public struct LocalToParent : ISystemStateComponentData
{
public float4x4 Value;
}
To detach a child from a parent, remove the Attached component from the child. When the TransformSystem is updated, the Parent component will be removed. Values in Position, Rotation, and Scale components will be interpreted as relative to World space.
The LocalToWorld matrix can be used to retrieve World positions.
For example:
var childWorldPosition = m_Manager.GetComponentData<LocalToWorld>(child).Value.c3