09-08-2024, 10:36 AM
(This post was last modified: 09-08-2024, 10:57 AM by goosejordan.)
(09-08-2024, 10:21 AM)Ferhat123 Wrote: Thank you for your answer but Is it relevant to stripping the rope like in the video that I shared? If you have example video that what this code do I would be very glad.
Here's where I use it.
This I think is a multi-stage rocket of a problem.
The code is for the interaction of clamping the tool on the cable and then pulling the cable through it.
Once that is in place you can store the position on the rope that was first attached to. Then pass that information to the rendering.
If you are talking about the rendering of a stripped rope I can't help you much right now. But I think you'd need a custom shader or modify the mesh extruder to achieve this.
Here's the full script, that should be a lot more helpful
Code:
using System;
using System.Collections.Generic;
using Obi;
using UnityEngine;
using UnityEngine.Splines;
public class RopeCursorPin : MonoBehaviour
{
private ObiPinConstraintsBatch batch = new ObiPinConstraintsBatch();
[SerializeField] private ObiRopeBase _rope;
[SerializeField] private Vector3 _offset;
[SerializeField] private Vector3 _direction;
[SerializeField] private float _clampLength;
[SerializeField] private float _position;
[SerializeField] private float _pinCompress = 1f;
[SerializeField] private float _fadeToCompliance;
[SerializeField] private SplineContainer _spline;
[SerializeField] private float _frictionForce;
[SerializeField] private float _movemementDamping;
public float ForwardFriction;
public float BackwardFriction;
private int _elementIndex;
private float _positionInElement;
private ObiColliderBase _obiCollider;
private float _prevPosition = 0;
private float _currentForce = 0;
private Vector3 _forwardsPull;
private Vector3 _backwardsPull;
private bool _isBound = false;
private bool _isRegistered = false;
[NonSerialized] private int[] _solverIndices;
[NonSerialized] private Vector3[] _localDirections;
[NonSerialized] private Vector3[] _localOffsets;
[NonSerialized] private int attachedColliderHandleIndex;
public ObiRopeBase Rope
{
get { return _rope; }
}
public bool IsBound
{
get { return _isBound; }
}
private void Awake()
{
_obiCollider = GetComponent<ObiColliderBase>();
_solverIndices = new int[100];
_localDirections = new Vector3[100];
_localOffsets = new Vector3[100];
}
public float BreakThreshold
{
get { return _frictionForce; }
set
{
if (!Mathf.Approximately(value, _frictionForce))
{
_frictionForce = value;
for (int i = 0; i < _solverIndices.Length; ++i)
batch.breakThresholds[i] = _frictionForce;
}
}
}
private void OnEnable()
{
if (_rope == null || _isRegistered) return;
_rope.OnPrepareStep += Actor_OnPrepareStep;
_rope.OnEndStep += Actor_OnEndStep;
_isRegistered = true;
}
private void OnDisable()
{
if (_rope == null || !_isRegistered) return;
_rope.OnPrepareStep -= Actor_OnPrepareStep;
_rope.OnEndStep -= Actor_OnEndStep;
_isRegistered = false;
}
public void TryCreateContact(ObiRope rope, HashSet<int> particles)
{
if (_isBound || rope == null) return;
Matrix4x4 solver2Grabber = transform.worldToLocalMatrix * rope.solver.transform.localToWorldMatrix;
// and its inverse:
Matrix4x4 grabber2Solver = solver2Grabber.inverse;
//First find longest unbroken link
int longestStart = 0;
int longestEnd = 0;
int currentStart = 0;
for (int i = 0; i < rope.elements.Count; i++)
{
if (particles.Contains(rope.elements[i].particle1)) continue;
if (i - currentStart > longestEnd - longestStart)
{
longestStart = currentStart;
longestEnd = i;
}
currentStart = i + 1;
}
if (longestStart >= longestEnd) return;
_rope = rope;
_spline.Spline.Clear();
for (int i = longestStart; i < longestEnd; i++)
{
Vector3 position =
_rope.solver.positions[_rope.solverIndices[i]];
_spline.Spline.Add(new BezierKnot(solver2Grabber.MultiplyPoint3x4(position)), TangentMode.AutoSmooth);
}
_elementIndex = longestStart;
_position = _elementIndex;
OnEnable();
}
public void ReleaseContact()
{
OnDisable();
if (_isBound && _rope != null)
{
var pinConstraints = _rope.GetConstraintsByType(Oni.ConstraintType.Pin) as ObiConstraints<ObiPinConstraintsBatch>;
pinConstraints.RemoveBatch(batch);
batch.Clear();
_rope.SetConstraintsDirty(Oni.ConstraintType.Pin);
_isBound = false;
}
_rope = null;
}
void Actor_OnPrepareStep(ObiActor act, float stepTime)
{
// Attachments must be updated at the start of the step, before performing any simulation.
if (_prevPosition != _position)
{
float elementLength = 1f;//_rope.elements[0].restLength;
_elementIndex = Mathf.FloorToInt(_position / elementLength);
_positionInElement = Mathf.Repeat(_position, elementLength) / elementLength;
UpdateConstraints(stepTime);
_prevPosition = _position;
}
}
private void Actor_OnEndStep(ObiActor act, float stepTime)
{
UpdateMovement(stepTime);
}
private void UpdateMovement(float stepTime)
{
if (!IsBound || !enabled || !_rope.isLoaded) return;
int startElement = Mathf.Clamp(_elementIndex - 1, 0, _rope.elements.Count - 1);
int endElement = Mathf.Clamp(_elementIndex + batch.activeConstraintCount - 1, 0, _rope.elements.Count - 1);
if (startElement >= endElement) return;
var solver = _rope.solver;
var solverConstraints = solver.GetConstraintsByType(Oni.ConstraintType.Distance) as ObiConstraints<ObiDistanceConstraintsBatch>;
float sqrTime = stepTime * stepTime;
float forwardForce = -SolverLambda(startElement, solverConstraints) / sqrTime;
float backwardForce = -SolverLambda(endElement, solverConstraints) / sqrTime;
float totalForce = forwardForce - backwardForce;
if (totalForce > ForwardFriction) ApplyForceToMovement(totalForce - ForwardFriction, sqrTime);
else if (totalForce < -BackwardFriction) ApplyForceToMovement(totalForce + BackwardFriction, sqrTime);
}
//Vector3 pullStart = LocalPullDirection(0, -1).normalized;
//Vector3 pullEnd = LocalPullDirection(batch.activeConstraintCount - 1, 1).normalized;
//_forwardsPull = pullStart * forwardForce;
//_backwardsPull = pullEnd * backwardForce;
/*
var actorConstraints = _rope.GetConstraintsByType(Oni.ConstraintType.Pin) as ObiConstraints<ObiDistanceConstraintsBatch>;
var solverConstraints = solver.GetConstraintsByType(Oni.ConstraintType.Pin) as ObiConstraints<ObiPinConstraintsBatch>;
if (actorConstraints != null && batch != null)
{
int pinBatchIndex = actorConstraints.batches.IndexOf(batch);
if (pinBatchIndex >= 0 && pinBatchIndex < _rope.solverBatchOffsets[(int)Oni.ConstraintType.Pin].Count)
{
int offset = _rope.solverBatchOffsets[(int)Oni.ConstraintType.Pin][pinBatchIndex];
var solverBatch = solverConstraints.batches[pinBatchIndex];
Vector3 pullStart = LocalPullDirection(0, -1).normalized;
Vector3 pullEnd = LocalPullDirection(batch.activeConstraintCount - 1, 1).normalized;
float sqrTime = stepTime * stepTime;
float forwardForce = -solverBatch.lambdas[offset * 4 + 3] / sqrTime;
float backwardForce = -solverBatch.lambdas[(offset + batch.activeConstraintCount - 1) * 4 + 3] / sqrTime;
//forwardForce *= Vector3.Dot(pullStart, _localDirections[0]);
//backwardForce *= Vector3.Dot(pullEnd, _localDirections[batch.activeConstraintCount - 1]);
_forwardsPull = pullStart * forwardForce;
_backwardsPull = pullEnd * backwardForce;
float totalForce = forwardForce - backwardForce;
if (totalForce > ForwardFriction) ApplyForceToMovement(totalForce - ForwardFriction, sqrTime);
else if (totalForce < -BackwardFriction) ApplyForceToMovement(totalForce + BackwardFriction, sqrTime);
}
}*/
private float SolverLambda(int elementIndex, ObiConstraints<ObiDistanceConstraintsBatch> solverConstraints)
{
int batchCount = solverConstraints.GetBatchCount();
int index = elementIndex / batchCount;
int batchIndex = elementIndex % batchCount;
int offset = _rope.solverBatchOffsets[(int)Oni.ConstraintType.Distance][batchIndex];
return solverConstraints.batches[batchIndex].lambdas[offset + index];
}
private Vector3 LocalPullDirection(int pinIndex, int offset)
{
var pAttachment = _solverIndices[pinIndex];
var nextP = _solverIndices[pinIndex] + offset;
var pAttachmentPos= _rope.solver.positions[pAttachment];
var nextPPos= _rope.solver.positions[nextP];
Vector3 diff = pAttachmentPos - nextPPos;
return transform.InverseTransformDirection(diff);
}
private void ApplyForceToMovement(float force, float sqrTime)
{
float movement = (force) * sqrTime;
movement = Mathf.Lerp(movement, 0, _movemementDamping);
int startElement = Mathf.Clamp(_elementIndex - 1, 0, _rope.elements.Count - 1);
float movementInElement = movement / _rope.elements[startElement].restLength;
_positionInElement += movementInElement;
if (_positionInElement < 0)
{
_positionInElement += 1f;
_positionInElement *= _rope.elements[startElement].restLength;
_elementIndex--;
_positionInElement /= _rope.elements[startElement].restLength;
} else if (_positionInElement > 1f)
{
_positionInElement -= 1f;
_positionInElement *= _rope.elements[startElement].restLength;
_elementIndex++;
_positionInElement /= _rope.elements[startElement].restLength;
}
_position = _elementIndex + _positionInElement;
}
private void UpdateConstraints(float stepTime)
{
float splineLength = _spline != null ? _spline.CalculateLength() : 0f;
var pinConstraints = _rope.GetConstraintsByType(Oni.ConstraintType.Pin) as ObiConstraints<ObiPinConstraintsBatch>;
pinConstraints.RemoveBatch(batch);
batch.Clear();
float firstParticleRestLength = _rope.elements[0].restLength;
int pinCount = 0;
if (_elementIndex >= _rope.elements.Count)
{
batch.activeConstraintCount = pinCount;
pinConstraints.AddBatch(batch);
_isBound = true;
_rope.SetConstraintsDirty(Oni.ConstraintType.Pin);
return;
}
float accumLength = (1 - _positionInElement) * (_elementIndex >= 0 ? _rope.elements[_elementIndex].restLength : firstParticleRestLength);
float remainderLength = accumLength;
float clampLength = _spline != null
? _spline.Spline.CalculateLength(_rope.transform.worldToLocalMatrix)
: _clampLength;
float pinCompress = _spline != null ? _pinCompress / _spline.transform.lossyScale.x : _pinCompress;
for (int i = 0; accumLength < clampLength; i++)
{
int elementIndex = _elementIndex + i;
if (elementIndex < 0 || elementIndex >= _rope.activeParticleCount)
{
accumLength += firstParticleRestLength * pinCompress;
continue;
}
float restLength = _rope.elements[i].restLength;
remainderLength = remainderLength % restLength;
Vector3 offset = _offset + _direction * accumLength;
Vector3 direction = _direction;
if (_spline != null)
{
float t = _spline.Spline.ConvertIndexUnit(
accumLength, PathIndexUnit.Distance,
PathIndexUnit.Normalized);
offset = transform.InverseTransformPoint(_spline.EvaluatePosition(t));
direction = transform.InverseTransformDirection(_spline.EvaluateTangent(t));
}
accumLength += restLength * pinCompress;
float complianceFade = 0;
if (i == 0) complianceFade = 1f - remainderLength / restLength;
else if (accumLength >= clampLength) complianceFade = remainderLength / restLength;
remainderLength += restLength;
_solverIndices[pinCount] = _rope.solverIndices[elementIndex];
batch.AddConstraint(_solverIndices[pinCount], _obiCollider, offset, Quaternion.identity, complianceFade * _fadeToCompliance, 100, float.PositiveInfinity);
_localDirections[pinCount] = direction.normalized;
_localOffsets[pinCount] = offset;
pinCount++;
}
batch.activeConstraintCount = pinCount;
pinConstraints.AddBatch(batch);
_isBound = true;
_rope.SetConstraintsDirty(Oni.ConstraintType.Pin);
}
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
if (!Application.isPlaying) return;
if (!_isBound) return;
Gizmos.DrawLine(transform.TransformPoint(_localOffsets[0]),
transform.TransformPoint(_localOffsets[0]) + transform.TransformDirection(_forwardsPull)*.001f);
Gizmos.DrawLine(transform.TransformPoint(_localOffsets[batch.activeConstraintCount - 1]),
transform.TransformPoint(_localOffsets[batch.activeConstraintCount - 1]) + transform.TransformDirection(_backwardsPull)*.001f);
}
#endif
}