Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
ObiColliders and Procedural Load
#12
(04-02-2018, 03:38 AM)jonworks Wrote: Hello,

Thank you for the suggestion, changing the resolution does seem to help a lot although I'm concerned about the impact on collision detection which I haven't been able to test yet.

Changing the resolution also was not a perfect solution and it's still too elastic, so I was trying your suggestion of tethering everything to the fixed particle.

 for (int j = rope.UsedParticles-1; j >= 0; j--){ 
            float dist = rope.InterparticleDistance * j;
            tetherBatch.AddConstraint(j,0,dist,1,1);    
        }


I have no idea how I'm supposed to write this but my approach above does not work because when you extend the rope with cursor the indices do not stay in order (IE the particle with index 1 stops being the next particle after the fixed particle.) How am I supposed to do this?

Iterate over distance constraints, as they do keep a fixed order:

Code:
private void UpdateTethers()
    {
        rope.TetherConstraints.RemoveFromSolver(null);
        ObiTetherConstraintBatch batch = (ObiTetherConstraintBatch)rope.TetherConstraints.GetBatches()[0];
        batch.Clear();

        ObiDistanceConstraintBatch dbatch = rope.DistanceConstraints.GetBatches()[0] as ObiDistanceConstraintBatch;
        for (int i = 0; i < dbatch.ConstraintCount; ++i)
            batch.AddConstraint(0,dbatch.springIndices[i*2+1], rope.InterparticleDistance*i, 1, 1);

        batch.Cook();
        rope.TetherConstraints.AddToSolver(null);
    }

Hint: you can get Unity to draw the constraints in the scene view by enabling the "visualize" checkbox for each constraint component in the inspector. This makes it easy to debug them.

Quote:Additionally although I haven't been able to test either yet - why do you recommend tethering each particle to the fixed particle instead of tethering each particle to the preceding particle?

Because then you'd have a chain of constraints and be back to square one. As I mentioned earlier, long chains = many iterations. This is a fundamental concept when dealing with all physics engines. If you've ever tried to create a really tall stack of boxes in any engine (and failed, as it is not trivial), the underlying problem is the same: each box is constrained to the one immediately under it, and that causes a long dependency chain that needs many iterations to be solved accurately. Few iterations will cause the boxes at the bottom to sink under the weight of the ones on top of them, and the entire tower will collapse.

The whole point of tethers is that they allow you to avoid chaining them (unlike distance constraints), giving each particle in the rope their own reference point and a condition that can be met in just 1 iteration. In the box tower analogy it would be equivalent to giving each box its own "floor" to directly sit on, at the appropriate height.

I think you'd find this blog post interesting.


Quote:Side note for anyone reading this: advancing the coroutine that creates the rope manually with movenext was suggested in case it was mandatory to perform certain rope functions on the same frame the rope is created. Doing this is not hard but I'm hoping that by posting the code I can save someone the few hours of research and guessing it took.

IEnumerator ienumerator = rope.GeneratePhysicRepresentationForMesh();
        while(!rope.Initialized) {
            ienumerator.MoveNext();
        }


I have not been able to observe any performance consequence / frame drop from doing this. The alternative is to, in every one of your functions that does anything with the rope, either check if rope is initialized and return if not, or set every one of them up as their own coroutine that waits for the rope to be initialized - either one of which creates huge bug potential.

If you read MoveNext's documentation (that I linked to), you've seen it returns a boolean value indicating whether there's more work to do. So it is usually used like this:
Code:
while (enumerator.MoveNext());
No need to check if the rope is Initialized or not.

Keep in mind that for short ropes -that take very little time to initialize- the drop is not noticeable. Longer ropes however do create a bit of a hiccup. I recommend using coroutines the way they are supposed to (yield).
Reply


Messages In This Thread
ObiColliders and Procedural Load - by jonworks - 18-01-2018, 07:03 AM
RE: ObiColliders and Procedural Load - by josemendez - 04-02-2018, 08:41 AM