[Bug?] Exception in ModelDisplayObjectBatch.Remove

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
twig314159
Posts: 7
Joined: Thu Apr 28, 2011 5:31 am

[Bug?] Exception in ModelDisplayObjectBatch.Remove

Post by twig314159 »

I'm using a MorphableEntity with a CompoundCollision object. In order to force the InstancedModelDrawer to update the vertex information for my MorphableEntity, I'm removing the entity from the drawer, making my modifications and then adding it back in.

This works fine, but after doing that a few times (anywhere from 8 to 20 times usually), I get the following exception:

Code: Select all

ArgumentException: Source array was not long enough.  Check srcIndex and length, and the array's lower bounds.
Here's the problematic code from ModelDisplayObjectBatch.cs:

Code: Select all

public void Remove(ModelDisplayObjectBase displayObject, InstancedModelDrawer drawer)
{
            //Modify vertex buffer
            var newVertices = new VertexPositionNormalTexture[vertices.Length - displayObject.BatchInformation.VertexCount];
            //Copy the first part back (before the display object)
==>         Array.Copy(vertices, 0, newVertices, 0, displayObject.BatchInformation.BaseVertexBufferIndex);
            //Copy the second part back (after the display object)
            Array.Copy(vertices, displayObject.BatchInformation.BaseVertexBufferIndex + displayObject.BatchInformation.VertexCount,
                       newVertices, displayObject.BatchInformation.BaseVertexBufferIndex,
                       vertices.Length - (displayObject.BatchInformation.BaseVertexBufferIndex + displayObject.BatchInformation.VertexCount));
            vertices = newVertices;
*snip*
}
The exception occurs on the line marked with "==>". What's happening is that at run time "displayObject.BatchInformation.BaseVertexBufferIndex" is greater than "vertices.Length - displayObject.BatchInformation.VertexCount".

Somewhere along the way something is getting messed up. I haven't yet been able to diagnose exactly where yet.

Norbo, is there anything off the top of your head that I may be doing wrong that would cause this? I'm debugging it now, but if you have some insight on where to look closer, it would be appreciated.

Thanks,
Twig
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: [Bug?] Exception in ModelDisplayObjectBatch.Remove

Post by Norbo »

That bug should be fixed in the development version: http://bepuphysics.codeplex.com/SourceC ... evelopment

If you're still encountering it in the development version, I must have missed something.
twig314159
Posts: 7
Joined: Thu Apr 28, 2011 5:31 am

Re: [Bug?] Exception in ModelDisplayObjectBatch.Remove

Post by twig314159 »

Norbo wrote:That bug should be fixed in the development version: http://bepuphysics.codeplex.com/SourceC ... evelopment
If you're still encountering it in the development version, I must have missed something.
I just pulled down the development version. Looks like it's fixed.

I've also came across 2 other bugs earlier this week that I fixed, but haven't notified you of yet. I'll let you know here in the forums, but for future reference, do you prefer I just fill out a bug report?

Bug #1
Stack overflow when assigning to MorphableEntity.CollisionInformation.

The problem is the "get" accessor refers to its own CollisionInformation property.

Code: Select all

        public new EntityCollidable CollisionInformation
        {
            get
            {
                return CollisionInformation;
            }
            set
            {
                SetCollisionInformation(value);
            }
        }
I believe the intention was to call the base class's version. As such I believe changing the code to what follows is what you intended.

Code: Select all

        public new EntityCollidable CollisionInformation
        {
            get
            {
                return base.CollisionInformation;
            }
            set
            {
                SetCollisionInformation(value);
            }
        }
Bug #2
Null reference exception in EntityCollidable.IsActive.

During my game play, it appears I get into a state where the narrow phase system is attempting to remove stale overlaps from a previous frame. The problem is that the system still has a reference to the collision information, but my code does not. By this time I've already destroyed the entity, so when the narrow phase runs this code:

Code: Select all

        void RemoveStaleOverlaps()
        {
            //Remove stale objects.
            //TODO: This could benefit from a custom data structure (a tiny amount).
            //TODO: This could possibly be done with a computation spreading approach.
            //Problem: Consider a collision pair that has contacts one frame, and in the next, no longer even has a broad phase overlap.
            //It will receive no update, and the collision pair will still have a contact in it.
            //Collision solver will operate on permanently out of date information.
            //One possible solution requires that the user of the narrow phase object checks its age, and if it's out of date, ignore it.
            //In a subsequent frame, the system will get rid of it.  This has an advantage of lowering the (somewhat tiny) per frame cost of removal management.
            //Additionally, in highly chaotic situations where collisions are constantly being created/destroyed, spreading out the computations
            //smooths the work out a bit.
            for (int i = narrowPhasePairs.Count - 1; i >= 0; i--)
            {
                INarrowPhasePair narrowPhaseObject = narrowPhasePairs[i];
                if (narrowPhaseObject.NeedsUpdate &&
                    //Overlap will not be refreshed if entries are inactive, but shouldn't remove narrow phase pair.
==>                    (narrowPhaseObject.BroadPhaseOverlap.entryA.IsActive || narrowPhaseObject.BroadPhaseOverlap.entryB.IsActive))
                {
                    narrowPhasePairs[i] = narrowPhasePairs[narrowPhasePairs.Count - 1];
                    narrowPhasePairs.RemoveAt(narrowPhasePairs.Count - 1);

                    OnRemovePair(narrowPhaseObject);
                }
                else
                    narrowPhaseObject.NeedsUpdate = true;
            }
        }
...it crashes because either of the broad phase entries (entryA or entryB) doesn't have an entity anymore.

I worked around this problem, by simply returning false in EntityCollidable.IsActive if the entity itself was null. It doesn't seem to cause any bad behavior, but it doesn't seem like the proper fix either. It feel clunky. Hopefully you'll know of a better fix. :)

Here's the callstack for reference:

Code: Select all

 	BEPUphysics.dll!BEPUphysics.Collidables.MobileCollidables.EntityCollidable.IsActive.get() Line 87	C#
	BEPUphysics.dll!BEPUphysics.NarrowPhaseSystems.NarrowPhase.RemoveStaleOverlaps() Line 258 + 0x29 bytes	C#
 	BEPUphysics.dll!BEPUphysics.NarrowPhaseSystems.NarrowPhase.UpdateSingleThreaded() Line 235 + 0x8 bytes	C#
 	BEPUphysics.dll!BEPUphysics.MultithreadedProcessingStage.Update() Line 59 + 0xb bytes	C#
 	BEPUphysics.dll!BEPUphysics.Space.DoTimeStep() Line 398 + 0x15 bytes	C#
 	BEPUphysics.dll!BEPUphysics.Space.Update(float dt) Line 430 + 0x8 bytes	C#
Let me know if you need additional information!

Thanks for the engine! So far so good. :)
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: [Bug?] Exception in ModelDisplayObjectBatch.Remove

Post by Norbo »

I'll let you know here in the forums, but for future reference, do you prefer I just fill out a bug report?
I don't mind too much either way. In the future, if it's something that doesn't require much discussion, putting it on the issue tracker is probably best. If it's not clear why something is blowing up (i.e. not clearly a single 'bug'), the forums are perfectly fine too.
I believe the intention was to call the base class's version. As such I believe changing the code to what follows is what you intended.
Yup, it's now fixed for the next version.
I worked around this problem, by simply returning false in EntityCollidable.IsActive if the entity itself was null. It doesn't seem to cause any bad behavior, but it doesn't seem like the proper fix either. It feel clunky. Hopefully you'll know of a better fix.
That's an interesting one. The narrow phase was designed to be fairly oblivious to everything but the broad phase overlaps list created by the broad phase so the non-hack fix isn't going to be super-trivial. I'll think about it for a while to find other failure modes. It may turn out that the single null check is the 'best' option, but we'll see :)

Thanks for the reports!
Post Reply