This is getting ridiculous. As the title says, I just want to raycast and get the child entity, just like in standard Unity → myRaycastHit.gameObject or myRaycastHit.collider.gameObject.
It seems impossible.
What I found in the changelog is:
Entity references in CompoundCollider children are no longer automatically set during baking since these references are not guaranteed to be valid in the World after baking. Only those entity references that appear in components and buffers, such as the PhysicsColliderKeyEntityPair buffer, are always guaranteed to be valid. Note that the PhysicsColliderKeyEntityPair buffer is still present on entities which contain a baked compound collider. Via collider keys, this buffer provides a mapping between the child colliders and the original entities that they were in at bake time.
I tried using the compoundCollider->GetColliderKeyToChildrenMapping method, and not only is it extremely slow for a compound collider with 15k entities, it also doesn’t return the Entity.
Seems like it is impossible as of right now to get the Entity reference of a child collider in a compound collider.
Please revert the change and let us access the Entity. I will check validity on my own, no need to remove that feature.
If there is another way to get the Entity, please make a Tutorial in the Docs, write it to the ScriptingAPI of the CompoundCollider and in the Manual under the Topic “CompoundCollider” (and here, as answer please).
The idea is that since entity remapping only really happens for component data and excludes blobs (and shared components), any entity values stored in the collider blob, even if they are set to the entities that exist at bake time, are totally meaningless since every other reference to the same entity would be replaced with the remapped entity.
The needed data on child colliders is still present on PhysicsColliderKeyEntityPair, in the same order as in the underlying collider blob. You just need to extract the child index from the collider key.
public static bool TryGetColliderEntity<TQueryResult>(
TQueryResult queryResult,
ComponentLookup<PhysicsCollider> colliderLookup,
BufferLookup<PhysicsColliderKeyEntityPair> physicsColliderKeyEntityPairLookup,
out Entity result)
where TQueryResult : IQueryResult
{
return TryGetColliderEntity(queryResult.ColliderKey, queryResult.Entity, colliderLookup, physicsColliderKeyEntityPairLookup, out result);
}
public static unsafe bool TryGetColliderEntity(
ColliderKey colliderKey,
Entity entity,
ComponentLookup<PhysicsCollider> colliderLookup,
BufferLookup<PhysicsColliderKeyEntityPair> physicsColliderKeyEntityPairLookup,
out Entity result)
{
if (colliderKey.Equals(ColliderKey.Empty)
|| !colliderLookup.TryGetComponent(entity, out var collider)
|| collider.Value.Value.Type != ColliderType.Compound)
{
result = entity;
return true;
}
ref CompoundCollider compoundCollider = ref Unity.Collections.LowLevel.Unsafe.UnsafeUtility.AsRef<CompoundCollider>(collider.Value.GetUnsafePtr());
if (!colliderKey.PopSubKey(compoundCollider.NumColliderKeyBits, out uint childIndex)
|| childIndex >= compoundCollider.NumChildren
|| !physicsColliderKeyEntityPairLookup.TryGetBuffer(entity, out var physicsColliderKeyEntityPairs)
|| childIndex >= physicsColliderKeyEntityPairs.Length)
{
result = Entity.Null;
return false;
}
result = physicsColliderKeyEntityPairs[(int)childIndex].Entity;
return true;
}
I just want to add that it can be extremely detrimental to performance to have compound colliders with 15k children, as this large number might affect the physics engine’s ability to properly parallelize the collision detection workload.
I suggest breaking these up into roughly colocated, smaller subsets. At bake time this can be achieved through additional root-level game objects within your subscene.
What does that mean? What is a remapped Entity? When I bake something, I get an Entity for each GameObject. And I can reference those Entities, right?
An Entity is a Struct with a Key/Index pointing to a location, right?
And when I convert a subscene, those locations are the actual Entities in my Game Scene, the Objects in my Hierarchy, no? So there would be no remapping required?
I feel like I am missing a fundamental concept here. The concept of remapping, probably.
I am working on destructible buildings, so these are physically moving objects - Rigidbodies with a lot of children. The actual collision solving seems to work just fine, but I can’t destroy individual walls, floors, glass panels of the compound collider, without getting the correct child entity on raycasts.
When a tower tilts and falls on the ground, I can still break the individual wall and floor elements of this tower, even after it became a rigidbody.
I already had everything working with PhysX but the reparenting caused a massive lag. On Every “SetParent()” call, PhysX would calculate something, as well as the Transform Component. And with about 15k reparenting calls, the lag was a few seconds. I tried using a coroutine and only reparent a few objects at a time but it still didn’t work. So here I am in ECS world, where batch reparenting is a thing. It almost worked in MonoBehaviour world, so I think it should be no issue in ECS world - the issue here is just how I can replicate the same logic, as far as I can tell.
Entity is composed of Index and Version. Index references a specific allocated index in the entity store used by the entity manager. There used to be per-world entity stores and thus per-world allocations (ENTITY_STORE_V1), but these days it’s all allocated from a global store. The version is used to allow distinguishing the entity currently assigned an index from destroyed entities that were assigned the same index in the past, so entity (3:1) (index 3, version 1) gets destroyed and a new entity (3:2) won’t be confused for the other one. You’re also prevented from using references to destroyed entities like (3:1) to get data.
Operations like entity instantiation and loading subscenes require assigning identities in the entity store. The entity store could have allocated indices to currently active entities. A number of factors make attempting to acquire specific indices+versions for the original entities generally unreliable, including the presence of singletons that didn’t exist at bake time, entities instantiated at runtime, multiple worlds allocating from the same store, and loading a given subscene multiple times.
The mechanism used to deal with this is remapping the origin entities to new Entity values, giving each entity a newly allocated identity and replacing references (in component data) to the original identities with the new ones. The remapping allows for inter-entity references to be preserved. Remapping only goes so far; it doesn’t extend into blob data, which is why the physics change was made.