18-12-2023, 04:15 PM
(18-12-2023, 01:04 PM)josemendez Wrote: Yes, it should work fine as long as particles are locked in the same position they're at prior to locking them, and resolution is high enough that it approximates a continuous cable well enough.
Now, if you need the cable bending to be kept to a minimum (very stiff cable) and at the same time reduce discretization issues to a minimum, these are at odds with each other since more particles means more work to keep the cable stiff.
Could you share the code you're currently using to lock particles in place, so that I may take a look to spot any potential problems?
kind regards,
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?