didac

Mesh collisions only horizontal movement

Recommended Posts

Hi,

I would like to create an environment with several objects (in the playground, 2 objects) that cannot be at the same position at the same time (cannot be superimposed). I used the moveWithCollisions method for the Mesh objects, and while it works as expected, when two objects collide and the ellipsoids around them are not identical in size, one of the objects goes to the top or to the bottom of the other. I would like for them to just stay in the same vertical position, and if they collide, simply prevent them from moving, not moving to the top or to the bottom of the other object.

Is there any thing you recommend?

Playground: https://playground.babylonjs.com/#1UK40Z 
If you move the red object towards the purple one, when they contact, the red object moves to the top of the purple one, and I would like them to stay one next to the other.

Thanks!

Share this post


Link to post
Share on other sites

I will rephrase my question: if I am moving an object with the mouse, I have the position before the movement, and I have the increment given by the mouse. If BEFORE the movement the two objects are not intersecting, but AFTER applying the increment with mesh.position.addInPlace(increment) they are intersecting, how can I avoid doing the movement BEFORE actually doing it?

I had the idea of checking the intersection after the movement, and if they intersect, subtract the increment and go to the original position. However, it looks like when I increase the position and then do the intersects check, the intersects() method does not detect the intersection just in the moment, but it has to do the rendering or something, and THEN it detects the intersection, when I have no longer control on it.

Do you have any idea on how to deal with it? (Playground: https://playground.babylonjs.com/#1UK40Z#2, please move the purple object towards the red one. The purple object turns white when it contacts the red one, and it cannot move back again because the system detects that it is intersecting the red one)
Thanks a lot!

 

Edit: is it a good idea to render before checking the intersect? (added the line 149 in https://playground.babylonjs.com/#1UK40Z#3)

Share this post


Link to post
Share on other sites

Ahh, you want to "predict" if the "upcoming" position change... will cause intersect.  Yep, been there... wanted that.  :)

After mouse has done a pointer-drag...

Preferred method:  IF upcoming mesh move WILL cause intersect, don't move the mesh, and perhaps return pointer to pre-drag position.

Kludgy method:  IF mesh move HAS caused intersect, move mesh to PREVIOUS non-intersect position, and allow continued dragging without interruption.  (disallow mesh overlap)

Did I re-state issue correctly?  I hope so.

Intersection prediction.  "Look-ahead".  :)

Ok, anyway, I modified a playground... https://playground.babylonjs.com/#1UK40Z#4 

Notice I disabled lines 154-156, and tried using some fancy line 153.  Notice it has a "scale" on it, which is the same as an amplifier or "power soak".

Line 153 eliminates diff2, and instead "negates" diff... but then amplifies that amount... * 1.5 (50% more counter-diff).

SO, I modded line 158 to use diff instead of diff2.  AND, I added or adjusted line 161... so that line 166 operated correctly when we "fell thru" to it.

Nothing really changed except... it doesn't get "stuck" anymore.  Perhaps it is easier to see what is happening... when it quits getting stuck-upon-intersect.

In line 153, change the 1.5 to be 1.0, and we get stuck-on-intersect again.  Go fig.  Perhaps we can learn why.  https://github.com/BabylonJS/Babylon.js/blob/master/src/Culling/babylon.boundingInfo.ts#L217  Nothing in there indicates a reason to get stuck.  hmm.

COULD IT BE... that WHEN an intersect happens... 3-5 diffs continued to happen.  In other words... it took time for intersect to be triggered... and 3-5 mouse drags happened SINCE the REAL position of intersection.  SO, you and I try to "back-up" the mesh position ONE diff-level.  BUT... that's not enough of a "back" to make it leave intersection state.  We actually need to back-up the mesh 3-5 diffs.  We need to set currentMesh.position to the current position minus 3-5 diff-moves.  THIS is why backing-out 1.5 diff-distance (150%)... takes us out-of intersect state.  Perhaps, this value needs adjusting or changes, depending upon how fast the pointer was traveling at the time of intersect.  Drag "velocity" will likely affect the size/magnitude of each diff-change value.  hmm.

Heavy theory, eh?  I could be right.  Ya just never know.  :)  Probably not.  heh

-------

getGroundPosition() is an interesting func.  It returns a "wobbly" diff.y... because of camera angle vs. ground angle, so I do a little currentMesh.y position forcing... in line 147.

------

SO, I have no real solutions, and I haven't designed a "prediction system"... but maybe SOMETHING is helpful, here.  Let's do more experiments and listen for more/wiser comments.

Share this post


Link to post
Share on other sites

Hi Wingnut,

You got the issue correctly. Thanks a lot for the comment and the ideas. Certainly backing up the mesh 3-5 diffs is not ideal, because if that is the case, then why not 6 or 7 diffs? I'll give it another try and let's see what I get.

Share this post


Link to post
Share on other sites

Well, I got something working. I don't know if its very inefficient but it works alright. It basically consists in rendering the scene outside of the rendering loop to check the intersections, and if there are intersections, I undo the operation and render again (without rendering again it still works but it glitches a little bit).

https://playground.babylonjs.com/#1UK40Z#7

Share this post


Link to post
Share on other sites

I don't know why, without the scene.render(), and AFTER moving the position, the intersect() check does NOT detect the intersection.

Maybe the intersect() needs the scene to be rendered work? Or probably the render() activates something that is not activated without it. If you comment the scene.render() line in https://playground.babylonjs.com/#1UK40Z#7 it clearly stops working. 

Probably you have a better intuition of the situation. In any case now it works correctly (maybe adding an overhead that is not completely necessary, but that I don't know how to avoid).

Thanks for the help!

Share this post


Link to post
Share on other sites

I do something just like this for a rewind + collision check feature. 

The trick is to use mesh.computeWorldMatrix(true) on the meshes that are being checked for collisions after being moved. This is the internal operation being performed by scene render that makes the collisions work (among other things, such as rendering). I think this is needed whenever moving and positioning objects in-between frames, esp if the object is being moved multiple times and checked for collisions before the next render.

In the case of my rewind collision check, I never actually wanted to render the object in the rewound position -- I just needed the object to be in the correct state so that babylon could do the math for me. For me that meant copying its original position, moving it to a new position, invoking computeWorldMatrix, doing the intersection test, and then restoring it to the original position. While not identical, this does come out somewhat similar to the notion of moving an object (or a copy of that object) until it collides, uncolliding it, and then having it in the uncollided position all before actually rendering anything. 

Here's the PG w/o scene render in the collision checks: https://playground.babylonjs.com/#1UK40Z#8 If I understand what you have made, then this in theory will never turn the torus white.

Share this post


Link to post
Share on other sites

Hi timetocode, this was exactly what I was looking for!

If I understand it correctly, it is exactly what I was doing, but instead of computing the WoldMatrix as a part of the rendering, doing it directly, without all the overhead of the rendering, and without the (small) fraction of time where the object is intersecting.

Thank you very much.

Share this post


Link to post
Share on other sites
On 12/8/2018 at 4:50 PM, didac said:

Certainly backing up the mesh 3-5 diffs is not ideal, because if that is the case, then why not 6 or 7 diffs?

Well, remember... that the velocity of the mouse pointer... at the time of intersect... matters.  With a fast drag, each diff value is large.  Slow drags, the diff values are small.

Sooo... it is difficult to determine how many diffs to back-out.  Smarter to do some quick boundingInfo measurements, and force some positions... based upon those.  De-overlap the two bounding boxes... but just barely de-overlapped.

Just MAYBE... a function could be added to BJS Tools... deOverLap(mesh1, mesh2).  mesh 1 doesn't move.  mesh2 re-positions itself... using the shortest distance... to de-over-lapped state (from mesh1).  Interesting.  (Might need an option to lock the Y axis during re-position.  ie. don't let mesh2 exit intersect state... via moving above or below mesh1.)

Or, perhaps some other prediction tools could be thought-up... now that we know more info.

@timetocode - What a fine explanation!  THANK YOU!  Fantastic. 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.