Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  How to attach a GameObject to a rope from script?
#1
Hi,

There is a rope and some objects in a table. I drag the rope and move, when the rope collide with an object, the object should be attached to the rope.
How should I implement this?

My idea is in the collision event of the rope and objects, I create a ControlPoint in the path of the rope, and a ObiParticleAttachment, and set the control point to the ObiParticleAttachment.

Code:
particlePos = solver.particleToActor[contact.bodyA].actor.transform.position;

int particleIndex = blueprint.path.ControlPointCount;
Vector3 localHit = rope.transform.InverseTransformPoint(particlePos);
blueprint.path.AddControlPoint(localHit, -localHit.normalized, localHit.normalized, Vector3.up, 0.1f, 0.1f, 1, 1, Color.white, "Control point");
blueprint.path.FlushEvents();
yield return blueprint.Generate();
Code:
ObiParticleAttachment attachment = rope.gameObject.AddComponent<ObiParticleAttachment>();
attachment.target = targetGrain;
attachment.particleGroup = blueprint.groups[particleIndex];
attachment.attachmentType = ObiParticleAttachment.AttachmentType.Dynamic;
attachment.compliance = 0;


But there are something wrong:
1. particlePos is the position of the rope not the collided point.
2. Got error "The particle group 'Control point' references a particle that does not exist in the actor 'Obi Rope'."

How do I implement this functionality?
Thanks in advance.
Reply
#2
Quote:My idea is in the collision event of the rope and objects, I create a ControlPoint in the path of the rope,

You can't create a control point at runtime. Or rather, it won't have any effect. Blueprints behave just like prefabs: once you instantiate a prefab, the instance will no longer be affected by changes made to the prefab. It's a "snapshot" of the prefab at the moment of instantiating it. Similarly, once you create an actor out of a blueprint, modifying the blueprint has no effect on the actor/actors instantiated from it.

Control points only exist in blueprints, to aid you in setting the initial shape and properties of the rope. At runtime, actors only contain particles and constraints.

Quote:1. particlePos is the position of the rope, not the collided point

You're retrieving the position of the rope actor:

Code:
solver.particleToActor[contact.bodyA].actor.transform.position;

You want the position of the particle that has collided, so use this instead:

Code:
solver.positions[solver.simplices[contact.bodyA]];

See:
http://obi.virtualmethodstudio.com/tutor...sions.html


Quote:2. Got error "The particle group 'Control point' references a particle that does not exist in the actor 'Obi Rope'."

Because that particle does not exist. You've regenerated the blueprint, but as I explained that does not change any existing ropes in the scene. In addition to this  you're accessing the groups array using a particle index, which does not make any sense (can result in out of bounds access exceptions):

Code:
attachment.particleGroup = blueprint.groups[particleIndex];

Should be:

Code:
attachment.particleGroup = blueprint.groups[groupIndex];

If your blueprint has 3 control points, "groupIndex" can only be 0, 1, or 2.


Quote:There is a rope and some objects in a table. I drag the rope and move, when the rope collide with an object, the object should be attached to the rope.
How should I implement this?

If you want two-way coupling between the rope and the object, you can create a new pin constraint at runtime. That's the simplest way. See adding/removing constraints in the "scripting constraints" section of the manual:

http://obi.virtualmethodstudio.com/tutor...aints.html

Internally, this is what a dynamic attachment does: it creates a pin constraint between the particle index corresponding to a control point, and a target object.
Reply
#3
(09-06-2021, 08:24 AM)josemendez Wrote: You can't create a control point at runtime. Or rather, it won't have any effect. Blueprints behave just like prefabs: once you instantiate a prefab, the instance will no longer be affected by changes made to the prefab. It's a "snapshot" of the prefab at the moment of instantiating it. Similarly, once you create an actor out of a blueprint, modifying the blueprint has no effect on the actor/actors instantiated from it.

Control points only exist in blueprints, to aid you in setting the initial shape and properties of the rope. At runtime, actors only contain particles and constraints.


You're retrieving the position of the rope actor:

Code:
solver.particleToActor[contact.bodyA].actor.transform.position;

You want the position of the particle that has collided, so use this instead:

Code:
solver.positions[solver.simplices[contact.bodyA]];

See:
http://obi.virtualmethodstudio.com/tutor...sions.html



Because that particle does not exist. You've regenerated the blueprint, but as I explained that does not change any existing ropes in the scene. In addition to this  you're accessing the groups array using a particle index, which does not make any sense (can result in out of bounds access exceptions):

Code:
attachment.particleGroup = blueprint.groups[particleIndex];

Should be:

Code:
attachment.particleGroup = blueprint.groups[groupIndex];

If your blueprint has 3 control points, "groupIndex" can only be 0, 1, or 2.



If you want two-way coupling between the rope and the object, you can create a new pin constraint at runtime. That's the simplest way. See adding/removing constraints in the "scripting constraints" section of the manual:

http://obi.virtualmethodstudio.com/tutor...aints.html

Internally, this is what a dynamic attachment does: it creates a pin constraint between the particle index corresponding to a control point, and a target object.
Thanks for your reply.
pin constraint works exactly as what I need.

But, after the gameobjet is attached to the rope, the rope is moving slightly.
The attached gameobject is rigidbody.
Before attaching, the rope is static perfectly.
How do I make the rope be in static after attaching rigidbody objects?
Reply
#4
(12-06-2021, 03:05 PM)wakin001 Wrote: Thanks for your reply.
pin constraint works exactly as what I need.

But, after the gameobjet is attached to the rope, the rope is moving slightly.
The attached gameobject is rigidbody.
Before attaching, the rope is static perfectly.
How do I make the rope be in static after attaching rigidbody objects?

As long as you've passed the correct offset to the pin constraint, the rope should not move at all.

You should use the current particle position expressed in the rigidbody's local space.

Can you share the code you used?
Reply
#5
(14-06-2021, 07:34 AM)josemendez Wrote: As long as you've passed the correct offset to the pin constraint, the rope should not move at all.

You should use the current particle position expressed in the rigidbody's local space.

Can you share the code you used?

 
Code:
private void AttachGrainToRope(int index, ObiColliderBase body)
{
    // create a new pin constraints batch
    ObiPinConstraintsBatch batch = new ObiPinConstraintsBatch();
    batches[index] = batch;
    
    // get a hold of the constraint type we want, in this case, pin constraints:
    var pinConstraints = rope.GetConstraintsByType(Oni.ConstraintType.Pin) as ObiConstraints<ObiPinConstraintsBatch>;

    batch.AddConstraint(index, body, Vector3.zero, Quaternion.identity, 0, 0, float.PositiveInfinity);

    // set the amount of active constraints in the batch to 2 (the ones we just added).
    batch.activeConstraintCount = 1;

    // append the batch to the pin constraints:
    pinConstraints.AddBatch(batch);

    // this will cause the solver to rebuild pin constraints at the beginning of the next frame:
    rope.SetConstraintsDirty(Oni.ConstraintType.Pin);    
}
 

   

I use this code to attach a grain object to a rope.
Reply
#6
You're passing Vector3.zero as the pin offset. This means the pinned particle will shift to the exact center of the rigidbody as soon as you activate the constraint.

Pass the current particle's position in local space instead, so that it doesn't move. Something like this:
Code:
var localPos = body.transform.InverseTransformPoint(solver.transform.TransformPoint(solver.positions[index]));

Remember that Unity's TransformPoint/Vector/Direction and InverseTransformPoint/Vector/Direction let you convert data from local to world space and vice-versa. You should get very comfortable with these:
https://docs.unity3d.com/ScriptReference...Point.html
https://docs.unity3d.com/ScriptReference...Point.html
Reply
#7
(14-06-2021, 08:11 AM)josemendez Wrote: You're passing Vector3.zero as the pin offset. This means the pinned particle will shift to the exact center of the rigidbody as soon as you activate the constraint.

Pass the current particle's position in local space instead, so that it doesn't move. Something like this:
Code:
var localPos = body.transform.InverseTransformPoint(solver.transform.TransformPoint(solver.positions[index]));

Remember that Unity's TransformPoint/Vector/Direction and InverseTransformPoint/Vector/Direction let you convert data from local to world space and vice-versa. You should get very comfortable with these:
https://docs.unity3d.com/ScriptReference...Point.html
https://docs.unity3d.com/ScriptReference...Point.html
Thank you. It works for me.

Now I attached some cubes onto the rope. And when I move the rope, sometimes some attached cubes will change its relative position to the rope.

For example, a cube is attached onto the left side of a rope. If I change the position of the rope, sometimes the position of the cube is changed to the right side of the rope. And seems the position of the cube is changed not the same frame of the rope, more like following. Because I can see the following animation.

Is it possible to make the relative position of the cube and the rope be static?
And update the position of the rope and cube at the same frame?
Reply
#8
I don't really understand what you mean... if the cube attached to the rope is not a rigidbody, there's literally no way its position can be affected/changed by the rope being simulated. In case they are, the only possible way for them to change their position is by rotating around the rope's medial axis (since ropes do not model torsion).

Could you share a video of this issue?
Reply
#9


The cube is a rigidbody:
   
Reply
#10
(16-06-2021, 04:48 PM)josemendez Wrote: In case they are (rigidbodies), the only possible way for them to change their position is by rotating around the rope's medial axis (since ropes do not model torsion).

This is completely normal, and documented in the manual:
http://obi.virtualmethodstudio.com/manua...setup.html

Quote:Ropes: Since regular particles have no orientation (only a position), torsion effects cannot be simulated.
Rods: Rods are built by chaining oriented particles using stretch/shear and bend/twist constraints. They are much more sophisticated than ropes, can simulate torsion effects and retain their rest shape.

See: https://en.wikipedia.org/wiki/Torsion_(mechanics)

One of the main differences between ropes and rods is that ropes do not simulate torsion, rods do. Ropes are free to rotate around their medial axis (along their "length"), so are any objects attached to it. The cubes attached to your snake will rotate to either side of it as it rolls around the table. If you want to simulate torsion, use rods.
Reply