godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.6k stars 21.1k forks source link

Continuous CD not working #9071

Closed ghost closed 1 year ago

ghost commented 7 years ago

Operating system or device - Godot version: 2.1.3 Stable (64-bit)

Issue description: The Rigidbody2D node does not appear to have correctly functioning Continuous Collision Detection (even thought the option is present). "Tunneling" occurs with both "Cast Ray" and "Cast Shape" options.

Steps to reproduce:

  1. Create a Rigidbody2D node and enable Continuous CD in it's properties (Cast Ray or Cast Shape).
  2. Create an Area2D node as a child of the Rigidbody2D node (so it has mass).
  3. Place the Rigidbody2D node overtop of a ColliderObject2D node (make it static because it should never move anyway).
  4. Set gravity scale to something large, like ... I dunno... 300 or something.
  5. Run the game, watch your Rigidbody2D either pass through the static collider or tunnel into it slightly.

I have tried both options (Cast Ray and Cast Shape) and neither of them seem to work. Looking back on previous issues posted here (and elsewhere), it appears Continuous CD was broken since version 2 of Godot was released and never got fixed. Is there any chance this can be corrected soon? It impacts a lot of my testing currently.

Zylann commented 7 years ago

Related to https://github.com/godotengine/godot/issues/6926 and https://github.com/godotengine/godot/issues/6664

ghost commented 7 years ago

I'd just like to add that comments in those related issues suggest it's only "Cast Ray" that's not working but I've tried this with both "Cast Ray" and "Cast Shape" and neither are working.

bojidar-bg commented 7 years ago

Potentially a result of d7d65fa2f2b51d03f7bdfcbceedca99188ce979c

kubecz3k commented 6 years ago

First of all thank you for your report and sorry for the delay.

We released Godot 3.0 in January 2018 after 18 months of work, fixing many old issues either directly, or by obsoleting/replacing the features they were referring to.

We still have hundreds of issues whose relevance/reproducibility needs to be checked against the current stable version, and that's where you can help us. Could you check if the issue that you described initially is still relevant/reproducible in Godot 3.0 or any newer version, and comment about its current status here?

For bug reports, please also make sure that the issue contains detailed steps to reproduce the bug and, if possible, a zipped project that can be used to reproduce it right away. This greatly speeds up debugging and bugfixing tasks for our contributors.

Our Bugsquad will review this issue more in-depth in 15 days, and potentially close it if its relevance could not be confirmed.

Thanks in advance.

Note: This message is being copy-pasted to many "stale" issues (90+ days without activity). It might happen that it is not meaningful for this specific issue or appears oblivious of the issue's context, if so please comment to notify the Bugsquad about it.

BeayemX commented 6 years ago

The bug still occurs for both Cast shape and Cast ray. Version tested: d87307d850186d27d2c27c5916ec8c4744c14979

bojidar-bg commented 5 years ago

Can someone retest after d403b4086c514647bba7620591061b7de7dfaf4b?

BeayemX commented 5 years ago

Tested with current master (11d77386221a4d911edee4fdbba5d3b9109a1c6b)

Cast ray does not tunnel through objects any more, but at high speeds, objects will not stop at the collision but instead will be set back quite far.

With Cast shape tunneling still appears

Both behaviours can be seen in this test project

CCDTest.zip

Zireael07 commented 5 years ago

Seemingly still an issue on 3.1?

BeayemX commented 5 years ago

Yes, still occurring on the latest master e16fc72ce

mitchcurtis commented 5 years ago

Oh thank god this is an issue and not just me doing it wrong. I have a 3-pixel wide (pixel art game, zoomed in) shield and a projectile that flies kinda quickly, and if I position the character's shield juuuuust right, the projectile gets past the shield. I tried both CCD options and neither of them helped. I really suck at physics, so I really hope this gets fixed.

Calinou commented 5 years ago

@mitchcurtis As a workaround for your particular case, you could make the shield's collision shape thicker. It should work well if its collision layers/masks are adjusted not to collide with the player or other parts of the world.

Zylann commented 5 years ago

Another workaround specifically for projectiles that mostly move in a straight line, is to use raycasts, or an elongated collision shape matching the motion of the projectile for 1 frame. It's a bit of code to write but it should work pretty well. (actually maybe doesnt need code at all, just different setup)

image

ZingBlue commented 5 years ago

I need this fixed in order to continue working on my game's mechanics, I am not a great programmer, I am (for now) pretty much a web dev(HTML, CSS, JS) and a year of Python. With my skill set, could I fix this bug? If not, can someone else fix it please?

ZingBlue commented 4 years ago

Someone please, before 3.2 releases, do something.

Calinou commented 4 years ago

@ZingBlue Sorry, 3.2 was too close to release, we couldn't afford doing something that potentially introduces a regression somewhere else. I advise you look at the workaround given above: https://github.com/godotengine/godot/issues/9071#issuecomment-529217698

ZingBlue commented 4 years ago

@Calinou No problem. I'll look into the workaround mentioned above.

Xrayez commented 4 years ago

Throughout my journey with Godot since 2.1 I wasn't sure whether CCD was actually working. This lead me to use Physics2DDirectSpaceState.intersect_shape and similar methods to be run every frame with RigidBody2D with custom_integrator on and disabling the shapes. :eyes:

Some gd-pseudocode:

class_name Arrow extends RigidBody2D

func _enter_tree():
    $shape_cast.shape = shape_owner_get_shape(0, 0).duplicate()

func _integrate_forces(state: Physics2DDirectBodyState):
    $shape_cast.force_shapecast_update()
    if $shape_cast.is_colliding():
        get_stuck()

Actually I managed to implement a ShapeCast2D node which can do shape casting similar to RayCast2D as a workaround (yet use cases not limited to CCD): https://github.com/godotengine/godot-proposals/issues/72#issuecomment-587981106

njor commented 4 years ago

Hi, this bug is more than three years old now, and there seems to be no plans to fix it in the foreseeable future, probably under the assumption that there are workarounds.

However, the possible workarounds do not cover all use cases. For example in my use case, I have a few small objects that can move fast in some situations and which must physically interact with each other in a realistic way. Ie. unlike simple projectiles, those objects do not disappear on collision but must bounce of each other. I cannot use the expanded shape workaround (or any of its variations) as it would change the impact point and bounce completely unrealistically and in a seemingly random and unpredictable direction depending on the exact collision position (while the bouncing angle must be predictable for the gameplay). The only « workaround » that I see would be to implement a custom collision detection and custom integrators myself, which would be extremely complex (and I think is beyond my skill set, and many game developer’s), and would be much slower than an engine-level implementation.

Another workaround would be to set a very high physics FPS in the hope that no objects will pass through one another. Which is what I am doing now for the time being during development (physics FPS = 180), but it does not guarantee that there will be no tunneling (it still sometimes happens when two objects have relatively high speed in opposite direction), and a high physics FPS can have a severe impact on performance.

I hope this bug can be given higher priority in the future.

Calinou commented 4 years ago

@njor We do aim to fix this issue eventually as it's labeled as a bug. See https://github.com/godotengine/godot-proposals/issues/570.

njor commented 4 years ago

Thank you for your answer. I see that the fix is planned for Godot 4, I hope this will be possible and will happen as planned. :-) And thank you (and all Godot contributors) for all your work on the engine.

WilliamTambellini commented 4 years ago

This bug is confirmed to also hit 3d physics: https://github.com/godotengine/godot/issues/41404

jordo commented 3 years ago

I can confirm CCD is not working in any physics engine. Bullet, godot 3d, and godot 2d. I've just tested on latest 3.2 release and on current master build :(

Exxion commented 3 years ago

I'm not exactly a master of Godot's engine code, so I could be wrong, but from my brief searches it looks like this is caused by a combination of things. I haven't looked at Bullet at all, but here's what I noticed with regard to Godot physics:

Both 2D and 3D:

2D:

3D:

EDIT: I overlooked something, and shapecasting is actually implemented in 2D. Why it doesn't work is over my head. In the specific case of shapecasting in 2D, if it did work, it would solve squishy collisions because its check is handled by the solver rather than a separate function called only if the solver doesn't detect anything.

EDIT: All the functions to actually perform the 2D shapecasting look pretty foolproof to me, so I suspect the problem lies somewhere in the checks to perform those functions or the functions to get the motion vector of the body or something. It should be fairly easy to diagnose with a debugger but I'd have to download the source and get the build set up and all that, and I don't really want to do that right now

Exxion commented 3 years ago

Yes, it seems that 2D shapecast doesn't work because it casts the shape along the vector defined by the difference between the origin of its new_transform and that of its transform at a time when they are the same. I definitely don't know enough about the physics engine code to fix this.

EDIT: Also, as someone else mentioned above, 2D raycasting does successfully detect collisions that would otherwise tunnel, but its calculation for where to stop the object isn't quite correct.

Exxion commented 3 years ago

Sorry for a third comment in a row, but this should be the last. Here's everything I've found out about CCD:

Bullet:

Godot 3D:

Godot 2D raycasting:

Godot 2D shapecasting:

WilliamTambellini commented 3 years ago

Hi @Exxion Tks for the investigation. I dont know what you mean by 'it works' but on my side I confirm that https://github.com/godotengine/godot/issues/41404 is still hitting the latest godot 3 release and enabling CCD does NOT fix the bug.

Exxion commented 3 years ago

It doesn't penetrate at high speed, which is what the CCD is meant to fix. CCD isn't even attempted if the object is not moving at high speed, so just pushing two objects together while neither is moving at high speed won't use CCD. That check could be removed, but I'm not really sure it would fix that bug anyway.

jordo commented 3 years ago

CCD SHOULD fix #41404. If i understand correctly, all that's happening in #41404 is the red box has a very large downward impulse applied to it. A strong impulse should just result in high velocity

Exxion commented 3 years ago

It's possible I messed something up, but just throwing a box with extremely high velocity at a static body with a convex polygon collider did result in the box stopping at the surface with CCD on and the box flying off into space with it off.

jordo commented 3 years ago

My wild guess for #41404 is that if/when a shape ends up moving fast enough, but ends up still colliding (just opposite side of colliding shape) on the next physics tick, it gets pushed out the wrong side (falls through the floor in video). If there is zero overlap, (maybe box is moving fast enough to NOT intersect shapes on the next tick, which perhaps CCD picks it up and figures out TOI and correctly resolves).

Exxion commented 3 years ago

Oh, it looks like Bullet CCD (at least against polygon colliders) doesn't work in 3.x but was fixed sometime since then in master.

EDIT: Wait, no, that's not right. There is something weird going on here. Let me amend "Bullet CCD works" to "Bullet CCD mostly works"

groud commented 3 years ago

@DimitriyPS This is not the place to flame anyone, please stay constructive.

DimitriyPS commented 3 years ago

I realized that an objective assessment is not constructive. Then I'll leave only the dry residue here.

For 5 years (I'm only talking about personal experience), collisions in Godot physics engines do not work.

And I have to repeat constructively, my issue is not limited to this issue!

akien-mga commented 3 years ago

For 5 years (I'm only talking about personal experience), collisions in Godot physics engines do not work.

As hundreds of Godot games using 2D and 3D physics show, this is simply not true.

If you experience specific bugs in your project, open bug reports for each issue with a project that can be used to reproduce the bug and thus fix it. Blanket statement that "things are broken" without a way to test or reproduce the issue are not useful and won't lead to any fixes.

DimitriyPS commented 3 years ago

As hundreds of Godot games using 2D and 3D physics show, this is simply not true.

I found these bugs not only in my own projects, but also in others that were published with the source code. Also, many games often avoid full-fledged simulation of things, this allows you to bypass bugs that exclude the defective operation of physical engines in Godot. Yes, I say with full confidence: 5 years that I use Godot, physical engines are not able to provide the basic mechanics of RigidBody.

Blanket statement that "things are broken" without a way to test or reproduce the issue are not useful and won't lead to any fixes.

@akien-mga , those same 5 years ago, I already published a minimal example with a physics error, but the situation is the same: you're a fool yourself, problems in your project, everything works in Godot. To be honest, physics completely demotivated me to work with Godot, it's a cry of the soul for wasting time, so I didn't want to prepare a minimal example. BUT! I am ready to spend time on it on the weekend, but looking back on these 5 years, I ask you to promise that if these are problems of the physics engine, that they will be fixed by release N (name the release number). What do you say to that?

akien-mga commented 3 years ago

No I'm not going to promise anything.

But we just hired a contributor to focus on physics issues for 6 months (which strangely enough prompted you to write a rant to welcome this, instead of pointing to actual issues that could be debugged and fixed), so yes, well defined bugs with clear steps to reproduce / reproduction projects will hopefully have a good chance to be fixed.

DimitriyPS commented 3 years ago

No I'm not going to promise anything.

Yes. I knew it. I have been in this ecosystem for a long time, I have already understood how it works. But even so, I will try to find the moral strength to once again yield to your "constructive" proposal and collect a minimal example.

If I knew the milestone, I would reorganize the tasks in the project and wait, but I find it more realistic perspective to continue learning the engine with the stable operation of the basic mechanics.

ghost commented 3 years ago

@pouleyKetchoupp Attaching an sort of MRP test project here for you, since this seems to be the most relevant issue for CCD.

CCD Test Cases.zip

It's a bit tossed together, but it compares KBs and RBs and a cast_motion() query. The cast motion holds up pretty well, but makes me wonder why the others have such odd results at higher force values. Are the issues more so in the node implementations?

The test starts at 20k force, but turning it down to 4k seems to also capture how RigidBodies sometimes interpenetrate and spring back out.

Xrayez commented 3 years ago

Partially related to #34215, I've also stumbled upon this physics parameter:

# Set this somewhere in `_ready()`.
Physics2DServer.space_set_param(get_world_2d().space, Physics2DServer.SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION, 0)

The default penetration is 0.3 as reported by equivalent space_get_param(...), perhaps it may improve the situation in some cases, but I'm just guessing and those might be yet again unimplemented parameters which are never used by the default physics backend.


Regarding the discussion whether physics work is prioritized... No, I think rendering is more important to the core developers (and investors), otherwise it would've been fixed already. Hopefully physics work is going to be prioritized in 4.1... But yeah I agree that that's something which could've been fixed long time ago, we'd probably have more interesting physics-based games made with Godot by now, but that's just me. 😛

But then again, Godot was probably not designed to handle heavy physics simulations in the first place, so we've got what we have now...

Calinou commented 3 years ago

Regarding the discussion whether physics work is prioritized... No, I think rendering is more important to the core developers (and investors), otherwise it would've been fixed already. Hopefully physics work is going to be prioritized in 4.1... But yeah I agree that that's something which could've been fixed long time ago, we'd probably have more interesting physics-based games made with Godot by now, but that's just me. :stuck_out_tongue:

Physics are already being prioritized for 4.0.

e344fde6bf commented 3 years ago

EDIT: Wait, no, that's not right. There is something weird going on here. Let me amend "Bullet CCD works" to "Bullet CCD mostly works" @Exxion

I had a look and it seems Bullet only supports continuous collision detection for convex collision shapes. Compound collision shapes (btCompound) are not supported. In Godot any collision shape that has a Transform() != identity needs to be wrapped in a btCompound (to set custom centre of mass). So CCD for RigidBody only works for (box, sphere, capsule, cylinder, convex hull) shapes when they have no translation or rotation relative to their parent. Note this only matters for the moving shape, so it'll still detect a collision if the other shape in the collision is concave/compound.

Another issue seems to be if you use collision layers and mask. Bullet's default handling for this seems to require (A.layer & B.mask) && (B.layer & A.mask) to be true for it to detect a collision when it performs the CCD sphere sweep.

I don't think Bullet's CCD handles cases where two fast moving objects cross paths at all.

Kinematic bodies in Godot actually perform a sweep test for each shape, so continuous collision detection seems to work for them, even for compound shapes.

However, Bullet's continuous collision detection for rigid bodies never seemed to prevent tunneling. So even if you use one of the currently supported configurations, it only prevents missed collisions by performing a sweep test with a sphere. There seems to be a way you can manual prevent tunnel in Bullet discussed in this post.

While not a complete fix, you can get much less tunneling for basic shapes by choosing the CCD sphere sweep radius as the largest sphere that fits entirely inside the shape. Currently, Godot set's this to 0.2 * bounding_sphere_raidus, so even if the shape is a sphere it can tunnel 80% of the way to the centre. I think a better default would be something like sweep_radius = min(aabb.x, aabb.y, aabb.z)/2 (edit: for convex hull you probably need to do min(p1, p2, ..., pn) and need the convex hull to contain the origin). However, I think you still need allow some penetration to guarantee that Bullet actually generates contact points after performing the sphere sweep.

Larger sweep radius ```cpp void RigidBodyBullet::set_continuous_collision_detection(bool p_enable) { if (p_enable) { btBody->setCcdMotionThreshold(1e-7); const btCollisionShape* shape = btBody->getCollisionShape(); if (!shape) { btBody->setCcdSweptSphereRadius(1.0); return; } /// CCD works on an embedded sphere with fixed radius, make sure this /// radius is embedded inside the convex objects, preferably smaller. btVector3 aabb_min; btVector3 aabb_max; shape->getAabb(btTransform::getIdentity(), aabb_min, aabb_max); btVector3 bounds = aabb_max - aabb_min; btScalar min_bound = MIN(bounds.x(), bounds.y()); min_bound = MIN(min_bound, bounds.z()); btBody->setCcdSweptSphereRadius(MAX(0.04, (min_bound / 2.0) - 0.04)); } else { btBody->setCcdMotionThreshold(0.); btBody->setCcdSweptSphereRadius(0.); } } ```

In summary, it seems Bullet doesn't have great support for CCD internally, so you'll have to do a fair bit of work to get it working correctly in all cases for rigid bodies.

skaiware commented 3 years ago

Thanks for the analysis @e344fde6bf Camille: aka @pouleyKetchoupp : would CCD work better with your retouches/enhancements of the Godot PhysicsEngine ?

pouleyKetchoupp commented 3 years ago

@skaiware I haven't looked into ccd yet, but given there are multiple reported issues, it's an area me or other contributors are going to check. And given @e344fde6bf's findings it seems there's some room for improvements.

unfa commented 3 years ago

Still an issue in Godot 4 pre-alpha. I have shell casings in my game (small objects) and they keep phasing through other objects even when Continuous Collision Detection is on.

lexum0 commented 2 years ago

CCD is completely broken in Godot 3.4, but seems to be working in Godot 2.1.4. What can we do to help fix it? It's an important feature when dealing with physics.

A workaround would be to detect the collision in GDScript using raycast and apply an impulse or change the velocity to simulate the collision, does anyone have more details on the implementation?

starry-abyss commented 2 years ago

I don't know if it's the proper way to deal with CCD, but HaxeFlixel engine stores previous positions of objects. This allows to detect overlaps not only for objects themselves, but also for the paths they moved along during the frame.

LowBudgetHomebrew commented 2 years ago

Cast ray ruins everything when on high speed and Cast Shape ruins everything by making it even worse. I hope this bug gets fixed soon, because I've met so many bad stuff in Godot and this one will be the last for me to turn away of Godot Engine

Calinou commented 2 years ago

@LowBudgetHomebrew Please don't bump issues without contributing significant new information. Use the :+1: reaction button on the first post instead.

loicmorvan commented 2 years ago

FYI I'm trying to make a little Pinball game with Godot v3.5.stable.official [991bb6ac7]. The only dynamic body is the ball (a single CircleShape2D, not thin), everything else so far is static or kinematic with CollisionPolygon2D. Whatever the CCD mode I choose the ball interpenetrates the other bodies (while it should never enter inside these bodies), or if its speed is too high (but not exaggerated) traverse static bodies.

I'm new to Godot, but I have a bit of knowledge on physics and physics engine implementations, so I would be pleased to try to help you fixing that, if I can ;)

Calinou commented 2 years ago

Whatever the CCD mode I choose the ball interpenetrates the other bodies (while it should never enter inside these bodies), or if its speed is too high (but not exaggerated) traverse static bodies.

Increasing physics FPS in the project settings will probably resolve this in your particular project (try 120, 180 or 240).

I'm new to Godot, but I have a bit of knowledge on physics and physics engine implementations, so I would be pleased to try to help you fixing that, if I can ;)

Thanks for your interest in contributing :slightly_smiling_face:

See Pull request workflow for guidelines. In particular, pull requests should target the master branch first (which means porting your project, or a minimal version of it to 4.0.alpha so you can test your changes).

GodotPhysics should also be fixed first, as that's what is used in 4.0 and is the only physics engine available for 2D in 3.x too. Bullet could be fixed later, as it's only used for 3D in 3.x (and people can switch to GodotPhysics there too).