升级obi

This commit is contained in:
2026-01-22 22:08:21 +08:00
parent 120b8cda26
commit 20f14322bc
1067 changed files with 149894 additions and 29583 deletions

View File

@@ -0,0 +1,21 @@
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,8 +1,7 @@
fileFormatVersion: 2
guid: 12c0ac28542b14de6a887a6a9067d86d
timeCreated: 1487351379
licenseType: Store
guid: 636fa558efd1441fdbf787bdda34c53a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0

View File

@@ -16,7 +16,7 @@ namespace Obi{
public virtual void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.PropertyField(position,property,label);
EditorGUI.PropertyField(position,property,label,true);
}
internal virtual void OnPreGUI(Rect position, SerializedProperty property){}
@@ -53,8 +53,9 @@ namespace Obi{
if (!attr.IsVisible(property))
return -EditorGUIUtility.standardVerticalSpacing;
// In case no attribute returns a modified height, return the property's default one:
float height = base.GetPropertyHeight(property, label);
// 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)

View File

@@ -48,15 +48,18 @@ namespace Obi{
// If any changes were detected, call the property setter:
if (EditorGUI.EndChangeCheck() && propertyFieldInfo != null)
{
// Record object state for undo:
Undo.RecordObject(property.serializedObject.targetObject, "Inspector");
// Call property setter:
propertyFieldInfo.SetValue(target,value,null);
foreach (var t in property.serializedObject.targetObjects)
{
// Record object state for undo:
Undo.RecordObject(t, "Inspector");
// Record prefab modification:
PrefabUtility.RecordPrefabInstancePropertyModifications(property.serializedObject.targetObject);
// Call property setter:
propertyFieldInfo.SetValue(t, value, null);
SetPropertyValue(property, propertyFieldInfo.PropertyType, value);
// Record prefab modification:
PrefabUtility.RecordPrefabInstancePropertyModifications(t);
}
}
EditorGUI.EndProperty();
@@ -68,18 +71,18 @@ namespace Obi{
private object GetSource(SerializedProperty property)
{
object target = property.serializedObject.targetObject;
object trgt = property.serializedObject.targetObject;
string[] data = property.propertyPath.Split('.');
if (data.Length == 1)
return target;
return trgt;
else{
for (int i = 0; i < data.Length-1;++i){
target = target.GetType().GetField(data[i]).GetValue(target);
trgt = trgt.GetType().GetField(data[i]).GetValue(trgt);
}
}
return target;
return trgt;
}
private object DrawProperty(Rect position, SerializedPropertyType propertyType, Type type, object value, GUIContent label)
@@ -120,7 +123,46 @@ namespace Obi{
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

@@ -14,6 +14,7 @@ namespace Obi{
private MethodInfo eventMethodInfo = null;
private FieldInfo fieldInfo = null;
private PropertyInfo propertyInfo = null;
public VisibleIf(string methodName, bool negate = false)
{
@@ -39,13 +40,19 @@ namespace Obi{
// 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);
if (eventMethodInfo != null)
// 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
Debug.LogWarning(string.Format("VisibleIf: Unable to find method or field {0} in {1}", eventName, eventOwnerType));
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;
}

View File

@@ -48,7 +48,7 @@ public class CoroutineJob{
private bool stop;
private Exception e;
public int asyncThreshold = 0; //Time in milliseconds that must pass before job switches to async mode. By default, the job is asynchronous from the start.
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;

View File

@@ -6,38 +6,31 @@ using System.Collections;
namespace Obi
{
public class EditorCoroutine
{
public class EditorCoroutine
{
public static bool ShowCoroutineProgressBar(string title, IEnumerator coroutine)
{
public static void ShowCoroutineProgressBar(string title, ref 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;
}
#if (UNITY_EDITOR)
if (coroutine != null){
CoroutineJob.ProgressInfo progressInfo;
do{
if (!coroutine.MoveNext())
progressInfo = null;
else
progressInfo = coroutine.Current as CoroutineJob.ProgressInfo;
if (progressInfo != null && EditorUtility.DisplayCancelableProgressBar(title, progressInfo.userReadableInfo, progressInfo.progress)){
progressInfo = null;
}
}while (progressInfo != null);
// once finished, clear progress bar and set coroutine to null.
coroutine = null;
// Unity bug here: https://issuetracker.unity3d.com/issues/unity-throws-nullreferenceexception-or-endlayoutgroup-errors-when-editorutility-dot-clearprogressbar-is-called
EditorUtility.ClearProgressBar();
}
#endif
}
}
}
}

View File

@@ -1,39 +0,0 @@
using UnityEngine;
using System;
namespace Obi
{
public class ObiAmbientForceZone : ObiExternalForce
{
public override void ApplyForcesToActor(ObiActor actor)
{
Matrix4x4 l2sTransform = actor.solver.transform.worldToLocalMatrix * transform.localToWorldMatrix;
Vector4 force = l2sTransform.MultiplyVector(Vector3.forward * (intensity + GetTurbulence(turbulence)));
if (actor.usesCustomExternalForces)
{
for (int i = 0; i < actor.activeParticleCount; ++i)
actor.solver.wind[actor.solverIndices[i]] += force;
}
else
{
for (int i = 0; i < actor.activeParticleCount; ++i)
actor.solver.externalForces[actor.solverIndices[i]] += force;
}
}
public void OnDrawGizmosSelected()
{
Gizmos.matrix = transform.localToWorldMatrix;
Gizmos.color = new Color(0,0.7f,1,1);
// arrow body:
ObiUtils.DrawArrowGizmo(0.5f + GetTurbulence(1),0.2f,0.3f,0.2f);
}
}
}

View File

@@ -1,50 +0,0 @@
using UnityEngine;
using System;
namespace Obi
{
public abstract class ObiExternalForce : MonoBehaviour
{
public float intensity = 0;
public float turbulence = 0;
public float turbulenceFrequency = 1;
public float turbulenceSeed = 0;
public ObiSolver[] affectedSolvers;
public void OnEnable()
{
foreach (ObiSolver solver in affectedSolvers)
{
if (solver != null)
solver.OnBeginStep += Solver_OnStepBegin;
}
}
public void OnDisable()
{
foreach (ObiSolver solver in affectedSolvers)
{
if (solver != null)
solver.OnBeginStep -= Solver_OnStepBegin;
}
}
void Solver_OnStepBegin(ObiSolver solver, float stepTime)
{
foreach (ObiActor actor in solver.actors)
{
if (actor != null)
ApplyForcesToActor(actor);
}
}
protected float GetTurbulence(float turbulenceIntensity){
return Mathf.PerlinNoise(Time.fixedTime * turbulenceFrequency,turbulenceSeed) * turbulenceIntensity;
}
public abstract void ApplyForcesToActor(ObiActor actor);
}
}

View File

@@ -0,0 +1,137 @@
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,5 +1,5 @@
fileFormatVersion: 2
guid: f05961933f21f46a683fc5d5beec4061
guid: 4978a525b6164476d96f5d28d8b309f8
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,63 +0,0 @@
using UnityEngine;
using System;
namespace Obi
{
public class ObiSphericalForceZone : ObiExternalForce
{
public float radius = 5;
public bool radial = true;
public override void ApplyForcesToActor(ObiActor actor)
{
float sqrRadius = radius * radius;
float finalIntensity = intensity + GetTurbulence(turbulence);
Matrix4x4 l2sTransform = actor.solver.transform.worldToLocalMatrix * transform.localToWorldMatrix;
Vector4 center = l2sTransform.MultiplyPoint3x4(Vector4.zero);
Vector4 forward = l2sTransform.MultiplyVector(Vector3.forward);
// Calculate force intensity for each actor particle:
for (int i = 0; i < actor.activeParticleCount; ++i){
Vector4 distanceVector = actor.solver.positions[actor.solverIndices[i]] - center;
float sqrMag = distanceVector.sqrMagnitude;
float falloff = Mathf.Clamp01((sqrRadius - sqrMag) / sqrRadius);
Vector4 force;
if (radial)
force = distanceVector/(Mathf.Sqrt(sqrMag) + float.Epsilon) * falloff * finalIntensity;
else
force = forward * falloff * finalIntensity;
if (actor.usesCustomExternalForces)
actor.solver.wind[actor.solverIndices[i]] += force;
else
actor.solver.externalForces[actor.solverIndices[i]] += force;
}
}
public void OnDrawGizmosSelected()
{
Gizmos.matrix = transform.localToWorldMatrix;
Gizmos.color = new Color(0,0.7f,1,1);
Gizmos.DrawWireSphere(Vector3.zero,radius);
float turb = GetTurbulence(1);
if (!radial){
ObiUtils.DrawArrowGizmo(radius + turb,radius*0.2f,radius*0.3f,radius*0.2f);
}else{
Gizmos.DrawLine(new Vector3(0,0,-radius*0.5f)*turb,new Vector3(0,0,radius*0.5f)*turb);
Gizmos.DrawLine(new Vector3(0,-radius*0.5f,0)*turb,new Vector3(0,radius*0.5f,0)*turb);
Gizmos.DrawLine(new Vector3(-radius*0.5f,0,0)*turb,new Vector3(radius*0.5f,0,0)*turb);
}
}
}
}

View File

@@ -1,5 +1,6 @@
using UnityEngine;
using UnityEngine.Events;
using Unity.Collections;
using System;
using System.Collections.Generic;
@@ -24,11 +25,11 @@ namespace Obi
public int Compare(Oni.Contact x, Oni.Contact y)
{
return CompareByRef(ref x, ref y, solver);
return CompareByRef(x, y, solver);
}
}
private static int CompareByRef(ref Oni.Contact a, ref Oni.Contact b, ObiSolver solver)
private static int CompareByRef(Oni.Contact a, Oni.Contact b, ObiSolver solver)
{
if (a.bodyB == b.bodyB)
{
@@ -64,7 +65,7 @@ namespace Obi
solver.OnCollision -= Solver_OnCollision;
}
private int FilterOutDistantContacts(Oni.Contact[] data, int count)
private int FilterOutDistantContacts(ObiNativeContactList data, int count)
{
int filteredCount = count;
@@ -72,12 +73,12 @@ namespace Obi
// 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)
ObiUtils.Swap(ref data[i], ref data[--filteredCount]);
data.Swap(i, --filteredCount);
return filteredCount;
}
private int RemoveDuplicates(Oni.Contact[] data, int count)
private int RemoveDuplicates(ObiNativeContactList data, int count)
{
if (count == 0)
return 0;
@@ -86,13 +87,13 @@ namespace Obi
// replacing duplicates by the first contact that's different:
int i = 0, r = 0;
while (++i != count)
if (CompareByRef(ref data[i], ref data[r], solver) != 0 && ++r != i)
if (CompareByRef(data[i], data[r], solver) != 0 && ++r != i)
data[r] = data[i];
return ++r;
}
private void InvokeCallbacks(Oni.Contact[] data, int count)
private void InvokeCallbacks(ObiNativeContactList data, int count)
{
int a = 0, b = 0;
int lengthA = count, lengthB = prevCount;
@@ -101,7 +102,7 @@ namespace Obi
while (a < lengthA && b < lengthB)
{
// compare both contacts:
int compare = CompareByRef(ref data[a], ref prevData[b], solver);
int compare = CompareByRef(data[a], prevData[b], solver);
// call the appropiate event depending on the comparison result:
if (compare < 0)
@@ -122,30 +123,26 @@ namespace Obi
onContactExit.Invoke(solver, prevData[b++]);
}
void Solver_OnCollision(object sender, ObiSolver.ObiCollisionEventArgs args)
void Solver_OnCollision(object sender, ObiNativeContactList contacts)
{
// here we access the internal backing array (Data) directly,
// instead of using the accessor property. This slightly improves performance.
// note: the backing array length is the lists' capacity, so we
// need to use args.contacts.Count to get the actual number of contacts.
// skip all contacts above the distance threshold by moving them to the end of the array:
int filteredCount = FilterOutDistantContacts(args.contacts.Data, args.contacts.Count);
int filteredCount = FilterOutDistantContacts(contacts, contacts.count);
// sort the remaining contacts by collider, then by actor:
Array.Sort(args.contacts.Data, 0, filteredCount, comparer);
contacts.AsNativeArray().Slice(0,filteredCount).Sort(comparer);
// remove duplicates:
filteredCount = RemoveDuplicates(args.contacts.Data, filteredCount);
filteredCount = RemoveDuplicates(contacts, filteredCount);
// zip trough the current and previous contact lists once, invoking events when appropiate.
InvokeCallbacks(args.contacts.Data, filteredCount);
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);
Array.Copy(args.contacts.Data, prevData, filteredCount);
contacts.CopyTo(prevData, 0, filteredCount);
prevCount = filteredCount;
}

View File

@@ -45,7 +45,7 @@ public class ObiContactGrabber : MonoBehaviour
}
}
private Dictionary<ObiSolver, ObiSolver.ObiCollisionEventArgs> collisionEvents = new Dictionary<ObiSolver, ObiSolver.ObiCollisionEventArgs>(); /**< store the current collision event*/
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.*/
@@ -69,7 +69,7 @@ public class ObiContactGrabber : MonoBehaviour
solver.OnCollision -= Solver_OnCollision;
}
private void Solver_OnCollision(object sender, Obi.ObiSolver.ObiCollisionEventArgs e)
private void Solver_OnCollision(object sender, ObiNativeContactList e)
{
collisionEvents[(ObiSolver)sender] = e;
}
@@ -122,10 +122,10 @@ public class ObiContactGrabber : MonoBehaviour
{
foreach (ObiSolver solver in solvers)
{
ObiSolver.ObiCollisionEventArgs collisionEvent;
ObiNativeContactList collisionEvent;
if (collisionEvents.TryGetValue(solver, out collisionEvent))
{
foreach (Oni.Contact contact in collisionEvent.contacts)
foreach (Oni.Contact contact in collisionEvent)
{
// this one is an actual collision:
if (contact.distance < 0.01f)

View File

@@ -0,0 +1,39 @@
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 +1,11 @@
fileFormatVersion: 2
guid: 8f33b658b41e945e0bae1d3f0af0830e
guid: 3a2bd12c1cc9c45428b37635331065db
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 092f06332c018434b8c8ea86164ef4fd, type: 3}
icon: {fileID: 2800000, guid: b7cec6e680e3a479ca03a89eccd4e052, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,101 @@
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

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

View File

@@ -0,0 +1,50 @@
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,8 +1,7 @@
fileFormatVersion: 2
guid: 4978a525b6164476d96f5d28d8b309f8
timeCreated: 1480349422
licenseType: Store
guid: dbcd2b1cce6ff448ebca664dd6c55e2d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0

View File

@@ -1,508 +1,70 @@
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 float m_Compliance = 0;
[SerializeField] [HideInInspector] [Delayed] private float m_BreakThreshold = float.PositiveInfinity;
using System;
using UnityEngine;
namespace Obi
[NonSerialized] private ObiPinConstraintsBatch pinBatch;
[NonSerialized] private ObiColliderBase attachedCollider;
[NonSerialized] private int attachedColliderHandleIndex;
{
[AddComponentMenu("Physics/Obi/Obi Particle Attachment", 820)]
[NonSerialized] private int[] m_SolverIndices;
[NonSerialized] private Vector3[] m_PositionOffsets = null;
[NonSerialized] private Quaternion[] m_OrientationOffsets = null;
[RequireComponent(typeof(ObiActor))]
[ExecuteInEditMode]
/// <summary>
/// The actor this attachment is added to.
/// </summary>
public ObiActor actor
{
get { return m_Actor; }
}
public class ObiParticleAttachment : MonoBehaviour
{
/// <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();
}
}
}
public enum AttachmentType
{
/// <summary>
/// The particle group that should be attached to the <see cref="target"/>.
/// </summary>
public ObiParticleGroup particleGroup
{
get
{
return m_ParticleGroup;
}
Static,
Dynamic
set
{
if (value != m_ParticleGroup)
{
m_ParticleGroup = value;
Bind();
}
}
}
}
/// <summary>
/// Whether this attachment is currently bound or not.
/// </summary>
public bool isBound
{
get { return m_Target != null && m_SolverIndices != null && m_PositionOffsets != null; }
}
[SerializeField] [HideInInspector] private ObiActor m_Actor;
[SerializeField] [HideInInspector] private Transform m_Target;
/// <summary>
/// Type of attachment, can be either static or dynamic.
/// </summary>
public AttachmentType attachmentType
{
get { return m_AttachmentType; }
set
{
if (value != m_AttachmentType)
{
DisableAttachment(m_AttachmentType);
m_AttachmentType = value;
EnableAttachment(m_AttachmentType);
}
}
}
[SerializeField] [HideInInspector] private ObiParticleGroup m_ParticleGroup;
/// <summary>
/// Should this attachment constraint particle orientations too?
/// </summary>
public bool constrainOrientation
{
get { return m_ConstrainOrientation; }
set
{
if (value != m_ConstrainOrientation)
{
DisableAttachment(m_AttachmentType);
m_ConstrainOrientation = value;
EnableAttachment(m_AttachmentType);
}
}
}
[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;
/// <summary>
/// Constraint compliance, in case this attachment is dynamic.
/// </summary>
/// High compliance values will increase the attachment's elasticity.
public float compliance
{
get { return m_Compliance; }
set
{
if (!Mathf.Approximately(value, m_Compliance))
{
m_Compliance = value;
if (m_AttachmentType == AttachmentType.Dynamic && pinBatch != null)
{
for (int i = 0; i < m_SolverIndices.Length; ++i)
pinBatch.stiffnesses[i * 2] = m_Compliance;
}
}
}
}
/// <summary>
/// Force thershold above which the attachment should break.
/// </summary>
/// Only affects dynamic attachments, as static attachments do not work with forces.
public float breakThreshold
{
get { return m_BreakThreshold; }
set
{
if (!Mathf.Approximately(value, m_BreakThreshold))
{
m_BreakThreshold = value;
if (m_AttachmentType == AttachmentType.Dynamic && pinBatch != null)
{
for (int i = 0; i < m_SolverIndices.Length; ++i)
pinBatch.breakThresholds[i] = m_BreakThreshold;
}
}
}
}
private void OnEnable()
{
m_Actor = GetComponent<ObiActor>();
m_Actor.OnBlueprintLoaded += Actor_OnBlueprintLoaded;
m_Actor.OnPrepareStep += Actor_OnPrepareStep;
m_Actor.OnEndStep += Actor_OnEndStep;
if (m_Actor.solver != null)
Actor_OnBlueprintLoaded(m_Actor, m_Actor.sourceBlueprint);
EnableAttachment(m_AttachmentType);
}
private void OnDisable()
{
DisableAttachment(m_AttachmentType);
m_Actor.OnBlueprintLoaded -= Actor_OnBlueprintLoaded;
m_Actor.OnPrepareStep -= Actor_OnPrepareStep;
m_Actor.OnEndStep -= Actor_OnEndStep;
}
private void OnValidate()
{
m_Actor = GetComponent<ObiActor>();
// private variables are serialized during script reloading, to keep their value. Must mark them explicitly as non-serialized.
[NonSerialized] private ObiPinConstraintsBatch pinBatch;
DisableAttachment(AttachmentType.Static);
DisableAttachment(AttachmentType.Dynamic);
EnableAttachment(m_AttachmentType);
}
[NonSerialized] private ObiColliderBase attachedCollider;
[NonSerialized] private int attachedColliderHandleIndex;
void Actor_OnBlueprintLoaded(ObiActor act, ObiActorBlueprint blueprint)
{
Bind();
}
void Actor_OnPrepareStep(ObiActor act, float stepTime)
{
[NonSerialized] private int[] m_SolverIndices;
[NonSerialized] private Vector3[] m_PositionOffsets = null;
}
[NonSerialized] private Quaternion[] m_OrientationOffsets = null;
private void Actor_OnEndStep(ObiActor act, float stepTime)
{
// dynamic attachments must be tested at the end of the step, once constraint forces have been calculated.
BreakDynamicAttachment(stepTime);
}
private void Bind()
{
/// <summary>
/// The actor this attachment is added to.
DisableAttachment(m_AttachmentType);
if (m_Target != null && m_ParticleGroup != null && m_Actor.isLoaded)
{
Matrix4x4 bindMatrix = m_Target.worldToLocalMatrix * m_Actor.solver.transform.localToWorldMatrix;
m_SolverIndices = new int[m_ParticleGroup.Count];
m_PositionOffsets = new Vector3[m_ParticleGroup.Count];
m_OrientationOffsets = new Quaternion[m_ParticleGroup.Count];
for (int i = 0; i < m_ParticleGroup.Count; ++i)
{
int particleIndex = m_ParticleGroup.particleIndices[i];
if (particleIndex >= 0 && particleIndex < m_Actor.solverIndices.Length)
{
m_SolverIndices[i] = m_Actor.solverIndices[particleIndex];
m_PositionOffsets[i] = bindMatrix.MultiplyPoint3x4(m_Actor.solver.positions[m_SolverIndices[i]]);
}
else
{
Debug.LogError("The particle group \'" + m_ParticleGroup.name + "\' references a particle that does not exist in the actor \'" + m_Actor.name + "\'.");
m_SolverIndices = null;
m_PositionOffsets = null;
m_OrientationOffsets = null;
return;
}
}
if (m_Actor.usesOrientedParticles)
{
Quaternion bindOrientation = bindMatrix.rotation;
for (int i = 0; i < m_ParticleGroup.Count; ++i)
{
int particleIndex = m_ParticleGroup.particleIndices[i];
if (particleIndex >= 0 && particleIndex < m_Actor.solverIndices.Length)
m_OrientationOffsets[i] = bindOrientation * m_Actor.solver.orientations[m_SolverIndices[i]];
}
}
}
else
{
m_PositionOffsets = null;
m_OrientationOffsets = null;
}
EnableAttachment(m_AttachmentType);
}
private void EnableAttachment(AttachmentType type)
{
if (enabled && m_Actor.isLoaded && isBound)
{
var solver = m_Actor.solver;
switch (type)
{
case AttachmentType.Dynamic:
var pins = m_Actor.GetConstraintsByType(Oni.ConstraintType.Pin) as ObiPinConstraintsData;
attachedCollider = m_Target.GetComponent<ObiColliderBase>();
if (pins != null && attachedCollider != null && pinBatch == null)
{
/// </summary>
public ObiActor actor
pinBatch = new ObiPinConstraintsBatch(pins);
for (int i = 0; i < m_SolverIndices.Length; ++i)
{
pinBatch.AddConstraint(m_SolverIndices[i],
attachedCollider,
m_PositionOffsets[i],
m_OrientationOffsets[i],
m_Compliance,
constrainOrientation ? 0 : 10000,
m_BreakThreshold);
pinBatch.activeConstraintCount++;
}
{
get { return m_Actor; }
}
/// <summary>
/// The target transform that the <see cref="particleGroup"/> should be attached to.
attachedColliderHandleIndex = -1;
if (attachedCollider.Handle != null)
attachedColliderHandleIndex = attachedCollider.Handle.index;
m_Actor.SetConstraintsDirty(Oni.ConstraintType.Pin);
}
break;
case AttachmentType.Static:
for (int i = 0; i < m_SolverIndices.Length; ++i)
if (m_SolverIndices[i] >= 0 && m_SolverIndices[i] < solver.invMasses.count)
solver.invMasses[m_SolverIndices[i]] = 0;
if (m_Actor.usesOrientedParticles && m_ConstrainOrientation)
{
for (int i = 0; i < m_SolverIndices.Length; ++i)
if (m_SolverIndices[i] >= 0 && m_SolverIndices[i] < solver.invRotationalMasses.count)
solver.invRotationalMasses[m_SolverIndices[i]] = 0;
}
m_Actor.UpdateParticleProperties();
break;
}
}
}
private void DisableAttachment(AttachmentType type)
{
if (isBound)
{
switch (type)
{
case AttachmentType.Dynamic:
if (pinBatch != null)
{
var pins = m_Actor.GetConstraintsByType(Oni.ConstraintType.Pin) as ObiConstraints<ObiPinConstraintsBatch>;
if (pins != null)
{
pins.RemoveBatch(pinBatch);
if (actor.isLoaded)
m_Actor.SetConstraintsDirty(Oni.ConstraintType.Pin);
}
attachedCollider = null;
pinBatch = null;
attachedColliderHandleIndex = -1;
}
break;
case AttachmentType.Static:
var solver = m_Actor.solver;
var blueprint = m_Actor.sourceBlueprint;
for (int i = 0; i < m_SolverIndices.Length; ++i)
{
int solverIndex = m_SolverIndices[i];
if (solverIndex >= 0 && solverIndex < solver.invMasses.count)
solver.invMasses[solverIndex] = blueprint.invMasses[i];
}
if (m_Actor.usesOrientedParticles)
{
for (int i = 0; i < m_SolverIndices.Length; ++i)
{
int solverIndex = m_SolverIndices[i];
if (solverIndex >= 0 && solverIndex < solver.invRotationalMasses.count)
solver.invRotationalMasses[solverIndex] = blueprint.invRotationalMasses[i];
}
}
m_Actor.UpdateParticleProperties();
break;
}
}
}
private void UpdateAttachment()
{
if (enabled && m_Actor.isLoaded && isBound)
{
var solver = m_Actor.solver;
switch (m_AttachmentType)
{
case AttachmentType.Dynamic:
/// </summary>
public Transform target
{
get { return m_Target; }
set
attachedCollider.Handle.index != attachedColliderHandleIndex)
{
attachedColliderHandleIndex = attachedCollider.Handle.index;
m_Actor.SetConstraintsDirty(Oni.ConstraintType.Pin);
}
break;
case AttachmentType.Static:
var blueprint = m_Actor.sourceBlueprint;
bool targetActive = m_Target.gameObject.activeInHierarchy;
{
if (value != m_Target)
{
m_Target = value;
Bind();
}
}
for (int i = 0; i < m_SolverIndices.Length; ++i)
{
int solverIndex = m_SolverIndices[i];
if (solverIndex >= 0 && solverIndex < solver.invMasses.count)
{
if (targetActive)
{
solver.invMasses[solverIndex] = 0;
solver.velocities[solverIndex] = Vector3.zero;
solver.startPositions[solverIndex] = solver.positions[solverIndex] = attachmentMatrix.MultiplyPoint3x4(m_PositionOffsets[i]);
}else
solver.invMasses[solverIndex] = blueprint.invMasses[i];
}
}
if (m_Actor.usesOrientedParticles && m_ConstrainOrientation)
{
Quaternion attachmentRotation = attachmentMatrix.rotation;
for (int i = 0; i < m_SolverIndices.Length; ++i)
{
int solverIndex = m_SolverIndices[i];
if (solverIndex >= 0 && solverIndex < solver.invRotationalMasses.count)
{
if (targetActive)
{
solver.invRotationalMasses[solverIndex] = 0;
solver.angularVelocities[solverIndex] = Vector3.zero;
solver.startOrientations[solverIndex] = solver.orientations[solverIndex] = attachmentRotation * m_OrientationOffsets[i];
}
else
solver.invRotationalMasses[solverIndex] = blueprint.invRotationalMasses[i];
}
}
}
break;
}
}
}
private void BreakDynamicAttachment(float stepTime)
{
if (enabled && m_AttachmentType == AttachmentType.Dynamic && m_Actor.isLoaded && isBound)
}
/// <summary>
var solver = m_Actor.solver;
var actorConstraints = m_Actor.GetConstraintsByType(Oni.ConstraintType.Pin) as ObiConstraints<ObiPinConstraintsBatch>;
var solverConstraints = solver.GetConstraintsByType(Oni.ConstraintType.Pin) as ObiConstraints<ObiPinConstraintsBatch>;
bool dirty = false;
if (actorConstraints != null && pinBatch != null)
{
int pinBatchIndex = actorConstraints.batches.IndexOf(pinBatch);
if (pinBatchIndex >= 0 && pinBatchIndex < actor.solverBatchOffsets[(int)Oni.ConstraintType.Pin].Count)
{
int offset = actor.solverBatchOffsets[(int)Oni.ConstraintType.Pin][pinBatchIndex];
var solverBatch = solverConstraints.batches[pinBatchIndex];
float sqrTime = stepTime * stepTime;
for (int i = 0; i < pinBatch.activeConstraintCount; i++)
{
/// The particle group that should be attached to the <see cref="target"/>.
/// </summary>
public ObiParticleGroup particleGroup
{
if (pinBatch.pinBodies[i] != attachedCollider.Handle)
{
pinBatch.pinBodies[i] = attachedCollider.Handle;
dirty = true;
}
get
{
return m_ParticleGroup;
if (-solverBatch.lambdas[(offset + i) * 4 + 3] / sqrTime > pinBatch.breakThresholds[i])
{
pinBatch.DeactivateConstraint(i);
dirty = true;
}
}
}
}
}
set
if (dirty)
m_Actor.SetConstraintsDirty(Oni.ConstraintType.Pin);
}
}
}
}
{

View File

@@ -22,23 +22,24 @@ namespace Obi
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;
}
void FixedUpdate()
private void Solver_OnEndSimulation(ObiSolver solver, float timeToSimulate, float substepTime)
{
ObiSolver solver = picker.solver;
if (solver != null && pickArgs != null)
{
// Calculate picking position in solver space:
Vector4 targetPosition = solver.transform.InverseTransformPoint(pickArgs.worldPosition);
@@ -52,7 +53,6 @@ namespace Obi
Vector4 velocity = solver.velocities[pickArgs.particleIndex];
solver.externalForces[pickArgs.particleIndex] = ((targetPosition - position) * springStiffness - velocity * springDamping) / invMass;
if (drawSpring)
{
lineRenderer.positionCount = 2;

View File

@@ -1,45 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Obi
{
[RequireComponent(typeof(ObiSolver))]
public class ObiParticleGridDebugger : MonoBehaviour
{
ObiSolver solver;
ObiNativeAabbList cells;
void OnEnable()
{
solver = GetComponent<ObiSolver>();
cells = new ObiNativeAabbList();
}
private void OnDisable()
{
cells.Dispose();
}
void LateUpdate ()
{
cells.count = solver.implementation.GetParticleGridSize();
solver.implementation.GetParticleGrid(cells);
}
void OnDrawGizmos()
{
if (cells != null)
{
Gizmos.color = Color.yellow;
for(int i = 0; i < cells.count; ++i)
Gizmos.DrawWireCube(cells[i].center, cells[i].size);
}
}
}
}

View File

@@ -63,13 +63,13 @@ namespace Obi
Matrix4x4 solver2World = solver.transform.localToWorldMatrix;
// Find the closest particle hit by the ray:
for (int i = 0; i < solver.renderablePositions.count; ++i)
for (int i = 0; i < solver.positions.count; ++i)
{
Vector3 worldPos = solver2World.MultiplyPoint3x4(solver.renderablePositions[i]);
Vector3 worldPos = solver2World.MultiplyPoint3x4(solver.positions[i]);
float mu;
Vector3 projected = ObiUtils.ProjectPointLine(worldPos, ray.origin, ray.origin + ray.direction, out mu, false);
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:
@@ -88,7 +88,7 @@ namespace Obi
if (pickedParticleIndex >= 0)
{
pickedParticleDepth = Camera.main.transform.InverseTransformVector(solver2World.MultiplyPoint3x4(solver.renderablePositions[pickedParticleIndex]) - Camera.main.transform.position).z;
pickedParticleDepth = Camera.main.transform.InverseTransformVector(solver2World.MultiplyPoint3x4(solver.positions[pickedParticleIndex]) - Camera.main.transform.position).z;
if (OnParticlePicked != null)
{

View File

@@ -1,215 +0,0 @@
using System;
using UnityEngine;
namespace Obi
{
[DisallowMultipleComponent]
public class ObiProfiler : MonoBehaviour
{
[Header("Appearance")]
public GUISkin skin;
public Color threadColor = Color.white;
public Color taskColor = new Color(0.1f, 1, 0.2f);
public Color parallelTaskColor = new Color(1,0.8f,0.2f);
//public Color idleColor = new Color(0.7f,0.7f,0.7f);
public Color renderTaskColor = new Color(0.2f, 0.7f, 1.0f);
public Color defaultTaskColor = new Color(1, 0.5f, 0.2f);
[Header("Visualization")]
public bool showPercentages = false;
public int profileThrottle = 30;
private Oni.ProfileInfo[] info;
private double frameStart;
private double frameEnd;
private int frameCounter = 0;
private int yPos = 25;
private bool profiling = false;
private float zoom = 1;
private Vector2 scrollPosition = Vector2.zero;
private static ObiProfiler _instance;
private void Awake()
{
if (_instance != null && _instance != this)
DestroyImmediate(this);
else{
_instance = this;
}
}
public void OnDestroy(){
#if (OBI_ONI_SUPPORTED)
_instance = null;
Oni.EnableProfiler(false);
#endif
}
private void OnEnable()
{
#if (OBI_ONI_SUPPORTED)
if (_instance != null && _instance.profiling)
Oni.EnableProfiler(true);
#endif
}
private void OnDisable()
{
#if (OBI_ONI_SUPPORTED)
if (_instance != null)
Oni.EnableProfiler(false);
#endif
}
public static void EnableProfiler()
{
#if (OBI_ONI_SUPPORTED)
if (_instance != null)
{
_instance.profiling = true;
if (_instance.isActiveAndEnabled)
Oni.EnableProfiler(true);
}
#endif
}
public static void DisableProfiler()
{
#if (OBI_ONI_SUPPORTED)
if (_instance != null)
{
_instance.profiling = false;
Oni.EnableProfiler(false);
}
#endif
}
public static void BeginSample(string name, byte type)
{
#if (OBI_ONI_SUPPORTED)
if (_instance != null)
Oni.BeginSample(name, type);
#endif
}
public static void EndSample()
{
#if (OBI_ONI_SUPPORTED)
if (_instance != null)
Oni.EndSample();
#endif
}
private void UpdateProfilerInfo(){
#if (OBI_ONI_SUPPORTED)
frameCounter--;
if (frameCounter <= 0)
{
int count = Oni.GetProfilingInfoCount();
info = new Oni.ProfileInfo[count];
Oni.GetProfilingInfo(info,count);
frameCounter = profileThrottle;
// Calculate frame duration:
frameStart = double.MaxValue;
frameEnd = double.MinValue;
foreach (Oni.ProfileInfo i in info){
frameStart = Math.Min(frameStart,i.start);
frameEnd = Math.Max(frameEnd,i.end);
}
}
Oni.ClearProfiler();
#endif
}
public void OnGUI()
{
#if (OBI_ONI_SUPPORTED)
if (Event.current.type == EventType.Layout)
UpdateProfilerInfo();
if (info == null)
return;
GUI.skin = skin;
int toolbarHeight = 20;
int threadHeight = 20;
int scrollViewWidth = (int)(Screen.width / zoom);
double frameDuration = frameEnd - frameStart;
// Toolbar:
GUI.BeginGroup(new Rect(0,0,Screen.width,toolbarHeight),"","Box");
GUI.Label(new Rect(5,0,50,toolbarHeight),"Zoom:");
zoom = GUI.HorizontalSlider(new Rect(50,5,100,toolbarHeight),zoom,0.005f,1);
GUI.Label(new Rect(Screen.width - 100,0,100,toolbarHeight),(frameDuration/1000.0f).ToString("0.###") + " ms/frame");
GUI.EndGroup();
// Timeline view:
scrollPosition = GUI.BeginScrollView(new Rect(0, toolbarHeight, Screen.width, Screen.height-20), scrollPosition,
new Rect(0, 0, scrollViewWidth, yPos+30)); // height depends on amount of threads.
GUI.color = threadColor;
GUI.Label(new Rect(5,0,200,20),"Thread 1");
GUI.Box(new Rect(0, 0, scrollViewWidth, 40),"","Thread");
yPos = 25;
uint currentThreadId = 0;
uint currentLevel = 0;
foreach (Oni.ProfileInfo i in info)
{
uint threadId = (i.info & (uint)Oni.ProfileMask.ThreadIdMask) >> 16;
uint level = (i.info & (uint)Oni.ProfileMask.StackLevelMask) >> 8;
uint type = i.info & (uint)Oni.ProfileMask.TypeMask;
if (currentThreadId != threadId){
yPos += threadHeight+1;
GUI.color = threadColor;
GUI.Label(new Rect(5,yPos+5,200,20),"Thread "+(threadId+1));
GUI.Box(new Rect(0, yPos+5, scrollViewWidth, 40),"","Thread");
yPos += 30;
}else if (currentLevel != level){
yPos += threadHeight+1;
}
currentLevel = level;
currentThreadId = threadId;
switch(type){
case 0: GUI.color = taskColor; break;
//case 1: GUI.color = idleColor; break;
case 2: GUI.color = parallelTaskColor; break;
case 3: GUI.color = renderTaskColor; break;
default: GUI.color = defaultTaskColor; break;
}
// task duration:
int taskStart = (int) ((i.start - frameStart) / frameDuration * (Screen.width-10) / zoom);
int taskEnd = (int) ((i.end - frameStart) / frameDuration * (Screen.width-10) / zoom);
int taskDuration = taskEnd-taskStart;
string name;
if (showPercentages)
{
double pctg = (i.end-i.start)/frameDuration*100;
name = i.name + " ("+pctg.ToString("0.#")+"%)";
}
else{
double ms = (i.end-i.start)/1000.0f;
name = i.name + " ("+ms.ToString("0.###")+"ms)";
}
GUI.Box(new Rect(taskStart, yPos, taskDuration-1, threadHeight),name,"Task");
}
GUI.EndScrollView();
#endif
}
}
}

View File

@@ -1,13 +0,0 @@
fileFormatVersion: 2
guid: 62e83a599724f45a4aa337d74764e572
timeCreated: 1482252100
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences:
- skin: {fileID: 11400000, guid: b90d3c214c99743b0865fc0e0d1f1a15, type: 2}
executionOrder: 0
icon: {fileID: 2800000, guid: 1c322d61eeb3640408ee1119729d5c21, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -34,9 +34,9 @@ namespace Obi
[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 = new ObiNativeIntList();
[HideInInspector] public ObiNativeFloatList stiffnesses = new ObiNativeFloatList();
[HideInInspector] public ObiNativeFloatList lambdas = new ObiNativeFloatList();
[HideInInspector] public ObiNativeIntList particleIndices;
[HideInInspector] public ObiNativeFloatList stiffnesses;
[HideInInspector] public ObiNativeFloatList lambdas;
//private IntPtr batch;
private IStitchConstraintsBatchImpl m_BatchImpl;
@@ -176,6 +176,10 @@ namespace Obi
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;
@@ -195,6 +199,10 @@ namespace Obi
// 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;
@@ -227,7 +235,6 @@ namespace Obi
m_BatchImpl.SetStitchConstraints(particleIndices, stiffnesses, lambdas, stitches.Count);
}
}
}

File diff suppressed because one or more lines are too long