添加插件

This commit is contained in:
2025-11-10 00:08:26 +08:00
parent 4059c207c0
commit 76f80db694
2814 changed files with 436400 additions and 178 deletions

View File

@@ -0,0 +1,52 @@
using System.Collections.Generic;
using UnityEngine;
namespace Obi
{
[CreateAssetMenu(fileName = "rope section", menuName = "Obi/Rope Section", order = 142)]
public class ObiRopeSection : ScriptableObject
{
[HideInInspector] public List<Vector2> vertices;
public int snapX = 0;
public int snapY = 0;
public int Segments{
get{return vertices.Count-1;}
}
public void OnEnable(){
if (vertices == null){
vertices = new List<Vector2>();
CirclePreset(8);
}
}
public void CirclePreset(int segments){
vertices.Clear();
for (int j = 0; j <= segments; ++j){
float angle = 2 * Mathf.PI / segments * j;
vertices.Add(Mathf.Cos(angle)*Vector2.right + Mathf.Sin(angle)*Vector2.up);
}
}
/**
* Snaps a float value to the nearest multiple of snapInterval.
*/
public static int SnapTo(float val, int snapInterval, int threshold){
int intVal = (int) val;
if (snapInterval <= 0)
return intVal;
int under = Mathf.FloorToInt(val / snapInterval) * snapInterval;
int over = under + snapInterval;
if (intVal - under < threshold) return under;
if (over - intVal < threshold) return over;
return intVal;
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: ee7737c43f5734f87be9e49d1bbfba78
labels:
- ObiRope
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: fdb742a900c8d453ea5ce5027e80ad00, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
using UnityEngine;
using System.Collections;
namespace Obi
{
// Abstracts rope topolgy as a list of elements.
[System.Serializable]
public class ObiStructuralElement
{
public int particle1;
public int particle2;
public float restLength;
public float constraintForce;
public float tearResistance;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2aecff76dda4241c5a0c15349e2419d3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 75e833f2b944640a5934c15fbec8ac00
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5172d3d605ca94f2db0ad73eaecbc4d4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
using UnityEngine;
using System;
using System.Collections;
namespace Obi
{
[Serializable]
public class ObiColorDataChannel : ObiPathDataChannelIdentity<Color>
{
public ObiColorDataChannel() : base(new ObiColorInterpolator3D()) { }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4078c779a63154dddac14f5a1e65a692
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
using System;
namespace Obi
{
[Serializable]
public class ObiPhaseDataChannel : ObiPathDataChannelIdentity<int>
{
public ObiPhaseDataChannel() : base(new ObiConstantInterpolator()) { }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9cfdcf019ed7249799993815bfc3c0bd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
using UnityEngine;
using System;
using System.Collections;
namespace Obi
{
[Serializable]
public class ObiMassDataChannel : ObiPathDataChannelIdentity<float>
{
public ObiMassDataChannel() : base(new ObiCatmullRomInterpolator()) { }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e55025008fa8f4bccae82dbaded0f019
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
using UnityEngine;
using System;
using System.Collections;
namespace Obi
{
[Serializable]
public class ObiNormalDataChannel : ObiPathDataChannelIdentity<Vector3>
{
public ObiNormalDataChannel() : base(new ObiCatmullRomInterpolator3D()) { }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4721087e73d0d422ab48ad62a2fd3d3b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,88 @@
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
namespace Obi
{
public interface IObiPathDataChannel
{
int Count { get; }
bool Dirty { get; }
void Clean();
void RemoveAt(int index);
}
public abstract class ObiPathDataChannel<T,U> : IObiPathDataChannel
{
protected ObiInterpolator<U> interpolator;
protected bool dirty = false;
public List<T> data = new List<T>();
public int Count
{
get { return data.Count; }
}
public bool Dirty
{
get { return dirty; }
}
public void Clean()
{
dirty = false;
}
public ObiPathDataChannel(ObiInterpolator<U> interpolator)
{
this.interpolator = interpolator;
}
public T this[int i]
{
get { return data[i]; }
set { data[i] = value; dirty = true; }
}
public void RemoveAt(int index)
{
data.RemoveAt(index);
dirty = true;
}
public U Evaluate(U v0, U v1, U v2, U v3, float mu)
{
return interpolator.Evaluate(v0, v1, v2, v3, mu);
}
public U EvaluateFirstDerivative(U v0, U v1, U v2, U v3, float mu)
{
return interpolator.EvaluateFirstDerivative(v0, v1, v2, v3, mu);
}
public U EvaluateSecondDerivative(U v0, U v1, U v2, U v3, float mu)
{
return interpolator.EvaluateSecondDerivative(v0, v1, v2, v3, mu);
}
public int GetSpanCount(bool closed)
{
int cps = Count;
if (cps < 2)
return 0;
return closed ? cps : cps - 1;
}
public int GetSpanControlPointAtMu(bool closed, float mu, out float spanMu)
{
int spanCount = GetSpanCount(closed);
spanMu = mu * spanCount;
int i = (mu >= 1f) ? (spanCount - 1) : (int)spanMu;
spanMu -= i;
return i;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 43ab47ea5c62b45248edce6a9d099626
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,94 @@
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
namespace Obi
{
public abstract class ObiPathDataChannelIdentity<T> : ObiPathDataChannel<T,T>
{
public ObiPathDataChannelIdentity(ObiInterpolator<T> interpolator) : base(interpolator)
{
}
public T GetFirstDerivative(int index)
{
int nextCP = (index + 1) % Count;
return EvaluateFirstDerivative(this[index],
this[index],
this[nextCP],
this[nextCP], 0);
}
public T GetSecondDerivative(int index)
{
int nextCP = (index + 1) % Count;
return EvaluateSecondDerivative(this[index],
this[index],
this[nextCP],
this[nextCP], 0);
}
public T GetAtMu(bool closed, float mu)
{
int cps = Count;
if (cps >= 2)
{
float p;
int i = GetSpanControlPointAtMu(closed, mu, out p);
int nextCP = (i + 1) % cps;
return Evaluate(this[i],
this[i],
this[nextCP],
this[nextCP], p);
}
else
{
throw new InvalidOperationException("Cannot get property in path because it has less than 2 control points.");
}
}
public T GetFirstDerivativeAtMu(bool closed, float mu)
{
int cps = Count;
if (cps >= 2)
{
float p;
int i = GetSpanControlPointAtMu(closed, mu, out p);
int nextCP = (i + 1) % cps;
return EvaluateFirstDerivative(this[i],
this[i],
this[nextCP],
this[nextCP], p);
}
else
{
throw new InvalidOperationException("Cannot get derivative in path because it has less than 2 control points.");
}
}
public T GetSecondDerivativeAtMu(bool closed, float mu)
{
int cps = Count;
if (cps >= 2)
{
float p;
int i = GetSpanControlPointAtMu(closed, mu, out p);
int nextCP = (i + 1) % cps;
return EvaluateSecondDerivative(this[i],
this[i],
this[nextCP],
this[nextCP], p);
}
else
{
throw new InvalidOperationException("Cannot get second derivative in path because it has less than 2 control points.");
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 61b5c82c04eb14f1999e94baa1f073bc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,124 @@
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
namespace Obi
{
[Serializable]
public class ObiPointsDataChannel : ObiPathDataChannel<ObiWingedPoint, Vector3>
{
public ObiPointsDataChannel() : base(new ObiCatmullRomInterpolator3D()) { }
public Vector3 GetTangent(int index)
{
int nextCP = (index + 1) % Count;
var wp1 = this[index];
var wp2 = this[nextCP];
return EvaluateFirstDerivative(wp1.position,
wp1.outTangentEndpoint,
wp2.inTangentEndpoint,
wp2.position, 0);
}
public Vector3 GetAcceleration(int index)
{
int nextCP = (index + 1) % Count;
var wp1 = this[index];
var wp2 = this[nextCP];
return EvaluateSecondDerivative(wp1.position,
wp1.outTangentEndpoint,
wp2.inTangentEndpoint,
wp2.position, 0);
}
/**
* Returns spline position at time mu, with 0<=mu<=1 where 0 is the start of the spline
* and 1 is the end.
*/
public Vector3 GetPositionAtMu(bool closed,float mu)
{
int cps = Count;
if (cps >= 2)
{
float p;
int i = GetSpanControlPointAtMu(closed, mu, out p);
int nextCP = (i + 1) % cps;
var wp1 = this[i];
var wp2 = this[nextCP];
return Evaluate(wp1.position,
wp1.outTangentEndpoint,
wp2.inTangentEndpoint,
wp2.position, p);
}
else
{
throw new InvalidOperationException("Cannot get position in path because it has zero control points.");
}
}
/**
* Returns normal tangent vector at time mu, with 0<=mu<=1 where 0 is the start of the spline
* and 1 is the end.
*/
public Vector3 GetTangentAtMu(bool closed, float mu)
{
int cps = Count;
if (cps >= 2)
{
float p;
int i = GetSpanControlPointAtMu(closed, mu, out p);
int nextCP = (i + 1) % cps;
var wp1 = this[i];
var wp2 = this[nextCP];
return EvaluateFirstDerivative(wp1.position,
wp1.outTangentEndpoint,
wp2.inTangentEndpoint,
wp2.position, p);
}
else
{
throw new InvalidOperationException("Cannot get derivative in path because it has less than 2 control points.");
}
}
/**
* Returns acceleration at time mu, with 0<=mu<=1 where 0 is the start of the spline
* and 1 is the end.
*/
public Vector3 GetAccelerationAtMu(bool closed, float mu)
{
int cps = Count;
if (cps >= 2)
{
float p;
int i = GetSpanControlPointAtMu(closed, mu, out p);
int nextCP = (i + 1) % cps;
var wp1 = this[i];
var wp2 = this[nextCP];
return EvaluateSecondDerivative(wp1.position,
wp1.outTangentEndpoint,
wp2.inTangentEndpoint,
wp2.position, p);
}
else
{
throw new InvalidOperationException("Cannot get second derivative in path because it has less than 2 control points.");
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d710ff448ae4e4a6f9351a678af9a8ac
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
using UnityEngine;
using System;
using System.Collections;
namespace Obi
{
[Serializable]
public class ObiRotationalMassDataChannel : ObiPathDataChannelIdentity<float>
{
public ObiRotationalMassDataChannel() : base(new ObiCatmullRomInterpolator()) { }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 28c38822e5a79441a8177689f83644e8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
using UnityEngine;
using System;
using System.Collections;
namespace Obi
{
[Serializable]
public class ObiThicknessDataChannel : ObiPathDataChannelIdentity<float>
{
public ObiThicknessDataChannel() : base(new ObiCatmullRomInterpolator()) { }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b414fbc6ce2db42299dc01619ed4fc97
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e85cc8f3b96cf4b4c9be1e6af0a0a99b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,49 @@
using UnityEngine;
using System.Collections;
namespace Obi
{
public class ObiCatmullRomInterpolator : ObiInterpolator<float>
{
/**
* 1D bezier spline interpolation
*/
public float Evaluate(float y0, float y1, float y2, float y3, float mu)
{
float imu = 1 - mu;
return imu * imu * imu * y0 +
3f * imu * imu * mu * y1 +
3f * imu * mu * mu * y2 +
mu * mu * mu * y3;
}
/**
* 1D catmull rom spline second derivative
*/
public float EvaluateFirstDerivative(float y0, float y1, float y2, float y3, float mu)
{
float imu = 1 - mu;
return 3f * imu * imu * (y1 - y0) +
6f * imu * mu * (y2 - y1) +
3f * mu * mu * (y3 - y2);
}
/**
* 1D catmull rom spline second derivative
*/
public float EvaluateSecondDerivative(float y0, float y1, float y2, float y3, float mu)
{
float imu = 1 - mu;
return 3f * imu * imu * (y1 - y0) +
6f * imu * mu * (y2 - y1) +
3f * mu * mu * (y3 - y2);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 93918aac247384d8289d151d77dc4dc2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,46 @@
using UnityEngine;
using System.Collections;
namespace Obi
{
public class ObiCatmullRomInterpolator3D : ObiInterpolator<Vector3>
{
private ObiCatmullRomInterpolator interpolator = new ObiCatmullRomInterpolator();
/**
* 3D spline interpolation
*/
public Vector3 Evaluate(Vector3 y0, Vector3 y1, Vector3 y2, Vector3 y3, float mu)
{
return new Vector3(interpolator.Evaluate(y0.x, y1.x, y2.x, y3.x, mu),
interpolator.Evaluate(y0.y, y1.y, y2.y, y3.y, mu),
interpolator.Evaluate(y0.z, y1.z, y2.z, y3.z, mu));
}
/**
* 3D spline first derivative
*/
public Vector3 EvaluateFirstDerivative(Vector3 y0, Vector3 y1, Vector3 y2, Vector3 y3, float mu)
{
return new Vector3(interpolator.EvaluateFirstDerivative(y0.x, y1.x, y2.x, y3.x, mu),
interpolator.EvaluateFirstDerivative(y0.y, y1.y, y2.y, y3.y, mu),
interpolator.EvaluateFirstDerivative(y0.z, y1.z, y2.z, y3.z, mu));
}
/**
* 3D spline second derivative
*/
public Vector3 EvaluateSecondDerivative(Vector3 y0, Vector3 y1, Vector3 y2, Vector3 y3, float mu)
{
return new Vector3(interpolator.EvaluateSecondDerivative(y0.x, y1.x, y2.x, y3.x, mu),
interpolator.EvaluateSecondDerivative(y0.y, y1.y, y2.y, y3.y, mu),
interpolator.EvaluateSecondDerivative(y0.z, y1.z, y2.z, y3.z, mu));
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 845dbd641b61b490bb94d745b6879e97
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,49 @@
using UnityEngine;
using System.Collections;
namespace Obi
{
public class ObiColorInterpolator3D : ObiInterpolator<Color>
{
private ObiCatmullRomInterpolator interpolator = new ObiCatmullRomInterpolator();
/**
* 3D spline interpolation
*/
public Color Evaluate(Color y0, Color y1, Color y2, Color y3, float mu)
{
return new Color(interpolator.Evaluate(y0.r, y1.r, y2.r, y3.r, mu),
interpolator.Evaluate(y0.g, y1.g, y2.g, y3.g, mu),
interpolator.Evaluate(y0.b, y1.b, y2.b, y3.b, mu),
interpolator.Evaluate(y0.a, y1.a, y2.a, y3.a, mu));
}
/**
* 3D spline first derivative
*/
public Color EvaluateFirstDerivative(Color y0, Color y1, Color y2, Color y3, float mu)
{
return new Color(interpolator.EvaluateFirstDerivative(y0.r, y1.r, y2.r, y3.r, mu),
interpolator.EvaluateFirstDerivative(y0.g, y1.g, y2.g, y3.g, mu),
interpolator.EvaluateFirstDerivative(y0.b, y1.b, y2.b, y3.b, mu),
interpolator.EvaluateFirstDerivative(y0.a, y1.a, y2.a, y3.a, mu));
}
/**
* 3D spline second derivative
*/
public Color EvaluateSecondDerivative(Color y0, Color y1, Color y2, Color y3, float mu)
{
return new Color(interpolator.EvaluateSecondDerivative(y0.r, y1.r, y2.r, y3.r, mu),
interpolator.EvaluateSecondDerivative(y0.g, y1.g, y2.g, y3.g, mu),
interpolator.EvaluateSecondDerivative(y0.b, y1.b, y2.b, y3.b, mu),
interpolator.EvaluateSecondDerivative(y0.a, y1.a, y2.a, y3.a, mu));
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1c2bda61c040346db8efd82f64c2422e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
using UnityEngine;
using System.Collections;
namespace Obi
{
public class ObiConstantInterpolator : ObiInterpolator<int>
{
/**
* constant interpolator
*/
public int Evaluate(int y0, int y1, int y2, int y3, float mu)
{
return mu < 0.5f ? y1 : y2;
}
/**
* derivative of constant value:
*/
public int EvaluateFirstDerivative(int y0, int y1, int y2, int y3, float mu)
{
return 0;
}
/**
* second derivative of constant value:
*/
public int EvaluateSecondDerivative(int y0, int y1, int y2, int y3, float mu)
{
return 0;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 33f10aef9ed544b14a762a9c6e8bf411
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,13 @@
using UnityEngine;
using System.Collections;
namespace Obi
{
public interface ObiInterpolator<T>
{
T Evaluate(T v0, T v1, T v2, T v3, float mu);
T EvaluateFirstDerivative(T v0, T v1, T v2, T v3, float mu);
T EvaluateSecondDerivative(T v0, T v1, T v2, T v3, float mu);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: af25f2a4d723548bfafa551b6da56d25
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,408 @@
using UnityEngine;
using UnityEngine.Events;
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using UnityEngine.Serialization;
namespace Obi
{
[System.Serializable]
public class PathControlPointEvent : UnityEvent<int>
{
}
[Serializable]
public class ObiPath
{
[HideInInspector] [SerializeField] List<string> m_Names = new List<string>();
[HideInInspector] [SerializeField] public ObiPointsDataChannel m_Points = new ObiPointsDataChannel();
[HideInInspector] [SerializeField] ObiNormalDataChannel m_Normals = new ObiNormalDataChannel();
[HideInInspector] [SerializeField] ObiColorDataChannel m_Colors = new ObiColorDataChannel();
[HideInInspector] [SerializeField] ObiThicknessDataChannel m_Thickness = new ObiThicknessDataChannel();
[HideInInspector] [SerializeField] ObiMassDataChannel m_Masses = new ObiMassDataChannel();
[HideInInspector] [SerializeField] ObiRotationalMassDataChannel m_RotationalMasses = new ObiRotationalMassDataChannel();
[FormerlySerializedAs("m_Phases")]
[HideInInspector] [SerializeField] ObiPhaseDataChannel m_Filters = new ObiPhaseDataChannel();
[HideInInspector] [SerializeField] private bool m_Closed = false;
protected bool dirty = false;
protected const int arcLenghtSamples = 20;
[HideInInspector] [SerializeField] protected List<float> m_ArcLengthTable = new List<float>();
[HideInInspector] [SerializeField] protected float m_TotalSplineLenght = 0.0f;
public UnityEvent OnPathChanged = new UnityEvent();
public PathControlPointEvent OnControlPointAdded = new PathControlPointEvent();
public PathControlPointEvent OnControlPointRemoved = new PathControlPointEvent();
public PathControlPointEvent OnControlPointRenamed = new PathControlPointEvent();
private IEnumerable<IObiPathDataChannel> GetDataChannels()
{
yield return m_Points;
yield return m_Normals;
yield return m_Colors;
yield return m_Thickness;
yield return m_Masses;
yield return m_RotationalMasses;
yield return m_Filters;
}
public ObiPointsDataChannel points { get { return m_Points; }}
public ObiNormalDataChannel normals { get { return m_Normals; } }
public ObiColorDataChannel colors { get { return m_Colors; } }
public ObiThicknessDataChannel thicknesses { get { return m_Thickness; } }
public ObiMassDataChannel masses { get { return m_Masses; } }
public ObiRotationalMassDataChannel rotationalMasses { get { return m_RotationalMasses; } }
public ObiPhaseDataChannel filters { get { return m_Filters; } }
public ReadOnlyCollection<float> ArcLengthTable
{
get { return m_ArcLengthTable.AsReadOnly(); }
}
public float Length
{
get { return m_TotalSplineLenght; }
}
public int ArcLengthSamples
{
get { return arcLenghtSamples; }
}
public int ControlPointCount
{
get { return m_Points.Count;}
}
public bool Closed
{
get { return m_Closed; }
set
{
if (value != m_Closed)
{
m_Closed = value;
dirty = true;
}
}
}
public int GetSpanCount()
{
return m_Points.GetSpanCount(m_Closed);
}
public int GetSpanControlPointForMu(float mu, out float spanMu)
{
return m_Points.GetSpanControlPointAtMu(m_Closed, mu, out spanMu);
}
public int GetClosestControlPointIndex(float mu)
{
float spanMu;
int cp = GetSpanControlPointForMu(mu, out spanMu);
if (spanMu > 0.5f)
return (cp + 1) % ControlPointCount;
else
return cp % ControlPointCount;
}
/**
* Returns the curve parameter (mu) at a certain length of the curve, using linear interpolation
* of the values cached in arcLengthTable.
*/
public float GetMuAtLenght(float length)
{
if (length <= 0) return 0;
if (length >= m_TotalSplineLenght) return 1;
int i;
for (i = 1; i < m_ArcLengthTable.Count; ++i)
{
if (length < m_ArcLengthTable[i]) break;
}
float prevMu = (i - 1) / (float)(m_ArcLengthTable.Count - 1);
float nextMu = i / (float)(m_ArcLengthTable.Count - 1);
float s = (length - m_ArcLengthTable[i - 1]) / (m_ArcLengthTable[i] - m_ArcLengthTable[i - 1]);
return prevMu + (nextMu - prevMu) * s;
}
/**
* Recalculates spline arc lenght in world space using Gauss-Lobatto adaptive integration.
* @param acc minimum accuray desired (eg 0.00001f)
* @param maxevals maximum number of spline evaluations we want to allow per segment.
*/
public float RecalculateLenght(Matrix4x4 referenceFrame, float acc, int maxevals)
{
if (referenceFrame == null)
{
m_TotalSplineLenght = 0;
return 0;
}
m_TotalSplineLenght = 0.0f;
m_ArcLengthTable.Clear();
m_ArcLengthTable.Add(0);
float step = 1 / (float)(arcLenghtSamples + 1);
int controlPoints = ControlPointCount;
if (controlPoints >= 2)
{
int spans = GetSpanCount();
for (int cp = 0; cp < spans; ++cp)
{
int nextCP = (cp + 1) % controlPoints;
var wp1 = m_Points[cp];
var wp2 = m_Points[nextCP];
Vector3 _p = referenceFrame.MultiplyPoint3x4(wp1.position);
Vector3 p = referenceFrame.MultiplyPoint3x4(wp1.outTangentEndpoint);
Vector3 p_ = referenceFrame.MultiplyPoint3x4(wp2.inTangentEndpoint);
Vector3 p__ = referenceFrame.MultiplyPoint3x4(wp2.position);
for (int i = 0; i <= Mathf.Max(1, arcLenghtSamples); ++i)
{
float a = i * step;
float b = (i + 1) * step;
float segmentLength = GaussLobattoIntegrationStep(_p, p, p_, p__, a, b,
m_Points.EvaluateFirstDerivative(_p, p, p_, p__, a).magnitude,
m_Points.EvaluateFirstDerivative(_p, p, p_, p__, b).magnitude, 0, maxevals, acc);
m_TotalSplineLenght += segmentLength;
m_ArcLengthTable.Add(m_TotalSplineLenght);
}
}
}
else
{
Debug.LogWarning("A path needs at least 2 control points to be defined.");
}
return m_TotalSplineLenght;
}
/**
* One step of the adaptive integration method using Gauss-Lobatto quadrature.
* Takes advantage of the fact that the arc lenght of a vector function is equal to the
* integral of the magnitude of first derivative.
*/
private float GaussLobattoIntegrationStep(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4,
float a, float b,
float fa, float fb, int nevals, int maxevals, float acc)
{
if (nevals >= maxevals) return 0;
// Constants used in the algorithm
float alpha = Mathf.Sqrt(2.0f / 3.0f);
float beta = 1.0f / Mathf.Sqrt(5.0f);
// Here the abcissa points and function values for both the 4-point
// and the 7-point rule are calculated (the points at the end of
// interval come from the function call, i.e., fa and fb. Also note
// the 7-point rule re-uses all the points of the 4-point rule.)
float h = (b - a) / 2;
float m = (a + b) / 2;
float mll = m - alpha * h;
float ml = m - beta * h;
float mr = m + beta * h;
float mrr = m + alpha * h;
nevals += 5;
float fmll = m_Points.EvaluateFirstDerivative(p1, p2, p3, p4, mll).magnitude;
float fml = m_Points.EvaluateFirstDerivative(p1, p2, p3, p4, ml).magnitude;
float fm = m_Points.EvaluateFirstDerivative(p1, p2, p3, p4, m).magnitude;
float fmr = m_Points.EvaluateFirstDerivative(p1, p2, p3, p4, mr).magnitude;
float fmrr = m_Points.EvaluateFirstDerivative(p1, p2, p3, p4, mrr).magnitude;
// Both the 4-point and 7-point rule integrals are evaluted
float integral4 = (h / 6) * (fa + fb + 5 * (fml + fmr));
float integral7 = (h / 1470) * (77 * (fa + fb) + 432 * (fmll + fmrr) + 625 * (fml + fmr) + 672 * fm);
// The difference betwen the 4-point and 7-point integrals is the
// estimate of the accuracy
if ((integral4 - integral7) < acc || mll <= a || b <= mrr)
{
if (!(m > a && b > m))
{
Debug.LogError("Spline integration reached an interval with no more machine numbers");
}
return integral7;
}
else
{
return GaussLobattoIntegrationStep(p1, p2, p3, p4, a, mll, fa, fmll, nevals, maxevals, acc)
+ GaussLobattoIntegrationStep(p1, p2, p3, p4, mll, ml, fmll, fml, nevals, maxevals, acc)
+ GaussLobattoIntegrationStep(p1, p2, p3, p4, ml, m, fml, fm, nevals, maxevals, acc)
+ GaussLobattoIntegrationStep(p1, p2, p3, p4, m, mr, fm, fmr, nevals, maxevals, acc)
+ GaussLobattoIntegrationStep(p1, p2, p3, p4, mr, mrr, fmr, fmrr, nevals, maxevals, acc)
+ GaussLobattoIntegrationStep(p1, p2, p3, p4, mrr, b, fmrr, fb, nevals, maxevals, acc);
}
}
public void SetName(int index, string name)
{
m_Names[index] = name;
if (OnControlPointRenamed != null)
OnControlPointRenamed.Invoke(index);
dirty = true;
}
public string GetName(int index)
{
return m_Names[index];
}
public void AddControlPoint(Vector3 position, Vector3 inTangentVector, Vector3 outTangentVector, Vector3 normal, float mass, float rotationalMass, float thickness, int filter, Color color, string name)
{
InsertControlPoint(ControlPointCount, position, inTangentVector, outTangentVector, normal, mass, rotationalMass, thickness, filter, color, name);
}
public void InsertControlPoint(int index, Vector3 position, Vector3 inTangentVector, Vector3 outTangentVector, Vector3 normal, float mass, float rotationalMass, float thickness, int filter, Color color, string name)
{
m_Points.data.Insert(index, new ObiWingedPoint(inTangentVector,position,outTangentVector));
m_Colors.data.Insert(index, color);
m_Normals.data.Insert(index, normal);
m_Thickness.data.Insert(index, thickness);
m_Masses.data.Insert(index, mass);
m_RotationalMasses.data.Insert(index, rotationalMass);
m_Filters.data.Insert(index, filter);
m_Names.Insert(index,name);
if (OnControlPointAdded != null)
OnControlPointAdded.Invoke(index);
dirty = true;
}
public int InsertControlPoint(float mu)
{
int controlPoints = ControlPointCount;
if (controlPoints >= 2)
{
if (!System.Single.IsNaN(mu))
{
float p;
int i = GetSpanControlPointForMu(mu, out p);
int next = (i + 1) % controlPoints;
var wp1 = m_Points[i];
var wp2 = m_Points[next];
Vector3 P0_1 = (1 - p) * wp1.position + p * wp1.outTangentEndpoint;
Vector3 P1_2 = (1 - p) * wp1.outTangentEndpoint + p * wp2.inTangentEndpoint;
Vector3 P2_3 = (1 - p) * wp2.inTangentEndpoint + p * wp2.position;
Vector3 P01_12 = (1 - p) * P0_1 + p * P1_2;
Vector3 P12_23 = (1 - p) * P1_2 + p * P2_3;
Vector3 P0112_1223 = (1 - p) * P01_12 + p * P12_23;
wp1.SetOutTangentEndpoint(P0_1);
wp2.SetInTangentEndpoint(P2_3);
m_Points[i] = wp1;
m_Points[next] = wp2;
Color color = m_Colors.Evaluate(m_Colors[i],
m_Colors[i],
m_Colors[next],
m_Colors[next], p);
Vector3 normal = m_Normals.Evaluate(m_Normals[i],
m_Normals[i],
m_Normals[next],
m_Normals[next], p);
float thickness = m_Thickness.Evaluate(m_Thickness[i],
m_Thickness[i],
m_Thickness[next],
m_Thickness[next], p);
float mass = m_Masses.Evaluate(m_Masses[i],
m_Masses[i],
m_Masses[next],
m_Masses[next], p);
float rotationalMass = m_RotationalMasses.Evaluate(m_RotationalMasses[i],
m_RotationalMasses[i],
m_RotationalMasses[next],
m_RotationalMasses[next], p);
int filter = m_Filters.Evaluate(m_Filters[i],
m_Filters[i],
m_Filters[next],
m_Filters[next], p);
InsertControlPoint(i + 1, P0112_1223, P01_12 - P0112_1223, P12_23 - P0112_1223, normal, mass,rotationalMass, thickness, filter, color, GetName(i));
return i + 1;
}
}
return -1;
}
public void Clear()
{
for (int i = ControlPointCount-1; i >= 0; --i)
RemoveControlPoint(i);
m_TotalSplineLenght = 0.0f;
m_ArcLengthTable.Clear();
m_ArcLengthTable.Add(0);
}
public void RemoveControlPoint(int index)
{
foreach (var channel in GetDataChannels())
channel.RemoveAt(index);
m_Names.RemoveAt(index);
if (OnControlPointRemoved != null)
OnControlPointRemoved.Invoke(index);
dirty = true;
}
public void FlushEvents()
{
bool isDirty = dirty;
foreach (var channel in GetDataChannels())
{
isDirty |= channel.Dirty;
channel.Clean();
}
if (OnPathChanged != null && isDirty)
{
dirty = false;
OnPathChanged.Invoke();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ee1575a4e45ef4a8ebafa0e5e2e51da5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,170 @@
using System;
using UnityEngine;
namespace Obi
{
public struct ObiPathFrame
{
public enum Axis
{
X = 0,
Y = 1,
Z = 2
}
public static ObiPathFrame Identity => new ObiPathFrame(Vector3.zero, Vector3.forward, Vector3.up, Vector3.right, Color.white, 0);
public Vector3 position;
public Vector3 tangent;
public Vector3 normal;
public Vector3 binormal;
public Vector4 color;
public float thickness;
public ObiPathFrame(Vector3 position, Vector3 tangent, Vector3 normal, Vector3 binormal, Vector4 color, float thickness){
this.position = position;
this.normal = normal;
this.tangent = tangent;
this.binormal = binormal;
this.color = color;
this.thickness = thickness;
}
public void Reset()
{
position = Vector3.zero;
tangent = Vector3.forward;
normal = Vector3.up;
binormal = Vector3.right;
color = Color.white;
thickness = 0;
}
public static ObiPathFrame operator +(ObiPathFrame c1, ObiPathFrame c2)
{
return new ObiPathFrame(c1.position + c2.position,c1.tangent + c2.tangent,c1.normal + c2.normal,c1.binormal + c2.binormal,c1.color + c2.color, c1.thickness + c2.thickness);
}
public static ObiPathFrame operator *(float f,ObiPathFrame c)
{
return new ObiPathFrame(c.position * f, c.tangent * f, c.normal * f, c.binormal * f,c.color * f, c.thickness * f);
}
public static void WeightedSum(float w1, float w2, float w3, in ObiPathFrame c1, in ObiPathFrame c2, in ObiPathFrame c3, ref ObiPathFrame sum)
{
sum.position.x = c1.position.x * w1 + c2.position.x * w2 + c3.position.x * w3;
sum.position.y = c1.position.y * w1 + c2.position.y * w2 + c3.position.y * w3;
sum.position.z = c1.position.z * w1 + c2.position.z * w2 + c3.position.z * w3;
sum.tangent.x = c1.tangent.x * w1 + c2.tangent.x * w2 + c3.tangent.x * w3;
sum.tangent.y = c1.tangent.y * w1 + c2.tangent.y * w2 + c3.tangent.y * w3;
sum.tangent.z = c1.tangent.z * w1 + c2.tangent.z * w2 + c3.tangent.z * w3;
sum.normal.x = c1.normal.x * w1 + c2.normal.x * w2 + c3.normal.x * w3;
sum.normal.y = c1.normal.y * w1 + c2.normal.y * w2 + c3.normal.y * w3;
sum.normal.z = c1.normal.z * w1 + c2.normal.z * w2 + c3.normal.z * w3;
sum.binormal.x = c1.binormal.x * w1 + c2.binormal.x * w2 + c3.binormal.x * w3;
sum.binormal.y = c1.binormal.y * w1 + c2.binormal.y * w2 + c3.binormal.y * w3;
sum.binormal.z = c1.binormal.z * w1 + c2.binormal.z * w2 + c3.binormal.z * w3;
sum.color.x = c1.color.x * w1 + c2.color.x * w2 + c3.color.x * w3;
sum.color.y = c1.color.y * w1 + c2.color.y * w2 + c3.color.y * w3;
sum.color.z = c1.color.z * w1 + c2.color.z * w2 + c3.color.z * w3;
sum.color.w = c1.color.w * w1 + c2.color.w * w2 + c3.color.w * w3;
sum.thickness = c1.thickness * w1 + c2.thickness * w2 + c3.thickness * w3;
}
public void SetTwist(float twist)
{
Quaternion twistQ = Quaternion.AngleAxis(twist, tangent);
normal = twistQ * normal;
binormal = twistQ * binormal;
}
public void SetTwistAndTangent(float twist, Vector3 tangent)
{
this.tangent = tangent;
normal = new Vector3(tangent.y, tangent.x, 0).normalized;
binormal = Vector3.Cross(normal, tangent);
Quaternion twistQ = Quaternion.AngleAxis(twist, tangent);
normal = twistQ * normal;
binormal = twistQ * binormal;
}
public void Transport(ObiPathFrame frame, float twist)
{
// Calculate delta rotation:
Quaternion rotQ = Quaternion.FromToRotation(tangent, frame.tangent);
Quaternion twistQ = Quaternion.AngleAxis(twist, frame.tangent);
Quaternion finalQ = twistQ * rotQ;
// Rotate previous frame axes to obtain the new ones:
normal = finalQ * normal;
binormal = finalQ * binormal;
tangent = frame.tangent;
position = frame.position;
thickness = frame.thickness;
color = frame.color;
}
public void Transport(Vector3 newPosition, Vector3 newTangent, float twist)
{
// Calculate delta rotation:
Quaternion rotQ = Quaternion.FromToRotation(tangent, newTangent);
Quaternion twistQ = Quaternion.AngleAxis(twist, newTangent);
Quaternion finalQ = twistQ * rotQ;
// Rotate previous frame axes to obtain the new ones:
normal = finalQ * normal;
binormal = finalQ * binormal;
tangent = newTangent;
position = newPosition;
}
// Transport, hinting the normal.
public void Transport(Vector3 newPosition, Vector3 newTangent, Vector3 newNormal, float twist)
{
normal = Quaternion.AngleAxis(twist, newTangent) * newNormal;
tangent = newTangent;
binormal = Vector3.Cross(normal, tangent);
position = newPosition;
}
public Matrix4x4 ToMatrix(Axis mainAxis)
{
Matrix4x4 basis = new Matrix4x4();
int xo = ((int)mainAxis) % 3 * 4;
int yo = ((int)mainAxis + 1) % 3 * 4;
int zo = ((int)mainAxis + 2) % 3 * 4;
basis[xo] = tangent[0];
basis[xo + 1] = tangent[1];
basis[xo + 2] = tangent[2];
basis[yo] = binormal[0];
basis[yo + 1] = binormal[1];
basis[yo + 2] = binormal[2];
basis[zo] = normal[0];
basis[zo + 1] = normal[1];
basis[zo + 2] = normal[2];
return basis;
}
public void DebugDraw(float size)
{
Debug.DrawRay(position, binormal * size, Color.red);
Debug.DrawRay(position, normal * size, Color.green);
Debug.DrawRay(position, tangent * size, Color.blue);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 237e9ecf813f646fd8502768445f4ab6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,101 @@
using UnityEngine;
using System;
namespace Obi
{
[ExecuteInEditMode]
[RequireComponent(typeof(ObiRopeBase))]
public class ObiPathSmoother : MonoBehaviour, ObiActorRenderer<ObiPathSmoother>
{
[Range(0, 1)]
[Tooltip("Curvature threshold below which the path will be decimated. A value of 0 won't apply any decimation. As you increase the value, decimation will become more aggresive.")]
public float decimation = 0;
[Range(0, 3)]
[Tooltip("Smoothing iterations applied to the path. A smoothing value of 0 won't perform any smoothing at all. Note that smoothing is applied after decimation.")]
public uint smoothing = 0;
[Tooltip("Twist in degrees applied to each sucessive path section.")]
public float twist = 0;
public ObiActor actor { get; private set; }
[HideInInspector] public int indexInSystem = 0;
public float SmoothLength
{
get
{
if (actor.isLoaded)
{
var system = actor.solver.GetRenderSystem<ObiPathSmoother>() as ObiPathSmootherRenderSystem;
if (system != null)
return system.GetSmoothLength(indexInSystem);
}
return 0;
}
}
public float SmoothSections
{
get {
if (actor.isLoaded)
{
var system = actor.solver.GetRenderSystem<ObiPathSmoother>() as ObiPathSmootherRenderSystem;
if (system != null)
return system.GetSmoothFrameCount(indexInSystem);
}
return 0;
}
}
public void OnEnable()
{
actor = GetComponent<ObiActor>();
((ObiActorRenderer<ObiPathSmoother>)this).EnableRenderer();
}
private void OnDisable()
{
((ObiActorRenderer<ObiPathSmoother>)this).DisableRenderer();
}
private void OnValidate()
{
((ObiActorRenderer<ObiPathSmoother>)this).SetRendererDirty(Oni.RenderingSystemType.AllSmoothedRopes);
}
public ObiPathFrame GetSectionAt(float mu)
{
if (actor.isLoaded)
{
var system = actor.solver.GetRenderSystem<ObiPathSmoother>() as ObiPathSmootherRenderSystem;
if (system != null)
return system.GetFrameAt(indexInSystem, mu);
}
return ObiPathFrame.Identity;
}
RenderSystem<ObiPathSmoother> ObiRenderer<ObiPathSmoother>.CreateRenderSystem(ObiSolver solver)
{
switch (solver.backendType)
{
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
case ObiSolver.BackendType.Burst: return new BurstPathSmootherRenderSystem(solver);
#endif
case ObiSolver.BackendType.Compute:
default:
if (SystemInfo.supportsComputeShaders)
return new ComputePathSmootherRenderSystem(solver);
return null;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 958c969cfb16745f192d4d7bd28b7178
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 8791eecf125744cbeadea65319c29d5a, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,100 @@
using UnityEngine;
using System;
using System.Collections;
namespace Obi
{
[Serializable]
public struct ObiWingedPoint
{
public enum TangentMode
{
Aligned,
Mirrored,
Free,
}
public TangentMode tangentMode;
public Vector3 inTangent;
public Vector3 position;
public Vector3 outTangent;
public Vector3 inTangentEndpoint
{
get { return position + inTangent; }
}
public Vector3 outTangentEndpoint
{
get { return position + outTangent; }
}
public ObiWingedPoint(Vector3 inTangent, Vector3 point, Vector3 outTangent)
{
this.tangentMode = TangentMode.Aligned;
this.inTangent = inTangent;
this.position = point;
this.outTangent = outTangent;
}
public void SetInTangentEndpoint(Vector3 value)
{
Vector3 newTangent = value - position;
switch (tangentMode)
{
case TangentMode.Mirrored: outTangent = -newTangent; break;
case TangentMode.Aligned: outTangent = -newTangent.normalized * outTangent.magnitude; break;
}
inTangent = newTangent;
}
public void SetOutTangentEndpoint(Vector3 value)
{
Vector3 newTangent = value - position;
switch (tangentMode)
{
case TangentMode.Mirrored: inTangent = -newTangent; break;
case TangentMode.Aligned: inTangent = -newTangent.normalized * inTangent.magnitude; break;
}
outTangent = newTangent;
}
public void SetInTangent(Vector3 value)
{
Vector3 newTangent = value;
switch (tangentMode)
{
case TangentMode.Mirrored: outTangent = -newTangent; break;
case TangentMode.Aligned: outTangent = -newTangent.normalized * outTangent.magnitude; break;
}
inTangent = newTangent;
}
public void SetOutTangent(Vector3 value)
{
Vector3 newTangent = value;
switch (tangentMode)
{
case TangentMode.Mirrored: inTangent = -newTangent; break;
case TangentMode.Aligned: inTangent = -newTangent.normalized * inTangent.magnitude; break;
}
outTangent = newTangent;
}
public void Transform(Vector3 translation, Quaternion rotation, Vector3 scale)
{
position += translation;
inTangent = rotation * Vector3.Scale(inTangent, scale);
outTangent = rotation * Vector3.Scale(outTangent, scale);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 76ee869b5f2e5440ea0a1c8a1e161cde
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: