Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
RESET Obi Softbody
#11
So just a quick update on my journey of resetting softbodies Guiño

Weirdly, the two-line script using the teleport still crashed my editor. I created a completely empty scene only with a solver and a softbody. When I reset its position and exit playmode afterwards, Unity crashes. BUT, your other script does work - I only had to swap the "count" parts to "Length".

Here's the adjusted script that lets Unity live (in my case):


using UnityEngine;
using Obi;

[RequireComponent(typeof(ObiSoftbody))]
public class ResetActor : MonoBehaviour
{
    ObiSoftbody softbody;
    Vector4[] originalPositions;
    Quaternion[] originalOrientations;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.G))
        {
            ResetToOriginalPosition();
        }
    }

    void OnEnable()
    {
        softbody = GetComponent<ObiSoftbody>();
        softbody.OnBlueprintLoaded += Softbody_OnBlueprintLoaded;
        if (softbody.isLoaded)
            Softbody_OnBlueprintLoaded(softbody, softbody.softbodyBlueprint);
    }

    void OnDisable()
    {
        softbody.OnBlueprintLoaded -= Softbody_OnBlueprintLoaded;
    }

    private void Softbody_OnBlueprintLoaded(ObiActor actor, ObiActorBlueprint blueprint)
    {
        originalPositions = new Vector4[softbody.solverIndices.Length];
        originalOrientations = new Quaternion[softbody.solverIndices.Length];

        for (int i = 0; i < softbody.solverIndices.Length; ++i)
        {
            int solverIndex = softbody.solverIndices[i];
            originalPositions[i] = softbody.solver.positions[solverIndex];
            originalOrientations[i] = softbody.solver.orientations[solverIndex];
        }
    }

    public void ResetToOriginalPosition()
    {
        for (int i = 0; i < softbody.solverIndices.Length; ++i)
        {
            int solverIndex = softbody.solverIndices[i];
            softbody.solver.positions[solverIndex] = originalPositions[i];
            softbody.solver.orientations[solverIndex] = originalOrientations[i];
            softbody.solver.velocities[solverIndex] = softbody.solver.angularVelocities[solverIndex] = Vector4.zero;
        }
    }
}


I know that the teleport shouldn't cause any problems, but Unity is a fickle bitch and maybe it helps any other person who has the same bug as me.

Cheers
Felix
Reply
#12
Propagate this code to other users when you see them need to reset any ObiActor (Rope, Cloth,Softbody or whatever)
This is needed when teleport, or optimize disable > move solver to new pos > enable back.

Code:
    public class ObiActorResetor {
        public ObiActor actor;
        Vector3 localPosition;
        Quaternion localRotation;

        public ObiActorResetor(ObiActor actor) {
            Setup(actor);
        }
        //do not do this in Awake, since at the time the obi solver still not done setup
        public void Setup(ObiActor actor) {
            this.actor = actor;
            var parent = actor.solver.transform;
            localPosition = parent.InverseTransformPoint(actor.transform.position);
            localRotation = Quaternion.Inverse(parent.rotation) * actor.transform.rotation;
        }
       
        //the action teleport can not do instantly, should sub it on next frame of the sim
        public void MarkShouldReset() {
            actor.solver.OnSimulationStart -= DoReset;
            actor.solver.OnSimulationStart += DoReset;
        }

        void DoReset(ObiSolver solver, float simulatedTime, float substepTime){
            var parent = actor.solver.transform;
            actor.Teleport(parent.TransformPoint(localPosition), parent.rotation * localRotation);
            actor.ResetParticles();
            actor.solver.OnSimulationStart -= DoReset;
        }
    }

How to use:
Setup on Start (softbody is a reference that you wired in inspector, this is for example, it can be anything: rope, obibone, cloth)
Code:
        ObiActorResetor softbodyResetor;

        private void Start()
        {
            softbodyResetor = new ObiActorResetor(softbody);
        }

When want to Reset / Restore it to starting local position related to the solver

Code:
        softbodyResetor.MarkShouldReset();
Reply