So I’m trying to design my own sweeptest. Basically the circle starts at the top, moves downward until one of the internal radial raycasts hit something, then depenetrates itself in the opposite sweep direction to find out the closest possible hit location. How exactly do I do the depenetration part? I’m very stuck.

You could get the normal of the plane you collide with from the raycast and move the ball in that direction.
You can also calculate the closes point to the plane. Then you know the direction and if you subtract it from the circle radius you know how far to push it back

In physics engine terms, you cannot solve arbitrary contacts only in a specific direction or at least that’s not useful in any solver.

The way it’s done in the solver is that you solve the contact constraint (ensuring no overlap) but you also have a joint constraint. In your cases you want to constrain it to a specific axis. That constraint works alongside the contact constraint with the result being that it’ll combine both. Contact constraints will move in one way and the axis constraint will constrain it another. Will this give you a perfect result always? No and this is why physics engines cannot solve everything but with iteration over several frames it works out unless the object contraints are completely opposing.

Of course in simple terms for above, you calculate the overlap solve for each plane then with that result, remove the axis component you don’t want. That’d be a quick hacky way of doing it.

There’s lots of other ways to solve the intersection in a single axis, especially with circles/spheres.

Sorry if you already answered this, bit confusing to me. After depenetration occurs, does the system check again to see if the object is still penetrating things? I think I have something working, but on weird slopes my system depenetrates the tire upwards and it’s still penetrating into the slope.

In short, to answer your question, a solver is iterative so in one sense yes, it “checks again” but that’s not strictly true. All the contacts are not recalculated each step, that would be disasterous for performance. It has contacts, it needs to find a solution given so many iterations allowed. This is why solvers typically perform multiple iterations. This results is “moving towards” the best solution. This can be particularly important for things like joint constraints which are much more dynamic in nature and these are often at work alongside contact constraints. Sort of a constraint battle. The idea being that given enough iterations, all these battles will win the solution war.

Longer version:

For any contact constraint where the contact is in overlap and therefore needs moving out of overlap, an impulse is calculated to do so. Often moving it out of overlap doesn’t happen in a single simulation step because doing so can result is overshoot (moving too far out of overlap).

There are often multiple contacts so multiple constraints at work at the same time. The solver will solve all these which will give a final impulse adjustment. This adjustment won’t be a perfect solution not simply because we’re not fully moving out of overlap in a single simulation step but also because of potentially opposing contact constraints.

Please note, the above can be picked apart to not be that accurate but I have tried to simplify what it’s doing. There’s a lot more to it, mostly related to stabilization: warm-starting, biases, position correction, clamping impulse sums etc. Also, PhysX works differently than Box2D albeit what I said above is mostly correct.