添加插件
This commit is contained in:
337
Assets/Obi/Scripts/RopeAndRod/Utils/ObiPinhole.cs
Normal file
337
Assets/Obi/Scripts/RopeAndRod/Utils/ObiPinhole.cs
Normal file
@@ -0,0 +1,337 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
[AddComponentMenu("Physics/Obi/Obi Pinhole", 820)]
|
||||
[RequireComponent(typeof(ObiRopeBase))]
|
||||
[ExecuteInEditMode]
|
||||
public class ObiPinhole : MonoBehaviour
|
||||
{
|
||||
|
||||
[SerializeField] [HideInInspector] private ObiRopeBase m_Rope;
|
||||
[SerializeField] [HideInInspector] private Transform m_Target;
|
||||
|
||||
[Range(0, 1)]
|
||||
[SerializeField] [HideInInspector] private float m_Position = 0;
|
||||
|
||||
[SerializeField] [HideInInspector] private bool m_LimitRange = false;
|
||||
[MinMax(0, 1)]
|
||||
[SerializeField] [HideInInspector] private Vector2 m_Range = new Vector2(0, 1);
|
||||
|
||||
[Range(0, 1)]
|
||||
[SerializeField] [HideInInspector] private float m_Friction = 0;
|
||||
[SerializeField] [HideInInspector] private float m_MotorSpeed = 0;
|
||||
[SerializeField] [HideInInspector] private float m_MotorForce = 0;
|
||||
[SerializeField] [HideInInspector] private float m_Compliance = 0;
|
||||
[SerializeField] [HideInInspector] private bool m_ClampAtEnds = true;
|
||||
|
||||
[SerializeField] [HideInInspector] private ObiPinholeConstraintsBatch.PinholeEdge currentEdge;
|
||||
[SerializeField] [HideInInspector] public ObiPinholeConstraintsBatch.PinholeEdge firstEdge;
|
||||
[SerializeField] [HideInInspector] public ObiPinholeConstraintsBatch.PinholeEdge lastEdge;
|
||||
|
||||
// private variables are serialized during script reloading, to keep their value. Must mark them explicitly as non-serialized.
|
||||
[NonSerialized] private ObiPinholeConstraintsBatch pinBatch;
|
||||
[NonSerialized] private ObiColliderBase attachedCollider;
|
||||
[NonSerialized] private int attachedColliderHandleIndex;
|
||||
|
||||
[NonSerialized] private Vector3 m_PositionOffset;
|
||||
[NonSerialized] private bool m_ParametersDirty = true;
|
||||
[NonSerialized] private bool m_PositionDirty = false;
|
||||
[NonSerialized] private bool m_RangeDirty = false;
|
||||
|
||||
/// <summary>
|
||||
/// The rope this attachment is added to.
|
||||
/// </summary>
|
||||
public ObiActor rope
|
||||
{
|
||||
get { return m_Rope; }
|
||||
}
|
||||
|
||||
public float edgeCoordinate
|
||||
{
|
||||
get { return currentEdge.coordinate; }
|
||||
}
|
||||
|
||||
public int edgeIndex
|
||||
{
|
||||
get { return currentEdge.edgeIndex; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The target transform that the pinhole should be attached to.
|
||||
/// </summary>
|
||||
public Transform target
|
||||
{
|
||||
get { return m_Target; }
|
||||
set
|
||||
{
|
||||
if (value != m_Target)
|
||||
{
|
||||
m_Target = value;
|
||||
Bind();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Normalized coordinate of the point along the rope where the pinhole is positioned.
|
||||
/// </summary>
|
||||
public float position
|
||||
{
|
||||
get { return m_Position; }
|
||||
set
|
||||
{
|
||||
if (!Mathf.Approximately(value, m_Position))
|
||||
{
|
||||
m_Position = value;
|
||||
CalculateMu();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool limitRange
|
||||
{
|
||||
get { return m_LimitRange; }
|
||||
set
|
||||
{
|
||||
if (m_LimitRange != value)
|
||||
{
|
||||
m_LimitRange = value;
|
||||
CalculateRange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Normalized coordinate of the point along the rope where the pinhole is positioned.
|
||||
/// </summary>
|
||||
public Vector2 range
|
||||
{
|
||||
get { return m_Range; }
|
||||
set
|
||||
{
|
||||
m_Range = value;
|
||||
CalculateRange();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether this pinhole is currently bound or not.
|
||||
/// </summary>
|
||||
public bool isBound
|
||||
{
|
||||
get { return m_Target != null && currentEdge.edgeIndex >= 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constraint compliance.
|
||||
/// </summary>
|
||||
/// High compliance values will increase the pinhole's elasticity.
|
||||
public float compliance
|
||||
{
|
||||
get { return m_Compliance; }
|
||||
set
|
||||
{
|
||||
if (!Mathf.Approximately(value, m_Compliance))
|
||||
{
|
||||
m_Compliance = value;
|
||||
m_ParametersDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float friction
|
||||
{
|
||||
get { return m_Friction; }
|
||||
set
|
||||
{
|
||||
if (!Mathf.Approximately(value, m_Friction))
|
||||
{
|
||||
m_Friction = value;
|
||||
m_ParametersDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float motorSpeed
|
||||
{
|
||||
get { return m_MotorSpeed; }
|
||||
set
|
||||
{
|
||||
if (!Mathf.Approximately(value, m_MotorSpeed))
|
||||
{
|
||||
m_MotorSpeed = value;
|
||||
m_ParametersDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float motorForce
|
||||
{
|
||||
get { return m_MotorForce; }
|
||||
set
|
||||
{
|
||||
if (!Mathf.Approximately(value, m_MotorForce))
|
||||
{
|
||||
m_MotorForce = value;
|
||||
m_ParametersDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool clampAtEnds
|
||||
{
|
||||
get { return m_ClampAtEnds; }
|
||||
set
|
||||
{
|
||||
if (m_ClampAtEnds != value)
|
||||
{
|
||||
m_ClampAtEnds = value;
|
||||
m_ParametersDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Force threshold above which the pinhole should break.
|
||||
/// </summary>
|
||||
[Delayed] public float breakThreshold = float.PositiveInfinity;
|
||||
|
||||
public float relativeVelocity { get; private set; }
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
m_Rope = GetComponent<ObiRopeBase>();
|
||||
m_Rope.OnBlueprintLoaded += Actor_OnBlueprintLoaded;
|
||||
m_Rope.OnSimulationStart += Actor_OnSimulationStart;
|
||||
m_Rope.OnRequestReadback += Actor_OnRequestReadback;
|
||||
|
||||
if (m_Rope.solver != null)
|
||||
Actor_OnBlueprintLoaded(m_Rope, m_Rope.sourceBlueprint);
|
||||
|
||||
EnablePinhole();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
DisablePinhole();
|
||||
|
||||
m_Rope.OnBlueprintLoaded -= Actor_OnBlueprintLoaded;
|
||||
m_Rope.OnSimulationStart -= Actor_OnSimulationStart;
|
||||
m_Rope.OnRequestReadback -= Actor_OnRequestReadback;
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
m_Rope = GetComponent<ObiRopeBase>();
|
||||
m_ParametersDirty = true;
|
||||
m_PositionDirty = true;
|
||||
m_RangeDirty = true;
|
||||
}
|
||||
|
||||
private void Actor_OnBlueprintLoaded(ObiActor act, ObiActorBlueprint blueprint)
|
||||
{
|
||||
Bind();
|
||||
}
|
||||
|
||||
private void Actor_OnSimulationStart(ObiActor act, float stepTime, float substepTime)
|
||||
{
|
||||
// Attachments must be updated at the start of the step, before performing any simulation.
|
||||
UpdatePinhole();
|
||||
|
||||
// if there's any broken constraint, flag pinhole constraints as dirty for remerging at the start of the next step.
|
||||
BreakPinhole(substepTime);
|
||||
}
|
||||
|
||||
private void Actor_OnRequestReadback(ObiActor actor)
|
||||
{
|
||||
if (enabled && m_Rope.isLoaded && isBound)
|
||||
{
|
||||
var solver = m_Rope.solver;
|
||||
|
||||
var actorConstraints = m_Rope.GetConstraintsByType(Oni.ConstraintType.Pinhole) as ObiConstraints<ObiPinholeConstraintsBatch>;
|
||||
var solverConstraints = solver.GetConstraintsByType(Oni.ConstraintType.Pinhole) as ObiConstraints<ObiPinholeConstraintsBatch>;
|
||||
|
||||
if (actorConstraints != null && pinBatch != null && actorConstraints.batchCount <= solverConstraints.batchCount)
|
||||
{
|
||||
int pinBatchIndex = actorConstraints.batches.IndexOf(pinBatch);
|
||||
if (pinBatchIndex >= 0 && pinBatchIndex < rope.solverBatchOffsets[(int)Oni.ConstraintType.Pinhole].Count)
|
||||
{
|
||||
var solverBatch = solverConstraints.batches[pinBatchIndex];
|
||||
|
||||
solverBatch.particleIndices.Readback();
|
||||
solverBatch.edgeMus.Readback();
|
||||
solverBatch.relativeVelocities.Readback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClampMuToRange()
|
||||
{
|
||||
if (m_LimitRange)
|
||||
{
|
||||
float maxCoord = lastEdge.GetRopeCoordinate(m_Rope);
|
||||
float minCoord = firstEdge.GetRopeCoordinate(m_Rope);
|
||||
|
||||
if (m_Position > maxCoord)
|
||||
{
|
||||
m_Position = maxCoord;
|
||||
currentEdge.edgeIndex = m_Rope.GetEdgeAt(m_Position, out currentEdge.coordinate);
|
||||
m_PositionDirty = true;
|
||||
}
|
||||
else if (m_Position < minCoord)
|
||||
{
|
||||
m_Position = minCoord;
|
||||
currentEdge.edgeIndex = m_Rope.GetEdgeAt(m_Position, out currentEdge.coordinate);
|
||||
m_PositionDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CalculateMu()
|
||||
{
|
||||
currentEdge.edgeIndex = m_Rope.GetEdgeAt(m_Position, out currentEdge.coordinate);
|
||||
ClampMuToRange();
|
||||
|
||||
m_PositionDirty = true;
|
||||
}
|
||||
|
||||
public void CalculateRange()
|
||||
{
|
||||
if (m_LimitRange)
|
||||
{
|
||||
firstEdge.edgeIndex = m_Rope.GetEdgeAt(m_Range.x, out firstEdge.coordinate);
|
||||
lastEdge.edgeIndex = m_Rope.GetEdgeAt(m_Range.y, out lastEdge.coordinate);
|
||||
}
|
||||
else
|
||||
{
|
||||
firstEdge.edgeIndex = m_Rope.GetEdgeAt(0, out firstEdge.coordinate);
|
||||
lastEdge.edgeIndex = m_Rope.GetEdgeAt(1, out lastEdge.coordinate);
|
||||
firstEdge.coordinate = -float.MaxValue;
|
||||
lastEdge.coordinate = float.MaxValue;
|
||||
}
|
||||
|
||||
ClampMuToRange();
|
||||
|
||||
m_RangeDirty = true;
|
||||
}
|
||||
|
||||
public void Bind()
|
||||
{
|
||||
// Disable pinhole.
|
||||
DisablePinhole();
|
||||
|
||||
if (m_Target != null && m_Rope.isLoaded)
|
||||
{
|
||||
Matrix4x4 bindMatrix = m_Target.worldToLocalMatrix * m_Rope.solver.transform.localToWorldMatrix;
|
||||
|
||||
var ropeBlueprint = m_Rope.sharedBlueprint as ObiRopeBlueprintBase;
|
||||
if (ropeBlueprint != null && ropeBlueprint.deformableEdges != null)
|
||||
{
|
||||
currentEdge.edgeIndex = m_Rope.GetEdgeAt(m_Position, out currentEdge.coordinate);
|
||||
|
||||
if (currentEdge.edgeIndex >= 0)
|
||||
{
|
||||
CalculateRange();
|
||||
11
Assets/Obi/Scripts/RopeAndRod/Utils/ObiPinhole.cs.meta
Normal file
11
Assets/Obi/Scripts/RopeAndRod/Utils/ObiPinhole.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2aadf7c5471054b0db8c70bd317bc272
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 214df93f7c2ed4c1094bb6105c050575, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
23
Assets/Obi/Scripts/RopeAndRod/Utils/ObiRopeAttach.cs
Normal file
23
Assets/Obi/Scripts/RopeAndRod/Utils/ObiRopeAttach.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public class ObiRopeAttach : MonoBehaviour
|
||||
{
|
||||
public ObiPathSmoother smoother;
|
||||
[Range(0,1)]
|
||||
public float m;
|
||||
|
||||
public void LateUpdate()
|
||||
{
|
||||
if (smoother != null && smoother.actor.isLoaded)
|
||||
{
|
||||
var trfm = smoother.actor.solver.transform;
|
||||
ObiPathFrame section = smoother.GetSectionAt(m);
|
||||
transform.position = trfm.TransformPoint(section.position);
|
||||
transform.rotation = trfm.rotation * Quaternion.LookRotation(section.tangent, section.binormal);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
11
Assets/Obi/Scripts/RopeAndRod/Utils/ObiRopeAttach.cs.meta
Normal file
11
Assets/Obi/Scripts/RopeAndRod/Utils/ObiRopeAttach.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93cd44c04a2944349b4fe311545b7e05
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
108
Assets/Obi/Scripts/RopeAndRod/Utils/ObiRopePrefabPlugger.cs
Normal file
108
Assets/Obi/Scripts/RopeAndRod/Utils/ObiRopePrefabPlugger.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
/**
|
||||
* This component plugs a prefab instance at each cut in the rope. Optionally, it will also place a couple instances at the start/end of an open rope.
|
||||
*/
|
||||
[RequireComponent(typeof(ObiPathSmoother))]
|
||||
public class ObiRopePrefabPlugger : MonoBehaviour
|
||||
{
|
||||
public GameObject prefab; /**< prefab object being instantiated at the rope cuts.*/
|
||||
public Vector3 instanceScale = Vector3.one;
|
||||
public bool plugTears = true;
|
||||
public bool plugStart = false;
|
||||
public bool plugEnd = false;
|
||||
|
||||
private List<GameObject> instances; /**< instances of the prefab being rendered. */
|
||||
private ObiPathSmoother smoother;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
instances = new List<GameObject>();
|
||||
smoother = GetComponent<ObiPathSmoother>();
|
||||
GetComponent<ObiActor>().OnInterpolate += UpdatePlugs;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
GetComponent<ObiActor>().OnInterpolate -= UpdatePlugs;
|
||||
ClearPrefabInstances();
|
||||
}
|
||||
|
||||
private GameObject GetOrCreatePrefabInstance(int index)
|
||||
{
|
||||
if (index < instances.Count)
|
||||
return instances[index];
|
||||
|
||||
GameObject tearPrefabInstance = Instantiate(prefab);
|
||||
tearPrefabInstance.hideFlags = HideFlags.HideAndDontSave;
|
||||
instances.Add(tearPrefabInstance);
|
||||
return tearPrefabInstance;
|
||||
}
|
||||
|
||||
public void ClearPrefabInstances()
|
||||
{
|
||||
for (int i = 0; i < instances.Count; ++i)
|
||||
DestroyImmediate(instances[i]);
|
||||
|
||||
instances.Clear();
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void UpdatePlugs(ObiActor actor, float simulatedTime, float substepTime)
|
||||
{
|
||||
if (!actor.isLoaded)
|
||||
return;
|
||||
|
||||
// cache the rope's transform matrix/quaternion:
|
||||
Matrix4x4 l2w = smoother.actor.solver.transform.localToWorldMatrix;
|
||||
Quaternion l2wRot = l2w.rotation;
|
||||
|
||||
int instanceIndex = 0;
|
||||
|
||||
var system = actor.solver.GetRenderSystem<ObiPathSmoother>() as ObiPathSmootherRenderSystem;
|
||||
int chunkCount = system.GetChunkCount(smoother.indexInSystem);
|
||||
|
||||
// place prefabs at the start/end of each curve:
|
||||
for (int c = 0; c < chunkCount; ++c)
|
||||
{
|
||||
if ((plugTears && c > 0) ||
|
||||
(plugStart && c == 0))
|
||||
{
|
||||
var instance = GetOrCreatePrefabInstance(instanceIndex++);
|
||||
instance.SetActive(true);
|
||||
|
||||
ObiPathFrame frame = system.GetFrameAt(smoother.indexInSystem, c, 0);
|
||||
instance.transform.position = l2w.MultiplyPoint3x4(frame.position);
|
||||
instance.transform.rotation = l2wRot * (Quaternion.LookRotation(-frame.tangent, frame.binormal));
|
||||
instance.transform.localScale = instanceScale;
|
||||
}
|
||||
|
||||
|
||||
if ((plugTears && c < chunkCount - 1) ||
|
||||
(plugEnd && c == chunkCount - 1))
|
||||
{
|
||||
var instance = GetOrCreatePrefabInstance(instanceIndex++);
|
||||
instance.SetActive(true);
|
||||
|
||||
int frameCount = system.GetSmoothFrameCount(smoother.indexInSystem, c);
|
||||
ObiPathFrame frame = system.GetFrameAt(smoother.indexInSystem, c, frameCount-1);
|
||||
instance.transform.position = l2w.MultiplyPoint3x4(frame.position);
|
||||
instance.transform.rotation = l2wRot * Quaternion.LookRotation(frame.tangent, frame.binormal);
|
||||
instance.transform.localScale = instanceScale;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// deactivate remaining instances:
|
||||
for (int i = instanceIndex; i < instances.Count; ++i)
|
||||
instances[i].SetActive(false);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4514513daf5b14cb689daa23e9d8575e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
62
Assets/Obi/Scripts/RopeAndRod/Utils/ObiRopeReel.cs
Normal file
62
Assets/Obi/Scripts/RopeAndRod/Utils/ObiRopeReel.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
[RequireComponent(typeof(ObiRopeCursor))]
|
||||
public class ObiRopeReel : MonoBehaviour
|
||||
{
|
||||
private ObiRopeCursor cursor;
|
||||
private ObiRope rope;
|
||||
|
||||
[Header("Roll out/in thresholds")]
|
||||
public float outThreshold = 0.8f;
|
||||
public float inThreshold = 0.4f;
|
||||
|
||||
[Header("Roll out/in speeds")]
|
||||
public float outSpeed = 4;
|
||||
public float inSpeed = 2;
|
||||
|
||||
public float maxLength = 10;
|
||||
|
||||
private float restLength;
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
cursor = GetComponent<ObiRopeCursor>();
|
||||
rope = GetComponent<ObiRope>();
|
||||
restLength = rope.restLength;
|
||||
}
|
||||
|
||||
public void OnValidate()
|
||||
{
|
||||
// Make sure the range thresholds don't cross:
|
||||
outThreshold = Mathf.Max(inThreshold, outThreshold);
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
// get current and rest lengths:
|
||||
float length = rope.CalculateLength();
|
||||
|
||||
// calculate difference between current length and rest length:
|
||||
float diff = Mathf.Max(0, length - restLength);
|
||||
|
||||
float lengthChange = 0;
|
||||
|
||||
// if the rope has been stretched beyond the reel out threshold, increase its rest length:
|
||||
if (diff > outThreshold)
|
||||
lengthChange = outSpeed * Time.deltaTime;
|
||||
|
||||
// if the rope is not stretched past the reel in threshold, decrease its rest length:
|
||||
if (diff < inThreshold)
|
||||
lengthChange = -inSpeed * Time.deltaTime;
|
||||
|
||||
// make sure not to exceed maxLength:
|
||||
lengthChange -= Mathf.Max(0, restLength + lengthChange - maxLength);
|
||||
|
||||
// set the new rest length:
|
||||
restLength = cursor.ChangeLength(lengthChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Obi/Scripts/RopeAndRod/Utils/ObiRopeReel.cs.meta
Normal file
11
Assets/Obi/Scripts/RopeAndRod/Utils/ObiRopeReel.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4793f08b8350d44db99d1bc98daf625b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user