Advertisement

Collision prevention Block to Block in 3d Space

Started by November 30, 2022 09:28 PM
19 comments, last by Tom Sloper 2 years ago

I have looked at the link and it is really hard to follow, since I only know pascal. I have seen that there are collisions for every different object, but for me, why is it so hard for block to block? I mean, the Checkcollision works perfectly fine. How would I compute the vec3 which pushes the Player out? I tried to solve it visualy by setting specific coordinates to 0 but that doesn’t work for all directions

I had a look in those hub files and since I am programming in Pascal, it is very hard to follow the code. I have seen that there are collision detections for every kind of shape. My collision detection is working just fine, I just need a way to calculate the vector that pushes the character out out the obstacle.

I can define the Players Hitbox as you recommend it. Can you give me the easiest way to calculate the vector? The only information that I have ist the position of the camera(player) and the Block. These coordinates are referring to the center of the Block/cam.

Advertisement

It's here: https://github.com/davideberly/GeometricTools/blob/master/GTE/Mathematics/DistAlignedBoxAlignedBox.h

But agree that's maybe a bit overkill. The problem is easy enough to figure out on your own, and easy enough you should understand how it works.

We can reduce the problem to 1D to figure it out. Basically we have two spans (or line segments), one static, the other should move to resolve penetration.

void ResolveSpan (float &dynCent, float &dynHWidth, float statCent, float statHWidth) // the & means the given variable can be changed by the function; the other variables are given as a copy
{
	float diff = dynCent - statCent; // difference between the centers
	float totalW = dynHWidth + statHWidth; // the sum of both half widths
	
	if (diff > 0) // dynamic span on the right side of the static
	{
		if (diff > totalW) 
			return; // it is so much on the right they do not intersect, so change nothing and return
		
		// intersection - project further to the right to resolve overlap
		float overlap = diff - totalW;
		dynCent += overlap; // done
	}
	else // same for the left side case...
	{
		if (diff < -totalW)
			return;
			
		float overlap = diff - totalW; // i'm uncertain and confused from the signs. Ideally i have a testcase prepared to compile and run, to fix it by trial and error if wrong.
		dynCent -= overlap;	
	}
} 

That's very simple math and logic, but already enough complexity to make me uncertain. : )
Assuming it works, we can now apply this to all 3 dimensions:

void ResolveAABoxCollision (AABox &dynamicBox, AABox staticBox)
{
	ResolveSpan (dynamicBox.center.x, dynamicBox.width*.5f, staticBox.center.x, staticBox.width*.5f);
	ResolveSpan (dynamicBox.center.y, dynamicBox.height*.5f, staticBox.center.y, staticBox.height*.5f);
	ResolveSpan (dynamicBox.center.z, dynamicBox.depth*.5f, staticBox.center.z, staticBox.depth*.5f);
}

So this should work for axis aligned boxes which are not allowed to rotate.
After the function the dynamic box is already displaced to the new and resolved position. To get a displacement vector you would do some minor changes (return signed overlap, and fill the 3 dimensions with that).

It should be fine for now. To handle an upright capsule vs. box, you would need to handle more cases, actually point vs. rectangle and line vs. rectangle.
Key is to treat the capsule as a point (from above) or as an axis aligned upwards line (from the side). Then you only need to ‘add’ the radius of the capsule to difference / overlap.

However, you should figure out sphere vs. box first, because that's a bit easier. The cases in detail here are then point in the ‘voronoi regions’ of either a face, a edge, or a corner of the box, if the sphere center is actually outside the box.
If the sphere center is inside, we only have the face region to detect. Here a 2D image to illustrate what i mean with such regions:

Red regions and circles are outside, green inside. Thin black lines show the displacement direction. They are no longer axis aligned in corner cases (and edge cases in 3D).

That's stuff every game dev should be able to do on his own, imo. But depending on your actual experience and education, it may well take years even to get to the point where you really need this and work on it.
The alternative is to use physics engines (or full game engines). But to use them, some basic knowledge and experience is required too. So it's never wrong trying to get as far as you can get.

at Aloxen: JoeJ probably told you already everything you need to know but here’s my take. If you want to prevent a collision from taking place you still need a bit of collision to take place, you need the later because you want to know when to stop the objects from moving.

My project`s facebook page is “DreamLand Page”

If you want no collision whatsoever between your objects you will have to make use of helper objects, larger objects surrounding your original objects that is. In this scenario the collision test should take place between the helper objects

My project`s facebook page is “DreamLand Page”

Calin said:

at Aloxen: JoeJ probably told you already everything you need to know but here’s my take. If you want to prevent a collision from taking place you still need a bit of collision to take place, you need the later because you want to know when to stop the objects from moving.

Sounds you describe a method of simulation where penetration never is allowed to happen.
This was the first take on rigid body simulation, but it has a big performance problem, so isn't practical for larger simulations with multiple bodies. Here's an example why:

Imagine a billiard game at the start. The white ball is shot towards the group of colored balls.
When the first collision happens, the hit colored ball will collide with two neighboring balls, each of them as well going to collide with two other balls, one of them being hit from two former balls at almost the same time. And so on.
If you want to simulate this with your approach, you have to order the collisions sequentially in time to find the first event. Then you roll back the whole simulation to this moment in time, and re-simulate from there.
Again many collisions are detected, the first needs to be found, rollback, restart from there. This continues until you are at the destination time.
Due to the exponentially growing complexity from the multi body problem, you will need hundreds of simulation steps, detecting thousands of collisions, to advance just one timestep. The simulation of one timestep takes longer than step size, and you're no longer real time.

The faster option which is now standard is to do only one simulation step, treat all found collisions to happen simultaneously, try to solve for reaction forces resolving all collisions, accept the small quantization error but hope the solution converges over time on failure cases. It works almost just as well and is much faster.

Maybe that's not what you meant but just to mention. A game like Minecraft has no multi body simulation anyway. There are no stacks of boxes which may tumble over or stay at rest, so the hard multi body problem requiring a solve isn't there.
But making a robust player controller colliding with a static world isn't easy either. However, it is not needed to predict and prevent penetration.
You can let the penetration happen, then resolve it. Next frame the same penetration will happen again, but if your resolve also gives the same result again, the behavior is stable and does not jitter.
To make your resolve stable and consistent, you need to conserve / minimize energy. Which is guaranteed if your resolve projects along the shortest distance.

But this isn't easy in case of multiple, simultaneous collisions. The classical test case is this:

The player tries to push into a narrow corner. The resolve from box A pushes into box B and vice versa. This often causes jitter in old games, or you might even get stuck so you can't move back.
I remember this was difficult for me to get right too, but can't remember the solution which worked for me. Probably it was just to add all resolution vectors together and applying the sum. Penetration would not be zero after the resolve, but it should converge towards that with time.
Now i'm a happy user of a physics engine and no longer need to care. :D

And in a Minecraft game there are no narrow corners, just right angles, which should help.

Advertisement

at JoeJ: I was under the impression he’s looking for something simple something that could be reduced to axis aligned CD in 2d

My project`s facebook page is “DreamLand Page”

And I was proud to get myself through OpenGL, actually understanding it xD.

Well here I am and I need it to get my game working for my school project. Im trying to understand what you two are saying.

First of all, @joej should I use box vs box for Player Block collision, or should the player be a sphere?

Second, what is does the dynamic and static part mean? If I it means what I think it means it is the camera/Player position Center coordinate. I don't think we have that in Pascal, but if what I just said was correct, then I know how to translate it into pascal.

I can tell you how my movement based on Keyboard inputs is working right now.

First, all key inputs are checked and a movement vector is created, which is based on those inputs. After that, set:

vec3 OldCamPos = camPos;
vec3 NewCamPos = CamPos+movement;

Then I Check if there would be a Collision with NewCamPos and the Block and if that is true, it should compute a Vector, which is then subtracted from CamPos.

After that it always comes CamPos += movement; and then CamPos is going into the LookAt function which moves the Camera.

Is there a mistake in the order of statements I made or would you do something different?

Aloxen said:
First of all, @joej should I use box vs box for Player Block collision, or should the player be a sphere?

It's up to you, really.
But as you mentioned Minecraft, i guess your world is a uniform grid of big voxels. Like a Super Mario tile map, just in 3D.
So the world is all axis aligned, and if you keep your box character axis aligned as well, it won't be much of a difference in comparison to a sphere character.
The difference will mostly show if you move towards a convex corner at 45 degrees angle. In this case, the box geometry of the character either snaps to the left or the right side from the corner, and then slides along.
A spherical shape would behave better. You would almost stop at contact with the corner, and then you have time to decide which side to choose for further movement.
Here a top-down view of the example:

Round shape will behave clearly better and more natural.
But for now, you can stick at the box, because it's easier. Add the spherical / capsule shaped shape to your todo list, in case there's still time left for such improvements later.

Aloxen said:
Second, what is does the dynamic and static part mean?

The dynamic box will be moved outside of the static box, which stays in place and never changes collision. So dynamic = characters, static = world.

Aloxen said:
Then I Check if there would be a Collision with NewCamPos and the Block and if that is true, it should compute a Vector, which is then subtracted from CamPos.

That's fine.
Using my code example you would first create box from the cameraPos (which you really should rename to playerPos eventually).
Then use it as the dynamic input for the function. Then set cameraPos to the displaced dynamicBox.center modified by the function.
Alternatively, the vector you talk about would be: dynamicBox.center - cameraPos. Adding this vector to cameraPos woudl bring the camera to the dispalced dynamicBox.center.

Aloxen said:
After that it always comes CamPos += movement; and then CamPos is going into the LookAt function which moves the Camera. Is there a mistake in the order of statements I made or would you do something different?

I would do it in this order:

  1. add movement to camera. (it might now penetrate the static world boxes)
    2. Resolve the collision.
    3. Render. (So our image does not show the penetrating state)

But technically and physically your plan would work equally well. It's only about a visual improvement.

Aloxen said:
And I was proud to get myself through OpenGL, actually understanding it xD.

Physics is harder than graphics. But this is how games work, not just how they look. How the player interacts with the simulation of a virtual world. So that's where the real magic is, i would say. ; )

Aloxen said:
I need it to get my game working for my school project.

Thread locked. We have a “no homework” policy here. We may need to institute a “no Pascal” rule too. :p

-- Tom Sloper -- sloperama.com

This topic is closed to new replies.

Advertisement