Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Performance issues
#1
I'm using Obi Rope to simulate cords and wires in a VR truck service simulator. Since it was extremely unpractical and unstable to let Obi manage the rope length constraints, i decided to make all rigidbodies kinematicForParticles and use spring joints between the plugs (and dummy rigidbodies pinning the ropes together at all junctions) to keep them connected, just using ObiRope to simulate the aesthetics of the cords with pin constraints. The results are not 100% accurate, but it looks good enough for my purposes. Despite this, and despite rendering over 30 million triangles in the scene, ObiRope still stands for over 60% of the CPU load. This is despite the fact that i only use 2 solvers (one in each sub-scene), each with all constraints except pin, stitch, distance and collision disabled, and iteration counts set to 3 and below. There are maybe around 50 obi colliders in the scene. I also have a resolution of below 0.2 on all my ropes - in total, there are roughly 700 particles simulating. If i hang ropes on the wall (by attaching a fixed joint to one of the plug ends), obi will eventually even crash unity very suddenly and without warning. I have changed it so that the solvers run in LateUpdate, and reduced the advection radius to 0.05, but the performance is still utter crap. Am i doing something wrong, or does it simply not get better than this?

EDIT: Before Unity crashes, i get a huge wave of errors starting with:

Assertion failed: Assertion failed on expression: 'CompareApproximately(det, 1.0F, .005f)'
UnityEngine.Quaternion:FromToRotation(Vector3, Vector3)
Obi.CurveFrame:Transport(Vector3, Vector3, Single) (at Assets/Obi/Scripts/Actors/ObiRope.cs:61)
Obi.ObiRope:UpdateRopeMesh() (at Assets/Obi/Scripts/Actors/ObiRope.cs:962)
Obi.ObiRope:UpdateProceduralRopeMesh() (at Assets/Obi/Scripts/Actors/ObiRope.cs:892)
Obi.ObiRope:UpdateVisualRepresentation() (at Assets/Obi/Scripts/Actors/ObiRope.cs:590)
Obi.ObiRope:OnSolverFrameEnd() (at Assets/Obi/Scripts/Actors/ObiRope.cs:365)
Obi.ObiSolver:EndFrame(Single) (at Assets/Obi/Scripts/Solver/ObiSolver.cs:536)
Obi.ObiSolver:LateUpdate() (at Assets/Obi/Scripts/Solver/ObiSolver.cs:665)


Eventually i get this:

rigidbody.velocity assign attempt for 'Breakout Box' is not valid. Input velocity is { NaN, NaN, NaN }.
UnityEngine.RigidbodyConfundidoet_velocity(Vector3)
Obi.ObiRigidbody:UpdateVelocities() (at Assets/Obi/Scripts/Collisions/ObiRigidbody.cs:68)
Obi.ObiColliderBase:UpdateRigidbody(Object, EventArgs) (at Assets/Obi/Scripts/Collisions/ObiColliderBase.cs:262)
Obi.ObiArbiter:WaitForAllSolvers() (at Assets/Obi/Scripts/Solver/ObiArbiter.cs:82)
Obi.ObiSolver:SimulateStep(Single) (at Assets/Obi/Scripts/Solver/ObiSolver.cs:499)
Obi.ObiSolver:LateUpdate() (at Assets/Obi/Scripts/Solver/ObiSolver.cs:659)

Assertion failed: Assertion failed on expression: 'fRoot >= Vector3f::epsilon'
UnityEngine.Quaternion:FromToRotation(Vector3, Vector3)
Obi.CurveFrame:Transport(Vector3, Vector3, Single) (at Assets/Obi/Scripts/Actors/ObiRope.cs:61)
Obi.ObiRope:UpdateRopeMesh() (at Assets/Obi/Scripts/Actors/ObiRope.cs:962)
Obi.ObiRope:UpdateProceduralRopeMesh() (at Assets/Obi/Scripts/Actors/ObiRope.cs:892)
Obi.ObiRope:UpdateVisualRepresentation() (at Assets/Obi/Scripts/Actors/ObiRope.cs:590)
Obi.ObiRope:OnSolverFrameEnd() (at Assets/Obi/Scripts/Actors/ObiRope.cs:365)
Obi.ObiSolver:EndFrame(Single) (at Assets/Obi/Scripts/Solver/ObiSolver.cs:536)
Obi.ObiSolver:LateUpdate() (at Assets/Obi/Scripts/Solver/ObiSolver.cs:665)

And also this:

Assertion failed: Invalid worldAABB. Object is too large or too far away from the origin.

The way i interpret it, a rounding error propagates in the quaternion calculations causing forces to be scaled high enough to instantly propel objects out of the scene. It's just a qualified guess, though, and i'm not sure why forces would be applied anyway since the objects are all kinematic as far as Obi is concerned. In this particular case, the crash only occurs when the cord is hanging against the wall, but i've had it before as well in various situations (Always the AABB error).

EDIT2: Some more of the errors:

Assertion failed: Converting invalid MinMaxAABB
UnityEngine.Mesh:SetTriangles(List`1, Int32, Boolean)
Obi.ObiRope:CommitMeshData() (at Assets/Obi/Scripts/Actors/ObiRope.cs:911)
Obi.ObiRope:UpdateRopeMesh() (at Assets/Obi/Scripts/Actors/ObiRope.cs:1037)
Obi.ObiRope:UpdateProceduralRopeMesh() (at Assets/Obi/Scripts/Actors/ObiRope.cs:892)
Obi.ObiRope:UpdateVisualRepresentation() (at Assets/Obi/Scripts/Actors/ObiRope.cs:590)
Obi.ObiRope:OnSolverFrameEnd() (at Assets/Obi/Scripts/Actors/ObiRope.cs:365)
Obi.ObiSolver:EndFrame(Single) (at Assets/Obi/Scripts/Solver/ObiSolver.cs:536)
Obi.ObiSolver:LateUpdate() (at Assets/Obi/Scripts/Solver/ObiSolver.cs:665)

Mesh '': abnormal mesh bounds - most likely it has some invalid vertices (+/-inifinity or NANs) due to errors exporting.
Mesh bounds min=(-1.#J, -1.#J, -1.#J), max=(-1.#J, -1.#J, -1.#J). Please make sure the mesh is exported without any errors.

Assertion failed: Invalid worldAABB. Object is too large or too far away from the origin.

It seems to be triggered primarily by collisions between ObiColliders with an attached ObiRigidbody.
Reply
#2
(24-01-2018, 04:00 PM)khalvr Wrote: I'm using Obi Rope to simulate cords and wires in a VR truck service simulator. Since it was extremely unpractical and unstable to let Obi manage the rope length constraints, i decided to make all rigidbodies kinematicForParticles and use spring joints between the plugs (and dummy rigidbodies pinning the ropes together at all junctions) to keep them connected, just using ObiRope to simulate the aesthetics of the cords with pin constraints. The results are not 100% accurate, but it looks good enough for my purposes. Despite this, and despite rendering over 30 million triangles in the scene, ObiRope still stands for over 60% of the CPU load. This is despite the fact that i only use 2 solvers (one in each sub-scene), each with all constraints except pin, stitch, distance and collision disabled, and iteration counts set to 3 and below. There are maybe around 50 obi colliders in the scene. I also have a resolution of below 0.2 on all my ropes - in total, there are roughly 700 particles simulating. If i hang ropes on the wall (by attaching a fixed joint to one of the plug ends), obi will eventually even crash unity very suddenly and without warning. I have changed it so that the solvers run in LateUpdate, and reduced the advection radius to 0.05, but the performance is still utter crap. Am i doing something wrong, or does it simply not get better than this?

Hi,

Mi take on this would be that the bottleneck is either rope rendering, or collision detection. Keep in mind that MeshColliders are extremely performance heavy, and should only be used sparingly, just in case you're over-using them. I'd need to see a pic of the profiler in deep profiling mode to be able to tell, though. 700 particles is well below the maximum that you can simulate with Obi.

Btw, advection radius is only useful in conjunction with Obi Fluid. Advection is used to move particles along with the fluid flow, so it will not make any difference in your case. You should check your timestep though, 0.01-0.02 is the preferred range. You'll find it in Unity's "Time" settings.

cheers,
Reply
#3
(24-01-2018, 04:00 PM)khalvr Wrote: Since it was extremely unpractical and unstable to let Obi manage the rope length constraints, i decided to make all rigidbodies kinematicForParticles and use spring joints between the plugs (and dummy rigidbodies pinning the ropes together at all junctions) to keep them connected, just using ObiRope to simulate the aesthetics of the cords with pin constraints.

When you say that it is "unpractical and unstable" to manage rope length constraints, what are you exactly referring to? I'd like to think that it is much more stable and way simpler to use tether constraints than placing rigidbodies at regular intervals and joining them with spring constraints, which is what it seems you're doing. Maybe we can help you come up with a better set up.
Reply
#4
Thank you for your quick response!

There are various reasons as to why the obi tethers have proven to be unreliable, i will try to list a few:
  • Pin constraints are rarely properly resolved and almost always leaves a gap between the pinned body and the rope.
  • Distance constraints are not really properly enforced either unless you set the iteration count to something ridiculously high. I want the cord to behave less like a rubber band and more like a proper cord.
  • We are using NewtonVR to handle interactions, which works through applying physical forces to objects to keep them near the hand. To prevent ObiRope from pulling the plugs out of their position in your hand, we'd set the ObiRigidbody to kinematic whenever it was held, but this also creates issues since it's often unclear when an object should stop being kinematic - for instance, i noticed that objects behave much better when hung on the wall (with a fixed joint) if it is set to kinematicForParticles, because otherwise you'd get the gap between the cord an the object as a result of pin constraints not converging. Generally, everything just started acting much better when we just set all the ObiRigidbodies to kinematic.
  • The resolution of the rope actually affects how much it bends (ugh), and having too low resolution will result in the cords passing through tables and other flat surfaces. The poor convergence of the distance constraint also means that the distance between the particles easily grows when you are holding one end.
  • It is hard to handle junctions in cords nicely, even with stitchers. This is problematic for us since we have a cord with 19 ends(!).

Also, to clarify about the spring joint solution: we don't actually use a full chain of rigidbodies since PhysX can't really handle this stably. What i mean is that we have one spring joint for each plug and each junction in the cord, just to enforce the max distance between these parts. The result is of course that the cord can't properly hang off an edge, but at least it won't start snaking around or acting all rubber-bandy like it did before. There was also an unproportionally large force excerted by the cord to the plugs, though that would likely be related to the low mass of each plug (0.1kg, similar to a single obi particle) - i never messed around with that too much. It would be nice to be able to input the link mass in the rope editor, i didn't realize you could change this until after a week or so.

I don't use any mesh colliders with ObiColliders attached to them, only primitives. Right now my greatest issue is the crash i mentioned.

Also, i ran some deep profiling, and apparently the mesh updating stands for almost all of it, and takes 40-50 ms.

On a different note, is there a scripting API documentation for interacting with Obi particles somewhere?
Reply
#5
(24-01-2018, 06:21 PM)khalvr Wrote: [*]Pin constraints are rarely properly resolved and almost always leaves a gap between the pinned body and the rope.

Change constraint enforcement order, so that pin constraints are resolved last. See the last bit of:
http://obi.virtualmethodstudio.com/tutor...olver.html

(24-01-2018, 06:21 PM)khalvr Wrote: Distance constraints are not really properly enforced either unless you set the iteration count to something ridiculously high. I want the cord to behave less like a rubber band and more like a proper cord.

You can reduce the timestep in Unity's time settings. This will cause the simulation to take smaller temporal steps, and will be much more effective than increasing iteration count.

(24-01-2018, 06:21 PM)khalvr Wrote: We are using NewtonVR to handle interactions, which works through applying physical forces to objects to keep them near the hand. To prevent ObiRope from pulling the plugs out of their position in your hand, we'd set the ObiRigidbody to kinematic whenever it was held, but this also creates issues since it's often unclear when an object should stop being kinematic - for instance, i noticed that objects behave much better when hung on the wall (with a fixed joint) if it is set to kinematicForParticles, because otherwise you'd get the gap between the cord an the object as a result of pin constraints not converging. Generally, everything just started acting much better when we just set all the ObiRigidbodies to kinematic.

As pointed out the gap is not a result of convergence issues, but constraint application order. By default pin constraints are applied before distance constraints, which makes the latter prevalent in the final result. Reversing the order gives priority to pin constraints and closes the gap since pin constraints are applied last and their actions are not "undone" by distance constraints.

(24-01-2018, 06:21 PM)khalvr Wrote: The resolution of the rope actually affects how much it bends (ugh), and having too low resolution will result in the cords passing through tables and other flat surfaces. The poor convergence of the distance constraint also means that the distance between the particles easily grows when you are holding one end.

This cannot be worked around as it is a result of how iterative physics solvers work: more resolution->more constraints->slower convergence->less bending resistance. You can increase the amount of bending constraints to compensate the higher resolution, though.

Objects that are marked as kinematicForParticles will cause the rope to be unable to perform two-way interaction with them, effectively making ropes "passive", which is something I don't think you want.

I will take a deeper look at the crash, but a first quick look suggests a energy feedback loop somewhere. This would cause a rigidbody to store up energy and "launch" itself incredibly far and fast. This is typical of local-space simulations being performed on the local space of a rigidbody that is in turn affected by the simulation, as this causes the reference frame for the sim to change as a result of the simulation itself. Having a deeper understanding of your hanging wall rope setup would help a lot though, as this can be very hard to reproduce.

(24-01-2018, 06:21 PM)khalvr Wrote: Also, i ran some deep profiling, and apparently the mesh updating stands for almost all of it, and takes 40-50 ms.

Keep in mind that every vertex in every rope is being recalculated from scratch every frame, plus normals, tangents and uvs, after being smoothed out using bezier splines. Depending on your rope "smoothness" parameter this can be a lot of work. Try switching to line rendering mode and see if that helps, that will reduce the poly count a lot. You can still use normal maps to make a line-rendered rope look 3D.

Here's a manual page on particle scripting:
http://obi.virtualmethodstudio.com/tutor...icles.html

Another one on collision callbacks in case you need them:
http://obi.virtualmethodstudio.com/tutor...sions.html
Reply
#6
[quote pid='1010' dateline='1516871445']
josemendez Wrote:Change constraint enforcement order, so that pin constraints are resolved last. See the last bit of:
http://obi.virtualmethodstudio.com/tutor...olver.html


You can reduce the timestep in Unity's time settings. This will cause the simulation to take smaller temporal steps, and will be much more effective than increasing iteration count.


As pointed out the gap is not a result of convergence issues, but constraint application order. By default pin constraints are applied before distance constraints, which makes the latter prevalent in the final result. Reversing the order gives priority to pin constraints and closes the gap since pin constraints are applied last and their actions are not "undone" by distance constraints.


This cannot be worked around as it is a result of how iterative physics solvers work: more resolution->more constraints->slower convergence->less bending resistance. You can increase the amount of bending constraints to compensate the higher resolution, though.

Objects that are marked as kinematicForParticles will cause the rope to be unable to perform two-way interaction with them, effectively making ropes "passive", which is something I don't think you want.

I will take a deeper look at the crash, but a first quick look suggests a energy feedback loop somewhere. This would cause a rigidbody to store up energy and "launch" itself incredibly far and fast. This is typical of local-space simulations being performed on the local space of a rigidbody that is in turn affected by the simulation, as this causes the reference frame for the sim to change as a result of the simulation itself. Having a deeper understanding of your hanging wall rope setup would help a lot though, as this can be very hard to reproduce.


Keep in mind that every vertex in every rope is being recalculated from scratch every frame, plus normals, tangents and uvs, after being smoothed out using bezier splines. Depending on your rope "smoothness" parameter this can be a lot of work. Try switching to line rendering mode and see if that helps, that will reduce the poly count a lot. You can still use normal maps to make a line-rendered rope look 3D.

Here's a manual page on particle scripting:
http://obi.virtualmethodstudio.com/tutor...icles.html

Another one on collision callbacks in case you need them:
http://obi.virtualmethodstudio.com/tutor...sions.html

[/quote]
Unfortunately, the part about constraint enforcement order is simply not true, at least not from my testing. For instance, i have a case where i want a rope to stay tense when attached between a series of points, but despite having the distance constraint solver last, with 15 iterations, and having the slack/stretching scales set to extremes, i still can't get it to tensen. I f i set the SOR factor to 1.5, it gets closer, but the whole cord starts to twitch and spin. Here is a picture of what i mean:

[attachment=67]

Setting the pin constraint last seems to work for simple two-ended ropes, but if you make something more complex there are no guarantees, especially not when working with VR where very large forces may be applied in order to force the object into your hand.  

My wall setup looks like this:

[attachment=68]

Basically, it is a rigidbody for each plug, with kinematic ObiRigidbodies and configurable joints with distance limits to tie them together. The top plug is attached into the air with a fixed joint with no target. The wall has an ObiCollider. It starts off all and well, and usually has time to comes to rest, but sooner or later it will cause a crash - often when one of the plugs collide with the wall (for instance if you grab one and drop it like a pendulum). The cord otherwise works fine if you're just holding it in your hand. 

I tried implementing the same cord multiple times with Obi constraints, but it just becomes too springy and never comes fully to rest. There are other somewhat infuriating aspects of working with ObiRopes which makes me want to stick to regular joints, like the fact that ropes inside a prefab will revert all non-applied changes when you press play, and the fact that you have to re-initialize the rope, thus being forced to re-do all the pin constraints, whenever you want to adjust the curve... i've been trying to make this work since September last year and the moment i accepted the compromise of using configurable joints, everything started acting much more like i wanted. Sorry if i come across as rude, i really do think this is a good product (especially for the price), and i appreciate your support, so far i've tried three different physics engines and this is the one which produces the most stable results. Still, it responds very poorly to the way you configure it.
Reply
#7
(25-01-2018, 12:42 PM)khalvr Wrote: Unfortunately, the part about constraint enforcement order is simply not true, at least not from my testing. For instance, i have a case where i want a rope to stay tense when attached between a series of points, but despite having the distance constraint solver last, with 15 iterations, and having the slack/stretching scales set to extremes, i still can't get it to tensen. I f i set the SOR factor to 1.5, it gets closer, but the whole cord starts to twitch and spin. Here is a picture of what i mean:



Setting the pin constraint last seems to work for simple two-ended ropes, but if you make something more complex there are no guarantees, especially not when working with VR where very large forces may be applied in order to force the object into your hand.  

My wall setup looks like this:



Basically, it is a rigidbody for each plug, with kinematic ObiRigidbodies and configurable joints with distance limits to tie them together. The top plug is attached into the air with a fixed joint with no target. The wall has an ObiCollider. It starts off all and well, and usually has time to comes to rest, but sooner or later it will cause a crash - often when one of the plugs collide with the wall (for instance if you grab one and drop it like a pendulum). The cord otherwise works fine if you're just holding it in your hand. 

I tried implementing the same cord multiple times with Obi constraints, but it just becomes too springy and never comes fully to rest. There are other somewhat infuriating aspects of working with ObiRopes which makes me want to stick to regular joints, like the fact that ropes inside a prefab will revert all non-applied changes when you press play, and the fact that you have to re-initialize the rope, thus being forced to re-do all the pin constraints, whenever you want to adjust the curve... i've been trying to make this work since September last year and the moment i accepted the compromise of using configurable joints, everything started acting much more like i wanted. Sorry if i come across as rude, i really do think this is a good product (especially for the price), and i appreciate your support, so far i've tried three different physics engines and this is the one which produces the most stable results. Still, it responds very poorly to the way you configure it.

I see some fundamental conceptual voids here: you cannot get a 100% tense chain of constraints in Obi, or in any existing engine for that matter. This is due to the way game physics engines work: given a problem, they try to get closer to the solution with every iteration, but they will never actually converge to the 100% accurate solution. In case of ropes/chains/etc, that means they cannot be completely rigid under any circumstance. You'd have to switch over to a different kind of specialized solver (ABA, eulerian segments, lemke, etc), losing a lot of flexibility/generality and performance in the process.

Try setting Unity's timestep to 0.01 or lower. This will reduce the need for higher iteration counts and make your ropes tenser.

Setting high SOR values is expected to cause instabilities, as it is a non-physical trick to give an extra "oomph" to each iteration at the cost of stability (as stated in the manual).

Constraint enforcement order will not cause the rope to become tenser, or affect its behavior in any way: it will only make sure the constraint that is solved last remains solved at the end of the frame. E.g: if you have both collision and pin constraints active, and you pin a particle to be inside a collider, there's two possible outcomes:

- The collision constraint "wins", and the particle is rendered outside of the collider.  (pin constraints solved first)
- The pin constraint "wins", and the particle is rendered inside of the collider. (pin constraints solved last)

Setting pin constraints to be enforced last will make the pinned particles stay very close to their pin location instead of leaving a gap due to distance/collision constraints fighting them, but that's it. The rope will not become tenser as a result.

The biggest issue I see in your setup now that I understand it a bit better is that imho you're misusing pin constraints. Pin constraints are meant to enable two-way coupling between non-kinematic rigidbodies and rope particles. That is, they cause the rigidbodies to react to the rope and viceversa. If your rigidbodies are completely kinematic, you're wasting away performance and stability by using them since there's no coupling to be done. You will get much better results by simply placing handles along your rope and parent them directly to the rigidbodies. This way the rope will follow them perfectly, as no simulation at all is performed -or needed- to keep the ropes attached to kinematic rigidbodies. This is also more performant than using pin constraints. See:
http://obi.virtualmethodstudio.com/tutor...ments.html
Reply
#8
Regarding tense ropes etc: i disagree, you can achieve tense ropes using articulated physics. I can see how there would be issues in a particle simulated rope, but i thought you'd get better results than this. Even though it is physically impossible to make a rope 100% straight between points, you can still minimize the amount of sag. An alternative (and most likely better) solution for this in my case would be to script each particle to pull towards the spline with a certain weight (when a nearby plug is disconnected, the particles become released). So firstly, what is your formula for evaluating the position of each particle on the spline? Or would it be even better to just save an array with the particle positions at start and use that? 


Thank you very much for the tip with handles, this is what i was looking for. I will try it out and see how it works, hopefully the crashes won't persist.
Reply
#9
(25-01-2018, 02:16 PM)khalvr Wrote: Regarding tense ropes etc: i disagree, you can achieve tense ropes using articulated physics. I can see how there would be issues in a particle simulated rope, but i thought you'd get better results than this. Even though it is physically impossible to make a rope 100% straight between points, you can still minimize the amount of sag. An alternative (and most likely better) solution for this in my case would be to script each particle to pull towards the spline with a certain weight (when a nearby plug is disconnected, the particles become released). So firstly, what is your formula for evaluating the position of each particle on the spline? Or would it be even better to just save an array with the particle positions at start and use that? 


Thank you very much for the tip with handles, this is what i was looking for. I will try it out and see how it works, hopefully the crashes won't persist.

Hi there,

I mentioned that you should switch to a different kind of solver for completely tense ropes, one of them is ABA: Articulated Body Algorithm (Featherstone's). However it has several drawbacks that limit its use:

- Impulse application is O(n) in the amount of bodies in the multibody (instead of O(1)). This can quickly degrade performance in relatively simple cases, and reduce the amount of "links" useable. A 100-bodies long chain sitting on the floor would require ten thousand impulse evaluations per frame, which is highly unpractical.

- Does not support loops of any kind, only acyclic hierarchies are supported.

In your case, you should really use tether constraints (also known as LRAs or long-range attachments). They basically allow you to achieve zero stretch in ropes that have at least 1 particle fixed/handled. They work by directly connecting each free particle to the 4 closest fixed/handled particles. This will make sure that they do not get too far away from the plugs, thus preventing any stretch. Using them in conjunction with handles should allow you to achieve perfectly tense and stable ropes. See:

http://obi.virtualmethodstudio.com/tutor...aints.html
Reply
#10
Do tether constraints only work with fixed particles, or do they also work with pin constraints? The way i deal with anchor points right now is to pin a dummy rigidbody to a specific particle and freeze it using a fixed joint. This has some side effects but is easy to configure. Is there an easy way of un-fixing a particle through script? Will i have to iterate through all the particles in the solver and check their distance to the point?
Reply