Animating the speed setting in Rigid Body World causes strange behavior with constraints #38391

Closed
opened 2014-01-29 03:04:27 +01:00 by gandalf3 · 20 comments
Member

System Information
Archlinux
Nvidia GTX 460

Blender Version
Broken: 2.69, 2.69.10 (c7ac0ed)

Short description of error
Animating the speed value causes constraints to behave weirdly.

Exact steps for others to reproduce the error
Based on rigid-body-speed.blend

  1. Open attached file
  2. Play animation. When the ball hits the stack of cubes, the /Speed// value gets set to .01. For some reason this makes the constraints behave in a very odd way.
  3. Remove the keyframes and play the animation again. The motion is as expected.

Changing the speed works fine without constraints though, see the other scene in the attached file.

**System Information** Archlinux Nvidia GTX 460 **Blender Version** Broken: 2.69, 2.69.10 (c7ac0ed) **Short description of error** Animating the speed value causes constraints to behave weirdly. **Exact steps for others to reproduce the error** Based on [rigid-body-speed.blend](https://archive.blender.org/developer/F75558/rigid-body-speed.blend) 1. Open attached file 2. Play animation. When the ball hits the stack of cubes, the /Speed// value gets set to .01. For some reason this makes the constraints behave in a very odd way. 3. Remove the keyframes and play the animation again. The motion is as expected. Changing the speed works fine without constraints though, see the other scene in the attached file.
Author
Member

Changed status to: 'Open'

Changed status to: 'Open'
Author
Member

Added subscriber: @gandalf3

Added subscriber: @gandalf3

Added subscriber: @CodeMatias

Added subscriber: @CodeMatias

It looks like a feature/bug where the simulation framerate is not dependent on the speed<-should be real framerate, which results in non-standard behavior. If you bake using 1000hz (or 600Hz) simulation instead of 60hz you get a reasonable result.

edit Upon further testing (and looking closely at both impact point and chain), it's not so much an issue with blender or bullet as it is poor simulation setup. The chain was made with point constraints that are under high displacement before impact, which was over-corrected when frame-rate was increased (ERP is dependent on frame-rate rather than simulation time). As expected using constraint over-ride or higher simulation iterations solves the issue, and applying the same ratios as speed to other parameters results in very similar joint displacement.Perhaps it's time to allow other solvers to be exposed? The current bullet2 code includes the 2.82 updates for MLCP solvers, which should provide hard constraints without time resolution dependence.

It looks like a feature/bug where the simulation framerate is not dependent on the *speed*<-should be real framerate, which results in non-standard behavior. If you bake using 1000hz (or 600Hz) simulation instead of 60hz you get a reasonable result. *edit* Upon further testing (and looking closely at both impact point and chain), it's not so much an issue with blender or bullet as it is poor simulation setup. The chain was made with point constraints that are under high displacement before impact, which was over-corrected when frame-rate was increased (ERP is dependent on frame-rate rather than simulation time). As expected using constraint over-ride or higher simulation iterations solves the issue, and applying the same ratios as speed to other parameters results in very similar joint displacement.Perhaps it's time to allow other solvers to be exposed? The current bullet2 code includes the 2.82 updates for MLCP solvers, which should provide hard constraints without time resolution dependence.
Member

Added subscriber: @LukasTonne

Added subscriber: @LukasTonne
Member

I think this is a problem with the way our rigid body system defines substeps for Bullet currently:
https://developer.blender.org/diffusion/B/browse/master/source/blender/blenkernel/intern/rigidbody.c;39eb314cb922b805e9126d5f0352f31c2f84f151$1367

Quoting from Bullet wiki pages:
"Bullet maintains an internal clock, in order to keep the actual length of ticks constant. This is pivotally important for framerate independence."

What happens with the time_scale value is that both the overall time step for a single frame as well as the "fixed" time step for Bullet are scaled. This is supposed to ensure a consistent resolution of ticks for every frame, but it looks like that throws off the Bullet solver, especially with such extreme differences (2.0 vs. 0.01).

I've managed to get the expected result by ignoring time scale for the fixed substeps, but this leads to very choppy motion since Bullet then only does a real tick every 30 frames or so ...

I think this is a problem with the way our rigid body system defines substeps for Bullet currently: https://developer.blender.org/diffusion/B/browse/master/source/blender/blenkernel/intern/rigidbody.c;39eb314cb922b805e9126d5f0352f31c2f84f151$1367 Quoting from [Bullet wiki pages](http://bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_The_World): "Bullet maintains an internal clock, in order to keep the actual length of ticks constant. This is pivotally important for framerate independence." What happens with the time_scale value is that both the overall time step for a single frame *as well as the "fixed" time step* for Bullet are scaled. This is supposed to ensure a consistent resolution of ticks for every frame, but it looks like that throws off the Bullet solver, especially with such extreme differences (2.0 vs. 0.01). I've managed to get the expected result by ignoring time scale for the fixed substeps, but this leads to very choppy motion since Bullet then only does a real tick every 30 frames or so ...

Added subscriber: @sreich

Added subscriber: @sreich

Yeah, it's a side effect of the way we do time scaling. Maybe it would be better to have it not change the steps per second (I tried that as well but you have to manually adjust the steps per seconds then, which is often not obvious).
From what I can tell, the problem doesn't necessarily have to do with not having a fixed time step though. It's jsut that the constraints get really stiff, when you do so many steps. You can get similar problems even without using the speed property.

You can try to play with the steps per second and see if it makes a difference (in this case increasing it even further seems to help).

Yeah, it's a side effect of the way we do time scaling. Maybe it would be better to have it not change the steps per second (I tried that as well but you have to manually adjust the steps per seconds then, which is often not obvious). From what I can tell, the problem doesn't necessarily have to do with not having a fixed time step though. It's jsut that the constraints get really stiff, when you do so many steps. You can get similar problems even without using the speed property. You can try to play with the steps per second and see if it makes a difference (in this case increasing it even further seems to help).

"From what I can tell, the problem doesn't necessarily have to do with not having a fixed time step though. It's jsut that the constraints get really stiff, when you do so many steps. You can get similar problems even without using the speed property."

Yes, it's caused by a sudden shift of any parameter that changes total constraint error correction per frame (speed, fps, iteration count, which determine joint error correction), and it's not limited to blender alone (did quick test in 2.82). Only real ways to fix it are:

  • Document and tell users to keep iterations-per-frame changes small
  • Apply some sort of filter to keep iteration-per-frame changes small (i.e. clamp step size * iteration changes to ~25% between frames), perhaps as an option
  • Use hard solvers like the MLCP (Dantzing/ Lemke) ones (doesn't solve everything since penetration issues would also cause a similar issue). Hard solver implementation should be the easiest of the bunch for those willing to build a modified version of the physics engine, it literally involves only replacing https://developer.blender.org/diffusion/B/browse/master/intern/rigidbody/rb_bullet_api.cpp;39eb314cb922b805e9126d5f0352f31c2f84f151$160 with the MLCP version (MLCP has auto-fallback to PGS if it fails, Building solver option into the system will be more complicated though). I can't really say if it will play nice with Blender in all cases, but this one is simple enough that it should be fine.

Currently Blender doesn't have proper joint motor implementations (i.e. hinge joint with internal motor), but if those are added the SequentialImpulseSolver will show motor strength variance depending on both iterations per frame and fps due to the same issue. Motors with extremely high fps can also be unstable especially if the speed is changed and it over-corrects for an error. It's not necessarily a bug, rather a limitation of the approximation used and settings for the simulation. Again, MLCP code fixes a lot of that at the cost of performance in some cases.

"From what I can tell, the problem doesn't necessarily have to do with not having a fixed time step though. It's jsut that the constraints get really stiff, when you do so many steps. You can get similar problems even without using the speed property." Yes, it's caused by a sudden shift of any parameter that changes total constraint error correction per frame (speed, fps, iteration count, which determine joint error correction), and it's not limited to blender alone (did quick test in 2.82). Only real ways to fix it are: - Document and tell users to keep iterations-per-frame changes small - Apply some sort of filter to keep iteration-per-frame changes small (i.e. clamp step size * iteration changes to ~25% between frames), perhaps as an option - Use hard solvers like the MLCP (Dantzing/ Lemke) ones (doesn't solve everything since penetration issues would also cause a similar issue). Hard solver implementation should be the easiest of the bunch for those willing to build a modified version of the physics engine, it literally involves only replacing https://developer.blender.org/diffusion/B/browse/master/intern/rigidbody/rb_bullet_api.cpp;39eb314cb922b805e9126d5f0352f31c2f84f151$160 with the MLCP version (MLCP has auto-fallback to PGS if it fails, Building solver option into the system will be more complicated though). I can't really say if it will play nice with Blender in all cases, but this one is simple enough that it should be fine. Currently Blender doesn't have proper joint motor implementations (i.e. hinge joint with internal motor), but if those are added the SequentialImpulseSolver will show motor strength variance depending on both iterations per frame and fps due to the same issue. Motors with extremely high fps can also be unstable especially if the speed is changed and it over-corrects for an error. It's not necessarily a bug, rather a limitation of the approximation used and settings for the simulation. Again, MLCP code fixes a lot of that at the cost of performance in some cases.

As far as I can see the best fix for now would be to either completely disallow animating the properties that intfuence timestep or just warn that bigger changes will have side effects.

As far as I can see the best fix for now would be to either completely disallow animating the properties that intfuence timestep or just warn that bigger changes will have side effects.
Author
Member

@sreich Animating the timestep is quite useful for slow motion effects, etc. As a user I would rather it not be disabled...
And it works fine in cases with no constraints.

BTW, I want to say thanks for implementing this feature :)

@sreich Animating the timestep is quite useful for slow motion effects, etc. As a user I would rather it not be disabled... And it works fine in cases with no constraints. BTW, I want to say thanks for implementing this feature :)

@gandalf3 it's not just a problem with constraints, if you change the speed of the simulation or the steps per second during collisions you'll have the same problem. So be careful.

After looking into it for a bit more, there might be a way of fixing it. That will have to wait for 2.71 though, I wouldn't want to risk introducing regression so close to release.

@CodeMatias: Using the MLCP solvers in bullet is not really an option for us unfortunately, they're just too slow. Also they don't fix this particular problem.

@gandalf3 it's not just a problem with constraints, if you change the speed of the simulation or the steps per second during collisions you'll have the same problem. So be careful. After looking into it for a bit more, there might be a way of fixing it. That will have to wait for 2.71 though, I wouldn't want to risk introducing regression so close to release. @CodeMatias: Using the MLCP solvers in bullet is not really an option for us unfortunately, they're just too slow. Also they don't fix this particular problem.

@sreich : The MLCP solvers are not perfect for linear displacements like this one, but they would help substantially in most common cases. In my Bullet simulations I generally find Dantzig MLCP to be about as effective as 100-200 iteration PGS with all other settings equal for minimizing joint error (the "bug"'s root cause). The .blend posted here works just fine if the iterations is cranked up to 200, so perhaps the MLCP solvers could have helped as well (though certainly not a 100% thing).

I can't talk for all cases, as I generally focus on robotic simulations with a low number of simulated items (3~18 motors in a chain), but the Dantzig solver tends to be only about three times slower than the standard PGS settings (10 iteration). In fact, it can be faster in some situations where you would otherwise need high iteration counts, especially when it doesn't have to fall back to PGS. The 200 iteration case I normally deal with actually makes Dantzig up to twice as fast as PGS. Of course the Lemke implementation, as it currently is, makes anything seem blazing fast; that algorithm would need serious baking time for even simple scenes.

But yes, it's not really necessary for Blender, though would be nice as an option.

Perhaps a realistic target for the next sprint would be making ERP dependent on Blender frame rate rather than bullet frame-rate? i.e. making framerate and iteration values fixed for a simulation (unlike now) and varying ERP based on the change in speed , perhaps using ERP = h kp / (h kp + kd) where kp and kd remain constant [ which should be ERP_corrected= ERP_base/ ( (1- ERP_base ) / Speed + ERP_base) ] . You should end up with joint error for a simulation dependent on the base "steps per second" and correction amount is the same for every Blender frame (no discontinuous stiffness). This would affect both joints and penetration too, which can be both good and bad depending on what you consider to be more necessary.
Since h is step size, you could possibly even make framerate variable and just replace Speed with a function of Speed and "steps per second", though it would require you to expose the ERP_base to the user and expect them to figure it out (because higher "steps per second" would no longer mean higher joint accuracy).

Unfortunately that goes beyond the simple stuff I could possibly submit as even a proof of concept patch, since it would involve exposing btContactSolverInfo()->m_erp and using it before the call linked to by lukastoenne (and so much more).

edit And I'm sure you probably have something better planned (which I noticed after reading the comment again)

@sreich : The MLCP solvers are not perfect for linear displacements like this one, but they would help substantially in most common cases. In my Bullet simulations I generally find Dantzig MLCP to be about as effective as 100-200 iteration PGS with all other settings equal for minimizing joint error (the "bug"'s root cause). The .blend posted here works just fine if the iterations is cranked up to 200, so perhaps the MLCP solvers could have helped as well (though certainly not a 100% thing). I can't talk for all cases, as I generally focus on robotic simulations with a low number of simulated items (3~18 motors in a chain), but the Dantzig solver tends to be only about three times slower than the standard PGS settings (10 iteration). In fact, it can be faster in some situations where you would otherwise need high iteration counts, especially when it doesn't have to fall back to PGS. The 200 iteration case I normally deal with actually makes Dantzig up to twice as fast as PGS. Of course the Lemke implementation, as it currently is, makes anything seem blazing fast; that algorithm would need serious baking time for even simple scenes. *But yes, it's not really necessary for Blender, though would be nice as an option.* Perhaps a realistic target for the next sprint would be making ERP dependent on Blender frame rate rather than bullet frame-rate? i.e. making framerate and iteration values fixed for a simulation (unlike now) and varying ERP based on the change in speed , perhaps using ERP = h kp / (h kp + kd) where kp and kd remain constant [ which should be ERP_corrected= ERP_base/ ( (1- ERP_base ) / Speed + ERP_base) ] . You should end up with joint error for a simulation dependent on the base "steps per second" and correction amount is the same for every Blender frame (no discontinuous stiffness). This would affect both joints and penetration too, which can be both good and bad depending on what you consider to be more necessary. Since h is step size, you could possibly even make framerate variable and just replace Speed with a function of Speed and "steps per second", though it would require you to expose the ERP_base to the user and expect them to figure it out (because higher "steps per second" would no longer mean higher joint accuracy). Unfortunately that goes beyond the simple stuff I could possibly submit as even a proof of concept patch, since it would involve exposing btContactSolverInfo()->m_erp and using it before the call linked to by lukastoenne (and so much more). *edit* And I'm sure you probably have something better planned (which I noticed after reading the comment again)
Sergej Reich was assigned by Sergey Sharybin 2014-02-03 12:56:49 +01:00

Added subscriber: @Sergey

Added subscriber: @Sergey

@sreich, you're the rigid body boss, so assigning to you to take care of the issue. Feel free to either fix, re-assign or move to TODO :)

@sreich, you're the rigid body boss, so assigning to you to take care of the issue. Feel free to either fix, re-assign or move to TODO :)

@sreich, any chance looking into the report? Disabling animation of time-related things seem fine to me. It's rather tricky to support anyway..

@sreich, any chance looking into the report? Disabling animation of time-related things seem fine to me. It's rather tricky to support anyway..
Author
Member

I would personally rather it be left as is than be disabled entirely, as it's very useful for neat slo-mo effects, even with the current limitations..

I would personally rather it be left as is than be disabled entirely, as it's *very* useful for neat slo-mo effects, even with the current limitations..

Ok, I think messing with bullet's main loop is not a good idea after all.
Closing this, as a limitation.

Ok, I think messing with bullet's main loop is not a good idea after all. Closing this, as a limitation.

Changed status from 'Open' to: 'Archived'

Changed status from 'Open' to: 'Archived'

Added subscriber: @JosephPoole

Added subscriber: @JosephPoole
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
6 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#38391
No description provided.