using System.Collections.Generic; using System.Threading; using Unity.Entities; namespace UnityEngine.Perception.GroundTruth { struct IdAssignmentParameters : IComponentData { public uint idStart; public uint idStep; } /// /// System which notifies the registered about additions. /// public class GroundTruthLabelSetupSystem : ComponentSystem { List m_ActiveGenerators = new List(); ThreadLocal m_MaterialPropertyBlocks = new ThreadLocal(); int m_CurrentObjectIndex = -1; /// protected override void OnCreate() { //These are here to inform the system runner the queries we are interested in. Without these calls, OnUpdate() might not be called GetEntityQuery(ComponentType.Exclude(), ComponentType.ReadOnly()); GetEntityQuery(ComponentType.ReadOnly(), ComponentType.ReadOnly()); } /// protected override void OnUpdate() { var entityQuery = Entities.WithAll().ToEntityQuery(); IdAssignmentParameters idAssignmentParameters; if (entityQuery.CalculateEntityCount() == 1) idAssignmentParameters = entityQuery.GetSingleton(); else idAssignmentParameters = new IdAssignmentParameters {idStart = 1, idStep = 1}; var entityCount = Entities.WithAll().ToEntityQuery().CalculateEntityCount(); if (entityCount == 0) m_CurrentObjectIndex = -1; Entities.WithNone().ForEach((Entity e, Labeling labeling) => { var objectIndex = (uint)Interlocked.Increment(ref m_CurrentObjectIndex); var instanceId = idAssignmentParameters.idStart + objectIndex * idAssignmentParameters.idStep; var gameObject = labeling.gameObject; if (!m_MaterialPropertyBlocks.IsValueCreated) m_MaterialPropertyBlocks.Value = new MaterialPropertyBlock(); InitGameObjectRecursive(gameObject, m_MaterialPropertyBlocks.Value, labeling, instanceId); EntityManager.AddComponentData(e, new GroundTruthInfo { instanceId = instanceId }); labeling.SetInstanceId(instanceId); }); } void InitGameObjectRecursive(GameObject gameObject, MaterialPropertyBlock mpb, Labeling labeling, uint instanceId) { var renderer = (Renderer)gameObject.GetComponent(); if (renderer == null) renderer = gameObject.GetComponent(); if (renderer != null) { renderer.GetPropertyBlock(mpb); foreach (var pass in m_ActiveGenerators) pass.SetupMaterialProperties(mpb, renderer, labeling, instanceId); renderer.SetPropertyBlock(mpb); var materialCount = renderer.materials.Length; for (int i = 0; i < materialCount; i++) { renderer.GetPropertyBlock(mpb, i); //Only apply to individual materials if there is already a MaterialPropertyBlock on it if (!mpb.isEmpty) { foreach (var pass in m_ActiveGenerators) pass.SetupMaterialProperties(mpb, renderer, labeling, instanceId); renderer.SetPropertyBlock(mpb, i); } } } for (var i = 0; i < gameObject.transform.childCount; i++) { var child = gameObject.transform.GetChild(i).gameObject; if (child.GetComponent() != null) continue; InitGameObjectRecursive(child, mpb, labeling, instanceId); } } /// /// Activates the given . /// will be called for all instances under each object containing a component. /// /// The generator to register public void Activate(IGroundTruthGenerator generator) { m_ActiveGenerators.Add(generator); Entities.ForEach((Labeling labeling, ref GroundTruthInfo info) => { var gameObject = labeling.gameObject; InitGameObjectRecursive(gameObject, m_MaterialPropertyBlocks.Value, labeling, info.instanceId); }); } /// /// Deactivates the given . It will no longer receive calls when instances are created. /// /// The generator to deactivate /// True if the was successfully removed. False if was not active. public bool Deactivate(IGroundTruthGenerator generator) { return m_ActiveGenerators.Remove(generator); } internal void RefreshLabeling(Entity labelingEntity) { EntityManager.RemoveComponent(labelingEntity); } } }