Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
"Stick" rigidbodies to softbody
#11
Hi,

Here's a sample script (written for latest Obi version):

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

[RequireComponent(typeof(ObiSoftbody))]
public class GlitterManager : MonoBehaviour
{

    private List<Glitter> glitters = new List<Glitter>();
    private ObiSoftbody softbody;

    void Start()
    {
        softbody = GetComponent<ObiSoftbody>();
        softbody.solver.OnCollision += Solver_OnCollision;
    }
    private void OnDestroy()
    {
        softbody.solver.OnCollision -= Solver_OnCollision;
    }

    private void Solver_OnCollision(ObiSolver solver, ObiSolver.ObiCollisionEventArgs e)
    {

        var world = ObiColliderWorld.GetInstance();

        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.TryGetComponent<Glitter>(out Glitter glitter))
                {
                    AttachGlitter(glitter, solver.simplices[contact.bodyA]);
                }
            }
        }
    }

    void AttachGlitter(Glitter glitter, int particleIndex)
    {
        if (!glitter.isAttached)
        {
            glitter.isAttached = true;
            glitter.unityRigidbody.isKinematic = true;
            glitter.obiCollider.Phase = 1;
            glitter.particleIndex = particleIndex;

            // build particle matrix:
            Matrix4x4 particleMatrix = Matrix4x4.TRS(softbody.GetParticlePosition(particleIndex),
                                                     softbody.GetParticleOrientation(particleIndex),
                                                     Vector3.one);

            // convert glitter position to particle's local space, and store it:
            glitter.offset = particleMatrix.inverse.MultiplyPoint3x4(glitter.transform.position);

            glitters.Add(glitter);
        }
    }

    private void UpdateGlitters()
    {
        foreach (var glitter in glitters)
        {
            // build particle matrix:
            Matrix4x4 particleMatrix = Matrix4x4.TRS(softbody.GetParticlePosition(glitter.particleIndex),
                                                     softbody.GetParticleOrientation(glitter.particleIndex),
                                                     Vector3.one);

            // convert glitter position to world space:
            glitter.transform.position = particleMatrix.MultiplyPoint3x4(glitter.offset);
        }
    }

    private void Update()
    {
        UpdateGlitters();
    }


}

The important parts are:

When attaching a glitter:
Code:
// build particle matrix:
Matrix4x4 particleMatrix = Matrix4x4.TRS(softbody.GetParticlePosition(particleIndex),
                                       softbody.GetParticleOrientation(particleIndex),
                                                     Vector3.one);

// convert glitter position to particle's local space, and store it:
glitter.offset = particleMatrix.inverse.MultiplyPoint3x4(glitter.transform.position);

When updating glitter position:
Code:
// build particle matrix:
Matrix4x4 particleMatrix = Matrix4x4.TRS(softbody.GetParticlePosition(particleIndex),
                                       softbody.GetParticleOrientation(particleIndex),
                                                     Vector3.one);

// convert glitter position to world space:
glitter.transform.position = particleMatrix.MultiplyPoint3x4(glitter.offset);

As you can see both are pretty much identical. You build a matrix using the particle's position and orientation both times. When attaching the glitter, you use the matrix to convert the glitter position to the particle's local space. When updating glitter, you use the matrix to convert the glitter offset (position in particle's local space) to world space.

So all I'm doing is converting a position from world to local space and storing it, then converting from local space to world space and applying it.

Here's the result:
Reply
#12
(10-05-2021, 09:51 AM)josemendez Wrote: Hi,

Here's a sample script (written for latest Obi version):

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

[RequireComponent(typeof(ObiSoftbody))]
public class GlitterManager : MonoBehaviour
{

    private List<Glitter> glitters = new List<Glitter>();
    private ObiSoftbody softbody;

    void Start()
    {
        softbody = GetComponent<ObiSoftbody>();
        softbody.solver.OnCollision += Solver_OnCollision;
    }
    private void OnDestroy()
    {
        softbody.solver.OnCollision -= Solver_OnCollision;
    }

    private void Solver_OnCollision(ObiSolver solver, ObiSolver.ObiCollisionEventArgs e)
    {

        var world = ObiColliderWorld.GetInstance();

        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.TryGetComponent<Glitter>(out Glitter glitter))
                {
                    AttachGlitter(glitter, solver.simplices[contact.bodyA]);
                }
            }
        }
    }

    void AttachGlitter(Glitter glitter, int particleIndex)
    {
        if (!glitter.isAttached)
        {
            glitter.isAttached = true;
            glitter.unityRigidbody.isKinematic = true;
            glitter.obiCollider.Phase = 1;
            glitter.particleIndex = particleIndex;

            // build particle matrix:
            Matrix4x4 particleMatrix = Matrix4x4.TRS(softbody.GetParticlePosition(particleIndex),
                                                     softbody.GetParticleOrientation(particleIndex),
                                                     Vector3.one);

            // convert glitter position to particle's local space, and store it:
            glitter.offset = particleMatrix.inverse.MultiplyPoint3x4(glitter.transform.position);

            glitters.Add(glitter);
        }
    }

    private void UpdateGlitters()
    {
        foreach (var glitter in glitters)
        {
            // build particle matrix:
            Matrix4x4 particleMatrix = Matrix4x4.TRS(softbody.GetParticlePosition(glitter.particleIndex),
                                                     softbody.GetParticleOrientation(glitter.particleIndex),
                                                     Vector3.one);

            // convert glitter position to world space:
            glitter.transform.position = particleMatrix.MultiplyPoint3x4(glitter.offset);
        }
    }

    private void Update()
    {
        UpdateGlitters();
    }


}

The important parts are:

When attaching a glitter:
Code:
// build particle matrix:
Matrix4x4 particleMatrix = Matrix4x4.TRS(softbody.GetParticlePosition(particleIndex),
                                       softbody.GetParticleOrientation(particleIndex),
                                                     Vector3.one);

// convert glitter position to particle's local space, and store it:
glitter.offset = particleMatrix.inverse.MultiplyPoint3x4(glitter.transform.position);

When updating glitter position:
Code:
// build particle matrix:
Matrix4x4 particleMatrix = Matrix4x4.TRS(softbody.GetParticlePosition(particleIndex),
                                       softbody.GetParticleOrientation(particleIndex),
                                                     Vector3.one);

// convert glitter position to world space:
glitter.transform.position = particleMatrix.MultiplyPoint3x4(glitter.offset);

As you can see both are pretty much identical. You build a matrix using the particle's position and orientation both times. When attaching the glitter, you use the matrix to convert the glitter position to the particle's local space. When updating glitter, you use the matrix to convert the glitter offset (position in particle's local space) to world space.

So all I'm doing is converting a position from world to local space and storing it, then converting from local space to world space and applying it.

Here's the result:

Thank you so much for the help. And also my apologies for making you write the code for me.
Reply