Obi Official Forum

Full Version: Obiparticleattachment
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi there, I am trying to grab my obi cloth in VR using steamVR. I tried attaching the cloth to the hand after any contact between the hand and any particle of the cloth using contact event handler and obi particle attachment but there is a huge gap between the hand and the particles attached. They’re attached correctly movement wise but they are not overlapping which makes it look weird. 
Thank you
(02-06-2021, 07:26 PM)mayaeraky Wrote: [ -> ]Hi there, I am trying to grab my obi cloth in VR using steamVR. I tried attaching the cloth to the hand after any contact between the hand and any particle of the cloth using contact event handler and obi particle attachment but there is a huge gap between the hand and the particles attached. They’re attached correctly movement wise but they are not overlapping which makes it look weird. 
Thank you


Hi there,

Without any details and no code it's hard to tell what could be wrong. My guesses are either:
1.- There's a collider conflicting with the attachment, preventing the particle from moving to its attached position.
2.- The attachment offset is wrong (the position of the particle at the time of attaching doesn't match the intended attachment pos).

Also note that ObiContactGrabber does pretty much this: exposes a Grab() method that attaches particles to the collider in contact with them.
(03-06-2021, 09:13 AM)josemendez Wrote: [ -> ]Hi there,

Without any details and no code it's hard to tell what could be wrong. My guesses are either:
1.- There's a collider conflicting with the attachment, preventing the particle from moving to its attached position.
2.- The attachment offset is wrong (the position of the particle at the time of attaching doesn't match the intended attachment pos).

Also note that ObiContactGrabber does pretty much this: exposes a Grab() method that attaches particles to the collider in contact with them.
Hi again,
I checked for both options and I don't think it's either of them but anyways I'm going to attach the code for you to check it if possible. The following script is added to the Obisolver.
Code:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Obi;
[RequireComponent(typeof(ObiSolver))]
public class CollisionEventHandler : MonoBehaviour
{

    ObiSolver solver;
    public int contactCount;
    //public GameObject obj;

    


    Obi.ObiSolver.ObiCollisionEventArgs frame;

    void Awake()
    {
        solver = GetComponent<Obi.ObiSolver>();
        //GetComponentInChildren<ObiCloth>().blueprint.ClearParticleGroups();
      
    }

    void OnEnable()
    {
        solver.OnCollision += Solver_OnCollision;
    }

    void OnDisable()
    {
        solver.OnCollision -= Solver_OnCollision;
    }

    void Solver_OnCollision(object sender, Obi.ObiSolver.ObiCollisionEventArgs e)
    {
        
        var world = ObiColliderWorld.GetInstance();

        // just iterate over all contacts in the current frame:
        foreach (Oni.Contact contact in e.contacts)
        {
            // if this one is an actual collision:
            if (contact.distance < 0.01)
            {
                ObiColliderBase col = world.colliderHandles[contact.bodyB].owner;
                if (col != null && (col.gameObject.name == "LeftHand" || col.gameObject.name == "RightHand"))
                {
                    Debug.Log("heree");
                    // get particles involved
                    int simplexStart = solver.simplexCounts.GetSimplexStartAndSize(contact.bodyA, out int simplexSize);



                    ObiParticleAttachment attachment = GetComponentInChildren<ObiParticleAttachment>();


                    ObiParticleGroup temp = attachment.particleGroup;
                    //List<int> collisionIndices = new List<int>();

                    //Debug.Log("Particle Groups: " + GetComponentInChildren<ObiCloth>().blueprint.groups.Count);
                    for (int i = 0; i < simplexSize; ++i)
                    {
                        int particleIndex = solver.simplices[simplexStart + i];


                        if (temp.particleIndices.Count < 3)
                            temp.particleIndices.Add(particleIndex);
                    }
                        //Debug.Log("Temp Count: " + temp.Count);

                        attachment.particleGroup = temp;
                        attachment.enabled = true;
                    }

                }
            }


        
        frame = e;
    }

    void OnDrawGizmos()
    {
        if (solver == null || frame == null || frame.contacts == null) return;

        Gizmos.matrix = solver.transform.localToWorldMatrix;

        contactCount = frame.contacts.Count;

        for (int i = 0; i < frame.contacts.Count; ++i)
        {
            var contact = frame.contacts.Data[i];

            //if (contact.distance > 0.001f) continue;

            Gizmos.color = (contact.distance <= 0) ? Color.red : Color.green;

            //Gizmos.color = new Color(((i * 100) % 255) / 255.0f, ((i * 50) % 255) / 255.0f, ((i * 20) % 255) / 255.0f);

            Vector3 point = frame.contacts.Data[i].pointB;

            Gizmos.DrawSphere(point, 0.01f);

            Gizmos.DrawRay(point, contact.normal * contact.distance);

            Gizmos.color = Color.cyan;
            Gizmos.DrawRay(point, contact.tangent * contact.tangentImpulse + contact.bitangent * contact.bitangentImpulse);

        }

      
    }

}

Also, about ObiContactGrabber I tried using it but for some reason it wouldn't grab the cloth when the method grab is called. I will add the code of it too in case you can check it and tell me how to make it work. The script is added to the hand along with ObicontactGrabber component, Obi collider, and sphere collider.
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Obi;
using Valve.VR;

//[RequireComponent(typeof(ObiSolver))]
public class handgrabbing : MonoBehaviour
{
    public SteamVR_Input_Sources source = SteamVR_Input_Sources.LeftHand;
    bool handclosed;
    ObiSolver held;
    ObiContactGrabber contact;
    // Start is called before the first frame update
    void Start()
    {
  //      held = GetComponent<Obi.ObiSolver>();
        contact = GetComponent<ObiContactGrabber>();
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        var world = ObiColliderWorld.GetInstance();

        if (SteamVR_Actions.default_GrabPinch.GetState(source)) {
            handclosed = true;
            Debug.Log("handclosed");
        } else {
            handclosed = false;
            Debug.Log("NOT handclosed");
        }

        if (!handclosed) {
            contact.Release();
        } else {
            contact.Grab();
        }
    }
}




if you need to ask me about any details, do not hesitate. 
Thank you
If you know why it's not working please let me know ASAP as I'm on a deadline.
Thank you
A slight variation of your code works fine for me. I simply replaced the SteamVr stuff with Input.GetKey(). Just make sure the collider in the hand is in contact with a particle:

Code:
//[RequireComponent(typeof(ObiSolver))]
public class handgrabbing : MonoBehaviour
{
    public SteamVR_Input_Sources source = SteamVR_Input_Sources.LeftHand;
    bool handclosed;
    ObiSolver held;
    ObiContactGrabber contact;
    // Start is called before the first frame update
    void Start()
    {
  //      held = GetComponent<Obi.ObiSolver>();
        contact = GetComponent<ObiContactGrabber>();
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        var world = ObiColliderWorld.GetInstance();

        if (Input.GetKey(KeyCode.Space)) {
            handclosed = true;
            Debug.Log("handclosed");
        } else {
            handclosed = false;
            Debug.Log("NOT handclosed");
        }

        if (!handclosed) {
            contact.Release();
        } else {
            contact.Grab();
        }
    }
}
(07-06-2021, 10:45 AM)josemendez Wrote: [ -> ]A slight variation of your code works fine for me. I simply replaced the SteamVr stuff with Input.GetKey(). Just make sure the collider in the hand is in contact with a particle:

Code:
//[RequireComponent(typeof(ObiSolver))]
public class handgrabbing : MonoBehaviour
{
    public SteamVR_Input_Sources source = SteamVR_Input_Sources.LeftHand;
    bool handclosed;
    ObiSolver held;
    ObiContactGrabber contact;
    // Start is called before the first frame update
    void Start()
    {
  //      held = GetComponent<Obi.ObiSolver>();
        contact = GetComponent<ObiContactGrabber>();
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        var world = ObiColliderWorld.GetInstance();

        if (Input.GetKey(KeyCode.Space)) {
            handclosed = true;
            Debug.Log("handclosed");
        } else {
            handclosed = false;
            Debug.Log("NOT handclosed");
        }

        if (!handclosed) {
            contact.Release();
        } else {
            contact.Grab();
        }
    }
}
Thank you so much will try it today.