using System; using Unity.Burst; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Entities; using Unity.Jobs; using Unity.Mathematics; namespace Unity.Transforms { public abstract class LocalToParentSystem : JobComponentSystem { private EntityQuery m_RootsGroup; // LocalToWorld = Parent.LocalToWorld * LocalToParent [BurstCompile] struct UpdateHierarchy : IJobChunk { [ReadOnly] public ArchetypeChunkComponentType LocalToWorldType; [ReadOnly] public ArchetypeChunkBufferType ChildType; [ReadOnly] public BufferFromEntity ChildFromEntity; [ReadOnly] public ComponentDataFromEntity LocalToParentFromEntity; [NativeDisableContainerSafetyRestriction] public ComponentDataFromEntity LocalToWorldFromEntity; void ChildLocalToWorld(float4x4 parentLocalToWorld, Entity entity) { var localToParent = LocalToParentFromEntity[entity]; var localToWorldMatrix = math.mul(parentLocalToWorld, localToParent.Value); LocalToWorldFromEntity[entity] = new LocalToWorld {Value = localToWorldMatrix}; if (ChildFromEntity.Exists(entity)) { var children = ChildFromEntity[entity]; for (int i = 0; i < children.Length; i++) { ChildLocalToWorld(localToWorldMatrix, children[i].Value); } } } public void Execute(ArchetypeChunk chunk, int index, int entityOffset) { var chunkLocalToWorld = chunk.GetNativeArray(LocalToWorldType); var chunkChildren = chunk.GetBufferAccessor(ChildType); for (int i = 0; i < chunk.Count; i++) { var localToWorldMatrix = chunkLocalToWorld[i].Value; var children = chunkChildren[i]; for (int j = 0; j < children.Length; j++) { ChildLocalToWorld(localToWorldMatrix, children[j].Value); } } } } protected override void OnCreate() { m_RootsGroup = GetEntityQuery(new EntityQueryDesc { All = new ComponentType[] { ComponentType.ReadOnly(), ComponentType.ReadOnly() }, None = new ComponentType[] { typeof(Parent) }, Options = EntityQueryOptions.FilterWriteGroup }); } protected override JobHandle OnUpdate(JobHandle inputDeps) { var localToWorldType = GetArchetypeChunkComponentType(true); var childType = GetArchetypeChunkBufferType(true); var childFromEntity = GetBufferFromEntity(true); var localToParentFromEntity = GetComponentDataFromEntity(true); var localToWorldFromEntity = GetComponentDataFromEntity(); var updateHierarchyJob = new UpdateHierarchy { LocalToWorldType = localToWorldType, ChildType = childType, ChildFromEntity = childFromEntity, LocalToParentFromEntity = localToParentFromEntity, LocalToWorldFromEntity = localToWorldFromEntity }; var updateHierarchyJobHandle = updateHierarchyJob.Schedule(m_RootsGroup, inputDeps); return updateHierarchyJobHandle; } } }