Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Any tutorial for stitcher?
#1
Hi.
I have been struggling to figure out how to use stitch constraints properly to connect multiple softbodies.
Is there any video or tutorial of stitch constraints?

[EDIT]
Here are some more info regarding the problem I am struggling with.
The obi stitcher has been set as you see in the image below. Each stitch has been set by AutoStitcher.cs which helps me to find indices of particle pairs and set all stitches in the Editor. (For better visualization of each stitch, I set each cube apart along X axis but they were located right next to each other when I set their stitches and hit play.)
[Image: gs9zU7V.png]
They looks ok to me but when I hit play, I get the result like the image below (Shown in wireframe mode). As you can see, the stitched particles are not lined up smoothly and they seem they are fighting (colliding) each other.

[Image: 1wETs54.png]Their softbody surface blueprint's Shape Smoothing and Anisotropy Neighborhood have been set to 0 so that I get all particles right on the mesh vertices.
[Image: USV1hlX.png]What else I should look into to make connect them seamlessly?

By the way, this is the code I use to set stitches. It figure out all pairs and export them to a xml file in the play mode, then use the xml file to set stitches in the Editor. I know the workflow is a bit too cumbersome but I could not figure out how to get particle positions without running it. Is there any better way?
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Obi;
using UnityEditor;

public class AutoStitcher : MonoBehaviour
{
    [System.Serializable]
    public struct STITCH_PAIR
    {
        public int index1;
        public int index2;
    }

    public List<STITCH_PAIR> stitchPairList = new List<STITCH_PAIR>();

    [SerializeField]
    ObiActor actor1;
    [SerializeField]
    ObiActor actor2;

    [SerializeField]
    float stitchMergin = 0.001f;

    private Mesh mesh1;
    private Mesh mesh2;

    // Start is called before the first frame update
    void Start()
    {
        FindPairs();
    }

    public void FindPairs()
    {
        stitchPairList.Clear();

        for (int i = 0; i < actor1.particleCount; i++)
        {
         
            int index1 = actor1.GetParticleRuntimeIndex(i);
            Vector3 pos1 = actor1.GetParticlePosition(index1);

            for ( int l = 0; l < actor2.particleCount; l++)
            {
                int index2 = actor2.GetParticleRuntimeIndex(l);
                Vector3 pos2 = actor2.GetParticlePosition(index2);
                float distance = Vector3.Distance(pos1, pos2);
                if (distance < stitchMergin)
                {
                    //obiStitcher.AddStitch(i, l);

                    STITCH_PAIR newPair;
                    newPair.index1 = i;
                    newPair.index2 = l;
                    stitchPairList.Add(newPair);

                    Debug.Log($"Index1: {i}, Index2: {l} Distance: {distance}");
                }
            }
        }
    }

    public void SaveStitchData()
    {
        string name = actor1.name + "_" + actor2.name;
        XmlUtil.Seialize<List<AutoStitcher.STITCH_PAIR>>("./Assets/" + name + ".xml", stitchPairList);
    }

    public void StitchActors()
    {
        string name = actor1.name + "_" + actor2.name;
        stitchPairList.Clear();
        stitchPairList = XmlUtil.Deserialize<List<AutoStitcher.STITCH_PAIR>>("./Assets/" + name + ".xml");
        ObiStitcher obiStitcher = gameObject.AddComponent<ObiStitcher>();
        obiStitcher.Actor1 = actor1;
        obiStitcher.Actor2 = actor2;

        foreach(STITCH_PAIR pair in stitchPairList)
        {
            obiStitcher.AddStitch(pair.index1, pair.index2);
        }
    }
}

[CustomEditor(typeof(AutoStitcher))]
public class AutoStitcherEditor : Editor
{
    AutoStitcher obj;

    public void OnEnable()
    {
        obj = (AutoStitcher)target;
    }
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        if (GUILayout.Button("Save Stitches(Only in Play Mode"))
        {
            if (!Application.isPlaying)
            {
                Debug.LogError("Only works when editor is playing.");
                return;
            }

            bool go = EditorUtility.DisplayDialog(
                "Save Stitches to xml file.",
                    "This will save particle pairs data to .xml file. " +
                    "Do you wish to continue?",
                    "Go Ahead",
                    "Cancel"
                );

            if (!go)
            {
                return;
            }

            obj.SaveStitchData();
        }

        if (GUILayout.Button("Bake Stitches(Only in Editor Mode"))
        {
            if (Application.isPlaying)
            {
                Debug.LogError("Only works when editor is not playing.");
                return;
            }

            bool go = EditorUtility.DisplayDialog(
                "Bake Stitches from xml file.",
                    "This will add obiStitch constraints to obi actors. " +
                    "Do you wish to continue?",
                    "Go Ahead",
                    "Cancel"
                );

            if (!go)
            {
                return;
            }

            obj.StitchActors();
        }
    }
}
Reply
#2
(16-10-2021, 11:23 AM)Snail921 Wrote: the stitched particles are not lined up smoothly and they seem they are fighting (colliding) each other.

That's because they probably are! Sonrisa

Unless you explicitly disable collisions between these particles, they will collide with each other. Coupled with the stitch constraints, this will lead to constraint fighting: particles are simultaneously trying to be exactly on top of each other (stitch), and away from each other (collision).

This is the same issue described in the manual that happens between colliders and particles when using dynamic attachments (pin constraints):
http://obi.virtualmethodstudio.com/manua...aints.html

Just set the collision filters so that these particles in particular don't collide with each other. For info on collision filtering, see "collision filtering" in the collisions page:
http://obi.virtualmethodstudio.com/manua...sions.html

At runtime, filters are just another per-particle property (like positions, velocities, etc), you can set them the usual way:
http://obi.virtualmethodstudio.com/manua...icles.html

Obi contains a helper function (ObiUtils.MakeFilter) to build filters for you, so that you don't have to deal with bitwise operations too much. Filters are made of a mask and a category. The mask is the first parameter of the function. Just keep in mind the mask is a bit mask (just like Unity's layer masks), so you build it by simply or'ing together bits. For instance, to build a filter set in category 0, that only collides with categories 1, 3, and 6:


Code:
int mask = (1 << 1) | (1 << 3) | (1 << 6);
int category = 0;
int filter = ObiUtils.MakeFilter(mask, category);
Reply
#3
Thank you for your help.
I finally make it work perfectly all in runtime without exporting/importing xml files or manual property painting.

My concern, at this moment, is that I may have problem when obi simulation keeps going and moves particles away while the AutoStitcher.cs is trying to find out particle pairs within the range of designated distance. 
Let me know your thought. Should I set stitches before starting (building) a game?
Code:
    public void StitchActorsRuntime()
    {
        ObiStitcher obiStitcher = gameObject.AddComponent<ObiStitcher>();
        obiStitcher.Actor1 = actor1;
        obiStitcher.Actor2 = actor2;

        int mask = 0;
        int category = 0;
        int filter = ObiUtils.MakeFilter(mask, category);

        for (int i = 0; i < actor1.particleCount; i++)
        {

            int index1 = actor1.GetParticleRuntimeIndex(i);
            Vector3 pos1 = actor1.GetParticlePosition(index1);

            for (int l = 0; l < actor2.particleCount; l++)
            {
                int index2 = actor2.GetParticleRuntimeIndex(l);
                Vector3 pos2 = actor2.GetParticlePosition(index2);
                float distance = Vector3.Distance(pos1, pos2);
                if (distance < stitchMergin)
                {
                    obiStitcher.AddStitch(i, l);
                   
                    int solverIndex = actor1.solverIndices[i];
                    solver.filters[index1] = filter;
                }
            }
        }

        obiStitcher.PushDataToSolver();
    }
Reply
#4
(21-10-2021, 06:45 AM)Snail921 Wrote: Thank you for your help.
I finally make it work perfectly all in runtime without exporting/importing xml files or manual property painting.My concern, at this moment, is that I may have problem when obi simulation keeps going and moves particles away while the AutoStitcher.cs is trying to find out particle pairs within the range of designated distance. 

You're welcome!

As far as your stitcher script goes, it seems to be single-threaded, synchronous code. If it runs as soon as the updater/solver are created, it should give them no chance to update the simulation and move particles around.

You could also deactivate the updater component until you ass the stitches, this way the simulation won't be updated.

Where is this code being run, in relation to the solver?
Reply
#5
(21-10-2021, 08:33 AM)josemendez Wrote: You're welcome!

As far as your stitcher script goes, it seems to be single-threaded, synchronous code. If it runs as soon as the updater/solver are created, it should give them no chance to update the simulation and move particles around.

You could also deactivate the updater component until you ass the stitches, this way the simulation won't be updated.

Where is this code being run, in relation to the solver?
I see, I think I got it though I think I still need to deepen my understanding about obi.
The solver is in the scene already and the code runs right after the scene starts. So code should work ok always if I understand your explanation correctly.

By the way, I read the your post regarding Full Body Volumetric Particles.
Quote:- Geodesic voxel clustering: automatic optimal cluster radius, clusters don't "jump" trough gaps in the model. For instance, clusters from the right leg of a character won't include particles from the left leg, even if they're spatially very close.
The geodesic voxel clustering has been exactly what I have been waiting for and the current obi's lack of that functionality is the one of  reasons why I am trying to automate stitching process. I can't wait for the update! Your asset is always so exciting!
Reply
#6
(21-10-2021, 05:16 PM)Snail921 Wrote: I see, I think I got it though I think I still need to deepen my understanding about obi.
The solver is in the scene already and the code runs right after the scene starts. So code should work ok always if I understand your explanation correctly.

By the way, I read the your post regarding Full Body Volumetric Particles.
The geodesic voxel clustering has been exactly what I have been waiting for and the current obi's lack of that functionality is the one of  reasons why I am trying to automate stitching process. I can't wait for the update! Your asset is always so exciting!

Thanks!

Judging from the screenshots, I see you're using lego-like pieces as your softbodies. If you could send over a few of those (to support(at)virtualmethodstudio.com), I can test the new blueprint generator with them to ensure it does a good job - and if it doesn't, fix it. Testing real-world use cases is always helpful to improve things!

cheers,
Reply
#7
(22-10-2021, 07:44 AM)josemendez Wrote: Thanks!

Judging from the screenshots, I see you're using lego-like pieces as your softbodies. If you could send over a few of those (to support(at)virtualmethodstudio.com), I can test the new blueprint generator with them to ensure it does a good job - and if it doesn't, fix it. Testing real-world use cases is always helpful to improve things!

cheers,
Yep, glad helping you. I have just sent some.
If you don't get it, let me know, please.
Reply
#8
(23-10-2021, 08:36 AM)Snail921 Wrote: Yep, glad helping you. I have just sent some.
If you don't get it, let me know, please.

Received, just downloaded them. Will get back to you with test results. Sonrisa
Reply