Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  Fixing particle causes slight "jump"?
#6
(18-12-2023, 04:15 PM)Christoffer Wrote:
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Obi;

public class SC_CableLengthController : MonoBehaviour
{
public float speed = 0.5f;
public SC_Spool spool;

private ObiRopeCursor cursor;
private ObiRope rope;

private List<Vector3> particlePosOffsets;
private List<bool> particleLockedStates;
private List<float> particleUnlockedTime;
private List<int> solverIndices;

private float unlockedTimeMin = 6.0f;
private int currentParticleIndex = 0;

void Start()
{
cursor = GetComponent<ObiRopeCursor>();
rope = GetComponent<ObiRope>();

particlePosOffsets = new List<Vector3>();
particleLockedStates = new List<bool>();
particleUnlockedTime = new List<float>();
solverIndices = new List<int>();

// Offset to skip start/end of rope
currentParticleIndex = 1;
for (int i = 4; i < rope.elements.Count-1; i++)
{
particlePosOffsets.Add(Vector3.zero);
particleLockedStates.Add(false);
particleUnlockedTime.Add((i * - 1.0f) - unlockedTimeMin);
solverIndices.Add(rope.solverIndices[i]);
}

solverIndices.Reverse();
}

void FixedUpdate()
{
// Increase rope length
cursor.ChangeLength(rope.restLength + (Time.fixedDeltaTime * speed));

Vector3 newPosition = new Vector3();
for (int i = 0; i < solverIndices.Count; i++)
{
particleUnlockedTime[i] += Time.fixedDeltaTime;

// Update locked particle positions
if (particleLockedStates[i] == true)
{
// World position -> Rotate around spool pivot (0,0,0) for simplicity
newPosition = spool.transform.rotation * particlePosOffsets[i];
Debug.DrawLine(newPosition, newPosition + Vector3.up, Color.red);

// World -> local
newPosition = newPosition - rope.solver.transform.position;
rope.solver.positions[solverIndices[i]] = new Vector4(newPosition.x, newPosition.y, newPosition.z, 1.0f);
}
}

// Lock vertices if they have been alive for X time. More heuristics added when locking works as intended.
if (particleUnlockedTime[currentParticleIndex] > unlockedTimeMin && currentParticleIndex < solverIndices.Count-1)
{
LockParticleAtIndex(currentParticleIndex);
currentParticleIndex++;
}
}

void LockParticleAtIndex(int particleIndex)
{
// Store particle position in world space, accounting for current spool rotation
particlePosOffsets[particleIndex] = Quaternion.Inverse(spool.transform.rotation) * ((Vector3)rope.solver.positions[solverIndices[particleIndex]] + rope.solver.transform.position);

particleLockedStates[particleIndex] = true;
rope.solver.invMasses[solverIndices[particleIndex]] = 0;
}

void Update()
{
if (Input.GetKeyDown(KeyCode.KeypadPlus))
{
spool.Speed += 1;
}
if (Input.GetKeyDown(KeyCode.KeypadMinus))
{
spool.Speed = Mathf.Max(0, spool.Speed - 1);
}
}
}

Particles are locked in LockParticleAtIndex() and their position is updated in FixedUpdate()
Vertices are currently locked based on time, but that is fine until (if) i get the "locking" to work properly.

I stumbled upon an old thread with a similar problem and i think this is closer to what i need. However, i would need the cable to loop around 1-2 laps before "converting" into a static mesh, as the speed of the spool might affect more of the cable than in the example.
I already experimented with having two cursors, on at the start extending rope, and one at the end retracting. This might work, but it is very senstive and easily ends up with the rope going though the center walls if the rope length is just a tiny bit too short.

Do you think this is feasible with either the "locking"- or static mesh-replacement method?

Hi,

There's two subtle bugs in your code:

- The 4th component in all dimensional data in Obi is expected to be zero, as it's only there for memory alignment reasons. You're passing 1.0 as the fourth component of positions instead, which will lead to incorrect constraint solves (as they all expect it to be zero).

- You're using FixedUpdate(), and Obi also uses FixedUpdate() by default in order to run before rigidbody physics. Since Unity's event call order is undefined for different components, your script might randomly run before or after particle simulation. You should use ObiSolver.OnEndStep instead, to ensure your code is called consistently after the simulation has run each frame.

Making these modifications to your code couldn't perceive any "jumps" in particle movement.

kind regards,
Reply


Messages In This Thread
RE: Fixing particle causes slight "jump"? - by josemendez - 19-12-2023, 11:53 AM