Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  Dynamic partial rope simulation?
#1
Hi!

I am creating a simulation where a cable is fed onto a spool, and for performance reasons i cant simulate the entire rope after more than a few turns of the spool.
I need to be able to stop the physics simulation for the particles that have reached about 1-2 turns on the spool, and after that they should be parented to the spool and only used for collision. The plan is to feed quite alot of rope with accurate collision. The user will be in charge of the speed on both rope feeding speed and spool speed, resulting in a failure if the tension gets too high.

Setup:
  • Rotating spool
  • Rope between a start position and the spool
  • Cursor at the start of the rope, calling ChangeLength on update
  • Spline point (particle group?) at the end of the rope, using attachment to connect it to the spool
  • Continously compare the pool of particles to the attached particle group, making sure all but the 100 particles closest to start are in the group
    (Essentially this means that each time one particle is added, another is added to the attachment group)


I have no idea if this is even remotely close to performant or even possible, but i know that the alternative of simulating the entire rope is not.
Especially as i am trying to use it as a cable with high stiffness (many Bending-constraint iterations).

Result:
Every other run the original attachment works.
Every other run half the rope is attached way off and incorrectly.
Seems almost as if the particle group is saved from the previous run.

I tried clearing the particle group in the Start-event, no difference.

If i create a new particle group on start and modify it time a new particle is added, then set that group as the attachment's particle group , the particles get attached but not to the correct transform. They just float in place as if attached to scene root.

Any tips on how to achieve the result im after?
Also, any tips on getting the feeling of a cable rather than a rope, without going overboard with iterations? Cant use ObiCable as i cant change the length of it in runtime :/

Edit:
Adding some code which is added to the ObiRope-object:

Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Obi;

public class SC_CableLengthController : MonoBehaviour
{
    public Transform attachmentTarget;
    public float speed = 0.5f;

    private ObiRopeCursor cursor;
    private ObiRope rope;
    private ObiParticleAttachment attachment;
    private ObiParticleGroup group;

    void Start()
    {
        cursor = GetComponentInChildren<ObiRopeCursor>();
        rope = GetComponent<ObiRope>();

        group = rope.blueprint.AppendNewParticleGroup("Frozen");

        attachment = gameObject.AddComponent<ObiParticleAttachment>();
        attachment.attachmentType = ObiParticleAttachment.AttachmentType.Static;
        attachment.target = attachmentTarget;
        attachment.particleGroup = group;
    }

    void FixedUpdate()
    {
        // Length
        cursor.ChangeLength(rope.restLength + (Time.fixedDeltaTime * speed));

        // Attachment
        Debug.Log((attachment.particleGroup.particleIndices.Count, rope.blueprint.groups[rope.blueprint.groups.Count - 1].particleIndices.Count));
        Debug.DrawLine(rope.GetParticlePosition(rope.elements[0].particle1), rope.GetParticlePosition(rope.elements[0].particle1) + (Vector3.up), Color.red, 1);

        for (int i = rope.elements.Count - 10; i > 60; i--) // Number of particles will be swapped for a more sophisticated distance based solution once i get the dynamic attachment/"freezing" to work as i intended.
        {
            Debug.DrawLine(rope.GetParticlePosition(rope.elements[i].particle1), rope.GetParticlePosition(rope.elements[i].particle1) + (Vector3.up), Color.red);

            if (!group.ContainsParticle(rope.elements[i].particle1))
            {
                attachment.particleGroup.particleIndices.Add(rope.elements[i].particle1);
            }
        }
    }
}



Thanks in advance, Christoffer
Reply
#2
(08-12-2023, 11:57 AM)Christoffer Wrote: I have no idea if this is even remotely close to performant or even possible, but i know that the alternative of simulating the entire rope is not.
Especially as i am trying to use it as a cable with high stiffness (many Bending-constraint iterations).

Hi!

You should not be using iterations to impart high stiffness on the cable, using substeps is a lot more efficient. You'll get stiffer cable with far less substeps than you would using iterations. See:
http://obi.virtualmethodstudio.com/manua...gence.html

(08-12-2023, 11:57 AM)Christoffer Wrote: Result:
Every other run the original attachment works.
Every other run half the rope is attached way off and incorrectly.

You're creating and serializing a new particle group every time the game starts, then copying its particle indices to the attachment's current particle group at runtime. This is not only conceptually wrong (what's the point of using groups if you're copying particle indices individually?) but quite inefficient, a better approach in your case would be to just deal with individual particles manually (see below).


(08-12-2023, 11:57 AM)Christoffer Wrote: Seems almost as if the particle group is saved from the previous run.

It is, you're appending a new particle group to the blueprint every time the game starts and blueprints are saved to disk (since they're assets). You might want to create a temporary particle group yourself using CreateInstance. See: http://obi.virtualmethodstudio.com/manua...ments.html

Quote:If i create a new particle group on start and modify it time a new particle is added, then set that group as the attachment's particle group , the particles get attached but not to the correct transform. They just float in place as if attached to scene root.

Adding particles to an already attached group will just freeze them in place -since they stop getting their dynamic simulation updated- it will not calculate bind transforms for the new particles in the group. Groups are attached/detached as a single entity: attaching / detaching a group takes place when setting the ObiParticleAttachment's group or target, but not when adding / removing individual particles from the group. Typically you'd:

  1. Detach the group (set the attachment's particleGroup to null)
  2. Add particles to the group
  3. Reattach the group (set the attachment's particleGroup back)

This can quickly get expensive if you're constantly adding/removing particles from a group one by one. If your intent is to deal with individual particles and attach/detach them individually, using groups will only complicate matters. A much simpler approach is to use the particles API to deactivate dynamics simulation on specific particles (by setting their inverse mass to zero), and just override their position. This is what attachments do internally, they just abstract individual particles into "groups" to make it easier to work with and reason about multiple particles.

(08-12-2023, 11:57 AM)Christoffer Wrote: Also, any tips on getting the feeling of a cable rather than a rope, without going overboard with iterations? Cant use ObiCable as i cant change the length of it in runtime :/

Reduce your blueprint's resolution and use surface collisions to compensate for the fewer particles. This will reduce overall cost of running the simulation, allowing you to spend more substeps on it, which in turns allows the simulation to reach much higher effective stiffness.

kind regards,
Reply
#3
Thank you for the insanely detailed answer, really helped and changed my understanding of the plugin!
Im have not yet reached a point where i can fully assess the performance, but it is looking really promising Sonrisa

Awesome support!

Edit:
Actually, one question that i cant find on the forums. Is it possible to re-activate a particle which invMass has been set to 0? Changing the mass to anything else after it has been set to 0 makes the particle go haywire, and if i switch back to 0 it jumps back to its previous location. Im assuming changing the invMass to something other than 0 isnt enough?

Edit2:
Solved, i continued to set position after restoring mass, my bad :<

Best regards, Christoffer
Reply