Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Scaling Softbody / Solver Updates
#1
Hi team,

I already discovered that it's possible to scale a softbody via the scaling solver way.
However, when I do this, many world coordinates change and (for instance) a camera script following the softbody introduces glitches.
Is there a better way to scale (increasingly, grow) softbodies or how do I compensate the glitches of the solver updates?

I hope it's clear what I wanna achieve. Obi is fantastic, but with some specific tasks I run into problems/limitations...

best regards
Michael
Reply
#2
(21-11-2022, 10:13 PM)nakoustix Wrote: I already discovered that it's possible to scale a softbody via the scaling solver way.
However, when I do this, many world coordinates change and (for instance) a camera script following the softbody introduces glitches.
Is there a better way to scale (increasingly, grow) softbodies or how do I compensate the glitches of the solver updates?

Hi!

If you scale (or rotate, or translate) the solver, all positions of particles inside of it will need to be converted from local space to world space (or more precisely, to the space your other scripts expect to use). This is not just some quirk exclusive to Obi,  the same would happen to regular GameObjects parented to another transform: their local and world space coordinates cease to be the same, and you need to convert back and forth.

Unity's Transform class has built-in methods to convert from local to world space and vice-versa, since it's a basic operation that gets used very often:

To transform a position from local to world (this is what you need to use to convert the position the camera follows):
https://docs.unity3d.com/ScriptReference...Point.html

To transform a vector from local to world:
https://docs.unity3d.com/ScriptReference...ector.html

To transform a position from world to local:
https://docs.unity3d.com/ScriptReference...Point.html

To transform a vector from world to local:
https://docs.unity3d.com/ScriptReference...ector.html

let me know if you need further help,

kind regards
Reply
#3
Hi Jose,

thanks for your quick response!

I'm (now) aware of that. Maybe I didn't understand the principle of the simulation "domain" right, but I think, upon further reading, I now do.
What's still confusing me is that an ObiActor will not act the same as a regular child GameObject. You pointed out the TransformPoint etc. methods (which is greatly appreciated), but to me it's still a myracle how i could compensate the change in the simulation since i can't set the local nor world coordinates of the ObiActor (ObiSoftbody in my case) directly since... well it's simulated Guiño

I made some small scripts to test this "domain behaviour" and it's clearly not the same with regular unity objects. Pls. see demonstration here: behaviour demo

The scripts are mainly the same, I just grab transforms from different components.
For ObiSolver:
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Obi;

[RequireComponent(typeof(ObiSolver))]
public class Test_ObiSolverScaler : MonoBehaviour
{
    [Range(0.1f, 5f)]
    public float scale = 2.0f;

    public ObiActor actor;

    private ObiSolver solver;

    private void Awake()
    {
        solver = GetComponent<ObiSolver>();
    }

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

    // Update is called once per frame
    void Update()
    {
        Vector3 actorPos = actor.transform.position;

        //Debug.Log("ActorPosWorld = " + actorPosWorld); 

        Vector3 actualScale = transform.localScale;

        actualScale.x = scale;
        actualScale.y = scale;
        actualScale.z = scale;

        transform.localScale = actualScale;

        actor.transform.localPosition = transform.InverseTransformPoint(actorPos);
    }
}



For TestSolver (with simple parent/child relation):

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


public class Test_DomainScale : MonoBehaviour
{
    [Range(0.1f, 5f)]
    public float scale = 2.0f;

    public Transform actor;

    private Transform solver;

    private void Awake()
    {
        solver = GetComponent<Transform>();
    }

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

    // Update is called once per frame
    void Update()
    {
        Vector3 actorPos = actor.transform.position;

        //Debug.Log("ActorPosWorld = " + actorPosWorld); 

        Vector3 actualScale = transform.localScale;

        actualScale.x = scale;
        actualScale.y = scale;
        actualScale.z = scale;

        transform.localScale = actualScale;

        actor.transform.localPosition = transform.InverseTransformPoint(actorPos);
    }
}


I'm just in the dark and really appreciate any help from you guys. Do I really need to update every particle position by hand? (I don't think that's gonna be performant..)
Or is there another way to scale the solver and therefore its simulated bodies and keep them running without positional changes?

Many thanks Sonrisa a fellow, maybe not so smart dev..

Michael Menzi
Reply
#4
(22-11-2022, 09:08 PM)nakoustix Wrote: Hi Jose,

thanks for your quick response!

I'm (now) aware of that. Maybe I didn't understand the principle of the simulation "domain" right, but I think, upon further reading, I now do.
What's still confusing me is that an ObiActor will not act the same as a regular child GameObject. You pointed out the TransformPoint etc. methods (which is greatly appreciated), but to me it's still a myracle how i could compensate the change in the simulation since i can't set the local nor world coordinates of the ObiActor (ObiSoftbody in my case) directly since... well it's simulated Guiño

I made some small scripts to test this "domain behaviour" and it's clearly not the same with regular unity objects. Pls. see demonstration here: behaviour demo

Hi!

I think you're still confused about the concept of vector spaces, which is very related to parenting transforms and "pivots": Both setups aren't equivalent: the object in the right (a regular GameObject) has its pivot in the center of the sphere mesh. That its, mesh vertices are laid out around the center of the transform. However the softbody has its pivot to the left of the softbody, because the softbody has moved to the right of the solver.

Try grabbing your GameObject sphere, parent it under another transform and move it to the right of its parent, then scale the parent transform. This is what's actually happening with the solver and the softbody, and you'll get the exact same behavior as you do with the solver.

(22-11-2022, 09:08 PM)nakoustix Wrote: The scripts are mainly the same, I just grab transforms from different components.
For ObiSolver:
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Obi;

[RequireComponent(typeof(ObiSolver))]
public class Test_ObiSolverScaler : MonoBehaviour
{
    [Range(0.1f, 5f)]
    public float scale = 2.0f;

    public ObiActor actor;

    private ObiSolver solver;

    private void Awake()
    {
        solver = GetComponent<ObiSolver>();
    }

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

    // Update is called once per frame
    void Update()
    {
        Vector3 actorPos = actor.transform.position;

        //Debug.Log("ActorPosWorld = " + actorPosWorld); 

        Vector3 actualScale = transform.localScale;

        actualScale.x = scale;
        actualScale.y = scale;
        actualScale.z = scale;

        transform.localScale = actualScale;

        actor.transform.localPosition = transform.InverseTransformPoint(actorPos);
    }
}

This bit:
Code:
Vector3 actorPos = actor.transform.position;
[...]
actor.transform.localPosition = transform.InverseTransformPoint(actorPos);

Doesn't make much sense. actorPos is already expressed in world space, so you could just do:
Code:
Vector3 actorPos = actor.transform.position;
[...]
actor.transform.position = actorPos;

What I meant about InverseTransformPoint is that you can use it to convert particle positions from solver to local space. So for instance, if you've calculated the center of mass of your softbody (by averaging all particle positions, which are expressed in the solver's local space, just like vertices in a mesh are expressed in the object's local space), you can get its value in world space by using solver.transform.InverseTransformPoint(). This comes in handy when moving softbodies around.


(22-11-2022, 09:08 PM)nakoustix Wrote: I'm just in the dark and really appreciate any help from you guys. Do I really need to update every particle position by hand? (I don't think that's gonna be performant..)

If you want to move/rotate a softbody, yes you need to move/rotate all its particles. There's no other way around it, because unlike a rigid object, a soft object doesn't really have a "pivot" point with respect to which all parts of it are fixed in place.

(22-11-2022, 09:08 PM)nakoustix Wrote: Or is there another way to scale the solver and therefore its simulated bodies and keep them running without positional changes?

Basically you want to:

- Calculate the world space position of all softbodies in the solver, and store them.
- Scale the solver down (all softbodies under it will shrink, and move towards the solver's center)
- Convert your stored world space positions to the solver's local space, and move the softbodies there. And with "moving a softbody", I mean moving all of its particles.

Conceptually this is exactly the same you'd do with regular Unity objects: imagine you've got several objects parented under a common parent transform, and you want to scale them all without altering their positions: you store their positions prior to scaling, scale the parent, then reset their positions to what they were before scaling.

Let me know if you need further help with this,

kind regards
Reply
#5
Corazón 
Thanks man... really, thank you very much for your time and effort you put into this thoughtful and quite specific answer!

I was now able to implement it in some sort. It's still not perfect, in the sense of still having simulation jerks when just placing particles back where they belong (or don't Confundido ), because of depenetration I guess (I may still do it mathematically incorrect and don't account for the scale change when placing particles back), but I think I do now understand better where the problems lie (definitely at my math side Triste ). 
I get that 3D math is very important to understand to do stuff like this, so I'll try to learn and understand it better.
Thanks for your help along the way Sonrisa

All the best

Michael
Reply