去掉obi,使用自写绳索
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8154151b8aa747e3870dae448f70d4b
|
||||
folderAsset: yes
|
||||
timeCreated: 1511453393
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 37995b0258e3041208a4b13bd6feb31c
|
||||
timeCreated: 1511965883
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd2e6690a4e514f0b93596b416ea6e1a
|
||||
timeCreated: 1515069828
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a02d36b0684b3461fad08bed56e9798c
|
||||
timeCreated: 1511529530
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bada34fec41c44b4b90af1fe27ca7a95
|
||||
timeCreated: 1440029519
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 636fa558efd1441fdbf787bdda34c53a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ac8601bd46d146168b508598e8a4f8c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17d0e7e43f7f844aba84497d6385c920
|
||||
timeCreated: 1511969575
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71f4de68ec5de40edbf3e4f24c49ba18
|
||||
timeCreated: 1511952779
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab2178abf0a6343e19742febdd9784e3
|
||||
timeCreated: 1511954360
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b22b3eff389444b1b4ab3bc2d6402b6
|
||||
timeCreated: 1511456560
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e52da649989a94da8b1a5d1e1fe5ff8a
|
||||
timeCreated: 1511456085
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,9 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 232dbc8dfe1624cc3ac35594884d0edd
|
||||
folderAsset: yes
|
||||
timeCreated: 1438097540
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b34adb10b4f264b629f464bfc872d515
|
||||
timeCreated: 1438097545
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 65c4fa737e0dc4ac8acb314d96b75115
|
||||
timeCreated: 1440488659
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,9 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57e51b62adcc84dc19a301be9ebf0e51
|
||||
folderAsset: yes
|
||||
timeCreated: 1480348631
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e94f08d8fe9ed4bdcbc71dde235e0ac1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4aa46c433c6d64b07bdfa8b2e40b03b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dbcd2b1cce6ff448ebca664dd6c55e2d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
{
|
||||
@@ -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:
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 30e140e2334fb4e2f9430c6ed936e4ca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -1,12 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8ac31071459b040f39f1d86300525ed4
|
||||
timeCreated: 1435569421
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6e41ed0a6b70c4f6bae2b72f0a3f89e4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 011ecd7e601cf4613b5b59bfd9d70895
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user