去掉obi,使用自写绳索

This commit is contained in:
2026-02-23 20:51:03 +08:00
parent cb636f862d
commit 91e2309eeb
2011 changed files with 2593 additions and 190578 deletions

View File

@@ -1,9 +0,0 @@
fileFormatVersion: 2
guid: b8154151b8aa747e3870dae448f70d4b
folderAsset: yes
timeCreated: 1511453393
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,45 +0,0 @@
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Obi{
[System.AttributeUsage(System.AttributeTargets.Field)]
public class ChildrenOnly : MultiPropertyAttribute
{
#if UNITY_EDITOR
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
float height = 0;
SerializedProperty it = property;
int depth = it.depth;
it.NextVisible(true);
do
{
EditorGUI.PropertyField(new Rect(position.x,position.y+height,position.width,EditorGUIUtility.singleLineHeight),it,true);
height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
}while (it.NextVisible(false) && it.depth != depth);
}
internal override float? GetPropertyHeight(SerializedProperty property, GUIContent label)
{
float height = -EditorGUIUtility.standardVerticalSpacing;
SerializedProperty it = property;
int depth = it.depth;
it.NextVisible(true);
do
{
height += EditorGUI.GetPropertyHeight(it, label) + EditorGUIUtility.standardVerticalSpacing;
}while (it.NextVisible(false) && it.depth != depth);
return height;
}
#endif
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 37995b0258e3041208a4b13bd6feb31c
timeCreated: 1511965883
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,26 +0,0 @@
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Obi{
#if UNITY_EDITOR
[System.AttributeUsage(System.AttributeTargets.Field)]
public class DisplayAs : MultiPropertyAttribute
{
string name;
public DisplayAs(string name)
{
this.name = name;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.PropertyField(position,property,new GUIContent(name),true);
}
}
#endif
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: dd2e6690a4e514f0b93596b416ea6e1a
timeCreated: 1515069828
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,25 +0,0 @@
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Obi{
[System.AttributeUsage(System.AttributeTargets.Field)]
public class Indent : MultiPropertyAttribute
{
#if UNITY_EDITOR
internal override void OnPreGUI(Rect position, SerializedProperty property)
{
EditorGUI.indentLevel++;
}
internal override void OnPostGUI(Rect position, SerializedProperty property)
{
EditorGUI.indentLevel--;
}
#endif
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: a02d36b0684b3461fad08bed56e9798c
timeCreated: 1511529530
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,56 +0,0 @@
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
using System.Reflection;
namespace Obi{
[System.AttributeUsage(System.AttributeTargets.Field)]
public class InspectorButtonAttribute : PropertyAttribute
{
public static float kDefaultButtonWidth = 80;
public readonly string MethodName;
private float _buttonWidth = kDefaultButtonWidth;
public float ButtonWidth
{
get { return _buttonWidth; }
set { _buttonWidth = value; }
}
public InspectorButtonAttribute(string MethodName)
{
this.MethodName = MethodName;
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(InspectorButtonAttribute))]
public class InspectorButtonPropertyDrawer : PropertyDrawer
{
private MethodInfo _eventMethodInfo = null;
public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
{
InspectorButtonAttribute inspectorButtonAttribute = (InspectorButtonAttribute)attribute;
Rect buttonRect = new Rect(position.x + (position.width - inspectorButtonAttribute.ButtonWidth) * 0.5f, position.y, inspectorButtonAttribute.ButtonWidth, position.height);
if (GUI.Button(buttonRect, label.text))
{
System.Type eventOwnerType = prop.serializedObject.targetObject.GetType();
string eventName = inspectorButtonAttribute.MethodName;
if (_eventMethodInfo == null)
_eventMethodInfo = eventOwnerType.GetMethod(eventName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (_eventMethodInfo != null)
_eventMethodInfo.Invoke(prop.serializedObject.targetObject, null);
else
Debug.LogWarning(string.Format("InspectorButton: Unable to find method {0} in {1}", eventName, eventOwnerType));
}
}
}
#endif
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: bada34fec41c44b4b90af1fe27ca7a95
timeCreated: 1440029519
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,21 +0,0 @@
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Obi{
[AttributeUsage(AttributeTargets.Field)]
public class LayerField : MultiPropertyAttribute
{
#if UNITY_EDITOR
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
property.intValue = EditorGUI.LayerField(position, label, property.intValue);
}
#endif
}
}

View File

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

View File

@@ -1,41 +0,0 @@
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Obi{
[System.AttributeUsage(System.AttributeTargets.Field)]
public class MinMaxAttribute : MultiPropertyAttribute
{
float min;
float max;
public MinMaxAttribute(float min, float max)
{
this.min = min;
this.max = max;
}
#if UNITY_EDITOR
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (property.propertyType == SerializedPropertyType.Vector2){
float minValue = property.vector2Value.x;
float maxValue = property.vector2Value.y;
EditorGUI.MinMaxSlider(position, label, ref minValue, ref maxValue, min, max);
var vec = Vector2.zero;
vec.x = minValue;
vec.y = maxValue;
property.vector2Value = vec;
}else{
EditorGUI.LabelField(position, label.text, "Use MinMaxAttribute with Vector2.");
}
}
#endif
}
}

View File

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

View File

@@ -1,29 +0,0 @@
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Obi{
[System.AttributeUsage(System.AttributeTargets.Field)]
public class MultiDelayed : MultiPropertyAttribute
{
#if UNITY_EDITOR
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// Now draw the property as a Slider or an IntSlider based on whether it's a float or integer.
if (property.propertyType == SerializedPropertyType.Float)
EditorGUI.DelayedFloatField(position, property, label);
else if (property.propertyType == SerializedPropertyType.Integer)
EditorGUI.DelayedIntField(position, property, label);
else if (property.propertyType == SerializedPropertyType.String)
EditorGUI.DelayedTextField(position, property, label);
else
EditorGUI.LabelField(position, label.text, "Use MultiRange with float or int.");
}
#endif
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 17d0e7e43f7f844aba84497d6385c920
timeCreated: 1511969575
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,97 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Obi{
[System.AttributeUsage(System.AttributeTargets.Field)]
public abstract class MultiPropertyAttribute : PropertyAttribute
{
#if UNITY_EDITOR
public IOrderedEnumerable<object> stored = null;
public virtual void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.PropertyField(position,property,label,true);
}
internal virtual void OnPreGUI(Rect position, SerializedProperty property){}
internal virtual void OnPostGUI(Rect position, SerializedProperty property){}
internal virtual bool IsVisible(SerializedProperty property){return true;}
internal virtual float? GetPropertyHeight( SerializedProperty property, GUIContent label){return null;}
#endif
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(MultiPropertyAttribute),true)]
public class MultiPropertyDrawer : PropertyDrawer
{
private MultiPropertyAttribute RetrieveAttributes()
{
MultiPropertyAttribute mAttribute = attribute as MultiPropertyAttribute;
// Get the attribute list, sorted by "order".
if (mAttribute.stored == null)
{
mAttribute.stored = fieldInfo.GetCustomAttributes(typeof(MultiPropertyAttribute), false).OrderBy(s => ((PropertyAttribute)s).order);
}
return mAttribute;
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
MultiPropertyAttribute mAttribute = RetrieveAttributes();
// If the attribute is invisible, regain the standard vertical spacing.
foreach (MultiPropertyAttribute attr in mAttribute.stored)
if (!attr.IsVisible(property))
return -EditorGUIUtility.standardVerticalSpacing;
// In case no attribute returns a modified height, return the property's default one:
float height = EditorGUI.GetPropertyHeight(property, label, true);
//base.GetPropertyHeight(property, label);
// Check if any of the attributes wants to modify height:
foreach (object atr in mAttribute.stored)
{
if (atr as MultiPropertyAttribute != null)
{
var tempheight = ((MultiPropertyAttribute)atr).GetPropertyHeight(property, label);
if (tempheight.HasValue)
{
height = tempheight.Value;
break;
}
}
}
return height;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
MultiPropertyAttribute mAttribute = RetrieveAttributes();
// Calls to IsVisible. If it returns false for any attribute, the property will not be rendered.
foreach (MultiPropertyAttribute attr in mAttribute.stored)
if (!attr.IsVisible(property)) return;
// Calls to OnPreRender before the last attribute draws the UI.
foreach (MultiPropertyAttribute attr in mAttribute.stored)
attr.OnPreGUI(position,property);
// The last attribute is in charge of actually drawing something:
((MultiPropertyAttribute)mAttribute.stored.Last()).OnGUI(position,property,label);
// Calls to OnPostRender after the last attribute draws the UI. These are called in inverse order.
foreach (MultiPropertyAttribute attr in mAttribute.stored.Reverse())
attr.OnPostGUI(position,property);
}
}
#endif
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 71f4de68ec5de40edbf3e4f24c49ba18
timeCreated: 1511952779
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,34 +0,0 @@
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Obi{
[System.AttributeUsage(System.AttributeTargets.Field)]
public class MultiRange : MultiPropertyAttribute
{
float min;
float max;
public MultiRange(float min, float max)
{
this.min = min;
this.max = max;
}
#if UNITY_EDITOR
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// Now draw the property as a Slider or an IntSlider based on whether it's a float or integer.
if (property.propertyType == SerializedPropertyType.Float)
EditorGUI.Slider(position, property, min, max, label);
else if (property.propertyType == SerializedPropertyType.Integer)
EditorGUI.IntSlider(position, property, (int)min, (int)max, label);
else
EditorGUI.LabelField(position, label.text, "Use MultiRange with float or int.");
}
#endif
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: ab2178abf0a6343e19742febdd9784e3
timeCreated: 1511954360
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,168 +0,0 @@
using System;
using System.Reflection;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Obi{
[System.AttributeUsage(System.AttributeTargets.Field)]
public class SerializeProperty : PropertyAttribute
{
public string PropertyName { get; private set; }
public SerializeProperty(string propertyName)
{
PropertyName = propertyName;
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(SerializeProperty))]
public class SerializePropertyAttributeDrawer : PropertyDrawer
{
private PropertyInfo propertyFieldInfo = null;
private object target = null;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (target == null)
target = GetSource(property);
// Find the property field using reflection, in order to get access to its getter/setter.
if (propertyFieldInfo == null)
propertyFieldInfo = target.GetType().GetProperty(((SerializeProperty)attribute).PropertyName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (propertyFieldInfo != null)
{
// Retrieve the value using the property getter:
object value = propertyFieldInfo.GetValue(target,null);
// Draw the property:
EditorGUI.BeginProperty(position,label,property);
EditorGUI.BeginChangeCheck();
value = DrawProperty(position,property.propertyType,propertyFieldInfo.PropertyType,value,label);
// If any changes were detected, call the property setter:
if (EditorGUI.EndChangeCheck() && propertyFieldInfo != null)
{
foreach (var t in property.serializedObject.targetObjects)
{
// Record object state for undo:
Undo.RecordObject(t, "Inspector");
// Call property setter:
propertyFieldInfo.SetValue(t, value, null);
SetPropertyValue(property, propertyFieldInfo.PropertyType, value);
// Record prefab modification:
PrefabUtility.RecordPrefabInstancePropertyModifications(t);
}
}
EditorGUI.EndProperty();
}else
{
EditorGUI.LabelField(position,"Error: could not retrieve property.");
}
}
private object GetSource(SerializedProperty property)
{
object trgt = property.serializedObject.targetObject;
string[] data = property.propertyPath.Split('.');
if (data.Length == 1)
return trgt;
else{
for (int i = 0; i < data.Length-1;++i){
trgt = trgt.GetType().GetField(data[i]).GetValue(trgt);
}
}
return trgt;
}
private object DrawProperty(Rect position, SerializedPropertyType propertyType, Type type, object value, GUIContent label)
{
switch (propertyType)
{
case SerializedPropertyType.Integer:
return EditorGUI.IntField(position,label,(int)value);
case SerializedPropertyType.Boolean:
return EditorGUI.Toggle(position,label,(bool)value);
case SerializedPropertyType.Float:
return EditorGUI.FloatField(position,label,(float)value);
case SerializedPropertyType.String:
return EditorGUI.TextField(position,label,(string)value);
case SerializedPropertyType.Color:
return EditorGUI.ColorField(position,label,(Color)value);
case SerializedPropertyType.ObjectReference:
return EditorGUI.ObjectField(position,label,(UnityEngine.Object)value,type,true);
case SerializedPropertyType.ExposedReference:
return EditorGUI.ObjectField(position,label,(UnityEngine.Object)value,type,true);
case SerializedPropertyType.LayerMask:
return EditorGUI.LayerField(position,label,(int)value);
case SerializedPropertyType.Enum:
return EditorGUI.EnumPopup(position,label,(Enum)value);
case SerializedPropertyType.Vector2:
return EditorGUI.Vector2Field(position,label,(Vector2)value);
case SerializedPropertyType.Vector3:
return EditorGUI.Vector3Field(position,label,(Vector3)value);
case SerializedPropertyType.Vector4:
return EditorGUI.Vector4Field(position,label,(Vector4)value);
case SerializedPropertyType.Rect:
return EditorGUI.RectField(position,label,(Rect)value);
case SerializedPropertyType.AnimationCurve:
return EditorGUI.CurveField(position,label,(AnimationCurve)value);
case SerializedPropertyType.Bounds:
return EditorGUI.BoundsField(position,label,(Bounds)value);
default:
throw new NotImplementedException("Unimplemented propertyType "+propertyType+".");
}
}
private void SetPropertyValue(SerializedProperty property, Type type, object value)
{
switch (property.propertyType)
{
case SerializedPropertyType.Integer:
property.intValue = (int)value; break;
case SerializedPropertyType.Boolean:
property.boolValue = (bool)value; break;
case SerializedPropertyType.Float:
property.floatValue = (float)value; break;
case SerializedPropertyType.String:
property.stringValue = (string)value; break;
case SerializedPropertyType.Color:
property.colorValue = (Color)value; break;
case SerializedPropertyType.ObjectReference:
property.objectReferenceValue = (UnityEngine.Object)value; break;
case SerializedPropertyType.ExposedReference:
property.exposedReferenceValue = (UnityEngine.Object)value; break;
case SerializedPropertyType.LayerMask:
property.intValue = (int)value; break;
case SerializedPropertyType.Enum:
property.enumValueIndex = (int)value; break;
case SerializedPropertyType.Vector2:
property.vector2Value = (Vector2)value; break;
case SerializedPropertyType.Vector3:
property.vector3Value = (Vector3)value; break;
case SerializedPropertyType.Vector4:
property.vector4Value = (Vector4)value; break;
case SerializedPropertyType.Rect:
property.rectValue = (Rect)value; break;
case SerializedPropertyType.AnimationCurve:
property.animationCurveValue = (AnimationCurve)value; break;
case SerializedPropertyType.Bounds:
property.boundsValue = (Bounds)value; break;
default:
throw new NotImplementedException("Unimplemented propertyType " + property.propertyType + ".");
}
}
}
#endif
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 9b22b3eff389444b1b4ab3bc2d6402b6
timeCreated: 1511456560
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,63 +0,0 @@
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
using System.Reflection;
namespace Obi{
[System.AttributeUsage(System.AttributeTargets.Field)]
public class VisibleIf : MultiPropertyAttribute
{
public string MethodName { get; private set; }
public bool Negate {get; private set;}
private MethodInfo eventMethodInfo = null;
private FieldInfo fieldInfo = null;
private PropertyInfo propertyInfo = null;
public VisibleIf(string methodName, bool negate = false)
{
this.MethodName = methodName;
this.Negate = negate;
}
#if UNITY_EDITOR
internal override bool IsVisible(SerializedProperty property)
{
return Visibility(property) == !Negate;
}
private bool Visibility(SerializedProperty property)
{
System.Type eventOwnerType = property.serializedObject.targetObject.GetType();
string eventName = MethodName;
// Try finding a method with the name provided:
if (eventMethodInfo == null)
eventMethodInfo = eventOwnerType.GetMethod(eventName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
// If we could not find a method with that name, look for a field:
if (eventMethodInfo == null && fieldInfo == null)
fieldInfo = eventOwnerType.GetField(eventName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
// or maybe a property
if (eventMethodInfo == null && fieldInfo == null && propertyInfo == null)
propertyInfo = eventOwnerType.GetProperty(eventName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (eventMethodInfo != null)
return (bool)eventMethodInfo.Invoke(property.serializedObject.targetObject, null);
else if (fieldInfo != null)
return (bool)fieldInfo.GetValue(property.serializedObject.targetObject);
else if (propertyInfo != null)
return (bool)propertyInfo.GetValue(property.serializedObject.targetObject);
else
Debug.LogWarning(string.Format("VisibleIf: Unable to find method, field or property {0} in {1}", eventName, eventOwnerType));
return true;
}
#endif
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: e52da649989a94da8b1a5d1e1fe5ff8a
timeCreated: 1511456085
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,9 +0,0 @@
fileFormatVersion: 2
guid: 232dbc8dfe1624cc3ac35594884d0edd
folderAsset: yes
timeCreated: 1438097540
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,130 +0,0 @@
using UnityEngine;
using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
namespace Obi{
/**
* Implementation of asynchronous jobs that can return data, throw exceptions, and have a duration threshold
* below which they are run synchronously.
*/
public class CoroutineJob{
public class ProgressInfo{
public string userReadableInfo;
public float progress;
public ProgressInfo(string userReadableInfo,float progress){
this.userReadableInfo = userReadableInfo;
this.progress = progress;
}
}
public object Result {
get{
if(e != null){
throw e;
}
return result;
}
}
public bool IsDone{
get{
return isDone;
}
}
public bool RaisedException{
get{
return raisedException;
}
}
private object result;
private bool isDone;
private bool raisedException;
private bool stop;
private Exception e;
public int asyncThreshold = 250; //Time in milliseconds that must pass before job switches to async mode. By default, the job is asynchronous from the start.
private void Init(){
isDone = false;
raisedException = false;
stop = false;
result = null;
}
/**
* Runs the provided coroutine in a completely syncrhonous way, just like it would if it wasn't a coroutine, and
* returns a list of all coroutine results, in the order they were yielded. Will immediately rethrow any exceptions thrown by the coroutine.
*/
public static object RunSynchronously(IEnumerator coroutine){
List<object> results = new List<object>();
if (coroutine == null){
return results;
}
try{
while(coroutine.MoveNext()){
results.Add(coroutine.Current);
}
}catch(Exception e){
throw e;
}
return results;
}
public IEnumerator Start(IEnumerator coroutine){
Init();
if (coroutine == null){
isDone = true;
yield break;
}
Stopwatch sw = new Stopwatch();
sw.Start();
while(!stop){
try{
if(!coroutine.MoveNext()){
isDone = true;
sw.Stop();
yield break;
}
}
catch(Exception e){
this.e = e;
raisedException = true;
UnityEngine.Debug.LogException(e);
isDone = true;
sw.Stop();
yield break;
}
result = coroutine.Current;
//If too much time has passed sine job start, switch to async mode:
if (sw.ElapsedMilliseconds > asyncThreshold){
yield return result;
}
}
}
public void Stop(){
stop = true;
}
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: b34adb10b4f264b629f464bfc872d515
timeCreated: 1438097545
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,36 +0,0 @@
using UnityEngine;
#if (UNITY_EDITOR)
using UnityEditor;
#endif
using System.Collections;
namespace Obi
{
public class EditorCoroutine
{
public static bool ShowCoroutineProgressBar(string title, IEnumerator coroutine)
{
bool cancelled = false;
#if (UNITY_EDITOR)
if (coroutine != null){
while (coroutine.MoveNext() && !cancelled)
{
var progressInfo = coroutine.Current as CoroutineJob.ProgressInfo;
cancelled |= EditorUtility.DisplayCancelableProgressBar(title, progressInfo.userReadableInfo, progressInfo.progress);
}
// once finished, set coroutine to null and clear progress bar.
coroutine = null;
EditorUtility.ClearProgressBar();
}
#endif
return cancelled;
}
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 65c4fa737e0dc4ac8acb314d96b75115
timeCreated: 1440488659
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,9 +0,0 @@
fileFormatVersion: 2
guid: 57e51b62adcc84dc19a301be9ebf0e51
folderAsset: yes
timeCreated: 1480348631
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,137 +0,0 @@
using UnityEngine;
namespace Obi
{
[ExecuteInEditMode]
[RequireComponent(typeof(ObiCollider))]
public class ObiForceZone : MonoBehaviour
{
[SerializeProperty("sourceCollider")]
[SerializeField] private ObiCollider m_SourceCollider;
protected ObiForceZoneHandle forcezoneHandle;
/// <summary>
/// The ObiCollider this ObiForceZone should affect.
/// </summary>
/// This is automatically set when you first create the ObiForceZone component, but you can override it afterwards.
public ObiCollider SourceCollider
{
set
{
if (value != null && value.gameObject != this.gameObject)
{
Debug.LogError("The ObiCollider component must reside in the same GameObject as ObiForceZone.");
return;
}
RemoveCollider();
m_SourceCollider = value;
AddCollider();
}
get { return m_SourceCollider; }
}
public ObiForceZoneHandle Handle
{
get
{
// don't check forcezoneHandle.isValid:
// CreateForceZone may defer creation, so we get a non-null, but invalid handle.
// If calling handle again right away before it becomes valid, it will call CreateForceZone again and create a second handle to the same zone.
if (forcezoneHandle == null)
{
var world = ObiColliderWorld.GetInstance();
// create the material:
forcezoneHandle = world.CreateForceZone();
forcezoneHandle.owner = this;
}
return forcezoneHandle;
}
}
public ForceZone.ZoneType type;
public ForceZone.ForceMode mode;
public float intensity;
[Header("Damping")]
public ForceZone.DampingDirection dampingDir;
public float damping = 0;
[Header("Falloff")]
public float minDistance;
public float maxDistance;
[Min(0)]
public float falloffPower = 1;
[Header("Tint")]
public Color color = Color.clear;
[Header("Pulse")]
public float pulseIntensity;
public float pulseFrequency;
public float pulseSeed;
protected float intensityVariation;
public void OnEnable()
{
forcezoneHandle = ObiColliderWorld.GetInstance().CreateForceZone();
forcezoneHandle.owner = this;
FindSourceCollider();
}
public void OnDisable()
{
RemoveCollider();
ObiColliderWorld.GetInstance().DestroyForceZone(forcezoneHandle);
}
private void FindSourceCollider()
{
if (SourceCollider == null)
SourceCollider = GetComponent<ObiCollider>();
else
AddCollider();
}
private void AddCollider()
{
if (m_SourceCollider != null)
m_SourceCollider.ForceZone = this;
}
private void RemoveCollider()
{
if (m_SourceCollider != null)
m_SourceCollider.ForceZone = null;
}
public virtual void UpdateIfNeeded()
{
if (!Handle.isValid)
return;
var fc = ObiColliderWorld.GetInstance().forceZones[Handle.index];
fc.type = type;
fc.mode = mode;
fc.intensity = intensity + intensityVariation;
fc.minDistance = minDistance;
fc.maxDistance = maxDistance;
fc.falloffPower = falloffPower;
fc.damping = damping;
fc.dampingDir = dampingDir;
fc.color = color;
ObiColliderWorld.GetInstance().forceZones[Handle.index] = fc;
}
public void Update()
{
if (Application.isPlaying)
intensityVariation = Mathf.PerlinNoise(Time.time * pulseFrequency, pulseSeed) * pulseIntensity;
}
}
}

View File

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

View File

@@ -1,151 +0,0 @@
using UnityEngine;
using UnityEngine.Events;
using Unity.Collections;
using System;
using System.Collections.Generic;
namespace Obi
{
[RequireComponent(typeof(ObiSolver))]
public class ObiContactEventDispatcher : MonoBehaviour
{
private ObiSolver solver;
private Oni.Contact[] prevData;
private int prevCount;
private ContactComparer comparer;
private class ContactComparer : IComparer<Oni.Contact>
{
ObiSolver solver;
public ContactComparer(ObiSolver solver)
{
this.solver = solver;
}
public int Compare(Oni.Contact x, Oni.Contact y)
{
return CompareByRef(x, y, solver);
}
}
private static int CompareByRef(Oni.Contact a, Oni.Contact b, ObiSolver solver)
{
if (a.bodyB == b.bodyB)
{
int hashA = solver.particleToActor[a.bodyA].actor.GetInstanceID();
int hashB = solver.particleToActor[b.bodyA].actor.GetInstanceID();
return hashA.CompareTo(hashB);
}
return a.bodyB.CompareTo(b.bodyB);
}
[System.Serializable]
public class ContactCallback : UnityEvent<ObiSolver, Oni.Contact> { }
public float distanceThreshold = 0.01f;
public ContactCallback onContactEnter = new ContactCallback();
public ContactCallback onContactStay = new ContactCallback();
public ContactCallback onContactExit = new ContactCallback();
void Awake()
{
solver = GetComponent<ObiSolver>();
comparer = new ContactComparer(solver);
prevData = new Oni.Contact[0];
}
void OnEnable()
{
solver.OnCollision += Solver_OnCollision;
}
void OnDisable()
{
solver.OnCollision -= Solver_OnCollision;
}
private int FilterOutDistantContacts(ObiNativeContactList data, int count)
{
int filteredCount = count;
// simply iterate trough all contacts,
// moving the ones above the threshold to the end of the array:
for (int i = count - 1; i >= 0; --i)
if (data[i].distance > distanceThreshold)
data.Swap(i, --filteredCount);
return filteredCount;
}
private int RemoveDuplicates(ObiNativeContactList data, int count)
{
if (count == 0)
return 0;
// assuming the array is sorted, iterate trough the array
// replacing duplicates by the first contact that's different:
int i = 0, r = 0;
while (++i != count)
if (CompareByRef(data[i], data[r], solver) != 0 && ++r != i)
data[r] = data[i];
return ++r;
}
private void InvokeCallbacks(ObiNativeContactList data, int count)
{
int a = 0, b = 0;
int lengthA = count, lengthB = prevCount;
// while we haven't reached the end of either array:
while (a < lengthA && b < lengthB)
{
// compare both contacts:
int compare = CompareByRef(data[a], prevData[b], solver);
// call the appropiate event depending on the comparison result:
if (compare < 0)
onContactEnter.Invoke(solver, data[a++]);
else if (compare > 0)
onContactExit.Invoke(solver, prevData[b++]);
else
{
onContactStay.Invoke(solver, data[a++]); b++;
}
}
// finish iterating trough both lists:
while (a < lengthA)
onContactEnter.Invoke(solver, data[a++]);
while (b < lengthB)
onContactExit.Invoke(solver, prevData[b++]);
}
void Solver_OnCollision(object sender, ObiNativeContactList contacts)
{
// skip all contacts above the distance threshold by moving them to the end of the array:
int filteredCount = FilterOutDistantContacts(contacts, contacts.count);
// sort the remaining contacts by collider, then by actor:
contacts.AsNativeArray().Slice(0,filteredCount).Sort(comparer);
// remove duplicates:
filteredCount = RemoveDuplicates(contacts, filteredCount);
// zip trough the current and previous contact lists once, invoking events when appropiate.
InvokeCallbacks(contacts, filteredCount);
// store current contact list/count for next frame.
// could get better performance by double buffering instead of copying:
if (filteredCount > prevData.Length)
Array.Resize(ref prevData, filteredCount);
contacts.CopyTo(prevData, 0, filteredCount);
prevCount = filteredCount;
}
}
}

View File

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

View File

@@ -1,178 +0,0 @@
using UnityEngine;
using System.Collections.Generic;
using Obi;
/**
* Sample component that makes a collider "grab" any particle it touches (regardless of which Actor it belongs to).
*/
[RequireComponent(typeof(ObiCollider))]
public class ObiContactGrabber : MonoBehaviour
{
public ObiSolver[] solvers = { };
public bool grabbed
{
get { return grabbedActors.Count > 0; }
}
/**
* Helper class that stores the index of a particle in the solver, its position in the grabber's local space, and its inverse mass previous to being grabbed.
* This makes it easy to tell if a particle has been grabbed, update its position while grabbing, and restore its mass after being released.
*/
private class GrabbedParticle : IEqualityComparer<GrabbedParticle>
{
public int index;
public float invMass;
public Vector3 localPosition;
public ObiSolver solver;
public GrabbedParticle(ObiSolver solver, int index, float invMass)
{
this.solver = solver;
this.index = index;
this.invMass = invMass;
}
public bool Equals(GrabbedParticle x, GrabbedParticle y)
{
return x.index == y.index;
}
public int GetHashCode(GrabbedParticle obj)
{
return index;
}
}
private Dictionary<ObiSolver, ObiNativeContactList> collisionEvents = new Dictionary<ObiSolver, ObiNativeContactList>(); /**< store the current collision event*/
private ObiCollider localCollider; /**< the collider on this gameObject.*/
private HashSet<GrabbedParticle> grabbedParticles = new HashSet<GrabbedParticle>(); /**< set to store all currently grabbed particles.*/
private HashSet<ObiActor> grabbedActors = new HashSet<ObiActor>(); /**< set of softbodies grabbed during this step.*/
private void Awake()
{
localCollider = GetComponent<ObiCollider>();
}
private void OnEnable()
{
if (solvers != null)
foreach (ObiSolver solver in solvers)
solver.OnCollision += Solver_OnCollision;
}
private void OnDisable()
{
if (solvers != null)
foreach (ObiSolver solver in solvers)
solver.OnCollision -= Solver_OnCollision;
}
private void Solver_OnCollision(object sender, ObiNativeContactList e)
{
collisionEvents[(ObiSolver)sender] = e;
}
private void UpdateParticleProperties()
{
// Update rest shape matching of all grabbed softbodies:
foreach (ObiActor actor in grabbedActors)
{
actor.UpdateParticleProperties();
}
}
/**
* Creates and stores a GrabbedParticle from the particle at the given index.
* Returns true if we sucessfully grabbed a particle, false if the particle was already grabbed.
*/
private bool GrabParticle(ObiSolver solver, int index)
{
GrabbedParticle p = new GrabbedParticle(solver, index, solver.invMasses[index]);
// in case this particle has not been grabbed yet:
if (!grabbedParticles.Contains(p))
{
Matrix4x4 solver2Grabber = transform.worldToLocalMatrix * solver.transform.localToWorldMatrix;
// record the particle's position relative to the grabber, and store it.
p.localPosition = solver2Grabber.MultiplyPoint3x4(solver.positions[index]);
grabbedParticles.Add(p);
// Set inv mass and velocity to zero:
solver.invMasses[index] = 0;
solver.velocities[index] = Vector4.zero;
return true;
}
return false;
}
/**
* Grabs all particles currently touching the grabber.
*/
public void Grab()
{
Release();
var world = ObiColliderWorld.GetInstance();
if (solvers != null && collisionEvents != null)
{
foreach (ObiSolver solver in solvers)
{
ObiNativeContactList collisionEvent;
if (collisionEvents.TryGetValue(solver, out collisionEvent))
{
foreach (Oni.Contact contact in collisionEvent)
{
// this one is an actual collision:
if (contact.distance < 0.01f)
{
var contactCollider = world.colliderHandles[contact.bodyB].owner;
int particleIndex = solver.simplices[contact.bodyA];
// if the current contact references our collider, proceed to grab the particle.
if (contactCollider == localCollider)
{
// try to grab the particle, if not already grabbed.
if (GrabParticle(solver, particleIndex))
grabbedActors.Add(solver.particleToActor[particleIndex].actor);
}
}
}
}
}
}
UpdateParticleProperties();
}
/**
* Releases all currently grabbed particles. This boils down to simply resetting their invMass.
*/
public void Release()
{
// Restore the inverse mass of all grabbed particles, so dynamics affect them.
foreach (GrabbedParticle p in grabbedParticles)
p.solver.invMasses[p.index] = p.invMass;
UpdateParticleProperties();
grabbedActors.Clear();
grabbedParticles.Clear();
}
/**
* Updates the position of the grabbed particles.
*/
private void FixedUpdate()
{
foreach (GrabbedParticle p in grabbedParticles)
{
Matrix4x4 grabber2Solver = p.solver.transform.worldToLocalMatrix * transform.localToWorldMatrix;
p.solver.positions[p.index] = grabber2Solver.MultiplyPoint3x4(p.localPosition);
}
}
}

View File

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

View File

@@ -1,39 +0,0 @@
using UnityEngine;
using System;
namespace Obi
{
[AddComponentMenu("Physics/Obi/Obi Foam Emitter", 1000)]
[ExecuteInEditMode]
[RequireComponent(typeof(ObiActor))]
[DisallowMultipleComponent]
public class ObiFoamEmitter : ObiFoamGenerator
{
public enum ShapeType
{
Cylinder = 0,
Box = 1
}
[Header("Emission shape")]
public ShapeType shape;
public Transform shapeTransform;
public Vector3 shapeSize = Vector3.one;
private float emissionAccumulator = 0;
public int GetParticleNumberToEmit(float deltaTime)
{
emissionAccumulator += foamGenerationRate * deltaTime;
int particles = (int)emissionAccumulator;
emissionAccumulator -= particles;
return particles;
}
public void Reset()
{
emissionAccumulator = 0;
}
}
}

View File

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

View File

@@ -1,101 +0,0 @@
using UnityEngine;
using System;
namespace Obi
{
/**
* Foam generators create diffuse particles in areas where certain conditions meet (high velocity constrasts, high vorticity, low density, high normal values, etc.). These particles
* are then advected trough the fluid velocity field.
*/
[AddComponentMenu("Physics/Obi/Obi Foam Generator", 1000)]
[ExecuteInEditMode]
[RequireComponent(typeof(ObiActor))]
[DisallowMultipleComponent]
public class ObiFoamGenerator : MonoBehaviour, ObiActorRenderer<ObiFoamGenerator>
{
public ObiActor actor { get; private set; }
[Header("Foam spawning")]
public float foamGenerationRate = 100;
public float foamPotential = 50;
[Range(0,1)]
public float foamPotentialDiffusion = 0.95f;
public Vector2 velocityRange = new Vector2(2, 4);
public Vector2 vorticityRange = new Vector2(4, 8);
[Header("Foam properties")]
public Light volumeLight;
public Color color = new Color(1,1,1,0.25f);
public float size = 0.02f;
[Range(0,1)]
public float sizeRandom = 0.2f;
public float lifetime = 5;
[Range(0, 1)]
public float lifetimeRandom = 0.2f;
public float buoyancy = 0.5f;
[Range(0, 1)]
public float drag = 0.5f;
[Range(0, 1)]
public float atmosphericDrag = 0.5f;
[Range(1, 50)]
public float airAging = 2;
[Range(0, 1)]
public float isosurface = 0.02f;
[Header("Density Control (Compute only)")]
[Range(0, 1)]
public float pressure = 1;
[Range(0, 1)]
public float density = 0.3f;
[Range(1, 4)]
public float smoothingRadius = 2.5f;
[Range(0, 1)]
public float viscosity = 0.5f;
[Min(0)]
public float surfaceTension = 2;
public void Awake()
{
actor = GetComponent<ObiActor>();
}
public void OnEnable()
{
((ObiActorRenderer<ObiFoamGenerator>)this).EnableRenderer();
}
public void OnDisable()
{
((ObiActorRenderer<ObiFoamGenerator>)this).DisableRenderer();
}
public void OnValidate()
{
((ObiActorRenderer<ObiFoamGenerator>)this).SetRendererDirty(Oni.RenderingSystemType.FoamParticles);
}
RenderSystem<ObiFoamGenerator> ObiRenderer<ObiFoamGenerator>.CreateRenderSystem(ObiSolver solver)
{
switch (solver.backendType)
{
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
case ObiSolver.BackendType.Burst: return new BurstFoamRenderSystem(solver);
#endif
case ObiSolver.BackendType.Compute:
default:
if (SystemInfo.supportsComputeShaders)
return new ComputeFoamRenderSystem(solver);
return null;
}
}
}
}

View File

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

View File

@@ -1,50 +0,0 @@
using UnityEngine;
using System.Runtime.CompilerServices;
namespace Obi
{
public static class ObiIntegration
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 IntegrateLinear(Vector4 position, Vector4 velocity, float dt)
{
return position + velocity * dt;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 DifferentiateLinear(Vector4 position, Vector4 prevPosition, float dt)
{
return (position - prevPosition) / dt;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Quaternion AngularVelocityToSpinQuaternion(Quaternion rotation, Vector4 angularVelocity, float dt)
{
var delta = new Quaternion(angularVelocity.x,
angularVelocity.y,
angularVelocity.z, 0);
var rot = delta * rotation;
var v = new Vector4(rot.x, rot.y, rot.z, rot.w) * 0.5f * dt;
return new Quaternion(v.x, v.y, v.z, v.w);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Quaternion IntegrateAngular(Quaternion rotation, Vector4 angularVelocity, float dt)
{
var spin = AngularVelocityToSpinQuaternion(rotation, angularVelocity, dt);
rotation.x += spin.x;
rotation.y += spin.y;
rotation.z += spin.z;
rotation.w += spin.w;
return rotation.normalized;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 DifferentiateAngular(Quaternion rotation, Quaternion prevRotation, float dt)
{
var delta = rotation * Quaternion.Inverse(prevRotation);
return new Vector4(delta.x, delta.y, delta.z, 0) * 2.0f / dt;
}
}
}

View File

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

View File

@@ -1,70 +0,0 @@
using System;
using UnityEngine;
namespace Obi
{
[AddComponentMenu("Physics/Obi/Obi Particle Attachment", 820)]
[RequireComponent(typeof(ObiActor))]
[ExecuteInEditMode]
public class ObiParticleAttachment : MonoBehaviour
{
public enum AttachmentType
{
Static,
Dynamic
}
[SerializeField] [HideInInspector] private ObiActor m_Actor;
[SerializeField] [HideInInspector] private Transform m_Target;
[SerializeField] [HideInInspector] private ObiParticleGroup m_ParticleGroup;
[SerializeField] [HideInInspector] private AttachmentType m_AttachmentType = AttachmentType.Static;
[SerializeField] [HideInInspector] private bool m_ConstrainOrientation = false;
[SerializeField] [HideInInspector] private bool m_Projection = false;
[SerializeField] [HideInInspector] private float m_Compliance = 0;
// private variables are serialized during script reloading, to keep their value. Must mark them explicitly as non-serialized.
[NonSerialized] private ObiPinConstraintsBatch pinBatch;
[NonSerialized] private ObiColliderBase attachedCollider;
[NonSerialized] private int attachedColliderHandleIndex;
[NonSerialized] private int[] m_SolverIndices;
[NonSerialized] private Vector3[] m_PositionOffsets = null;
[NonSerialized] private Quaternion[] m_OrientationOffsets = null;
/// <summary>
/// The actor this attachment is added to.
/// </summary>
public ObiActor actor
{
get { return m_Actor; }
}
/// <summary>
/// The target transform that the <see cref="particleGroup"/> should be attached to.
/// </summary>
public Transform target
{
get { return m_Target; }
set
{
if (value != m_Target)
{
m_Target = value;
Bind();
}
}
}
/// <summary>
/// The particle group that should be attached to the <see cref="target"/>.
/// </summary>
public ObiParticleGroup particleGroup
{
get
{
return m_ParticleGroup;
}
set
{

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 4d03c9194b7ab4aaba4dfa5afec22c69
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 528d201bc10084452b24974deb16a423, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,84 +0,0 @@
using System;
using UnityEngine;
namespace Obi
{
[RequireComponent(typeof(LineRenderer))]
[RequireComponent(typeof(ObiParticlePicker))]
public class ObiParticleDragger : MonoBehaviour
{
public float springStiffness = 500;
public float springDamping = 50;
public bool drawSpring = true;
private LineRenderer lineRenderer;
private ObiParticlePicker picker;
private ObiParticlePicker.ParticlePickEventArgs pickArgs;
void OnEnable()
{
lineRenderer = GetComponent<LineRenderer>();
picker = GetComponent<ObiParticlePicker>();
picker.OnParticlePicked.AddListener(Picker_OnParticleDragged);
picker.OnParticleDragged.AddListener(Picker_OnParticleDragged);
picker.OnParticleReleased.AddListener(Picker_OnParticleReleased);
picker.solver.OnSimulationStart += Solver_OnEndSimulation;
}
void OnDisable()
{
picker.solver.OnSimulationStart -= Solver_OnEndSimulation;
picker.OnParticlePicked.RemoveListener(Picker_OnParticleDragged);
picker.OnParticleDragged.RemoveListener(Picker_OnParticleDragged);
picker.OnParticleReleased.RemoveListener(Picker_OnParticleReleased);
lineRenderer.positionCount = 0;
}
private void Solver_OnEndSimulation(ObiSolver solver, float timeToSimulate, float substepTime)
{
if (solver != null && pickArgs != null)
{
// Calculate picking position in solver space:
Vector4 targetPosition = solver.transform.InverseTransformPoint(pickArgs.worldPosition);
// Calculate effective inverse mass:
float invMass = solver.invMasses[pickArgs.particleIndex];
if (invMass > 0)
{
// Calculate and apply spring force:
Vector4 position = solver.positions[pickArgs.particleIndex];
Vector4 velocity = solver.velocities[pickArgs.particleIndex];
solver.externalForces[pickArgs.particleIndex] = ((targetPosition - position) * springStiffness - velocity * springDamping) / invMass;
if (drawSpring)
{
lineRenderer.positionCount = 2;
lineRenderer.SetPosition(0, pickArgs.worldPosition);
lineRenderer.SetPosition(1, solver.transform.TransformPoint(position));
}
else
{
lineRenderer.positionCount = 0;
}
}
}
}
void Picker_OnParticleDragged(ObiParticlePicker.ParticlePickEventArgs e)
{
pickArgs = e;
}
void Picker_OnParticleReleased(ObiParticlePicker.ParticlePickEventArgs e)
{
pickArgs = null;
lineRenderer.positionCount = 0;
}
}
}

View File

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

View File

@@ -1,140 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace Obi
{
public class ObiParticlePicker : MonoBehaviour
{
public class ParticlePickEventArgs : EventArgs
{
public int particleIndex;
public Vector3 worldPosition;
public ParticlePickEventArgs(int particleIndex, Vector3 worldPosition)
{
this.particleIndex = particleIndex;
this.worldPosition = worldPosition;
}
}
[Serializable]
public class ParticlePickUnityEvent : UnityEvent<ParticlePickEventArgs> { }
public ObiSolver solver;
public float radiusScale = 1;
public ParticlePickUnityEvent OnParticlePicked;
public ParticlePickUnityEvent OnParticleHeld;
public ParticlePickUnityEvent OnParticleDragged;
public ParticlePickUnityEvent OnParticleReleased;
private Vector3 lastMousePos = Vector3.zero;
private int pickedParticleIndex = -1;
private float pickedParticleDepth = 0;
void Awake()
{
lastMousePos = Input.mousePosition;
}
void LateUpdate()
{
if (solver != null)
{
// Click:
if (Input.GetMouseButtonDown(0))
{
pickedParticleIndex = -1;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
float closestMu = float.MaxValue;
float closestDistance = float.MaxValue;
Matrix4x4 solver2World = solver.transform.localToWorldMatrix;
// Find the closest particle hit by the ray:
for (int i = 0; i < solver.positions.count; ++i)
{
Vector3 worldPos = solver2World.MultiplyPoint3x4(solver.positions[i]);
float mu;
Vector3 projected = ObiUtils.ProjectPointLine(ray.origin, ray.origin + ray.direction, worldPos, out mu, false);
float distanceToRay = Vector3.SqrMagnitude(worldPos - projected);
// Disregard particles behind the camera:
mu = Mathf.Max(0, mu);
float radius = solver.principalRadii[i][0] * radiusScale;
if (distanceToRay <= radius * radius && distanceToRay < closestDistance && mu < closestMu)
{
closestMu = mu;
closestDistance = distanceToRay;
pickedParticleIndex = i;
}
}
if (pickedParticleIndex >= 0)
{
pickedParticleDepth = Camera.main.transform.InverseTransformVector(solver2World.MultiplyPoint3x4(solver.positions[pickedParticleIndex]) - Camera.main.transform.position).z;
if (OnParticlePicked != null)
{
Vector3 worldPosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pickedParticleDepth));
OnParticlePicked.Invoke(new ParticlePickEventArgs(pickedParticleIndex, worldPosition));
}
}
}
else if (pickedParticleIndex >= 0)
{
// Drag:
Vector3 mouseDelta = Input.mousePosition - lastMousePos;
if (mouseDelta.magnitude > 0.01f && OnParticleDragged != null)
{
Vector3 worldPosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pickedParticleDepth));
OnParticleDragged.Invoke(new ParticlePickEventArgs(pickedParticleIndex, worldPosition));
}
else if (OnParticleHeld != null)
{
Vector3 worldPosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pickedParticleDepth));
OnParticleHeld.Invoke(new ParticlePickEventArgs(pickedParticleIndex, worldPosition));
}
// Release:
if (Input.GetMouseButtonUp(0))
{
if (OnParticleReleased != null)
{
Vector3 worldPosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pickedParticleDepth));
OnParticleReleased.Invoke(new ParticlePickEventArgs(pickedParticleIndex, worldPosition));
}
pickedParticleIndex = -1;
}
}
}
lastMousePos = Input.mousePosition;
}
}
}

View File

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

View File

@@ -1,240 +0,0 @@
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Obi
{
/**
* ObiStitcher will create stitch constraints between 2 actors. All actors must be assigned to the same solver.
* - Add the constraint batch to the solver once all actors have been added.
* - If any of the actors is removed from the solver, remove the stitcher too.
* - Stitch constraints can keep n particles together, respecting their masses.
* - In edit mode, select the actors to be stitched and then select groups of particles and click "stitch". Or, create stitches by closeness.
*/
[ExecuteInEditMode]
public class ObiStitcher : MonoBehaviour
{
[Serializable]
public class Stitch
{
public int particleIndex1;
public int particleIndex2;
public Stitch(int particleIndex1, int particleIndex2)
{
this.particleIndex1 = particleIndex1;
this.particleIndex2 = particleIndex2;
}
}
[SerializeField] [HideInInspector] private List<Stitch> stitches = new List<Stitch>();
[SerializeField] [HideInInspector] private ObiActor actor1 = null; /**< one of the actors used by the stitcher.*/
[SerializeField] [HideInInspector] private ObiActor actor2 = null; /**< the second actor used by the stitcher.*/
[HideInInspector] public ObiNativeIntList particleIndices;
[HideInInspector] public ObiNativeFloatList stiffnesses;
[HideInInspector] public ObiNativeFloatList lambdas;
//private IntPtr batch;
private IStitchConstraintsBatchImpl m_BatchImpl;
private bool inSolver = false;
public ObiActor Actor1
{
set
{
if (actor1 != value)
{
UnregisterActor(actor1);
actor1 = value;
RegisterActor(actor1);
}
}
get { return actor1; }
}
public ObiActor Actor2
{
set
{
if (actor2 != value)
{
UnregisterActor(actor2);
actor2 = value;
RegisterActor(actor2);
}
}
get { return actor2; }
}
public int StitchCount
{
get { return stitches.Count; }
}
public IEnumerable<Stitch> Stitches
{
get { return stitches.AsReadOnly(); }
}
private void RegisterActor(ObiActor actor)
{
if (actor != null)
{
actor.OnBlueprintLoaded += Actor_OnBlueprintLoaded;
actor.OnBlueprintUnloaded += Actor_OnBlueprintUnloaded;
if (actor.solver != null)
Actor_OnBlueprintLoaded(actor, actor.sourceBlueprint);
}
}
private void UnregisterActor(ObiActor actor)
{
if (actor != null)
{
actor.OnBlueprintLoaded -= Actor_OnBlueprintLoaded;
actor.OnBlueprintUnloaded -= Actor_OnBlueprintUnloaded;
if (actor.solver != null)
Actor_OnBlueprintUnloaded(actor, actor.sourceBlueprint);
}
}
public void OnEnable()
{
RegisterActor(actor1);
RegisterActor(actor2);
}
public void OnDisable()
{
UnregisterActor(actor1);
UnregisterActor(actor2);
}
/**
* Adds a new stitch to the stitcher. Note that unlike calling Clear(), AddStitch does not automatically perform a
* PushDataToSolver(). You should manually call it once you're done adding multiple stitches.
* @param index of a particle in the first actor.
* @param index of a particle in the second actor.
* @return constrant index, that can be used to remove it with a call to RemoveStitch.
*/
public int AddStitch(int particle1, int particle2)
{
stitches.Add(new Stitch(particle1, particle2));
return stitches.Count - 1;
}
/**
* Removes. Note that unlike calling Clear(), AddStitch does not automatically perform a
* PushDataToSolver(). You should manually call it once you're done adding multiple stitches.
* @param constraint index.
*/
public void RemoveStitch(int index)
{
if (index >= 0 && index < stitches.Count)
stitches.RemoveAt(index);
}
public void Clear()
{
stitches.Clear();
PushDataToSolver();
}
void Actor_OnBlueprintUnloaded(ObiActor actor, ObiActorBlueprint blueprint)
{
// when any actor is removed from solver, remove stitches.
this.RemoveFromSolver(actor.solver);
}
void Actor_OnBlueprintLoaded(ObiActor actor, ObiActorBlueprint blueprint)
{
// when both actors are in the same solver, add stitches.
if (actor1 != null && actor2 != null && actor1.isLoaded && actor2.isLoaded)
{
if (actor1.solver != actor2.solver)
{
Debug.LogError("ObiStitcher cannot handle actors in different solvers.");
return;
}
AddToSolver(actor1.solver);
}
}
private void AddToSolver(ObiSolver solver)
{
if (!inSolver)
{
inSolver = true;
particleIndices = new ObiNativeIntList();
stiffnesses = new ObiNativeFloatList();
lambdas = new ObiNativeFloatList();
// create a constraint batch (CreateStitchConstraints() in burst returns a singleton):
m_BatchImpl = solver.implementation.CreateConstraintsBatch(Oni.ConstraintType.Stitch) as IStitchConstraintsBatchImpl;
// push current data to solver:
PushDataToSolver();
// enable/disable the batch:
m_BatchImpl.enabled = isActiveAndEnabled;
}
}
private void RemoveFromSolver(ObiSolver solver)
{
// remove the constraint batch from the solver
// (no need to destroy it as its destruction is managed by the solver)
// Oni.RemoveBatch(actor1.solver.OniSolver, batch);
if (inSolver && m_BatchImpl != null)
{
lambdas.Dispose();
particleIndices.Dispose();
stiffnesses.Dispose();
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IStitchConstraintsBatchImpl);
m_BatchImpl.Destroy();
m_BatchImpl = null;
inSolver = false;
}
}
public void PushDataToSolver()
{
if (!inSolver)
return;
// set solver constraint data:
lambdas.Clear();
particleIndices.ResizeUninitialized(stitches.Count * 2);
stiffnesses.ResizeUninitialized(stitches.Count);
lambdas.ResizeUninitialized(stitches.Count);
for (int i = 0; i < stitches.Count; i++)
{
particleIndices[i * 2] = actor1.solverIndices[stitches[i].particleIndex1];
particleIndices[i * 2 + 1] = actor2.solverIndices[stitches[i].particleIndex2];
stiffnesses[i] = 0;
lambdas[i] = 0;
}
m_BatchImpl.SetStitchConstraints(particleIndices, stiffnesses, lambdas, stitches.Count);
}
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: cdace116829344344988718be4fb70ab
timeCreated: 1489589304
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: ec05a2c75bb4a4ce5a3a1baa76b4c8d5, type: 3}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 8ac31071459b040f39f1d86300525ed4
timeCreated: 1435569421
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,48 +0,0 @@
using UnityEngine;
using System.Collections;
namespace Obi
{
public static class ObiVectorMath
{
public static void Cross(Vector3 a, Vector3 b, ref float x, ref float y, ref float z)
{
x = a.y * b.z - a.z * b.y;
y = a.z * b.x - a.x * b.z;
z = a.x * b.y - a.y * b.x;
}
public static void Cross(Vector3 a, Vector3 b, ref Vector3 res)
{
res.x = a.y * b.z - a.z * b.y;
res.y = a.z * b.x - a.x * b.z;
res.z = a.x * b.y - a.y * b.x;
}
public static void Cross(float ax, float ay, float az, float bx, float by, float bz, ref float x, ref float y, ref float z)
{
x = ay * bz - az * by;
y = az * bx - ax * bz;
z = ax * by - ay * bx;
}
/**
* res = b - a
*/
public static void Subtract(Vector3 a, Vector3 b, ref Vector3 res)
{
res.x = b.x - a.x;
res.y = b.y - a.y;
res.z = b.z - a.z;
}
public static void BarycentricInterpolation(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 n1, Vector3 n2, Vector3 n3, Vector3 coords, float height, ref Vector3 res)
{
res.x = coords.x * p1.x + coords.y * p2.x + coords.z * p3.x + (coords.x * n1.x + coords.y * n2.x + coords.z * n3.x) * height;
res.y = coords.x * p1.y + coords.y * p2.y + coords.z * p3.y + (coords.x * n1.y + coords.y * n2.y + coords.z * n3.y) * height;
res.z = coords.x * p1.z + coords.y * p2.z + coords.z * p3.z + (coords.x * n1.z + coords.y * n2.z + coords.z * n3.z) * height;
}
}
}

View File

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

View File

@@ -1,38 +0,0 @@
using UnityEngine;
namespace Obi
{
[RequireComponent(typeof(ObiActor))]
public class SetCategory : MonoBehaviour
{
public int category;
private ObiActor act;
private void Awake()
{
act = GetComponent<ObiActor>();
act.OnBlueprintLoaded += OnLoad;
if (act.isLoaded)
act.SetFilterCategory(category);
}
private void OnDestroy()
{
act.OnBlueprintLoaded -= OnLoad;
}
private void OnValidate()
{
category = Mathf.Clamp(category, ObiUtils.MinCategory, ObiUtils.MaxCategory);
if (act != null && act.isLoaded)
act.SetFilterCategory(category);
}
private void OnLoad(ObiActor actor, ObiActorBlueprint blueprint)
{
actor.SetFilterCategory(category);
}
}
}

View File

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