升级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

@@ -76,8 +76,8 @@ namespace Obi
{
particleIndices[m_ActiveConstraintCount + i] = actor.solverIndices[batch.particleIndices[i]];
aerodynamicCoeffs[(m_ActiveConstraintCount + i) * 3] = batch.aerodynamicCoeffs[i*3];
aerodynamicCoeffs[(m_ActiveConstraintCount + i) * 3 + 1] = user.drag;
aerodynamicCoeffs[(m_ActiveConstraintCount + i) * 3 + 2] = user.lift;
aerodynamicCoeffs[(m_ActiveConstraintCount + i) * 3 + 1] = user.GetDrag(batch, i);
aerodynamicCoeffs[(m_ActiveConstraintCount + i) * 3 + 2] = user.GetLift(batch, i);
}
base.Merge(actor, other);
@@ -96,6 +96,10 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
aerodynamicCoeffs.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -115,6 +115,12 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
restBends.Dispose();
bendingStiffnesses.Dispose();
plasticity.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -116,6 +116,12 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
restDarbouxVectors.Dispose();
plasticity.Dispose();
stiffnesses.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -120,6 +120,12 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
firstParticle.Dispose();
numParticles.Dispose();
lengths.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -42,6 +42,7 @@ namespace Obi
bool DeactivateConstraint(int constraintIndex);
bool ActivateConstraint(int constraintIndex);
void DeactivateAllConstraints();
void ActivateAllConstraints();
void Clear();
@@ -100,8 +101,12 @@ namespace Obi
protected abstract void SwapConstraints(int sourceIndex, int destIndex);
public abstract void GetParticlesInvolved(int index, List<int> particles);
public abstract void AddToSolver(ObiSolver solver);
public abstract void RemoveFromSolver(ObiSolver solver);
public virtual void AddToSolver(ObiSolver solver) { }
public virtual void RemoveFromSolver(ObiSolver solver) {
particleIndices.Dispose();
lambdas.Dispose();
}
protected virtual void CopyConstraint(ObiConstraintsBatch batch, int constraintIndex) { }
@@ -176,6 +181,11 @@ namespace Obi
m_ActiveConstraintCount = 0;
}
public void ActivateAllConstraints()
{
m_ActiveConstraintCount = m_ConstraintCount;
}
// Swaps the constraint with the last one and reduces the amount of constraints by one.
public void RemoveConstraint(int constraintIndex)
{

View File

@@ -30,7 +30,7 @@ namespace Obi
get { return m_BatchImpl; }
}
public ObiDistanceConstraintsBatch(int a = 0)
public ObiDistanceConstraintsBatch(ObiDistanceConstraintsData constraints = null) : base()
{
}
@@ -135,6 +135,11 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
restLengths.Dispose();
stiffnesses.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -8,12 +8,12 @@ namespace Obi
[Serializable]
public class ObiPinConstraintsBatch : ObiConstraintsBatch
{
protected IPinConstraintsBatchImpl m_BatchImpl;
protected IPinConstraintsBatchImpl m_BatchImpl;
/// <summary>
/// for each constraint, handle of the pinned collider.
/// </summary>
[HideInInspector] public List<ObiColliderHandle> pinBodies = new List<ObiColliderHandle>();
[HideInInspector] public List<ObiColliderHandle> pinBodies = new List<ObiColliderHandle>();
/// <summary>
/// index of the pinned collider in the collider world.
@@ -23,22 +23,17 @@ namespace Obi
/// <summary>
/// Pin position expressed in the attachment's local space.
/// </summary>
[HideInInspector] public ObiNativeVector4List offsets = new ObiNativeVector4List();
[HideInInspector] public ObiNativeVector4List offsets = new ObiNativeVector4List();
/// <summary>
/// Rest Darboux vector for each constraint.
/// </summary>
[HideInInspector] public ObiNativeQuaternionList restDarbouxVectors = new ObiNativeQuaternionList();
[HideInInspector] public ObiNativeQuaternionList restDarbouxVectors = new ObiNativeQuaternionList();
/// <summary>
/// Compliances of pin constraits. 2 float per constraint (positional and rotational compliance).
/// </summary>
[HideInInspector] public ObiNativeFloatList stiffnesses = new ObiNativeFloatList();
/// <summary>
/// One float per constraint: break threshold.
/// </summary>
[HideInInspector] public ObiNativeFloatList breakThresholds = new ObiNativeFloatList();
[HideInInspector] public ObiNativeFloatList stiffnesses = new ObiNativeFloatList();
public override Oni.ConstraintType constraintType
{
@@ -54,18 +49,17 @@ namespace Obi
{
}
public void AddConstraint(int solverIndex, ObiColliderBase body, Vector3 offset, Quaternion restDarboux, float linearCompliance, float rotationalCompliance, float breakThreshold)
public void AddConstraint(int solverIndex, ObiColliderBase body, Vector3 offset, Quaternion restDarboux, float linearCompliance, float rotationalCompliance, bool projectRenderable = false)
{
RegisterConstraint();
particleIndices.Add(solverIndex);
pinBodies.Add(body != null ? body.Handle : new ObiColliderHandle());
colliderIndices.Add(body != null ? body.Handle.index : -1);
offsets.Add(offset);
offsets.Add(new Vector4(offset.x, offset.y, offset.z, projectRenderable ? 1:0));
restDarbouxVectors.Add(restDarboux);
stiffnesses.Add(linearCompliance);
stiffnesses.Add(rotationalCompliance);
breakThresholds.Add(breakThreshold);
}
public override void Clear()
@@ -108,13 +102,11 @@ namespace Obi
offsets.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
restDarbouxVectors.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
stiffnesses.ResizeUninitialized((m_ActiveConstraintCount + batch.activeConstraintCount) * 2);
breakThresholds.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
lambdas.ResizeInitialized((m_ActiveConstraintCount + batch.activeConstraintCount) * 4);
offsets.CopyFrom(batch.offsets, 0, m_ActiveConstraintCount, batch.activeConstraintCount);
restDarbouxVectors.CopyFrom(batch.restDarbouxVectors, 0, m_ActiveConstraintCount, batch.activeConstraintCount);
stiffnesses.CopyFrom(batch.stiffnesses, 0, m_ActiveConstraintCount * 2, batch.activeConstraintCount * 2);
breakThresholds.CopyFrom(batch.breakThresholds, 0, m_ActiveConstraintCount, batch.activeConstraintCount);
for (int i = 0; i < batch.activeConstraintCount; ++i)
{
@@ -139,6 +131,13 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
restDarbouxVectors.Dispose();
colliderIndices.Dispose();
offsets.Dispose();
stiffnesses.Dispose();
if (solver != null && solver.implementation != null)
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -0,0 +1,220 @@
using UnityEngine;
using System;
using System.Collections.Generic;
namespace Obi
{
[Serializable]
public class ObiPinholeConstraintsBatch : ObiConstraintsBatch
{
[Serializable]
public struct PinholeEdge
{
public int edgeIndex;
public float coordinate;
public PinholeEdge(int edgeIndex, float coordinate)
{
this.edgeIndex = edgeIndex;
this.coordinate = coordinate;
}
public float GetRopeCoordinate(ObiActor actor)
{
int edgeCount = actor.GetDeformableEdgeCount();
return edgeCount > 0 ? Mathf.Clamp01((edgeIndex + coordinate) / edgeCount) : 0;
}
}
protected IPinholeConstraintsBatchImpl m_BatchImpl;
/// <summary>
/// for each constraint, handle of the pinned collider.
/// </summary>
[HideInInspector] public List<ObiColliderHandle> pinBodies = new List<ObiColliderHandle>();
/// <summary>
/// for each constraint, reference to the actor pinned.
/// </summary>
[HideInInspector] public List<ObiActor> pinActors = new List<ObiActor>();
/// <summary>
/// index of the pinned collider in the collider world.
/// </summary>
[HideInInspector] public ObiNativeIntList colliderIndices = new ObiNativeIntList();
/// <summary>
/// Pinhole position expressed in the attachment's local space.
/// </summary>
[HideInInspector] public ObiNativeVector4List offsets = new ObiNativeVector4List();
/// <summary>
// Normalized coordinate along current edge.
/// </summary>
[HideInInspector] public ObiNativeFloatList edgeMus = new ObiNativeFloatList();
/// <summary>
/// Edge range as 2 ints (first edge, last edge) for each constraint.
/// </summary>
[HideInInspector] public ObiNativeIntList edgeRanges = new ObiNativeIntList();
/// <summary>
/// Min/max cooridnate in each of the first and last edges as 2 floats for each constraint.
/// </summary>
[HideInInspector] public ObiNativeFloatList edgeRangeMus = new ObiNativeFloatList();
/// <summary>
/// Parameters of pinhole constraints. 5 floats per constraint (compliance, friction, motor speed, motor force and normalized coordinate along edge).
/// </summary>
[HideInInspector] public ObiNativeFloatList parameters = new ObiNativeFloatList();
/// <summary>
/// Relative velocities between rope and pinhole.
/// </summary>
[HideInInspector] public ObiNativeFloatList relativeVelocities = new ObiNativeFloatList();
public override Oni.ConstraintType constraintType
{
get { return Oni.ConstraintType.Pinhole; }
}
public override IConstraintsBatchImpl implementation
{
get { return m_BatchImpl; }
}
public ObiPinholeConstraintsBatch(ObiPinholeConstraintsData constraints = null) : base()
{
}
public void AddConstraint(PinholeEdge edge, PinholeEdge firstEdge, PinholeEdge lastEdge, ObiActor actor, ObiColliderBase body, Vector3 offset, float compliance, float friction, float motorSpeed, float motorForce, bool clampAtEnds)
{
RegisterConstraint();
particleIndices.Add(edge.edgeIndex);
edgeMus.Add(edge.coordinate);
edgeRanges.Add(firstEdge.edgeIndex);
edgeRanges.Add(lastEdge.edgeIndex);
edgeRangeMus.Add(firstEdge.coordinate);
edgeRangeMus.Add(lastEdge.coordinate);
pinBodies.Add(body != null ? body.Handle : new ObiColliderHandle());
pinActors.Add(actor);
colliderIndices.Add(body != null ? body.Handle.index : -1);
offsets.Add(offset);
parameters.Add(compliance);
parameters.Add(friction);
parameters.Add(motorSpeed);
parameters.Add(motorForce);
parameters.Add(clampAtEnds ? 1 : 0);
relativeVelocities.Add(0);
}
public override void Clear()
{
base.Clear();
particleIndices.Clear();
pinBodies.Clear();
colliderIndices.Clear();
offsets.Clear();
edgeMus.Clear();
edgeRanges.Clear();
edgeRangeMus.Clear();
parameters.Clear();
relativeVelocities.Clear();
}
public override void GetParticlesInvolved(int index, List<int> particles)
{
particles.Add(particleIndices[index]);
}
protected override void SwapConstraints(int sourceIndex, int destIndex)
{
particleIndices.Swap(sourceIndex, destIndex);
pinBodies.Swap(sourceIndex, destIndex);
colliderIndices.Swap(sourceIndex, destIndex);
offsets.Swap(sourceIndex, destIndex);
edgeMus.Swap(sourceIndex, destIndex);
edgeRanges.Swap(sourceIndex * 2, destIndex * 2);
edgeRanges.Swap(sourceIndex * 2 + 1, destIndex * 2 + 1);
edgeRangeMus.Swap(sourceIndex * 2, destIndex * 2);
edgeRangeMus.Swap(sourceIndex * 2 + 1, destIndex * 2 + 1);
for (int i = 0; i < 5; ++i)
parameters.Swap(sourceIndex * 5 + i, destIndex * 5 + i);
relativeVelocities.Swap(sourceIndex, destIndex);
}
public override void Merge(ObiActor actor, IObiConstraintsBatch other)
{
var batch = other as ObiPinholeConstraintsBatch;
if (batch != null)
{
particleIndices.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
colliderIndices.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
offsets.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
edgeRanges.ResizeUninitialized((m_ActiveConstraintCount + batch.activeConstraintCount) * 2);
edgeRangeMus.ResizeUninitialized((m_ActiveConstraintCount + batch.activeConstraintCount) * 2);
edgeMus.ResizeUninitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
parameters.ResizeUninitialized((m_ActiveConstraintCount + batch.activeConstraintCount) * 5);
relativeVelocities.ResizeInitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
lambdas.ResizeInitialized(m_ActiveConstraintCount + batch.activeConstraintCount);
edgeMus.CopyFrom(batch.edgeMus, 0, m_ActiveConstraintCount, batch.activeConstraintCount);
edgeRangeMus.CopyFrom(batch.edgeRangeMus, 0, m_ActiveConstraintCount * 2, batch.activeConstraintCount * 2);
offsets.CopyFrom(batch.offsets, 0, m_ActiveConstraintCount, batch.activeConstraintCount);
relativeVelocities.CopyFrom(batch.relativeVelocities, 0, m_ActiveConstraintCount, batch.activeConstraintCount);
parameters.CopyFrom(batch.parameters, 0, m_ActiveConstraintCount * 5, batch.activeConstraintCount * 5);
for (int i = 0; i < batch.activeConstraintCount; ++i)
{
int currentEdge = -1, firstEdge = -1, lastEdge = -1;
if (batch.pinActors[i] != null)
{
currentEdge = batch.pinActors[i].deformableEdgesOffset + batch.particleIndices[i];
firstEdge = batch.pinActors[i].deformableEdgesOffset + batch.edgeRanges[i * 2];
lastEdge = batch.pinActors[i].deformableEdgesOffset + batch.edgeRanges[i * 2 + 1];
}
edgeRanges[(m_ActiveConstraintCount + i) * 2] = firstEdge;
edgeRanges[(m_ActiveConstraintCount + i) * 2 + 1] = lastEdge;
particleIndices[m_ActiveConstraintCount + i] = Mathf.Clamp(currentEdge, firstEdge, lastEdge);
colliderIndices[m_ActiveConstraintCount + i] = batch.pinBodies[i] != null ? batch.pinBodies[i].index : -1;
}
base.Merge(actor, other);
}
}
public override void AddToSolver(ObiSolver solver)
{
if (solver != null && solver.implementation != null)
{
m_BatchImpl = solver.implementation.CreateConstraintsBatch(constraintType) as IPinholeConstraintsBatchImpl;
if (m_BatchImpl != null)
m_BatchImpl.SetPinholeConstraints(particleIndices, colliderIndices, offsets, edgeMus, edgeRanges, edgeRangeMus, parameters, relativeVelocities, lambdas, m_ActiveConstraintCount);
}
}
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
edgeRanges.Dispose();
colliderIndices.Dispose();
offsets.Dispose();
parameters.Dispose();
if (solver != null && solver.implementation != null)
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}
}
}

View File

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

View File

@@ -8,38 +8,38 @@ namespace Obi
[Serializable]
public class ObiShapeMatchingConstraintsBatch : ObiConstraintsBatch
{
protected IShapeMatchingConstraintsBatchImpl m_BatchImpl;
protected IShapeMatchingConstraintsBatchImpl m_BatchImpl;
/// <summary>
/// index of the first particle in each constraint.
/// </summary>
public ObiNativeIntList firstIndex = new ObiNativeIntList();
public ObiNativeIntList firstIndex = new ObiNativeIntList();
/// <summary>
/// amount of particles in each constraint.
/// </summary>
public ObiNativeIntList numIndices = new ObiNativeIntList();
public ObiNativeIntList numIndices = new ObiNativeIntList();
/// <summary>
/// whether the constraint is implicit (0) or explicit (>0).
/// </summary>
public ObiNativeIntList explicitGroup = new ObiNativeIntList();
public ObiNativeIntList explicitGroup = new ObiNativeIntList();
/// <summary>
/// 5 floats per constraint: stiffness, plastic yield, creep, recovery and max deformation.
/// </summary>
public ObiNativeFloatList materialParameters = new ObiNativeFloatList();
public ObiNativeFloatList materialParameters = new ObiNativeFloatList();
/// <summary>
/// rest center of mass for each constraint.
/// </summary>
public ObiNativeVector4List restComs = new ObiNativeVector4List();
public ObiNativeVector4List restComs = new ObiNativeVector4List();
/// <summary>
/// current center of mass for each constraint.
/// </summary>
public ObiNativeVector4List coms = new ObiNativeVector4List();
public ObiNativeVector4List coms = new ObiNativeVector4List();
/// <summary>
/// current best-match orientation for each constraint.
@@ -96,7 +96,7 @@ namespace Obi
{
int first = firstIndex[index];
int num = numIndices[index];
for (int i = first; i < first + num; ++i)
for (int i = first; i < first + num; ++i)
particles.Add(particleIndices[i]);
}
@@ -154,7 +154,7 @@ namespace Obi
// shape matching constraint particle indices are not reordered when deactivating constraints,
// so instead of using batch.activeConstraintCount, batch.constraintCount. We need all of them.
int numActiveIndices = 0;
for (int i = 0; i < batch.constraintCount; ++i)
for (int i = 0; i < batch.constraintCount; ++i)
numActiveIndices += batch.numIndices[i];
particleIndices.ResizeUninitialized(initialIndexCount + numActiveIndices);
@@ -209,6 +209,19 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
firstIndex.Dispose();
numIndices.Dispose();
explicitGroup.Dispose();
materialParameters.Dispose();
restComs.Dispose();
coms.Dispose();
orientations.Dispose();
linearTransforms.Dispose();
plasticDeformations.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -131,6 +131,13 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
skinPoints.Dispose();
skinNormals.Dispose();
skinRadiiBackstop.Dispose();
skinCompliance.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -141,6 +141,13 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
orientationIndices.Dispose();
restLengths.Dispose();
restOrientations.Dispose();
stiffnesses.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -104,6 +104,11 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
maxLengthsScales.Dispose();
stiffnesses.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -126,6 +126,13 @@ namespace Obi
public override void RemoveFromSolver(ObiSolver solver)
{
base.RemoveFromSolver(solver);
firstTriangle.Dispose();
numTriangles.Dispose();
restVolumes.Dispose();
pressureStiffness.Dispose();
//Remove batch:
solver.implementation.DestroyConstraintsBatch(m_BatchImpl as IConstraintsBatchImpl);
}

View File

@@ -13,18 +13,8 @@ namespace Obi
set;
}
float drag
{
get;
set;
}
float lift
{
get;
set;
}
float GetDrag(ObiAerodynamicConstraintsBatch batch, int constraintIndex);
float GetLift(ObiAerodynamicConstraintsBatch batch, int constraintIndex);
}
[Serializable]

View File

@@ -0,0 +1,16 @@
using UnityEngine;
using System.Collections;
using System;
namespace Obi
{
[Serializable]
public class ObiPinholeConstraintsData : ObiConstraints<ObiPinholeConstraintsBatch>
{
public override ObiPinholeConstraintsBatch CreateBatch(ObiPinholeConstraintsBatch source = null)
{
return new ObiPinholeConstraintsBatch();
}
}
}

View File

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

View File

@@ -8,8 +8,8 @@ namespace Obi
{
Oni.ConstraintType? GetConstraintType();
IObiConstraintsBatch GetBatch(int i);
int GetBatchCount();
IObiConstraintsBatch GetBatch(int i);
int batchCount { get; }
void Clear();
bool AddToSolver(ObiSolver solver);
@@ -17,6 +17,7 @@ namespace Obi
int GetConstraintCount();
int GetActiveConstraintCount();
void ActivateAllConstraints();
void DeactivateAllConstraints();
void Merge(ObiActor actor, IObiConstraints other);
@@ -28,6 +29,8 @@ namespace Obi
[NonSerialized] protected ObiSolver m_Solver;
[HideInInspector] public List<T> batches = new List<T>();
public int batchCount { get => batches == null ? 0 : batches.Count; }
// merges constraints from a given actor with this one.
public void Merge(ObiActor actor, IObiConstraints other)
{
@@ -42,11 +45,11 @@ namespace Obi
actor.solverBatchOffsets[constraintType].Clear();
// create new empty batches if needed:
int newBatches = Mathf.Max(0, others.GetBatchCount() - GetBatchCount());
int newBatches = Mathf.Max(0, others.batchCount - batchCount);
for (int i = 0; i < newBatches; ++i)
AddBatch(CreateBatch());
for (int i = 0; i < other.GetBatchCount(); ++i)
for (int i = 0; i < other.batchCount; ++i)
{
// store this batch's offset:
actor.solverBatchOffsets[constraintType].Add(batches[i].activeConstraintCount);
@@ -64,11 +67,6 @@ namespace Obi
return null;
}
public int GetBatchCount()
{
return batches == null ? 0 : batches.Count;
}
public int GetConstraintCount()
{
int count = 0;
@@ -101,6 +99,14 @@ namespace Obi
batch.DeactivateAllConstraints();
}
public void ActivateAllConstraints()
{
if (batches != null)
foreach (T batch in batches)
if (batch != null)
batch.ActivateAllConstraints();
}
public T GetFirstBatch()
{
return (batches != null && batches.Count > 0) ? batches[0] : null;

View File

@@ -1,106 +1 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Obi
{
/**
* General greedy graph coloring algorithm for constraints. Input:
* - List of particle indices used by all constraints.
* - List of per-constraint offsets of the first constrained particle in the previous array, with the total amount of particle indices in the last position.
*
* The output is a color for each constraint. Constraints of the same color are guaranteed to not share any partices.
*/
public class GraphColoring
{
private List<int> m_ParticleIndices;
private List<int> m_ConstraintIndices;
private List<List<int>> m_ConstraintsPerParticle;
public IReadOnlyList<int> particleIndices => m_ParticleIndices.AsReadOnly();
public IReadOnlyList<int> constraintIndices => m_ConstraintIndices.AsReadOnly();
public GraphColoring(int particleCount = 0)
{
m_ParticleIndices = new List<int>();
m_ConstraintIndices = new List<int>();
m_ConstraintsPerParticle = new List<List<int>>(particleCount);
for (int i = 0; i < particleCount; ++i)
m_ConstraintsPerParticle.Add(new List<int>());
}
public void Clear()
{
m_ParticleIndices.Clear();
m_ConstraintIndices.Clear();
for (int i = 0; i < m_ConstraintsPerParticle.Count; ++i)
m_ConstraintsPerParticle[i].Clear();
}
public void AddConstraint(int[] particles)
{
for (int i = 0; i < particles.Length; ++i)
{
while (particles[i] >= m_ConstraintsPerParticle.Count)
m_ConstraintsPerParticle.Add(new List<int>());
m_ConstraintsPerParticle[particles[i]].Add(m_ConstraintIndices.Count);
}
m_ConstraintIndices.Add(m_ParticleIndices.Count);
m_ParticleIndices.AddRange(particles);
}
public IEnumerator Colorize(string progressDescription, List<int> colors)
{
m_ConstraintIndices.Add(m_ParticleIndices.Count);
int constraintCount = Mathf.Max(0, m_ConstraintIndices.Count - 1);
colors.Clear();
if (constraintCount == 0)
yield break;
colors.Capacity = constraintCount;
bool[] availability = new bool[constraintCount];
for (int i = 0; i < constraintCount; ++i)
{
colors.Add(-1);
availability[i] = true;
}
// For each constraint:
for (int i = 0; i < constraintCount; ++i)
{
// iterate over its particles:
for (int j = m_ConstraintIndices[i]; j < m_ConstraintIndices[i + 1]; ++j)
{
// for each particle, get constraints affecting it:
foreach (int k in m_ConstraintsPerParticle[m_ParticleIndices[j]])
{
// skip ourselves:
if (i == k) continue;
// both constraints share a particle so mark the neighbour color as unavailable:
if (colors[k] >= 0)
availability[colors[k]] = false;
}
}
// Assign the first available color:
for (colors[i] = 0; colors[i] < constraintCount; ++colors[i])
if (availability[colors[i]])
break;
// Reset availability flags:
for (int j = 0; j < constraintCount; ++j)
availability[j] = true;
yield return new CoroutineJob.ProgressInfo(progressDescription, i / (float)constraintCount);
}
}
}
}
using System;

View File

@@ -3,6 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
using System.IO;
#if UNITY_EDITOR
using UnityEditor;
@@ -16,7 +17,9 @@ namespace Obi
public delegate void BlueprintCallback(ObiActorBlueprint blueprint);
public event BlueprintCallback OnBlueprintGenerate;
[HideInInspector] [SerializeField] protected uint m_Checksum;
[HideInInspector] [SerializeField] protected bool m_Empty = true;
[HideInInspector] [SerializeField] protected bool m_Edited = false; /**< Whether there's been any modifications to blueprint data since generating it. This is used to tell whether it can be re-generated without data loss.*/
[HideInInspector] [SerializeField] protected int m_ActiveParticleCount = 0;
[HideInInspector] [SerializeField] protected int m_InitialActiveParticleCount = 0;
[HideInInspector] [SerializeField] protected Bounds _bounds = new Bounds();
@@ -24,6 +27,7 @@ namespace Obi
/**Particle components*/
[HideInInspector] public Vector3[] positions = null; /**< Particle positions.*/
[HideInInspector] public Vector4[] restPositions = null; /**< Particle rest positions, used to filter collisions.*/
[HideInInspector] public Vector4[] restNormals = null; /**< Particle local-space normal in xyz, SDF in w. Used for softbody collisions.*/
[HideInInspector] public Quaternion[] orientations = null; /**< Particle orientations.*/
[HideInInspector] public Quaternion[] restOrientations = null; /**< Particle rest orientations.*/
@@ -35,7 +39,7 @@ namespace Obi
[HideInInspector] public float[] invRotationalMasses = null;
[FormerlySerializedAs("phases")]
[HideInInspector] public int[] filters = null; /**< Particle filters*/
[HideInInspector] public int[] filters = null; /**< Particle filters*/
[HideInInspector] public Vector3[] principalRadii = null; /**< Particle ellipsoid principal radii. These are the ellipsoid radius in each axis.*/
[HideInInspector] public Color[] colors = null; /**< Particle colors (not used by all actors, can be null)*/
@@ -59,6 +63,14 @@ namespace Obi
/** Particle groups.*/
[HideInInspector] public List<ObiParticleGroup> groups = new List<ObiParticleGroup>();
/**
* Checksum value generated from particle positions and orientations.
*/
public uint checksum
{
get { return m_Checksum; }
}
/**
* Returns the amount of particles used by this blueprint.
*/
@@ -72,6 +84,16 @@ namespace Obi
get { return m_ActiveParticleCount; }
}
public Oni.SimplexType simplexTypes
{
get
{
return Oni.SimplexType.Point | // points (single particles) are always available.
(edges != null ? Oni.SimplexType.Edge : 0) |
(triangles != null ? Oni.SimplexType.Triangle : 0);
}
}
/**
* Returns whether this group uses oriented particles.
*/
@@ -80,12 +102,11 @@ namespace Obi
get
{
return invRotationalMasses != null && invRotationalMasses.Length > 0 &&
orientations != null && orientations.Length > 0 &&
restOrientations != null && restOrientations.Length > 0;
orientations != null && orientations.Length > 0;
}
}
public virtual bool usesTethers
public virtual bool usesTethers
{
get { return false; }
}
@@ -99,6 +120,7 @@ namespace Obi
{
positions.Swap(index, m_ActiveParticleCount);
restPositions.Swap(index, m_ActiveParticleCount);
restNormals.Swap(index, m_ActiveParticleCount);
orientations.Swap(index, m_ActiveParticleCount);
restOrientations.Swap(index, m_ActiveParticleCount);
velocities.Swap(index, m_ActiveParticleCount);
@@ -108,6 +130,14 @@ namespace Obi
filters.Swap(index, m_ActiveParticleCount);
principalRadii.Swap(index, m_ActiveParticleCount);
colors.Swap(index, m_ActiveParticleCount);
m_Edited = true;
}
public bool edited
{
get { return m_Edited; }
set { m_Edited = value; }
}
/**
@@ -148,7 +178,7 @@ namespace Obi
{
if (positions.Length > 0)
{
_bounds = new Bounds(positions[0],Vector3.zero);
_bounds = new Bounds(positions[0], Vector3.zero);
for (int i = 1; i < positions.Length; ++i)
_bounds.Encapsulate(positions[i]);
}
@@ -161,27 +191,42 @@ namespace Obi
get { return _bounds; }
}
protected void GenerateChecksum()
{
using (MemoryStream ms = new MemoryStream())
{
if (positions != null)
foreach (var p in positions) ms.Concatenate(p);
if (orientations != null)
foreach (var o in orientations) ms.Concatenate(o);
ms.Flush();
m_Checksum = ObiUtils.Adler32(ms.ToArray());
}
}
public IEnumerable<IObiConstraints> GetConstraints()
{
if (distanceConstraintsData != null && distanceConstraintsData.GetBatchCount() > 0)
if (distanceConstraintsData != null && distanceConstraintsData.batchCount > 0)
yield return distanceConstraintsData;
if (bendConstraintsData != null && bendConstraintsData.GetBatchCount() > 0)
if (bendConstraintsData != null && bendConstraintsData.batchCount > 0)
yield return bendConstraintsData;
if (skinConstraintsData != null && skinConstraintsData.GetBatchCount() > 0)
if (skinConstraintsData != null && skinConstraintsData.batchCount > 0)
yield return skinConstraintsData;
if (tetherConstraintsData != null && tetherConstraintsData.GetBatchCount() > 0)
if (tetherConstraintsData != null && tetherConstraintsData.batchCount > 0)
yield return tetherConstraintsData;
if (stretchShearConstraintsData != null && stretchShearConstraintsData.GetBatchCount() > 0)
if (stretchShearConstraintsData != null && stretchShearConstraintsData.batchCount > 0)
yield return stretchShearConstraintsData;
if (bendTwistConstraintsData != null && bendTwistConstraintsData.GetBatchCount() > 0)
if (bendTwistConstraintsData != null && bendTwistConstraintsData.batchCount > 0)
yield return bendTwistConstraintsData;
if (shapeMatchingConstraintsData != null && shapeMatchingConstraintsData.GetBatchCount() > 0)
if (shapeMatchingConstraintsData != null && shapeMatchingConstraintsData.batchCount > 0)
yield return shapeMatchingConstraintsData;
if (aerodynamicConstraintsData != null && aerodynamicConstraintsData.GetBatchCount() > 0)
if (aerodynamicConstraintsData != null && aerodynamicConstraintsData.batchCount > 0)
yield return aerodynamicConstraintsData;
if (chainConstraintsData != null && chainConstraintsData.GetBatchCount() > 0)
if (chainConstraintsData != null && chainConstraintsData.batchCount > 0)
yield return chainConstraintsData;
if (volumeConstraintsData != null && volumeConstraintsData.GetBatchCount() > 0)
if (volumeConstraintsData != null && volumeConstraintsData.batchCount > 0)
yield return volumeConstraintsData;
}
@@ -226,6 +271,24 @@ namespace Obi
return Quaternion.identity;
}
public Vector3 GetParticleRestPosition(int index)
{
if (restPositions != null && index < restPositions.Length)
{
return restPositions[index];
}
return Vector3.zero;
}
public Quaternion GetParticleRestOrientation(int index)
{
if (restOrientations != null && index < restOrientations.Length)
{
return restOrientations[index];
}
return Quaternion.identity;
}
public void GetParticleAnisotropy(int index, ref Vector4 b1, ref Vector4 b2, ref Vector4 b3)
{
if (orientations != null && index < orientations.Length)
@@ -270,7 +333,7 @@ namespace Obi
public void GenerateImmediate()
{
var g = Generate();
while (g.MoveNext()){}
while (g.MoveNext()) { }
}
public IEnumerator Generate()
@@ -288,24 +351,37 @@ namespace Obi
m_InitialActiveParticleCount = m_ActiveParticleCount;
foreach (IObiConstraints constraints in GetConstraints())
for (int i = 0; i < constraints.GetBatchCount(); ++i)
for (int i = 0; i < constraints.batchCount; ++i)
constraints.GetBatch(i).initialActiveConstraintCount = constraints.GetBatch(i).activeConstraintCount;
CommitBlueprintChanges();
#if UNITY_EDITOR
EditorUtility.SetDirty(this);
if (!Application.isPlaying)
{
EditorUtility.SetDirty(this);
}
#endif
if (OnBlueprintGenerate != null)
OnBlueprintGenerate(this);
OnBlueprintGenerate?.Invoke(this);
}
// Called at the end of blueprint generation. Also automatically called when exiting blueprint editor.
// This generates a checksum for the blueprint, and in some case extra data (such as default skinmaps for cloth and softbodies).
public virtual void CommitBlueprintChanges()
{
GenerateChecksum();
}
public void Clear()
{
m_Empty = true;
edited = false;
m_ActiveParticleCount = 0;
positions = null;
restPositions = null;
restNormals = null;
orientations = null;
restOrientations = null;
velocities = null;
@@ -313,7 +389,6 @@ namespace Obi
invMasses = null;
invRotationalMasses = null;
filters = null;
//phases = null;
principalRadii = null;
colors = null;
@@ -355,7 +430,7 @@ namespace Obi
{
EditorUtility.SetDirty(this);
if (saveImmediately)
AssetDatabase.SaveAssets();
AssetDatabase.SaveAssetIfDirty(this);
}
}
else
@@ -364,6 +439,8 @@ namespace Obi
groups.Insert(index, group);
}
edited = true;
return group;
}
return null;
@@ -393,7 +470,7 @@ namespace Obi
{
EditorUtility.SetDirty(this);
if (saveImmediately)
AssetDatabase.SaveAssets();
AssetDatabase.SaveAssetIfDirty(this);
}
}
else
@@ -406,6 +483,8 @@ namespace Obi
DestroyImmediate(group, true);
}
edited = true;
return true;
}
return false;
@@ -425,7 +504,7 @@ namespace Obi
{
EditorUtility.SetDirty(this);
if (saveImmediately)
AssetDatabase.SaveAssets();
AssetDatabase.SaveAssetIfDirty(this);
}
}
else
@@ -434,26 +513,39 @@ namespace Obi
groups[index].name = name;
}
edited = true;
return true;
}
return false;
}
public void ClearParticleGroups(bool saveImmediately = true)
public void ClearParticleGroups(bool registerUndo = true, bool saveImmediately = true)
{
if (groups.Count == 0) return;
#if UNITY_EDITOR
if (!Application.isPlaying)
{
Undo.RecordObject(this, "Clear particle groups");
for (int i = 0; i < groups.Count; ++i)
if (groups[i] != null)
Undo.DestroyObjectImmediate(groups[i]);
if (registerUndo)
{
Undo.RecordObject(this, "Clear particle groups");
for (int i = 0; i < groups.Count; ++i)
if (groups[i] != null)
Undo.DestroyObjectImmediate(groups[i]);
}
else
{
for (int i = 0; i < groups.Count; ++i)
if (groups[i] != null)
DestroyImmediate(groups[i], true);
}
if (EditorUtility.IsPersistent(this))
{
EditorUtility.SetDirty(this);
if (saveImmediately)
AssetDatabase.SaveAssets();
AssetDatabase.SaveAssetIfDirty(this);
}
}
else
@@ -488,7 +580,7 @@ namespace Obi
private bool DoesParticleShareConstraints(IObiConstraints constraints, int index, List<int> particles, bool[] selected)
{
bool shared = false;
for (int i = 0; i < constraints.GetBatchCount(); ++i)
for (int i = 0; i < constraints.batchCount; ++i)
{
var batch = constraints.GetBatch(i);
for (int j = 0; j < batch.activeConstraintCount; ++j)
@@ -508,7 +600,7 @@ namespace Obi
private void DeactivateConstraintsWithInactiveParticles(IObiConstraints constraints, List<int> particles)
{
for (int j = 0; j < constraints.GetBatchCount(); ++j)
for (int j = 0; j < constraints.batchCount; ++j)
{
var batch = constraints.GetBatch(j);
@@ -526,6 +618,8 @@ namespace Obi
}
}
}
edited = true;
}
private void ParticlesSwappedInGroups(int index, int newIndex)
@@ -541,9 +635,11 @@ namespace Obi
group.particleIndices[i] = newIndex;
}
}
edited = true;
}
public void RemoveSelectedParticles(ref bool[] selected, bool optimize = true)
public virtual void RemoveSelectedParticles(ref bool[] selected, bool optimize = true)
{
List<int> particles = new List<int>();
@@ -571,7 +667,7 @@ namespace Obi
// Update constraints:
foreach (IObiConstraints constraints in GetConstraints())
for (int j = 0; j < constraints.GetBatchCount(); ++j)
for (int j = 0; j < constraints.batchCount; ++j)
constraints.GetBatch(j).ParticlesSwapped(i, m_ActiveParticleCount);
// Update groups:
@@ -585,6 +681,9 @@ namespace Obi
foreach (IObiConstraints constraints in GetConstraints())
DeactivateConstraintsWithInactiveParticles(constraints, particles);
CommitBlueprintChanges();
edited = true;
}
public void RestoreRemovedParticles()
@@ -592,9 +691,10 @@ namespace Obi
m_ActiveParticleCount = m_InitialActiveParticleCount;
foreach (IObiConstraints constraints in GetConstraints())
for (int j = 0; j < constraints.GetBatchCount(); ++j)
for (int j = 0; j < constraints.batchCount; ++j)
constraints.GetBatch(j).activeConstraintCount = constraints.GetBatch(j).initialActiveConstraintCount;
CommitBlueprintChanges();
}
public virtual void GenerateTethers(bool[] selected) { }