14-11-2019, 12:48 PM
(14-11-2019, 11:58 AM)manurocker95 Wrote: Okay, my script is something like
Code:using System;
using UnityEngine;
namespace Obi
{
[RequireComponent(typeof(LineRenderer))]
[RequireComponent(typeof(ObiParticlePicker))]
public class OBIExampleDragger : MonoBehaviour
{
public bool drawSpring = true;
private LineRenderer lineRenderer;
private ObiParticlePicker picker;
private ObiParticlePicker.ParticlePickEventArgs pickArgs;
public UnityEngine.Events.UnityEvent OnParticlePicked;
public UnityEngine.Events.UnityEvent OnParticleDragged;
public UnityEngine.Events.UnityEvent OnParticleReleased;
public float draggedInMass = 0f;
void OnEnable()
{
lineRenderer = GetComponent<LineRenderer>();
picker = GetComponent<ObiParticlePicker>();
picker.OnParticlePicked.AddListener(Picker_OnParticleDragged);
picker.OnParticleDragged.AddListener(Picker_OnParticleDragged);
picker.OnParticleReleased.AddListener(Picker_OnParticleReleased);
}
void OnDisable()
{
picker.OnParticlePicked.RemoveListener(Picker_OnParticleDragged);
picker.OnParticleDragged.RemoveListener(Picker_OnParticleDragged);
picker.OnParticleReleased.RemoveListener(Picker_OnParticleReleased);
lineRenderer.positionCount = 0;
}
private void FixedUpdate()
{
ObiSolver solver = picker.solver;
if (solver != null && pickArgs != null)
{
// Calculate picking position in solver space:
Vector4 targetPosition = pickArgs.worldPosition;
if (solver.simulateInLocalSpace)
targetPosition = solver.transform.InverseTransformPoint(targetPosition);
// Calculate effective inverse mass:
float invMass = solver.invMasses[pickArgs.particleIndex];
draggedInMass = invMass;
if (invMass > 0)
{
// Calculate and apply spring force:
solver.positions[pickArgs.particleIndex] = (targetPosition);
solver.invMasses[pickArgs.particleIndex] = 0f;
solver.velocities[pickArgs.particleIndex] = Vector4.zero;
if (drawSpring)
{
lineRenderer.positionCount = 2;
lineRenderer.SetPosition(0, targetPosition);
lineRenderer.SetPosition(1, position);
}
else
{
lineRenderer.positionCount = 0;
}
}
}
}
void Picker_OnParticleDragged(ObiParticlePicker.ParticlePickEventArgs e)
{
pickArgs = e;
OnParticlePicked?.Invoke();
OnParticleDragged?.Invoke();
}
void Picker_OnParticleReleased(ObiParticlePicker.ParticlePickEventArgs e)
{
pickArgs = null;
lineRenderer.positionCount = 0;
OnParticleReleased?.Invoke();
}
public void OnReleased()
{
ObiSolver solver = picker.solver;
if (solver != null && pickArgs != null)
solver.invMasses[pickArgs.particleIndex] = draggedInMass;
}
}
}
Hi, it's *almost* correct.
Whenever you manually change the inverse mass (and thus, the mass) of a particle involved in a shape matching constraint, you need to recalculate the shape matching cluster's rest state. I really should have pointed this out before, kinda took it for granted it but it's not entirely obvious. My apologies.
Lastly, it only works for 1 particle (like the default dragger). There's cases where you want to grab multiple particles, but well that's just an additional bonus.
My next post contains a complete example that works via contact callbacks, so you can grab multiple particles that are in touch with a collider (or inside a trigger, for that matter).