Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Join us on Thursday, June 8, for a Q&A with Unity's Content Pipeline group here on the forum, and on the Unity Discord, and discuss topics around Content Build, Import Workflows, Asset Database, and Addressables!
    Dismiss Notice

Official Unity Physics 0.4.0 - Contact Solver Stabilization Heuristic

Discussion in 'Physics for ECS' started by petarmHavok, Jun 18, 2020.

  1. petarmHavok


    Nov 20, 2018
    With the 0.4.0 release of Unity.Physics we've added a mechanism which improves general stability of dynamic bodies stacked on top of each other. We call this the ‘Contact Solver Stabilization Heuristic’.

    Proper stability in piles of dynamic bodies requires the physics simulation to be able to preserve state (mostly because of inaccuracies coming from iterative solving of contact points), as well as approximate friction solving. Stateful physics engines such as Havok.Physics can cache useful information from the previous solve step (applied impulse, error in calculation) and use that information for calculations in the current step, thus fixing the small artifacts that accumulate over time.

    Since Unity.Physics is a stateless physics engine (to allow for easy deterministic rollback scenarios, as well as lightweight simulation), no information from previous step can be used. That’s why we developed this new heuristic approach for stabilizing the solver calculations and allowing for stable piles of bodies.
    We'll try to use this thread to explain the usability, configurability, heuristics and behavior considerations of the new feature, as well as potential artifacts.

    The feature is off by default to avoid breaking existing behavior in your scenes. However, it is easily turned on in the PhysicsStepAuthoring component, where all you need to do in a typical scenario is set EnableSolverStabilizationHeuristic to true.

    We’ve enabled the new heuristic specifically in the 2b1. Motion Properties – Mass and Pyramids scene in the UnityPhysicsSamples project. There is also a specific group of test scenes under Assets/Tests/Stacking to highlight the behavior of the bodies with the new feature enabled, as well as its strengths and weaknesses.

    To enable this feature for all the sample scenes you can also toggle the setting in the ‘Physics Scene Basic Elements\Physics Settings’ prefab.

    For advanced usage, looking in PhysicsStep.SolverStabilizationHeuristicSettings you can find 4 parameters:
    - EnableSolverStabilization, which is a global switch to enable/disable the feature and defaults to false; the rest of the parameters are only used if this is set to true, and will be explained in more detail in the next section, since we are just listing them here

    - EnableFrictionVelocities, which enables/disables the friction velocities heuristic
    - VelocityClippingFactor, which controls the intensity of the velocity clipping heuristic
    - InertiaScalingFactor, which controls the intensity of the inertia scaling heuristic

    Code (CSharp):
    1. // Settings for controlling the solver stabilization heuristic.
    2. public struct StabilizationHeuristicSettings
    3. {
    4.     private byte m_EnableSolverStabilization;
    6.     // Global switch to enable/disable the whole heuristic (false by default)
    7.     public bool EnableSolverStabilization
    8.     {
    9.         get => m_EnableSolverStabilization > 0;
    10.         set => m_EnableSolverStabilization = (byte)(value ? 1 : 0);
    11.     }
    13.     // Individual features control (only valid when EnableSolverStabilizationHeuristic is true)
    14.     private byte m_EnableFrictionVelocities;
    16.     // Switch to enable/disable heuristic when calculating friction velocities.
    17.     // Should be disabled only if it is causing behavior issues.
    18.     public bool EnableFrictionVelocities
    19.     {
    20.         get => m_EnableFrictionVelocities > 0;
    21.         set => m_EnableFrictionVelocities = (byte)(value ? 1 : 0);
    22.     }
    24.     // Controls the intensity of the velocity clipping.
    25.     // Defaults to 1.0f, while other values will scale the intensity up/down.
    26.     // Shouldn't go higher than 5.0f, as it will result in bad behavior (too aggressive velocity clipping).
    27.     // Set it to 0.0f to disable the feature.
    28.     public float VelocityClippingFactor;
    30.     // Controls the intensity of inertia scaling.
    31.     // Defaults to 1.0f, while other values will scale the intensity up/down.
    32.     // Shouldn't go higher than 5.0f, as it will result in bad behavior (too high inertia of bodies).
    33.     // Set it to 0.0f to disable the feature.
    34.     public float InertiaScalingFactor;
    36.     public static readonly StabilizationHeuristicSettings Default = new StabilizationHeuristicSettings
    37.     {
    38.         m_EnableSolverStabilization = 0,
    39.         m_EnableFrictionVelocities = 1,
    40.         VelocityClippingFactor = 1.0f,
    41.         InertiaScalingFactor = 1.0f
    42.     };
    43. }
    All these individual parameters default to sensible values that should work in most cases and are only exposed to fine tune some specific scenarios we might have forgotten to cover.

    This feature does not enable natural physical behavior of piles of bodies, but instead uses heuristics to analyze the scene and surroundings of bodies and make smart decisions that reduce the artifacts of stateless solving of contacts.

    Friction velocities heuristic
    This heuristic chooses which velocity it is going to use when doing friction calculations in the contact solver. The choice is between current intermediate velocity coming from other contacts being solved, and the one the body had at the beginning of the step. Whichever produces smaller energy is chosen as the velocity for friction calculations, and only for that (contact solving is still done the same way as before). This reduces artifacts coming from stateless solving of friction contact points, which is the main reason body piles were previously not stable.

    You can control this heuristic by simply turning it on or off via SolverStabilizationHeuristicSettings.EnableFrictionVelocities, but it should usually be enabled unless proven to cause issues. There is a small chance of missing out on friction response, as well as jitter in complex colliders being stacked.

    Inertia scaling heuristic
    The idea behind this one is that each body can “inspect” its surroundings by simply counting its neighbors and then scale its inertia based on that. When we decide what counts as the neighbor, we look at body pairs that are being solved as contacts (not necessarily have impulse applied), and only with some predefined mass ratio. A body is counted as a neighbor of a specific body if it’s heavier, or up to 2 times lighter than that body. So, a body of 1kg will not be counted as a neighbor of a 10kg body, but the same 10kg body will be the neighbor of the 1kg body.

    The SolverStabilizationHeuristicSettings.InertiaScalingFactor controls the intensity of this behavior. It defaults to 1.0 which translates to each neighbor contributing with a factor of 0.2 to body’s inertia. So, a body with 5 neighbors will results in double (1.0 + 5 * 0.2) the inertia in that particular solving step. Increasing this factor to 2.0 for example will scale the individual body contribution to 0.4 in this case. Also, this factor can reduce this contribution in the same manner. One should be careful when tweaking this value as really low values can effectively disable the feature, while high values can make bodies have no angular effects due to high inertia. Set this to 0 to completely disable this heuristic.

    Velocity clipping heuristic
    Previous 2 heuristics significantly reduce the leftover velocities in body piles that introduce jitter and disable stabilization of piles, but they still don’t remove them completely. That’s why there is a velocity clipping heuristic enabled after each solver iteration to make sure these leftover velocities are zeroed out. Now, only sideways linear velocities are zeroed out, so velocity along the direction of gravity is never touched, as it doesn’t affect stability of the piles in a negative way. Gravity also has an effect on the intensity of the clipping, since by default all velocities that are smaller than 0.25 * gravity in one step (which is around 4cm/s at 60Hz) in directions other than gravity direction will be zeroed out.

    Angular velocities will also be clipped to 0 below some threshold, that scales the threshold for linear clipping with the size of the body. They will only be clipped if linear velocities were clipped, so fast-moving bodies will not be affected.

    Velocity clipping intensity is controlled via SolverStabilizationHeuristicSettings.VelocityClippingFactor. Again, a factor of 2.0 will make the gravity coefficient rise to 0.5, while smaller values will reduce it, the same way as in inertia scaling. Consequently, the same warnings apply, so be careful with really small and really large values. Again, set it to 0 to disable this heuristic.

    Behavior considerations
    It should be obvious by now that this feature affects default physics behavior in a non-physically-correct way (setting small velocities to 0, reducing energy in friction and increasing inertia of bodies). However, since all of these individual features are not very aggressive and only appear in a limited number of cases (mostly a lot of bodies in piles), they should produce decent behavior in most cases. Individual parameters are there to tweak some non-standard behaviors if the need arises.

    You will notice more overall stability in piles and less drift of bodies, as well as stability of stacks of bodies. Also, individual bodies flying through air, or just having large velocities, as well as sitting alone on the ground, shouldn’t be affected in any visible way.

    As mentioned above, this is clearly not a correct behavior, so there will be artifacts.

    Bodies can get settled in piles in strange orientations due to velocity clipping and inertia scaling and may appear as if they should tumble over or continue to move.

    Bodies moving at really small velocities can simply get stuck, or if they continue to move, they may not affect other bodies in a way you would expect, since that interaction could be zeroed out due to the clipping.

    Body piles and stacks may keep their formation when you expect them to move or fall apart. Imagine a stack of bodies on a sideways moving platform with small (but not 0) friction. The platform will not be able to affect the pile enough to move it due to stabilization heuristics. Also, stacks on mild slopes with low (or 0) friction might not slide, since stabilization keeps them in place. However, vertically moving platforms will be fine, since, as mentioned above, velocity along gravity is never touched.

    upload_2020-6-18_15-33-16.png upload_2020-6-18_15-33-20.png

    Some of these artifacts are covered in the demos under Tests/Stacking/ComplexStacking to show you what to expect in those scenarios.

    This is a new feature and we expect it to evolve over time. Please use this thread to ask any questions or request more detailed explanations on any of the pieces, as well as provide feedback on behavior. We are eager to see how this will be used in your applications and are looking forward to hearing your feedback!
  2. roryo


    May 21, 2009
    This sounds like a great solution. Unfortunately, I can't see a EnableSolverStabilizationHeuristic checkbox in the PhysicsStepAuthoring component.

    Image 9-13-20 at 2.17 PM.jpeg

    I am using Unity Physics 0.3.2 in Unity 2019..3.15f1. Is there a different version I should try?

  3. tertle


    Jan 25, 2011
    This post is about physics 0.4.0 though the latest is 0.4.1 now
    This requires unity 19.4
  4. petarmHavok


    Nov 20, 2018
    Yes, this was added in 0.4.0.
    roryo likes this.
  5. roryo


    May 21, 2009
    That did the trick! Thanks, @petarmHavok!
    petarmHavok likes this.
  6. steveeHavok


    Mar 19, 2019