Page 1 of 1

[v2][Solved] Character Demo - Sliding as if on ice

Posted: Wed Oct 02, 2019 1:25 am
by WRZ1
Hello there!

Impressive library, really solid work with lot's of helpful examples. First of all I want apologize for the wall of text that emerged from describing my issue.

Having no background using physics engines on such a low level I have tried to understand the concepts and implementation over the last couple days. While I made quite some progress I'm still struggling a bit to integrate the character demo into my project.

The problem is that my character is sliding as if it was on ice. It has trouble to accelerate and stop movement once the movementDirection is set to (0,0). Collisions seem to work, jumping is a bit moon-like aswell though. Before preparing and pasting a lot of sample code that would basically be the demo itself, I''ll quickly describe my project and which modifications I have made. Maybe you have an idea on what it could be this already.

My project is a pretty simple server, running a fixed time per update loop with 60hz and a dt of 1/60f. It's using Lidgren for networking and Unity3D as the game client, which works fine so far. I have a server-side PlayerController class in which I put the CharacterInput code, this act's as a networked input receiver. As I don't want to permanently send the clients movementDirection, I send state changes of the movementDirection and have the server keep running the simulation and CharacterController.UpdateCharacterGoals() in the server update loop. That's all the reason I've split the input values from the actual CharacterController.UpdateCharacterGoals() call.

However, on the buttonDownEvent of WASD the game sends a packet to the server that contains the current movementDirection (x/y values, always -1/0/1 nothing in between), which is stored on my server-side PlayerController. On buttonUpEvent of WASD the game basically sends a stopMovement packet, which set's the PlayerControllers movementDirection to (0,0).

CharacterController.UpdateCharacterGoals() is called in the servers update loop, where CharacterController.UpdateCharacterGoals() takes the current movementDirection from it's associated PlayerController instead of having it passed as function arguments.

Those are the few modifications I made to implement it into my existing architecture. There was still a small issue left in CharacterMotionConstraint.tt:, where I had to replace "IConstraintDescription<<#=prefix#>CharacterMotionConstraint>" with "IOneBodyConstraintDescription<<#=prefix#>CharacterMotionConstraint>" to fix an issue in CharacterController.cs:755 :

Code: Select all

Code: character.MotionConstraintHandle = Simulation.Solver.Add(character.BodyHandle, ref pendingConstraint.Description);
Error: Argument 2 cannot be passed with "ref" (Having german error messages, hope that is the correct one in english)
Last but not least, something I can't really test in the demo unfortunately but suspect might have something to do with my issue and is also quite annoying.. while having 2 or more players, jumping on another one throws an assertion error in Solver.cs:62. Interestingly this is called from basically the same code as above, but a few lines below at line 762 where dynamics are handled instead of statics.

The character demo works fine when compiling it on my machine (not even the issue with the CharacterMotionConstraint), all using the latest github master commit.

Edit #1: After further debugging I know a little bit more. The ice-issue has it's cause identified, so it's a "linear velocity decreasing to zero too slowly"-problem, which explains the moon-like jumping as well. After further checking, it seems like the simulation rate in the demo is depending on my frame rate, as per the comment in Demo.cs:

Code: Select all

//In the demos, we use one time step per frame. We don't bother modifying the physics time step duration for different monitors so different refresh rates
//change the rate of simulation. This doesn't actually change the result of the simulation, though, and the simplicity is a good fit for the demos.
That seems to explain why having a server tick rate of 60 compared to my framerate in the demo (probably a few hundred) changes how the character accelerates/stops. After increasing my tick rate it seems to improve the behaviour, but it can't be the solution to have my server run at about 500 ticks/second..?

This is how I implemented my update loop if that's important, but from the logs it seems to be doing what it should:

Code: Select all

        private const int SECOND_AS_MS = 1000;
        
        private float TickRate = 60;
        private TickRateTime = SECOND_AS_MS / options.TickRate;
            
        private void StartUpdateLoop()
        {
            double begin;
            double elapsed;
            double remaining;

            while (true)
            {
                begin = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;

                Update();

                elapsed = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - begin;
                remaining = TickRateTime - elapsed;

                Logger.Trace($"Tick duration: {elapsed} ms");
                Logger.Trace($"Remaining to {TickRate} hz cap: {remaining} ms");

                // Sleep until the next tick, but at least 1ms to not ramp up CPU usage
                Thread.Sleep(Math.Max(1, (int)remaining));
            }
        }
        
        public void Update()
        {
            Logger.Trace("Server Tick processing");

            // First we read what ever inputs we have
            ReadMessages();

            foreach (KeyValuePair<long, Session> session in clients)
            {
                session.Value.playerController.Update(false, 0.01f);
            }

            // Then we process the physics
            physicsEngine.Update(options.PhysicsEngineOptions.dt);

            // Send playfield update messages
            BroadcastPlayfield();

            Logger.Trace("Server Tick finished");
        }
Edit #2: PROBLEM SOLVED: The problem was sitting infront of the screen, it was not related to your awesome library but rather to how I used the Unity3d inputs. That comes from diving into everything at once.. However, for reference I'll provide my embarassing simple solution to my ice issue:

Code: Select all

Input.GetAxis("Horizontal"); // Returns filtered/lerped values, not hard -1/0/1 values as naively assumed
Input.GetAxisRaw("Horizontal"); // This is what you're looking for in a case like mine, does infact return -1/0/1 without intermediate values
Thanks for reading everything, hope you had a good laugh at least.. took me way too much time than I want to admit :lol:

Cheers

Re: [v2][Solved] Character Demo - Sliding as if on ice

Posted: Wed Oct 02, 2019 7:17 pm
by Norbo
Glad you figured out the core issue! Here's some extra info about some of the other stuff you ran into:
Those are the few modifications I made to implement it into my existing architecture. There was still a small issue left in CharacterMotionConstraint.tt:, where I had to replace "IConstraintDescription<<#=prefix#>CharacterMotionConstraint>" with "IOneBodyConstraintDescription<<#=prefix#>CharacterMotionConstraint>" to fix an issue in CharacterController.cs:755
Thanks for the report; it should now be fixed in master. I suspect this will also avoid the assert you hit.
That seems to explain why having a server tick rate of 60 compared to my framerate in the demo (probably a few hundred) changes how the character accelerates/stops. After increasing my tick rate it seems to improve the behaviour, but it can't be the solution to have my server run at about 500 ticks/second..?
This is how I implemented my update loop if that's important, but from the logs it seems to be doing what it should:
The demos cap out at the monitor refresh rate, so typically 60-144hz (or maybe 240 if you have one of those superspeedy ones).

That update loop implementation will suffer from resolution issues, though. DateTime.Now.Ticks is documented as being dependent on the OS's system timer. In Windows, the default interrupt frequency is only 64hz, so the error could be over 15 milliseconds.

Thread.Sleep(>=1) suffers from the same resolution issues. It'll sleep at least that many milliseconds, but you might end up overshooting by a full interrupt cycle. You'll probably want to use a higher resolution timer, like the Stopwatch class (provided IsHighResolution is true), combined with tighter waits as the remaining time goes below the interrupt cycle duration (hinted spin waits, possibly with yields or sleep(0)).

Re: [v2][Solved] Character Demo - Sliding as if on ice

Posted: Thu Oct 03, 2019 11:10 pm
by WRZ1
Thanks for the quick response! Master-branch has the constraint template file fixed, error is gone.

The assertion/jumping on another body issue was caused by something else, but after some debugging I could fix the assertion issue as well, for some reason there was a "ref" lingering around in CharacterControllers.cs:762 where it didn't belong. That called the wrong Solver.Add() for this context.

Code: Select all

character.MotionConstraintHandle = Simulation.Solver.Add(ref character.BodyHandle, character.Support.Handle, ref pendingConstraint.Description);
The info regarding my update loop is highly appreciated, need to improve that loop for sure. Reading up on spin waits, the difference to Thread.Sleep() seems to be that they prevent the interpreter from swapping threads, thus allowing tighter and more precise loops?

Re: [v2][Solved] Character Demo - Sliding as if on ice

Posted: Fri Oct 04, 2019 12:50 am
by Norbo
Reading up on spin waits, the difference to Thread.Sleep() seems to be that they prevent the interpreter from swapping threads, thus allowing tighter and more precise loops?
Roughly, yup.

Spin waits won't relinquish the timeslice to another pending thread. The OS thread scheduler still might swap it out, but it'll be a rarer event based on a periodic interrupt.

Thread.Sleep(0) relinquishes the timeslice to any other thread on the CPU, but doesn't specify a minimum wait period. If there's no other thread to schedule, it could return immediately. If the newly scheduled thread completes quickly, the original thread could be rescheduled.

Thread.Sleep(1 or higher) relinquishes the timeslice and blocks the calling thread from being rescheduled by the OS for a minimum of the given duration, and there's no guarantee the thread will be rescheduled after the specified wait duration. That tends to cause very long delays (relative to the scale of a 60hz update).

There's also a Thread.Yield() which functions similarly to Thread.Sleep(0), but only considers the subset of threads running on the current core as potential replacements.

Re: [v2][Solved] Character Demo - Sliding as if on ice

Posted: Fri Oct 04, 2019 2:15 am
by WRZ1
Thanks a lot! That's a really helpful summary and looks like all my issues are solved and I even improved my core loop.

Since the namespace of Stopwatch is in Diagnostics, I actually thought it wasn't made for production things and put it aside.. but well, what should I say? It's ridiculously precise from what I have seen in the console. Also had worries that a SpinWait would hog up the CPU, but nah all fine and handling everything at 0% CPU usage. Code looks also a lot cleaner now, but will obviously get some more things added like replacing the while condition with something useful.

Code: Select all

        private void StartUpdateLoop()
        {
            Stopwatch timer = new System.Diagnostics.Stopwatch();
            SpinWait spinner = new System.Threading.SpinWait();
            timer.Start();

            while (true)
            {
                timer.Restart();

                Update();

                while (timer.Elapsed.TotalMilliseconds <= options.TickRateTime)
                {
                    spinner.SpinOnce();
                }
            }
        }

Re: [v2][Solved] Character Demo - Sliding as if on ice

Posted: Fri Oct 04, 2019 4:38 pm
by Norbo
Nice!

Notably I was a little imprecise- the SpinWait type can internally relinquish the timeslice if the wait is long (for a spin wait), but it does so in a careful way to avoid both crazy long stalls and eating the CPU like a full while(true){} spin wait would.

Re: [v2][Solved] Character Demo - Sliding as if on ice

Posted: Fri Oct 04, 2019 9:43 pm
by WRZ1
Good to know.. however I just got to the infamous point of “The more I know, the less I realize I know” and have a lot of dots to connect. :D

Just when everything worked as expected I realized the differences between a dynamic and kinematic character controller. It totally makes sense to showcase a dynamic character controller instead of a kinematic one in a physics engine demo, but unfortunately a lot of games seem the benefit from a kinematic one.

Thus depending on the skill level your documentation/demos are aimed at, it may be useful to have a short description explaining there are different types of character controllers and that the demo one is a dynamic implementation? Similar to how the PhysX manual has it explained (which I can personally just recommend to skim over when unfamiliar with the concepts, gives a good idea about what a physics engine consists of):

https://docs.nvidia.com/gameworks/conte ... llers.html

Thanks a lot for your time!

Re: [v2][Solved] Character Demo - Sliding as if on ice

Posted: Sat Oct 05, 2019 12:44 am
by Norbo
I added a few sparse notes that it is indeed a dynamic character. I don't intend to publish much in the way of beginner to intermediate documentation, though- my historical efforts in that regard did not pay off, and most of the underlying concepts are general enough that someone else already did the work for me in a different engine :P

Incidentally, most of the problems with dynamic characters mentioned in that document aren't actually a problem in practice, at least in bepuphysics v2. The only one of note would be the lack of direct control- it's true that directly teleporting objects around isn't very kind to a dynamic simulation.

Re: [v2][Solved] Character Demo - Sliding as if on ice

Posted: Sat Oct 05, 2019 1:37 am
by WRZ1
Alright, beginners probably won’t go the route of implementing a custom physics engine that often anyways. From my part it was a complete lack of knowing any physics engine concepts, but as you said can be found pretty easily once you know what to look for. Whatever, learned a ton of new stuff and it’s hilarious running around with 10 other clients stacked onto each other :lol:

I‘ll stick with the dynamic one for now and see what can be achieved. Had the mass of my player at 0.01f to maybe have instant acceleration, but that seemed to push collision resolution off the charts and me too far away from collisions. Tweaking the maxVerticalForce will mitigate that effect but bring back some „momentum“.. Let’s see what will stick.

Re: [v2][Solved] Character Demo - Sliding as if on ice

Posted: Sat Oct 05, 2019 9:50 pm
by WRZ1
it's true that directly teleporting objects around isn't very kind to a dynamic simulation
Teleporting into space without collisions should be fine, and what you said only applies when I trigger a collision while changing the position or otherwise make it hard for velocity-based constraints.. is that correct? Edit: After reading a few comments in the BEPUphysics 1 CharacterController I suspect I should also somehow reset things like contacts.. just curious here, the real questions continue below.

A dynamic character controller won't make me happy in the long run and it will be easier to implement client-side prediction with a kinematic one, so I'll go that route probably.

For the kinematic controller to work, does it make sense to build a collision constraint/resolver for kinematic character controllers that adjusts position instead of velocity?

That resolver must handle collision resolution when colliding with statics and world object kinematics (floating moving platform for example). No collisions between kinematic character controllers is an advantage either, since they will interact on a distance/line of sight base and I don't need that as a overhead either. Dynamics are not important as I don't see an actual use case in my game for now, but obviously would be cool if they still interact properly between each other and static bodies.

Hope you get the idea, was hard to not end up writing another novel to explain everything. The alternative would be to do everything manually, which hurts just by thinking about it. Spinning circles here on how to approach this in the "correct" way, without inventing the wheel a few times over or building something that will just perform badly.

Re: [v2][Solved] Character Demo - Sliding as if on ice

Posted: Sat Oct 05, 2019 10:40 pm
by Norbo
Teleporting into space without collisions should be fine, and what you said only applies when I trigger a collision while changing the position or otherwise make it hard for velocity-based constraints.. is that correct?
Teleporting a completely unconstrained object to another completely unconstrained location is fine, yes. And even if constraints are present, the worst case is error that has to be recovered through position correction alone since there is no associated velocity, causing a soft-looking collision or constraint response. So it's not a big deal.

It is something to keep in mind for characters that are more interactive- say, dragging other objects around, holding objects, pulling on a rope, and so on. I lean towards trying to keep everything physically consistent to allow fully dynamic behavior with no weird corner cases.
However, a dynamic character controller won't make me happy in the long run and it will be easier to implement client-side prediction with a kinematic one, so I'll go that route probably.
There isn't much difficulty in client-side prediction with a dynamic character. The ease of a kinematic character tends to arise from the fact that it has very limited interactions with other objects, so rewind-replay isn't crazy expensive. But a dynamic character can be handled in the same way- you could put dynamic characters in their own sub-simulation for replay, for example. A number of users have done similar things in the past even in v1 where it was a bit more complicated and slow.
Hope you get the idea, was hard to not end up writing another novel to explain everything. The alternative would be to do everything manually, which hurts just by thinking about it. Spinning circles here on how to approach this in the "correct" way, without inventing the wheel a few times over or building something that will just perform badly.
Before you go down this path, I should offer a warning- making a robust, featureful character is one of the harder tasks in game physics. This is doubly true for kinematic characters that have to hack together everything that a dynamic body gets for free. Depending on the behavior/robustness target, it could take months of effort, especially as a first attempt. It's very likely the final result will be an order of magnitude slower than the simple demos dynamic character, or worse.

Full kinematic characters make sense for behaviors which are just fundamentally at odds with physical consistency and have no expectation of dynamic interaction, but if the behavior is anything close to physically consistent... a properly managed dynamic character will likely be massively easier and a lot faster.

But yes, it is technically possible to make a dedicated position-level solver to help handle character motion. At the end of that you won't be using much of the physics engine at all, but it is technically possible.

I'd strongly recommend considering what exact issues a dynamic character poses for your use case, consider how long it would take to address them in a dynamics-compatible way, and compare that to the yikestown that is a ground-up robust kinematic character.

Re: [v2][Solved] Character Demo - Sliding as if on ice

Posted: Sat Oct 05, 2019 10:44 pm
by Norbo
Edit: After reading a few comments in the BEPUphysics 1 CharacterController I suspect I should also somehow reset things like contacts..
That was an artifact of v1's persistent contact manifolds. It would attempt to bring the previous frame's contacts forward if possible. v2 abandoned that in favor of pure one-shot manifolds which tend to be more robust and don't require any kind of reset.

Re: [v2][Solved] Character Demo - Sliding as if on ice

Posted: Sun Oct 06, 2019 1:48 am
by WRZ1
Teleporting a completely unconstrained object to another completely unconstrained location is fine, yes. And even if constraints are present, the worst case is error that has to be recovered through position correction alone since there is no associated velocity, causing a soft-looking collision or constraint response. So it's not a big deal.

It is something to keep in mind for characters that are more interactive- say, dragging other objects around, holding objects, pulling on a rope, and so on. I lean towards trying to keep everything physically consistent to allow fully dynamic behavior with no weird corner cases.
That sounds like it'll work for my cases then, nice.
There isn't much difficulty in client-side prediction with a dynamic character. The ease of a kinematic character tends to arise from the fact that it has very limited interactions with other objects, so rewind-replay isn't crazy expensive. But a dynamic character can be handled in the same way- you could put dynamic characters in their own sub-simulation for replay, for example. A number of users have done similar things in the past even in v1 where it was a bit more complicated and slow.
The reason I thought it'll be "easier" with kinematics was a misconception. Before I realized I should at least use BEPUs collision detection to resolve the position, I was thinking about doing everything by hand. Well, quickly realized the same as you, I'd literally not be using the physics engine anymore at all haha.

However that thought is not too far off, while writing my previous post I was thinking about exactly that - do I even need the engine? I stumbled upon BEPU because I was looking for a way to have server-side world-coordinates with collision detection, raycasts and line of sight checks. So while some of my requirements seem to indicate I don't need a physic engine, it looks like the other solution would be to implement the required components myself or via other non-existing or old libraries. Thus a physic engine seems to give me exactly the required tools for everything, and in addition I'll be able to conveniently add physics objects in case I need it.
Before you go down this path, I should offer a warning- making a robust, featureful character is one of the harder tasks in game physics. This is doubly true for kinematic characters [...]
Indeed.. the more I work with it, the more often I am like "Ahh so that was happening in game X back then". Tells a lot if even huge AAA titles have their fair share of issues with controllers sometimes. To my luck if I ever implement for example sliding, I'd consider that fancy already. The game just doesn't expect much freedom fortunately, so while it will of course take some time to get everything right, it should be considerable. Also thought about buying a kinematic character controller asset for unity, which would at least spare me from doing all the heavy-lifting. I could a) easily use it in the client and b) tear out all the movement logic to re-implement it server-side. Won't be a piece of cake, but with some patience I think that could work out... trying to get in contact with the author right now.

I'll stick with the dynamic solution for now, it's just a matter of convenience at the moment and totally fine for prototyping stage anyway. Maybe I can even get it to feel right.. until then there's lot of things to do anyway.

Thanks again for your insightful input, really a huge help and mad respect for what you've achieved here so far, just astonishing tbh.