Using OverlapAabb() within Entities.ForEach

As the title says, I am attempting to call OverlapAabb() from within a system's Entities.ForEach. Unfortunately, I have not been able to get this to work and have been getting an out of range exception from the OverlapAabb() call, specifically from this line in AabbLeaf() from Broadphase.cs:

RigidBody body = m_Bodies[rigidBodyIndex];

I should mention that I am not converting any GameObjects to entities, rather, I create all entities with PhysicsCollider and other required components at runtime. The package version I am using is 0.4.1.

Even though the error was different, I tried using the suggestions from this post, specifically, adding [UpdateBefore(typeof(EndFramePhysicsSystem))] and [UpdateAfter(typeof(StepPhysicsWorld))] to the system in question and Dependency = JobHandle.CombineDependencies(Dependency, buildPhysicsWorld.GetOutputDependency()); prior to scheduling the ForEach, this did not fix the problem however. I also tried to running this system only after a few frames had passed to see if uninitialized components were the culprit but that did not work either.

This is my block of code from inside ForEach:

var hitList = new Unity.Collections.NativeList<int>(1024, Allocator.Temp);
collisionWorld.OverlapAabb(
    new OverlapAabbInput
    {
        Aabb = new Aabb { Max = myMaxValue, Min = myMinValue },
        Filter = new CollisionFilter
        {
            BelongsTo = ~0u,
            CollidesWith = ~0u,
            GroupIndex = 0,
        }
    },
    ref hitList
);

Any help at all would be greatly appreciated!

It should be

Dependency = JobHandle.CombineDependencies(Dependency, stepPhysicsWorld.GetOutputDependency());

// do foreach stuff

endFramePhysicsSystem.AddInputDependency(Dependency);
1 Like

Thanks for the quick reply!

After adding these two lines I still get an error, albeit a different one. This new error is a null reference exception pointing to this line from AabbOverlap() in BoundingVolumeHierarchy.cs:

Node* node = m_Nodes + nodeIndex;

Removing the UpdateAfter and UpdateBefore that I mentioned in my first post didn't change this. I also tried delaying this systems first run again with no luck.

Judging by the fact that m_Nodes is a member of BoundingVolumeHierarchy I'm worried that I'm missing some call to build the BVH in the first place. I didn't see any such requirement in the documentation, but I'll go back to double check...

If BuildPhysicsWorld system is not running, then you need to build the BVH on your own. But if this system is running, you should be good to go. Where did you get your collisionWorld from?

I fetch the CollisionWorld each time OnUpdate() is called from a PhysicsWorld member. The PhysicsWorld is instantiated in OnCreate() with World.GetOrCreateSystem().PhysicsWorld

[quote]
If BuildPhysicsWorld system is not running, then you need to build the BVH on your own. But if this system is running, you should be good to go.
[/quote]

I checked in the entities debugger and it says BuildPhysicsWorld is running. I'll continue looking into this problem today

After checking the physics samples I stumbled across the solution. I changed this

BuildPhysicsWorld m_PhysicsWorld;

protected override void OnCreate()
{
    m_PhysicsWorld = World.GetOrCreateSystem<BuildPhysicsWorld>().PhysicsWorld;
}

protected override void OnUpdate()
{
    var colWorld = m_PhysicsWorld.CollisionWorld;

    // Entities.ForEach...
}

to

BuildPhysicsWorld m_BuildPhysicsWorld;

protected override void OnCreate()
{
    m_BuildPhysicsWorld = World.GetOrCreateSystem<BuildPhysicsWorld>();
}

protected override void OnUpdate()
{
    var colWorld = m_BuildPhysicsWorld.PhysicsWorld.CollisionWorld;

    // Entities.ForEach...
}

Yes, you need to get the physics world each frame from the BuildPhysicsWorld. Did that help in the end?

Yes, it did, thanks again for the help!

2 Likes

Im getting an error when I do this

code:

protected override void OnUpdate()
    {
        var ecb = buffer.CreateCommandBuffer().AsParallelWriter();
        var step = World.GetOrCreateSystem<StepPhysicsWorld>();
        var bpw = World.GetOrCreateSystem<BuildPhysicsWorld>();
        var endframe = World.GetOrCreateSystem<EndFramePhysicsSystem>();
        var pw = bpw.PhysicsWorld;
        var cw = pw.CollisionWorld;

        Dependency = JobHandle.CombineDependencies(Dependency, step.GetOutputDependency());

        Entities
            .ForEach((in DynamicBuffer<TriggerBuffer> buffer, in LocalToWorld ltw) =>
            {
                var aabb = pw.CalculateAabb(new RigidTransform(ltw.Value)); //this caused the error below

                var input = new OverlapAabbInput { Aabb = aabb };
                var hitList = new NativeList<int>(Allocator.Temp);
                cw.OverlapAabb(input, ref hitList); //does not like this....?
                Debug.Log(hitList.Length);
                hitList.Dispose();
            })
            .Schedule();

        endframe.AddInputDependency(Dependency);
    }

error:

InvalidOperationException: The writeable Unity.Collections.NativeArray`1[Unity.Physics.RigidBody] <>c__DisplayClass_OnUpdate_LambdaJob0.JobData.pw.CollisionWorld.m_Bodies is the same Unity.Collections.NativeArray`1[Unity.Physics.RigidBody] as <>c__DisplayClass_OnUpdate_LambdaJob0.JobData.cw.m_Bodies, two containers may not be the same (aliasing).

any ideas?

nvm. This new code worked:

protected override void OnUpdate()
    {
        var ecb = buffer.CreateCommandBuffer().AsParallelWriter();
        var pw = bpw.PhysicsWorld;
        var cw = pw.CollisionWorld;

        Dependency = JobHandle.CombineDependencies(Dependency, step.GetOutputDependency());

        Dependency = Entities
            .ForEach((in DynamicBuffer<TriggerBuffer> buffer, in PhysicsCollider col, in LocalToWorld ltw) =>
            {
                var aabb = col.Value.Value.CalculateAabb(new RigidTransform(ltw.Value));
                var input = new OverlapAabbInput
                {
                    Aabb = aabb,
                    Filter = new CollisionFilter()
                    {
                        BelongsTo = ~0u,
                        CollidesWith = ~0u, // all 1s, so all layers, collide with everything
                        GroupIndex = 0
                    }
                };
                var hitList = new NativeList<int>(Allocator.Temp);
                cw.OverlapAabb(input, ref hitList);
                Debug.Log(hitList.Length);
            })
            .Schedule(Dependency);
        Dependency.Complete(); // can this be avoided?
        endFrame.AddInputDependency(Dependency);
    }

still don't like the sync point, if it can be avoided?...but it works.

You need to order your system somewhere, for example after ExportPhysicsWorld and before EndFramePhysicsSystem. Not just with dependencies, but also with attributes on your system (UpdateBefore and UpdateAfter). Then you won't need a sync point.

I've explained it here just yesterday https://forum.unity.com/threads/trouble-getting-collisionworld-calculatedistance-to-work.1005046/#post-6532307

3 Likes