Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  Mesh Flies away on Simulation
#1
Hi,

I am currently making a simple mesh work with the cloth simulation using custom meshes made through unity. The mesh I am currently using is extremely simple of two rectangles that are stitched together using Obistitcher. The problem I am having however is  that the mesh flies away immediately after I start simulating (I am also using a custom obiupdater to handle the simulation) and I am not sure what is causing this. 

Here is the example of whats occuring https://youtu.be/xJC8gUavDDA


Custom ObiUpdater 
Code:
private void Awake()
        {
            _currentSimulationTime = 0;


            if (solvers == null)
                solvers.Add(gameObject.GetComponent<ObiSolver>());
           
        }

        [ContextMenu("Toggle Simulation")]
        public void ToggleSimulate() => isSimulating = !isSimulating;

        private void FixedUpdate()
        {
            if (!isSimulating)
                return;
           
            if (_currentSimulationTime >= _simulateTime)
            {
                isSimulating = false;
                return;
            }
           
            BeginStep(Time.fixedDeltaTime);

            float substepDelta = Time.fixedDeltaTime / _substeps;

            for (int i = 0; i < _substeps; ++i)
                Substep(Time.fixedDeltaTime,substepDelta,_substeps - i);
           
            EndStep(substepDelta);


            Interpolate(2, 100);
            _currentSimulationTime += Time.fixedDeltaTime;
        }

        private void Update()
        {
            if (!isSimulating)
            {
                if (_currentSimulationTime >= _simulateTime)
                {
                    _currentSimulationTime = 0f;
                    gameObject.GetComponent<MeshController>().BakeMesh();
                }
                
                return;
            }
           
            if (_currentSimulationTime >= _simulateTime)
            {
                isSimulating = false;
                return;
            }
           
            ObiProfiler.EnableProfiler();
            Interpolate(Time.fixedDeltaTime,_currentSimulationTime);
            ObiProfiler.DisableProfiler();

            _currentSimulationTime += Time.deltaTime;

        }
       
    }
Reply
#2
Hi there!

You're passing 2 and 100 to the interpolate method, and you're calling it on FixedUpdate():

Code:
void FixedUpdate()
{
//....//
Interpolate(2, 100);
}

This makes no sense whatsoever and will most likely cause some very wonky behavior. Not sure if its the culprit but it is a pretty darn good candidate Sonrisa.


What Interpolate() does is take the physics states at the end of the previous frame and the current frame, and use the remaining render time to interpolate between the two. The resulting state is then rendered to the screen. Quoting the documentation for it:

Quote:Finalizes the frame by performing physics state interpolation. This is usually used for mesh generation, rendering setup and other tasks that must take place after all physics steps for this frame are done.

As per the docs, Interpolate() must be called once all physics steps have been done: this is usually during LateUpdate(). Calling it in between physics updates like you're doing will yield strange results. Furthermore, the parameters you're passing just seem to be values chosen at random. The first parameter is the step time expressed in seconds, which in your case should be Time.fixedDeltaTime. The second parameter is the amount of time yet to be simulated which you don't seem to be keeping track of at all.

On a side note, you're adding both the timestep length (fixedDeltaTime) and the update time (Time.deltaTime) to _currentSimulationTime, which doesn't make any sense either. Then you're doing an extra Interpolate() call at the end of the frame, passing this incorrect value as the second parameter.

If you intend to keep track of the amount of time that needs to be simulated -which is definitely a good idea, as you need it for interpolation!- you need to add Time.deltaTime at the end of each Update call, and subtract Time.fixedDeltaTime at the end of each FixedUpdate() call.

You can use the ObiFixedUpdater component as reference on how to do this. Let me know if you need further help.

kind regards,
Reply
#3
Hi!

Thanks for the assistance for the obiupdater I definitely was unaware of what I was completely doing exactly so I referred to the obiupdaters and what you have mentioned and updated my updater and now it does seem to run better however unfortunately the original problem still persists. 

Would you have any other idea to what else it might be? 

Here is the generation for the mesh and its obicloth blueprint

Code:
public void Initialise(MeshData data)
        {
            _data = data;
           StartCoroutine(InitialiseCoroutine());
        }
       
     

        IEnumerator InitialiseCoroutine()
        {
            _mesh = new Mesh();

           
           
            var vertexes = new List<Vector3>();

            foreach (var vertex in _data.Vertices)
                vertexes.Add(vertex.Position);

            _mesh.vertices = vertexes.ToArray();
            _mesh.uv = _data.UVs;
            _mesh.triangles = _data.Triangles;
            _meshFilter.mesh = _mesh;

            _meshRenderer.material = _data.Fabric.Material;

            _meshCollider.sharedMesh = _mesh;
            _collider.sourceCollider = _meshCollider;

            _solver.AddActor(_actor);
       
            var blueprint = _actor.blueprint as ObiClothBlueprint;
            blueprint.inputMesh = _mesh;

            yield return StartCoroutine(GenerateBlueprintCoroutine(blueprint));
        }

        IEnumerator GenerateBlueprintCoroutine(ObiClothBlueprint blueprint)
        {
            yield return StartCoroutine(blueprint.Generate());
            GetComponent<ObiCloth>().clothBlueprint = blueprint;
            HasGeneratedBlueprint = true;
            //_solver.UpdateBackend();
        }


New Updater

Code:
   private void FixedUpdate()
        {
            if (!isSimulating)
                return;
           
            if (_currentSimulationTime >= _simulateTime)
            {
                isSimulating = false;
                return;
            }
           
            ObiProfiler.EnableProfiler();

           
            BeginStep(Time.fixedDeltaTime);

            float substepDelta = Time.fixedDeltaTime / _substeps;

            for (int i = 0; i < _substeps; ++i)
                Substep(Time.fixedDeltaTime,substepDelta,_substeps - i);
           
            EndStep(substepDelta);

            ObiProfiler.DisableProfiler();

            _currentSimulationTime -= Time.fixedDeltaTime;

        }

        private void Update()
        {
            if (!isSimulating)
            {
                if (_currentSimulationTime >= _simulateTime)
                {
                    _currentSimulationTime = 0f;
                    gameObject.GetComponent<MeshController>().BakeMesh();
                }
                 
                return;
            }
           
            if (_currentSimulationTime >= _simulateTime)
            {
                isSimulating = false;
                return;
            }
           
            ObiProfiler.EnableProfiler();
            Interpolate(Time.fixedDeltaTime,_currentSimulationTime);
            ObiProfiler.DisableProfiler();

            _currentSimulationTime += Time.deltaTime;

        }
       
    }
Reply
#4
(08-12-2021, 05:44 PM)Biggerest Wrote: Hi!

Thanks for the assistance for the obiupdater I definitely was unaware of what I was completely doing exactly so I referred to the obiupdaters and what you have mentioned and updated my updater and now it does seem to run better however unfortunately the original problem still persists. 

Would you have any other idea to what else it might be? 

Hi!

If the mesh is still flying away, maybe there's a scale mismatch between the blueprint and the cloth transform? What's are scale values of your cloth transform?


Regarding your current code: I don't think you need a custom updater for your purposes. You seem to be confusing the amount of un-simulated game time (which is what the updater keeps track of) with the net amount of time simulated since the start of the simulation. These are two completely different things.

This:
Quote:if (_currentSimulationTime >= _simulateTime)
            {
                isSimulating = false;
                return;
            }

Will not stop the simulation once you've simulated more than _simulateTime, since _currentSimulationTime is the amount of time that has passed in the game but has not yet been simulated by the physics engine.

This value will never be larger than Time.deltaTime, since Unity will call FixedUpdate() multiple times per frame as long as _currentSimulationTime is larger or equal to Time.fixedDeltaTime. If you're unsure how FixedUpdate() works, please refer to Unity's manual.

If you want to keep track of the time passed since simulation and then stop simulating, you can just keep track of it manually (by accumulating Time.deltaTime) and then disabling the updater component once it's larger than _simulateTime. Using the default ObiFixedUpdater will work just fine for this.

kind regards,
Reply