重新导入obi

This commit is contained in:
2026-04-06 11:35:18 +08:00
parent 05fa2d6e5e
commit ae3002a0e2
1643 changed files with 232496 additions and 13 deletions

View File

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

View File

@@ -0,0 +1,26 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
namespace Obi
{
public class BurstAerodynamicConstraints : BurstConstraintsImpl<BurstAerodynamicConstraintsBatch>
{
public BurstAerodynamicConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.Aerodynamics)
{
}
public override IConstraintsBatchImpl CreateConstraintsBatch()
{
var dataBatch = new BurstAerodynamicConstraintsBatch(this);
batches.Add(dataBatch);
return dataBatch;
}
public override void RemoveBatch(IConstraintsBatchImpl batch)
{
batches.Remove(batch as BurstAerodynamicConstraintsBatch);
batch.Destroy();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,112 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
using System.Collections;
namespace Obi
{
public class BurstAerodynamicConstraintsBatch : BurstConstraintsBatchImpl, IAerodynamicConstraintsBatchImpl
{
private NativeArray<float> aerodynamicCoeffs;
public BurstAerodynamicConstraintsBatch(BurstAerodynamicConstraints constraints)
{
m_Constraints = constraints;
m_ConstraintType = Oni.ConstraintType.Aerodynamics;
}
public void SetAerodynamicConstraints(ObiNativeIntList particleIndices, ObiNativeFloatList aerodynamicCoeffs, int count)
{
this.particleIndices = particleIndices.AsNativeArray<int>();
this.aerodynamicCoeffs = aerodynamicCoeffs.AsNativeArray<float>();
m_ConstraintCount = count;
}
public override JobHandle Initialize(JobHandle inputDeps, float substepTime)
{
return inputDeps;
}
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
var projectConstraints = new AerodynamicConstraintsBatchJob()
{
particleIndices = particleIndices,
aerodynamicCoeffs = aerodynamicCoeffs,
positions = solverImplementation.positions,
velocities = solverImplementation.velocities,
normals = solverImplementation.normals,
wind = solverImplementation.wind,
invMasses = solverImplementation.invMasses,
deltaTime = substepTime
};
return projectConstraints.Schedule(m_ConstraintCount, 32, inputDeps);
}
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
{
return inputDeps;
}
[BurstCompile]
public struct AerodynamicConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] [NativeDisableParallelForRestriction] public NativeArray<float> aerodynamicCoeffs;
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float4> normals;
[ReadOnly] public NativeArray<float4> wind;
[ReadOnly] public NativeArray<float> invMasses;
[NativeDisableContainerSafetyRestriction]
public NativeArray<float4> velocities;
[ReadOnly] public float deltaTime;
public void Execute(int i)
{
int p = particleIndices[i];
float area = aerodynamicCoeffs[i * 3];
float dragCoeff = aerodynamicCoeffs[i * 3 + 1];
float liftCoeff = aerodynamicCoeffs[i * 3 + 2];
if (invMasses[p] > 0)
{
float4 relVelocity = velocities[p] - wind[p];
float rvSqrMag = math.lengthsq(relVelocity);
if (rvSqrMag < BurstMath.epsilon)
return;
float4 rvNorm = relVelocity / math.sqrt(rvSqrMag);
// calculate surface normal (always facing wind)
float4 surfNormal = normals[p] * math.sign(math.dot(normals[p], rvNorm));
// aerodynamic_factor was originally multiplied by air_density. The density is now premultiplied in lift and drag.
float aerodynamicFactor = 0.5f * rvSqrMag * area;
float attackAngle = math.dot(surfNormal,rvNorm);
float3 liftDirection = math.normalizesafe(math.cross(math.cross(surfNormal.xyz, rvNorm.xyz), rvNorm.xyz));
//drag:
velocities[p] += (-dragCoeff * rvNorm +
// lift:
liftCoeff * new float4(liftDirection.xyz,0)) *
// scale
attackAngle * math.min(aerodynamicFactor * invMasses[p] * deltaTime, 1000);
}
}
}
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,26 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
namespace Obi
{
public class BurstBendConstraints : BurstConstraintsImpl<BurstBendConstraintsBatch>
{
public BurstBendConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.Bending)
{
}
public override IConstraintsBatchImpl CreateConstraintsBatch()
{
var dataBatch = new BurstBendConstraintsBatch(this);
batches.Add(dataBatch);
return dataBatch;
}
public override void RemoveBatch(IConstraintsBatchImpl batch)
{
batches.Remove(batch as BurstBendConstraintsBatch);
batch.Destroy();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,169 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
using System.Collections;
namespace Obi
{
public class BurstBendConstraintsBatch : BurstConstraintsBatchImpl, IBendConstraintsBatchImpl
{
private NativeArray<float> restBends;
private NativeArray<float2> stiffnesses;
private NativeArray<float2> plasticity;
BendConstraintsBatchJob projectConstraints;
ApplyBendConstraintsBatchJob applyConstraints;
public BurstBendConstraintsBatch(BurstBendConstraints constraints)
{
m_Constraints = constraints;
m_ConstraintType = Oni.ConstraintType.Bending;
}
public void SetBendConstraints(ObiNativeIntList particleIndices, ObiNativeFloatList restBends, ObiNativeVector2List bendingStiffnesses, ObiNativeVector2List plasticity, ObiNativeFloatList lambdas, int count)
{
this.particleIndices = particleIndices.AsNativeArray<int>();
this.restBends = restBends.AsNativeArray<float>();
this.stiffnesses = bendingStiffnesses.AsNativeArray<float2>();
this.plasticity = plasticity.AsNativeArray<float2>();
this.lambdas = lambdas.AsNativeArray<float>();
m_ConstraintCount = count;
projectConstraints.particleIndices = this.particleIndices;
projectConstraints.restBends = this.restBends;
projectConstraints.stiffnesses = this.stiffnesses;
projectConstraints.plasticity = this.plasticity;
projectConstraints.lambdas = this.lambdas;
applyConstraints.particleIndices = this.particleIndices;
}
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
projectConstraints.positions = solverImplementation.positions;
projectConstraints.invMasses = solverImplementation.invMasses;
projectConstraints.deltas = solverImplementation.positionDeltas;
projectConstraints.counts = solverImplementation.positionConstraintCounts;
projectConstraints.deltaTime = substepTime;
return projectConstraints.Schedule(m_ConstraintCount, 32, inputDeps);
}
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
{
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
applyConstraints.positions = solverImplementation.positions;
applyConstraints.deltas = solverImplementation.positionDeltas;
applyConstraints.counts = solverImplementation.positionConstraintCounts;
applyConstraints.sorFactor = parameters.SORFactor;
return applyConstraints.Schedule(m_ConstraintCount, 64, inputDeps);
}
[BurstCompile]
public struct BendConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public NativeArray<float2> stiffnesses;
[ReadOnly] public NativeArray<float2> plasticity; //plastic yield, creep
public NativeArray<float> restBends;
public NativeArray<float> lambdas;
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float> invMasses;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<int> counts;
[ReadOnly] public float deltaTime;
public void Execute(int i)
{
int p1 = particleIndices[i * 3];
int p2 = particleIndices[i * 3 + 1];
int p3 = particleIndices[i * 3 + 2];
float w1 = invMasses[p1];
float w2 = invMasses[p2];
float w3 = invMasses[p3];
float wsum = w1 + w2 + 2 * w3;
float4 bendVector = positions[p3] - (positions[p1] + positions[p2] + positions[p3]) / 3.0f;
float bend = math.length(bendVector);
float constraint = bend - restBends[i];
constraint = math.max(0, constraint - stiffnesses[i].x) +
math.min(0, constraint + stiffnesses[i].x);
// plasticity:
if (math.abs(constraint) > plasticity[i].x)
restBends[i] += constraint * plasticity[i].y * deltaTime;
// calculate time adjusted compliance
float compliance = stiffnesses[i].y / (deltaTime * deltaTime);
// since the third particle moves twice the amount of the other 2, the modulus of its gradient is 2:
float dlambda = (-constraint - compliance * lambdas[i]) / (wsum + compliance + BurstMath.epsilon);
float4 correction = dlambda * bendVector / (bend + BurstMath.epsilon);
lambdas[i] += dlambda;
deltas[p1] -= correction * 2 * w1;
deltas[p2] -= correction * 2 * w2;
deltas[p3] += correction * 4 * w3;
counts[p1]++;
counts[p2]++;
counts[p3]++;
}
}
[BurstCompile]
public struct ApplyBendConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public float sorFactor;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
public void Execute(int i)
{
int p1 = particleIndices[i * 3];
int p2 = particleIndices[i * 3 + 1];
int p3 = particleIndices[i * 3 + 2];
if (counts[p1] > 0)
{
positions[p1] += deltas[p1] * sorFactor / counts[p1];
deltas[p1] = float4.zero;
counts[p1] = 0;
}
if (counts[p2] > 0)
{
positions[p2] += deltas[p2] * sorFactor / counts[p2];
deltas[p2] = float4.zero;
counts[p2] = 0;
}
if (counts[p3] > 0)
{
positions[p3] += deltas[p3] * sorFactor / counts[p3];
deltas[p3] = float4.zero;
counts[p3] = 0;
}
}
}
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,26 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
namespace Obi
{
public class BurstBendTwistConstraints : BurstConstraintsImpl<BurstBendTwistConstraintsBatch>
{
public BurstBendTwistConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.BendTwist)
{
}
public override IConstraintsBatchImpl CreateConstraintsBatch()
{
var dataBatch = new BurstBendTwistConstraintsBatch(this);
batches.Add(dataBatch);
return dataBatch;
}
public override void RemoveBatch(IConstraintsBatchImpl batch)
{
batches.Remove(batch as BurstBendTwistConstraintsBatch);
batch.Destroy();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,182 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
using System.Collections;
namespace Obi
{
public class BurstBendTwistConstraintsBatch : BurstConstraintsBatchImpl, IBendTwistConstraintsBatchImpl
{
private NativeArray<int> orientationIndices;
private NativeArray<quaternion> restDarboux;
private NativeArray<float3> stiffnesses;
private NativeArray<float2> plasticity;
public BurstBendTwistConstraintsBatch(BurstBendTwistConstraints constraints)
{
m_Constraints = constraints;
m_ConstraintType = Oni.ConstraintType.BendTwist;
}
public void SetBendTwistConstraints(ObiNativeIntList orientationIndices, ObiNativeQuaternionList restDarboux, ObiNativeVector3List stiffnesses, ObiNativeVector2List plasticity, ObiNativeFloatList lambdas, int count)
{
this.orientationIndices = orientationIndices.AsNativeArray<int>();
this.restDarboux = restDarboux.AsNativeArray<quaternion>();
this.stiffnesses = stiffnesses.AsNativeArray<float3>();
this.plasticity = plasticity.AsNativeArray<float2>();
this.lambdas = lambdas.AsNativeArray<float>();
m_ConstraintCount = count;
}
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
var projectConstraints = new BendTwistConstraintsBatchJob()
{
orientationIndices = orientationIndices,
restDarboux = restDarboux,
stiffnesses = stiffnesses,
plasticity = plasticity,
lambdas = lambdas.Reinterpret<float, float3>(),
orientations = solverImplementation.orientations,
invRotationalMasses = solverImplementation.invRotationalMasses,
orientationDeltas = solverImplementation.orientationDeltas,
orientationCounts = solverImplementation.orientationConstraintCounts ,
deltaTime = substepTime
};
return projectConstraints.Schedule(m_ConstraintCount, 32, inputDeps);
}
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
{
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
var applyConstraints = new ApplyBendTwistConstraintsBatchJob()
{
orientationIndices = orientationIndices,
orientations = solverImplementation.orientations,
orientationDeltas = solverImplementation.orientationDeltas,
orientationCounts = solverImplementation.orientationConstraintCounts,
sorFactor = parameters.SORFactor
};
return applyConstraints.Schedule(m_ConstraintCount, 64, inputDeps);
}
[BurstCompile]
public struct BendTwistConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> orientationIndices;
[ReadOnly] public NativeArray<float3> stiffnesses;
[ReadOnly] public NativeArray<float2> plasticity;
public NativeArray<quaternion> restDarboux;
public NativeArray<float3> lambdas;
[ReadOnly] public NativeArray<quaternion> orientations;
[ReadOnly] public NativeArray<float> invRotationalMasses;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<quaternion> orientationDeltas;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<int> orientationCounts;
[ReadOnly] public float deltaTime;
public void Execute(int i)
{
int q1 = orientationIndices[i * 2];
int q2 = orientationIndices[i * 2 + 1];
float w1 = invRotationalMasses[q1];
float w2 = invRotationalMasses[q2];
// calculate time adjusted compliance
float3 compliances = stiffnesses[i] / (deltaTime * deltaTime);
// rest and current darboux vectors
quaternion rest = restDarboux[i];
quaternion omega = math.mul(math.conjugate(orientations[q1]), orientations[q2]);
quaternion omega_plus;
omega_plus.value = omega.value + rest.value; //delta Omega with - omega_0
omega.value -= rest.value; //delta Omega with + omega_0
if (math.lengthsq(omega.value) > math.lengthsq(omega_plus.value))
omega = omega_plus;
// plasticity
if (math.lengthsq(omega.value) > plasticity[i].x * plasticity[i].x)
{
rest.value += omega.value * plasticity[i].y * deltaTime;
restDarboux[i] = rest;
}
float3 dlambda = (omega.value.xyz - compliances * lambdas[i]) / (compliances + new float3(w1 + w2 + BurstMath.epsilon));
//discrete Darboux vector does not have vanishing scalar part
quaternion dlambdaQ = new quaternion(dlambda[0], dlambda[1], dlambda[2],0);
quaternion d1 = orientationDeltas[q1];
quaternion d2 = orientationDeltas[q2];
d1.value += math.mul(orientations[q2], dlambdaQ).value * w1;
d2.value -= math.mul(orientations[q1], dlambdaQ).value * w2;
orientationDeltas[q1] = d1;
orientationDeltas[q2] = d2;
orientationCounts[q1]++;
orientationCounts[q2]++;
lambdas[i] += dlambda;
}
}
[BurstCompile]
public struct ApplyBendTwistConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> orientationIndices;
[ReadOnly] public float sorFactor;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<quaternion> orientations;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<quaternion> orientationDeltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> orientationCounts;
public void Execute(int i)
{
int p1 = orientationIndices[i * 2];
int p2 = orientationIndices[i * 2 + 1];
if (orientationCounts[p1] > 0)
{
quaternion q = orientations[p1];
q.value += orientationDeltas[p1].value * sorFactor / orientationCounts[p1];
orientations[p1] = math.normalize(q);
orientationDeltas[p1] = new quaternion(0, 0, 0, 0);
orientationCounts[p1] = 0;
}
if (orientationCounts[p2] > 0)
{
quaternion q = orientations[p2];
q.value += orientationDeltas[p2].value * sorFactor / orientationCounts[p2];
orientations[p2] = math.normalize(q);
orientationDeltas[p2] = new quaternion(0, 0, 0, 0);
orientationCounts[p2] = 0;
}
}
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,109 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Burst;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using System.Collections;
namespace Obi
{
public abstract class BurstConstraintsBatchImpl : IConstraintsBatchImpl
{
protected IBurstConstraintsImpl m_Constraints;
protected Oni.ConstraintType m_ConstraintType;
protected bool m_Enabled = true;
protected int m_ConstraintCount = 0;
public Oni.ConstraintType constraintType
{
get { return m_ConstraintType; }
}
public bool enabled
{
set
{
if (m_Enabled != value)
m_Enabled = value;
}
get { return m_Enabled; }
}
public IConstraints constraints
{
get { return m_Constraints; }
}
public ObiSolver solverAbstraction
{
get { return ((BurstSolverImpl)m_Constraints.solver).abstraction; }
}
public BurstSolverImpl solverImplementation
{
get { return (BurstSolverImpl)m_Constraints.solver; }
}
protected NativeArray<int> particleIndices;
protected NativeArray<float> lambdas;
public virtual JobHandle Initialize(JobHandle inputDeps, float substepTime)
{
if (lambdas.IsCreated)
{
// no need for jobs here, memclear is faster and we don't pay scheduling overhead.
unsafe
{
UnsafeUtility.MemClear(NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(lambdas),
lambdas.Length * UnsafeUtility.SizeOf<float>());
}
}
return inputDeps;
}
// implemented by concrete constraint subclasses.
public abstract JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps);
public abstract JobHandle Apply(JobHandle inputDeps, float substepTime);
public virtual void Destroy()
{
// clean resources allocated by the batch, no need for a default implementation.
}
public void SetConstraintCount(int constraintCount)
{
m_ConstraintCount = constraintCount;
}
public int GetConstraintCount()
{
return m_ConstraintCount;
}
public static void ApplyPositionDelta(int particleIndex, float sorFactor, ref NativeArray<float4> positions, ref NativeArray<float4> deltas, ref NativeArray<int> counts)
{
if (counts[particleIndex] > 0)
{
positions[particleIndex] += deltas[particleIndex] * sorFactor / counts[particleIndex];
deltas[particleIndex] = float4.zero;
counts[particleIndex] = 0;
}
}
public static void ApplyOrientationDelta(int particleIndex, float sorFactor, ref NativeArray<quaternion> orientations, ref NativeArray<quaternion> deltas, ref NativeArray<int> counts)
{
if (counts[particleIndex] > 0)
{
quaternion q = orientations[particleIndex];
q.value += deltas[particleIndex].value * sorFactor / counts[particleIndex];
orientations[particleIndex] = math.normalize(q);
deltas[particleIndex] = new quaternion(0, 0, 0, 0);
counts[particleIndex] = 0;
}
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,145 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using System.Collections;
using System.Collections.Generic;
namespace Obi
{
public interface IBurstConstraintsImpl : IConstraints
{
JobHandle Initialize(JobHandle inputDeps, float substepTime);
JobHandle Project(JobHandle inputDeps, float stepTime, float substepTime, int substeps);
void Dispose();
IConstraintsBatchImpl CreateConstraintsBatch();
void RemoveBatch(IConstraintsBatchImpl batch);
}
public abstract class BurstConstraintsImpl<T> : IBurstConstraintsImpl where T : BurstConstraintsBatchImpl
{
protected BurstSolverImpl m_Solver;
public List<T> batches = new List<T>();
protected Oni.ConstraintType m_ConstraintType;
public Oni.ConstraintType constraintType
{
get { return m_ConstraintType; }
}
public ISolverImpl solver
{
get { return m_Solver; }
}
public BurstConstraintsImpl(BurstSolverImpl solver, Oni.ConstraintType constraintType)
{
this.m_ConstraintType = constraintType;
this.m_Solver = solver;
}
public virtual void Dispose()
{
}
public abstract IConstraintsBatchImpl CreateConstraintsBatch();
public abstract void RemoveBatch(IConstraintsBatchImpl batch);
public virtual int GetConstraintCount()
{
int count = 0;
if (batches == null) return count;
foreach (T batch in batches)
if (batch != null)
count += batch.GetConstraintCount();
return count;
}
public JobHandle Initialize(JobHandle inputDeps, float substepTime)
{
// initialize all batches in parallel:
if (batches.Count > 0)
{
NativeArray<JobHandle> deps = new NativeArray<JobHandle>(batches.Count, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
for (int i = 0; i < batches.Count; ++i)
deps[i] = batches[i].enabled ? batches[i].Initialize(inputDeps, substepTime) : inputDeps;
JobHandle result = JobHandle.CombineDependencies(deps);
deps.Dispose();
return result;
}
return inputDeps;
}
public JobHandle Project(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
UnityEngine.Profiling.Profiler.BeginSample("Project");
var parameters = m_Solver.abstraction.GetConstraintParameters(m_ConstraintType);
switch(parameters.evaluationOrder)
{
case Oni.ConstraintParameters.EvaluationOrder.Sequential:
inputDeps = EvaluateSequential(inputDeps, stepTime, substepTime, substeps);
break;
case Oni.ConstraintParameters.EvaluationOrder.Parallel:
inputDeps = EvaluateParallel(inputDeps, stepTime, substepTime, substeps);
break;
}
UnityEngine.Profiling.Profiler.EndSample();
return inputDeps;
}
protected virtual JobHandle EvaluateSequential(JobHandle inputDeps, float stepTime, float substepTime,int substeps)
{
// evaluate and apply all batches:
for (int i = 0; i < batches.Count; ++i)
{
if (batches[i].enabled)
{
inputDeps = batches[i].Evaluate(inputDeps, stepTime, substepTime, substeps);
inputDeps = batches[i].Apply(inputDeps, substepTime);
m_Solver.ScheduleBatchedJobsIfNeeded();
}
}
return inputDeps;
}
protected virtual JobHandle EvaluateParallel(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
// evaluate all batches:
for (int i = 0; i < batches.Count; ++i)
if (batches[i].enabled)
{
inputDeps = batches[i].Evaluate(inputDeps, stepTime, substepTime, substeps);
m_Solver.ScheduleBatchedJobsIfNeeded();
}
// then apply them:
for (int i = 0; i < batches.Count; ++i)
if (batches[i].enabled)
{
inputDeps = batches[i].Apply(inputDeps, substepTime);
m_Solver.ScheduleBatchedJobsIfNeeded();
}
return inputDeps;
}
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,26 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
namespace Obi
{
public class BurstChainConstraints : BurstConstraintsImpl<BurstChainConstraintsBatch>
{
public BurstChainConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.Chain)
{
}
public override IConstraintsBatchImpl CreateConstraintsBatch()
{
var dataBatch = new BurstChainConstraintsBatch(this);
batches.Add(dataBatch);
return dataBatch;
}
public override void RemoveBatch(IConstraintsBatchImpl batch)
{
batches.Remove(batch as BurstChainConstraintsBatch);
batch.Destroy();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,217 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
using System.Collections;
namespace Obi
{
public class BurstChainConstraintsBatch : BurstConstraintsBatchImpl, IChainConstraintsBatchImpl
{
private NativeArray<int> firstIndex;
private NativeArray<int> numIndices;
private NativeArray<float2> restLengths;
public BurstChainConstraintsBatch(BurstChainConstraints constraints)
{
m_Constraints = constraints;
m_ConstraintType = Oni.ConstraintType.Chain;
}
public void SetChainConstraints(ObiNativeIntList particleIndices, ObiNativeVector2List restLengths, ObiNativeIntList firstIndex, ObiNativeIntList numIndices, int count)
{
this.particleIndices = particleIndices.AsNativeArray<int>();
this.firstIndex = firstIndex.AsNativeArray<int>();
this.numIndices = numIndices.AsNativeArray<int>();
this.restLengths = restLengths.AsNativeArray<float2>();
m_ConstraintCount = count;
}
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
var projectConstraints = new ChainConstraintsBatchJob()
{
particleIndices = particleIndices,
firstIndex = firstIndex,
numIndices = numIndices,
restLengths = restLengths,
positions = solverImplementation.positions,
invMasses = solverImplementation.invMasses,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts
};
return projectConstraints.Schedule(m_ConstraintCount, 4, inputDeps);
}
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
{
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
var applyConstraints = new ApplyChainConstraintsBatchJob()
{
particleIndices = particleIndices,
firstIndex = firstIndex,
numIndices = numIndices,
positions = solverImplementation.positions,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
sorFactor = parameters.SORFactor
};
return applyConstraints.Schedule(m_ConstraintCount, 8, inputDeps);
}
[BurstCompile]
public struct ChainConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public NativeArray<int> firstIndex;
[ReadOnly] public NativeArray<int> numIndices;
[ReadOnly] public NativeArray<float2> restLengths;
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float> invMasses;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<int> counts;
public void Execute(int c)
{
int numEdges = numIndices[c] - 1;
int first = firstIndex[c];
float minLength = restLengths[c].y;
float maxLength = restLengths[c].y;
// (ni:constraint gradient, di:desired lenght)
NativeArray<float4> ni = new NativeArray<float4>(numEdges, Allocator.Temp);
NativeArray<float> di = new NativeArray<float>(numEdges, Allocator.Temp);
for (int i = 0; i < numEdges; ++i)
{
int edge = first + i;
float4 p1 = positions[particleIndices[edge]];
float4 p2 = positions[particleIndices[edge+1]];
float4 diff = p1 - p2;
float distance = math.length(diff);
float correction = 0;
if (distance >= maxLength)
correction = distance - maxLength;
else if (distance <= minLength)
correction = distance - minLength;
di[i] = correction;
ni[i] = new float4(diff/(distance + BurstMath.epsilon));
}
// calculate ai (subdiagonals), bi (diagonals) and ci (superdiagonals):
NativeArray<float3> diagonals = new NativeArray<float3>(numEdges, Allocator.Temp);
for (int i = 0; i < numEdges; ++i)
{
int edge = first + i;
float w_i_ = invMasses[particleIndices[edge]];
float w__i = invMasses[particleIndices[edge+1]];
float4 ni__ = (i > 0) ? ni[i - 1] : float4.zero;
float4 n_i_ = ni[i];
float4 n__i = (i < numEdges - 1) ? ni[i + 1] : float4.zero;
diagonals[i] = new float3(
-w_i_ * math.dot(n_i_, ni__), // ai
w_i_ + w__i, // bi
-w__i * math.dot(n_i_, n__i));// ci
}
NativeArray<float2> sweep = new NativeArray<float2>(numEdges, Allocator.Temp);
// solve step #1, forward sweep:
for (int i = 0; i < numEdges; ++i)
{
int edge = first + i;
float cip_ = (i > 0) ? sweep[i - 1].x : 0;
float dip_ = (i > 0) ? sweep[i - 1].y : 0;
float den = diagonals[i].y - cip_ * diagonals[i].x;
if (den != 0)
{
sweep[i] = new float2((diagonals[i].z / den),
(di[i] - dip_ * diagonals[i].x) / den);
}
else
sweep[i] = float2.zero;
}
// solve step #2, backward sweep:
NativeArray<float> xi = new NativeArray<float>(numEdges, Allocator.Temp);
for (int i = numEdges - 1; i >= 0; --i)
{
int edge = first + i;
float xi_ = (i < numEdges - 1) ? xi[i + 1] : 0;
xi[i] = sweep[i].y - sweep[i].x * xi_;
}
// calculate deltas:
for (int i = 0; i < numIndices[c]; ++i)
{
int index = first + i;
float4 ni__ = (i > 0) ? ni[i - 1] : float4.zero;
float4 n_i_ = (i < numIndices[c] - 1) ? ni[i] : float4.zero;
float xi_ = (i > 0) ? xi[i - 1] : 0;
float nxi = (i < numIndices[c] - 1) ? xi[i] : 0;
int p = particleIndices[index];
deltas[p] -= invMasses[p] * (-ni__ * xi_ + n_i_ * nxi);
counts[p]++;
}
}
}
[BurstCompile]
public struct ApplyChainConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public NativeArray<int> firstIndex;
[ReadOnly] public NativeArray<int> numIndices;
[ReadOnly] public float sorFactor;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
public void Execute(int i)
{
int first = firstIndex[i];
int last = first + numIndices[i];
for (int k = first; k < last; ++k)
{
int p = particleIndices[k];
if (counts[p] > 0)
{
positions[p] += deltas[p] * sorFactor / counts[p];
deltas[p] = float4.zero;
counts[p] = 0;
}
}
}
}
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,49 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Mathematics;
using Unity.Burst;
using System;
using System.Collections;
namespace Obi
{
[BurstCompile]
public struct ApplyCollisionConstraintsBatchJob : IJob
{
[ReadOnly] public NativeArray<BurstContact> contacts;
[ReadOnly] public NativeArray<int> simplices;
[ReadOnly] public SimplexCounts simplexCounts;
[NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableParallelForRestriction] public NativeArray<int> counts;
[NativeDisableParallelForRestriction] public NativeArray<quaternion> orientations;
[NativeDisableParallelForRestriction] public NativeArray<quaternion> orientationDeltas;
[NativeDisableParallelForRestriction] public NativeArray<int> orientationCounts;
[ReadOnly] public Oni.ConstraintParameters constraintParameters;
public void Execute()
{
for (int i = 0; i < contacts.Length; ++i)
{
int simplexStart = simplexCounts.GetSimplexStartAndSize(contacts[i].bodyA, out int simplexSize);
for (int j = 0; j < simplexSize; ++j)
{
int particleIndex = simplices[simplexStart + j];
BurstConstraintsBatchImpl.ApplyPositionDelta(particleIndex, constraintParameters.SORFactor, ref positions, ref deltas, ref counts);
BurstConstraintsBatchImpl.ApplyOrientationDelta(particleIndex, constraintParameters.SORFactor, ref orientations, ref orientationDeltas, ref orientationCounts);
}
}
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,33 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
namespace Obi
{
public class BurstColliderCollisionConstraints : BurstConstraintsImpl<BurstColliderCollisionConstraintsBatch>
{
public BurstColliderCollisionConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.Collision)
{
}
public override IConstraintsBatchImpl CreateConstraintsBatch()
{
var dataBatch = new BurstColliderCollisionConstraintsBatch(this);
batches.Add(dataBatch);
return dataBatch;
}
public override void RemoveBatch(IConstraintsBatchImpl batch)
{
batches.Remove(batch as BurstColliderCollisionConstraintsBatch);
batch.Destroy();
}
public override int GetConstraintCount()
{
if (!((BurstSolverImpl)solver).colliderContacts.IsCreated)
return 0;
return ((BurstSolverImpl)solver).colliderContacts.Length;
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,330 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
using System.Collections;
namespace Obi
{
public class BurstColliderCollisionConstraintsBatch : BurstConstraintsBatchImpl, IColliderCollisionConstraintsBatchImpl
{
public BurstColliderCollisionConstraintsBatch(BurstColliderCollisionConstraints constraints)
{
m_Constraints = constraints;
m_ConstraintType = Oni.ConstraintType.Collision;
}
public override JobHandle Initialize(JobHandle inputDeps, float substepTime)
{
var updateContacts = new UpdateContactsJob()
{
prevPositions = solverImplementation.prevPositions,
prevOrientations = solverImplementation.prevOrientations,
velocities = solverImplementation.velocities,
radii = solverImplementation.principalRadii,
invMasses = solverImplementation.invMasses,
invInertiaTensors = solverImplementation.invInertiaTensors,
particleMaterialIndices = solverImplementation.collisionMaterials,
collisionMaterials = ObiColliderWorld.GetInstance().collisionMaterials.AsNativeArray<BurstCollisionMaterial>(),
simplices = solverImplementation.simplices,
simplexCounts = solverImplementation.simplexCounts,
shapes = ObiColliderWorld.GetInstance().colliderShapes.AsNativeArray<BurstColliderShape>(),
transforms = ObiColliderWorld.GetInstance().colliderTransforms.AsNativeArray<BurstAffineTransform>(),
rigidbodies = ObiColliderWorld.GetInstance().rigidbodies.AsNativeArray<BurstRigidbody>(),
rigidbodyLinearDeltas = solverImplementation.abstraction.rigidbodyLinearDeltas.AsNativeArray<float4>(),
rigidbodyAngularDeltas = solverImplementation.abstraction.rigidbodyAngularDeltas.AsNativeArray<float4>(),
contacts = ((BurstSolverImpl)constraints.solver).colliderContacts,
inertialFrame = ((BurstSolverImpl)constraints.solver).inertialFrame
};
return updateContacts.Schedule(((BurstSolverImpl)constraints.solver).colliderContacts.Length, 128, inputDeps);
}
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
var projectConstraints = new CollisionConstraintsBatchJob()
{
positions = solverImplementation.positions,
prevPositions = solverImplementation.prevPositions,
orientations = solverImplementation.orientations,
prevOrientations = solverImplementation.prevOrientations,
invMasses = solverImplementation.invMasses,
radii = solverImplementation.principalRadii,
particleMaterialIndices = solverImplementation.collisionMaterials,
simplices = solverImplementation.simplices,
simplexCounts = solverImplementation.simplexCounts,
shapes = ObiColliderWorld.GetInstance().colliderShapes.AsNativeArray<BurstColliderShape>(),
transforms = ObiColliderWorld.GetInstance().colliderTransforms.AsNativeArray<BurstAffineTransform>(),
collisionMaterials = ObiColliderWorld.GetInstance().collisionMaterials.AsNativeArray<BurstCollisionMaterial>(),
rigidbodies = ObiColliderWorld.GetInstance().rigidbodies.AsNativeArray<BurstRigidbody>(),
rigidbodyLinearDeltas = solverImplementation.abstraction.rigidbodyLinearDeltas.AsNativeArray<float4>(),
rigidbodyAngularDeltas = solverImplementation.abstraction.rigidbodyAngularDeltas.AsNativeArray<float4>(),
deltas = solverAbstraction.positionDeltas.AsNativeArray<float4>(),
counts = solverAbstraction.positionConstraintCounts.AsNativeArray<int>(),
contacts = ((BurstSolverImpl)constraints.solver).colliderContacts,
inertialFrame = ((BurstSolverImpl)constraints.solver).inertialFrame,
constraintParameters = parameters,
solverParameters = solverAbstraction.parameters,
substeps = substeps,
stepTime = stepTime,
substepTime = substepTime
};
return projectConstraints.Schedule(inputDeps);
}
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
{
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
var applyConstraints = new ApplyCollisionConstraintsBatchJob()
{
contacts = ((BurstSolverImpl)constraints.solver).colliderContacts,
simplices = solverImplementation.simplices,
simplexCounts = solverImplementation.simplexCounts,
positions = solverImplementation.positions,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
orientations = solverImplementation.orientations,
orientationDeltas = solverImplementation.orientationDeltas,
orientationCounts = solverImplementation.orientationConstraintCounts,
constraintParameters = parameters
};
return applyConstraints.Schedule(inputDeps);
}
/**
* Updates contact data (such as contact distance) at the beginning of each substep. This is
* necessary because contacts are generalted only once at the beginning of each step, not every substep.
*/
[BurstCompile]
public struct UpdateContactsJob : IJobParallelFor
{
[ReadOnly] public NativeArray<float4> prevPositions;
[ReadOnly] public NativeArray<quaternion> prevOrientations;
[ReadOnly] public NativeArray<float4> velocities;
[ReadOnly] public NativeArray<float4> radii;
[ReadOnly] public NativeArray<float> invMasses;
[ReadOnly] public NativeArray<float4> invInertiaTensors;
[ReadOnly] public NativeArray<int> particleMaterialIndices;
[ReadOnly] public NativeArray<BurstCollisionMaterial> collisionMaterials;
// simplex arrays:
[ReadOnly] public NativeArray<int> simplices;
[ReadOnly] public SimplexCounts simplexCounts;
[ReadOnly] public NativeArray<BurstColliderShape> shapes;
[ReadOnly] public NativeArray<BurstAffineTransform> transforms;
[ReadOnly] public NativeArray<BurstRigidbody> rigidbodies;
[ReadOnly] public NativeArray<float4> rigidbodyLinearDeltas;
[ReadOnly] public NativeArray<float4> rigidbodyAngularDeltas;
public NativeArray<BurstContact> contacts;
[ReadOnly] public BurstInertialFrame inertialFrame;
public void Execute(int i)
{
var contact = contacts[i];
int simplexStart = simplexCounts.GetSimplexStartAndSize(contact.bodyA, out int simplexSize);
// get the material from the first particle in the simplex:
int aMaterialIndex = particleMaterialIndices[simplices[simplexStart]];
bool rollingContacts = aMaterialIndex >= 0 ? collisionMaterials[aMaterialIndex].rollingContacts > 0 : false;
float4 relativeVelocity = float4.zero;
float4 simplexPrevPosition = float4.zero;
quaternion simplexPrevOrientation = new quaternion(0, 0, 0, 0);
float simplexInvMass = 0;
float4 simplexInvInertia = float4.zero;
float simplexRadius = 0;
for (int j = 0; j < simplexSize; ++j)
{
int particleIndex = simplices[simplexStart + j];
relativeVelocity += velocities[particleIndex] * contact.pointA[j];
simplexPrevPosition += prevPositions[particleIndex] * contact.pointA[j];
simplexPrevOrientation.value += prevOrientations[particleIndex].value * contact.pointA[j];
simplexInvMass += invMasses[particleIndex] * contact.pointA[j];
simplexInvInertia += invInertiaTensors[particleIndex] * contact.pointA[j];
simplexRadius += BurstMath.EllipsoidRadius(contact.normal, prevOrientations[particleIndex], radii[particleIndex].xyz) * contact.pointA[j];
}
// if there's a rigidbody present, subtract its velocity from the relative velocity:
int rigidbodyIndex = shapes[contact.bodyB].rigidbodyIndex;
if (rigidbodyIndex >= 0)
{
relativeVelocity -= BurstMath.GetRigidbodyVelocityAtPoint(rigidbodyIndex, contact.pointB, rigidbodies, rigidbodyLinearDeltas, rigidbodyAngularDeltas, inertialFrame.frame);
int bMaterialIndex = shapes[contact.bodyB].materialIndex;
rollingContacts |= bMaterialIndex >= 0 ? collisionMaterials[bMaterialIndex].rollingContacts > 0 : false;
}
// update contact distance
contact.distance = math.dot(simplexPrevPosition - contact.pointB, contact.normal) - simplexRadius;
// calculate contact point in A's surface:
float4 contactPoint = contact.pointB + contact.normal * contact.distance;
// update contact orthonormal basis:
contact.CalculateBasis(relativeVelocity);
// calculate A's contact mass.
contact.CalculateContactMassesA(simplexInvMass, simplexInvInertia, simplexPrevPosition, simplexPrevOrientation, contactPoint, rollingContacts);
// calculate B's contact mass.
if (rigidbodyIndex >= 0)
contact.CalculateContactMassesB(rigidbodies[rigidbodyIndex], inertialFrame.frame);
contacts[i] = contact;
}
}
[BurstCompile]
public struct CollisionConstraintsBatchJob : IJob
{
[ReadOnly] public NativeArray<float4> prevPositions;
[ReadOnly] public NativeArray<quaternion> orientations;
[ReadOnly] public NativeArray<quaternion> prevOrientations;
[ReadOnly] public NativeArray<float> invMasses;
[ReadOnly] public NativeArray<float4> radii;
[ReadOnly] public NativeArray<int> particleMaterialIndices;
// simplex arrays:
[ReadOnly] public NativeArray<int> simplices;
[ReadOnly] public SimplexCounts simplexCounts;
[ReadOnly] public NativeArray<BurstColliderShape> shapes;
[ReadOnly] public NativeArray<BurstAffineTransform> transforms;
[ReadOnly] public NativeArray<BurstCollisionMaterial> collisionMaterials;
[ReadOnly] public NativeArray<BurstRigidbody> rigidbodies;
public NativeArray<float4> rigidbodyLinearDeltas;
public NativeArray<float4> rigidbodyAngularDeltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
public NativeArray<BurstContact> contacts;
[ReadOnly] public BurstInertialFrame inertialFrame;
[ReadOnly] public Oni.ConstraintParameters constraintParameters;
[ReadOnly] public Oni.SolverParameters solverParameters;
[ReadOnly] public float stepTime;
[ReadOnly] public float substepTime;
[ReadOnly] public int substeps;
public void Execute()
{
for (int i = 0; i < contacts.Length; ++i)
{
var contact = contacts[i];
int simplexStart = simplexCounts.GetSimplexStartAndSize(contact.bodyA, out int simplexSize);
int colliderIndex = contact.bodyB;
// Skip contacts involving triggers:
if (shapes[colliderIndex].flags > 0)
continue;
// Get the rigidbody index (might be < 0, in that case there's no rigidbody present)
int rigidbodyIndex = shapes[colliderIndex].rigidbodyIndex;
// Combine collision materials (use material from first particle in simplex)
BurstCollisionMaterial material = CombineCollisionMaterials(simplices[simplexStart], colliderIndex);
// Get relative velocity at contact point.
// As we do not consider true ellipses for collision detection, particle contact points are never off-axis.
// So particle angular velocity does not contribute to normal impulses, and we can skip it.
float4 simplexPosition = float4.zero;
float4 simplexPrevPosition = float4.zero;
float simplexRadius = 0;
for (int j = 0; j < simplexSize; ++j)
{
int particleIndex = simplices[simplexStart + j];
simplexPosition += positions[particleIndex] * contact.pointA[j];
simplexPrevPosition += prevPositions[particleIndex] * contact.pointA[j];
simplexRadius += BurstMath.EllipsoidRadius(contact.normal, orientations[particleIndex], radii[particleIndex].xyz) * contact.pointA[j];
}
// project position to the end of the full step:
float4 posA = math.lerp(simplexPrevPosition, simplexPosition, substeps);
posA += -contact.normal * simplexRadius;
float4 posB = contact.pointB;
if (rigidbodyIndex >= 0)
posB += BurstMath.GetRigidbodyVelocityAtPoint(rigidbodyIndex, contact.pointB, rigidbodies, rigidbodyLinearDeltas, rigidbodyAngularDeltas, inertialFrame.frame) * stepTime;
// adhesion:
float lambda = contact.SolveAdhesion(posA, posB, material.stickDistance, material.stickiness, stepTime);
// depenetration:
lambda += contact.SolvePenetration(posA, posB, solverParameters.maxDepenetration * stepTime);
// Apply normal impulse to both simplex and rigidbody:
if (math.abs(lambda) > BurstMath.epsilon)
{
float4 delta = lambda * contact.normal * BurstMath.BaryScale(contact.pointA) / substeps;
for (int j = 0; j < simplexSize; ++j)
{
int particleIndex = simplices[simplexStart + j];
deltas[particleIndex] += delta * invMasses[particleIndex] * contact.pointA[j];
counts[particleIndex]++;
}
// Apply position deltas immediately, if using sequential evaluation:
if (constraintParameters.evaluationOrder == Oni.ConstraintParameters.EvaluationOrder.Sequential)
{
for (int j = 0; j < simplexSize; ++j)
{
int particleIndex = simplices[simplexStart + j];
BurstConstraintsBatchImpl.ApplyPositionDelta(particleIndex, constraintParameters.SORFactor, ref positions, ref deltas, ref counts);
}
}
if (rigidbodyIndex >= 0)
{
BurstMath.ApplyImpulse(rigidbodyIndex, -lambda / stepTime * contact.normal, contact.pointB, rigidbodies, rigidbodyLinearDeltas, rigidbodyAngularDeltas, inertialFrame.frame);
}
}
contacts[i] = contact;
}
}
private BurstCollisionMaterial CombineCollisionMaterials(int entityA, int entityB)
{
// Combine collision materials:
int particleMaterialIndex = particleMaterialIndices[entityA];
int colliderMaterialIndex = shapes[entityB].materialIndex;
if (colliderMaterialIndex >= 0 && particleMaterialIndex >= 0)
return BurstCollisionMaterial.CombineWith(collisionMaterials[particleMaterialIndex], collisionMaterials[colliderMaterialIndex]);
else if (particleMaterialIndex >= 0)
return collisionMaterials[particleMaterialIndex];
else if (colliderMaterialIndex >= 0)
return collisionMaterials[colliderMaterialIndex];
return new BurstCollisionMaterial();
}
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,35 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
namespace Obi
{
public class BurstColliderFrictionConstraints : BurstConstraintsImpl<BurstColliderFrictionConstraintsBatch>
{
public BurstColliderFrictionConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.Friction)
{
}
public override IConstraintsBatchImpl CreateConstraintsBatch()
{
var dataBatch = new BurstColliderFrictionConstraintsBatch(this);
batches.Add(dataBatch);
return dataBatch;
}
public override void RemoveBatch(IConstraintsBatchImpl batch)
{
batches.Remove(batch as BurstColliderFrictionConstraintsBatch);
batch.Destroy();
}
public override int GetConstraintCount()
{
if (!((BurstSolverImpl)solver).colliderContacts.IsCreated)
return 0;
return ((BurstSolverImpl)solver).colliderContacts.Length;
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,284 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
namespace Obi
{
public class BurstColliderFrictionConstraintsBatch : BurstConstraintsBatchImpl, IColliderFrictionConstraintsBatchImpl
{
public BurstColliderFrictionConstraintsBatch(BurstColliderFrictionConstraints constraints)
{
m_Constraints = constraints;
m_ConstraintType = Oni.ConstraintType.Friction;
}
public override JobHandle Initialize(JobHandle inputDeps, float substepTime)
{
return inputDeps;
}
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
if (!((BurstSolverImpl)constraints.solver).colliderContacts.IsCreated)
return inputDeps;
var projectConstraints = new FrictionConstraintsBatchJob()
{
positions = solverImplementation.positions,
prevPositions = solverImplementation.prevPositions,
orientations = solverImplementation.orientations,
prevOrientations = solverImplementation.prevOrientations,
invMasses = solverImplementation.invMasses,
invInertiaTensors = solverImplementation.invInertiaTensors,
radii = solverImplementation.principalRadii,
particleMaterialIndices = solverImplementation.collisionMaterials,
simplices = solverImplementation.simplices,
simplexCounts = solverImplementation.simplexCounts,
shapes = ObiColliderWorld.GetInstance().colliderShapes.AsNativeArray<BurstColliderShape>(),
transforms = ObiColliderWorld.GetInstance().colliderTransforms.AsNativeArray<BurstAffineTransform>(),
collisionMaterials = ObiColliderWorld.GetInstance().collisionMaterials.AsNativeArray<BurstCollisionMaterial>(),
rigidbodies = ObiColliderWorld.GetInstance().rigidbodies.AsNativeArray<BurstRigidbody>(),
rigidbodyLinearDeltas = solverImplementation.abstraction.rigidbodyLinearDeltas.AsNativeArray<float4>(),
rigidbodyAngularDeltas = solverImplementation.abstraction.rigidbodyAngularDeltas.AsNativeArray<float4>(),
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
orientationDeltas = solverImplementation.orientationDeltas,
orientationCounts = solverImplementation.orientationConstraintCounts,
contacts = ((BurstSolverImpl)constraints.solver).colliderContacts,
inertialFrame = ((BurstSolverImpl)constraints.solver).inertialFrame,
substeps = substeps,
stepTime = stepTime,
substepTime = substepTime
};
return projectConstraints.Schedule(inputDeps);
}
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
{
if (!((BurstSolverImpl)constraints.solver).colliderContacts.IsCreated)
return inputDeps;
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
var applyConstraints = new ApplyCollisionConstraintsBatchJob()
{
contacts = ((BurstSolverImpl)constraints.solver).colliderContacts,
simplices = solverImplementation.simplices,
simplexCounts = solverImplementation.simplexCounts,
positions = solverImplementation.positions,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
orientations = solverImplementation.orientations,
orientationDeltas = solverImplementation.orientationDeltas,
orientationCounts = solverImplementation.orientationConstraintCounts,
constraintParameters = parameters
};
return applyConstraints.Schedule(inputDeps);
}
[BurstCompile]
public struct FrictionConstraintsBatchJob : IJob
{
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float4> prevPositions;
[ReadOnly] public NativeArray<quaternion> orientations;
[ReadOnly] public NativeArray<quaternion> prevOrientations;
[ReadOnly] public NativeArray<float> invMasses;
[ReadOnly] public NativeArray<float4> invInertiaTensors;
[ReadOnly] public NativeArray<float4> radii;
[ReadOnly] public NativeArray<int> particleMaterialIndices;
// simplex arrays:
[ReadOnly] public NativeArray<int> simplices;
[ReadOnly] public SimplexCounts simplexCounts;
[ReadOnly] public NativeArray<BurstColliderShape> shapes;
[ReadOnly] public NativeArray<BurstAffineTransform> transforms;
[ReadOnly] public NativeArray<BurstCollisionMaterial> collisionMaterials;
[ReadOnly] public NativeArray<BurstRigidbody> rigidbodies;
public NativeArray<float4> rigidbodyLinearDeltas;
public NativeArray<float4> rigidbodyAngularDeltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<quaternion> orientationDeltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> orientationCounts;
public NativeArray<BurstContact> contacts;
[ReadOnly] public BurstInertialFrame inertialFrame;
[ReadOnly] public float stepTime;
[ReadOnly] public float substepTime;
[ReadOnly] public int substeps;
public void Execute()
{
for (int i = 0; i < contacts.Length; ++i)
{
var contact = contacts[i];
// Get the indices of the particle and collider involved in this contact:
int simplexStart = simplexCounts.GetSimplexStartAndSize(contact.bodyA, out int simplexSize);
int colliderIndex = contact.bodyB;
// Skip contacts involving triggers:
if (shapes[colliderIndex].flags > 0)
continue;
// Get the rigidbody index (might be < 0, in that case there's no rigidbody present)
int rigidbodyIndex = shapes[colliderIndex].rigidbodyIndex;
// Combine collision materials (use material from first particle in simplex)
BurstCollisionMaterial material = CombineCollisionMaterials(simplices[simplexStart], colliderIndex);
// Calculate relative velocity:
float4 rA = float4.zero, rB = float4.zero;
float4 prevPositionA = float4.zero;
float4 linearVelocityA = float4.zero;
float4 angularVelocityA = float4.zero;
float4 invInertiaTensorA = float4.zero;
quaternion orientationA = new quaternion(0, 0, 0, 0);
float simplexRadiusA = 0;
for (int j = 0; j < simplexSize; ++j)
{
int particleIndex = simplices[simplexStart + j];
prevPositionA += prevPositions[particleIndex] * contact.pointA[j];
linearVelocityA += BurstIntegration.DifferentiateLinear(positions[particleIndex],prevPositions[particleIndex], substepTime) * contact.pointA[j];
angularVelocityA += BurstIntegration.DifferentiateAngular(orientations[particleIndex], prevOrientations[particleIndex], substepTime) * contact.pointA[j];
invInertiaTensorA += invInertiaTensors[particleIndex] * contact.pointA[j];
orientationA.value += orientations[particleIndex].value * contact.pointA[j];
simplexRadiusA += BurstMath.EllipsoidRadius(contact.normal, prevOrientations[particleIndex], radii[particleIndex].xyz) * contact.pointA[j];
}
float4 relativeVelocity = linearVelocityA;
// Add particle angular velocity if rolling contacts are enabled:
if (material.rollingContacts > 0)
{
rA = -contact.normal * simplexRadiusA;
relativeVelocity += new float4(math.cross(angularVelocityA.xyz, rA.xyz), 0);
}
// Subtract rigidbody velocity:
if (rigidbodyIndex >= 0)
{
// Note: unlike rA, that is expressed in solver space, rB is expressed in world space.
rB = inertialFrame.frame.TransformPoint(contact.pointB) - rigidbodies[rigidbodyIndex].com;
relativeVelocity -= BurstMath.GetRigidbodyVelocityAtPoint(rigidbodyIndex, contact.pointB, rigidbodies, rigidbodyLinearDeltas, rigidbodyAngularDeltas, inertialFrame.frame);
}
// Determine impulse magnitude:
float2 impulses = contact.SolveFriction(relativeVelocity, material.staticFriction, material.dynamicFriction, stepTime);
if (math.abs(impulses.x) > BurstMath.epsilon || math.abs(impulses.y) > BurstMath.epsilon)
{
float4 tangentImpulse = impulses.x * contact.tangent;
float4 bitangentImpulse = impulses.y * contact.bitangent;
float4 totalImpulse = tangentImpulse + bitangentImpulse;
float baryScale = BurstMath.BaryScale(contact.pointA);
for (int j = 0; j < simplexSize; ++j)
{
int particleIndex = simplices[simplexStart + j];
//(tangentImpulse * contact.tangentInvMassA + bitangentImpulse * contact.bitangentInvMassA) * dt;
deltas[particleIndex] += (tangentImpulse * contact.tangentInvMassA + bitangentImpulse * contact.bitangentInvMassA) * substepTime * contact.pointA[j] * baryScale;
counts[particleIndex]++;
}
if (rigidbodyIndex >= 0)
{
BurstMath.ApplyImpulse(rigidbodyIndex, -totalImpulse, contact.pointB, rigidbodies, rigidbodyLinearDeltas, rigidbodyAngularDeltas, inertialFrame.frame);
}
// Rolling contacts:
if (material.rollingContacts > 0)
{
// Calculate angular velocity deltas due to friction impulse:
float4x4 solverInertiaA = BurstMath.TransformInertiaTensor(invInertiaTensorA, orientationA);
float4 angVelDeltaA = math.mul(solverInertiaA, new float4(math.cross(rA.xyz, totalImpulse.xyz), 0));
float4 angVelDeltaB = float4.zero;
// Final angular velocities, after adding the deltas:
angularVelocityA += angVelDeltaA;
float4 angularVelocityB = float4.zero;
// Calculate weights (inverse masses):
float invMassA = math.length(math.mul(solverInertiaA, math.normalizesafe(angularVelocityA)));
float invMassB = 0;
if (rigidbodyIndex >= 0)
{
angVelDeltaB = math.mul(-rigidbodies[rigidbodyIndex].inverseInertiaTensor, new float4(math.cross(rB.xyz, totalImpulse.xyz), 0));
angularVelocityB = rigidbodies[rigidbodyIndex].angularVelocity + angVelDeltaB;
invMassB = math.length(math.mul(rigidbodies[rigidbodyIndex].inverseInertiaTensor, math.normalizesafe(angularVelocityB)));
}
// Calculate rolling axis and angular velocity deltas:
float4 rollAxis = float4.zero;
float rollingImpulse = contact.SolveRollingFriction(angularVelocityA, angularVelocityB, material.rollingFriction, invMassA, invMassB, ref rollAxis);
angVelDeltaA += rollAxis * rollingImpulse * invMassA;
angVelDeltaB -= rollAxis * rollingImpulse * invMassB;
// Apply orientation delta to particles:
quaternion orientationDelta = BurstIntegration.AngularVelocityToSpinQuaternion(orientationA, angVelDeltaA, substepTime);
for (int j = 0; j < simplexSize; ++j)
{
int particleIndex = simplices[simplexStart + j];
quaternion qA = orientationDeltas[particleIndex];
qA.value += orientationDelta.value;
orientationDeltas[particleIndex] = qA;
orientationCounts[particleIndex]++;
}
// Apply angular velocity delta to rigidbody:
if (rigidbodyIndex >= 0)
{
float4 angularDelta = rigidbodyAngularDeltas[rigidbodyIndex];
angularDelta += angVelDeltaB;
rigidbodyAngularDeltas[rigidbodyIndex] = angularDelta;
}
}
}
contacts[i] = contact;
}
}
private BurstCollisionMaterial CombineCollisionMaterials(int entityA, int entityB)
{
// Combine collision materials:
int particleMaterialIndex = particleMaterialIndices[entityA];
int colliderMaterialIndex = shapes[entityB].materialIndex;
if (colliderMaterialIndex >= 0 && particleMaterialIndex >= 0)
return BurstCollisionMaterial.CombineWith(collisionMaterials[particleMaterialIndex], collisionMaterials[colliderMaterialIndex]);
else if (particleMaterialIndex >= 0)
return collisionMaterials[particleMaterialIndex];
else if (colliderMaterialIndex >= 0)
return collisionMaterials[colliderMaterialIndex];
return new BurstCollisionMaterial();
}
}
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,452 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
using Unity.Jobs;
using Unity.Burst;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
namespace Obi
{
public class BurstDensityConstraints : BurstConstraintsImpl<BurstDensityConstraintsBatch>
{
public NativeList<int> fluidParticles;
public NativeArray<float4> eta;
public NativeArray<float4> smoothPositions;
public NativeArray<float3x3> anisotropies;
public BurstDensityConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.Density)
{
fluidParticles = new NativeList<int>(Allocator.Persistent);
}
public override IConstraintsBatchImpl CreateConstraintsBatch()
{
var dataBatch = new BurstDensityConstraintsBatch(this);
batches.Add(dataBatch);
return dataBatch;
}
public override void Dispose()
{
fluidParticles.Dispose();
}
public override void RemoveBatch(IConstraintsBatchImpl batch)
{
batches.Remove(batch as BurstDensityConstraintsBatch);
batch.Destroy();
}
protected override JobHandle EvaluateSequential(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
return EvaluateParallel(inputDeps, stepTime, substepTime, substeps);
}
protected override JobHandle EvaluateParallel(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
inputDeps = UpdateInteractions(inputDeps);
// evaluate all batches as a chain of dependencies:
for (int i = 0; i < batches.Count; ++i)
{
if (batches[i].enabled)
{
inputDeps = batches[i].Evaluate(inputDeps, stepTime, substepTime, substeps);
m_Solver.ScheduleBatchedJobsIfNeeded();
}
}
// calculate per-particle lambdas:
inputDeps = CalculateLambdas(inputDeps, substepTime);
// then apply them:
for (int i = 0; i < batches.Count; ++i)
{
if (batches[i].enabled)
{
inputDeps = batches[i].Apply(inputDeps, substepTime);
m_Solver.ScheduleBatchedJobsIfNeeded();
}
}
return inputDeps;
}
public JobHandle ApplyVelocityCorrections(JobHandle inputDeps, float deltaTime)
{
eta = new NativeArray<float4>(((BurstSolverImpl)solver).particleCount, Allocator.TempJob);
for (int i = 0; i < batches.Count; ++i)
{
if (batches[i].enabled)
{
inputDeps = batches[i].CalculateViscosityAndNormals(inputDeps, deltaTime);
m_Solver.ScheduleBatchedJobsIfNeeded();
}
}
for (int i = 0; i < batches.Count; ++i)
{
if (batches[i].enabled)
{
inputDeps = batches[i].CalculateVorticity(inputDeps);
m_Solver.ScheduleBatchedJobsIfNeeded();
}
}
inputDeps = ApplyVorticityAndAtmosphere(inputDeps, deltaTime);
m_Solver.ScheduleBatchedJobsIfNeeded();
return inputDeps;
}
public JobHandle CalculateAnisotropyLaplacianSmoothing(JobHandle inputDeps)
{
// if the constraints are deactivated or we need no anisotropy:
if (((BurstSolverImpl)solver).abstraction.parameters.maxAnisotropy <= 1)
return IdentityAnisotropy(inputDeps);
smoothPositions = new NativeArray<float4>(((BurstSolverImpl)solver).particleCount, Allocator.TempJob);
anisotropies = new NativeArray<float3x3>(((BurstSolverImpl)solver).particleCount, Allocator.TempJob);
for (int i = 0; i < batches.Count; ++i)
{
if (batches[i].enabled)
{
inputDeps = batches[i].AccumulateSmoothPositions(inputDeps);
m_Solver.ScheduleBatchedJobsIfNeeded();
}
}
inputDeps = AverageSmoothPositions(inputDeps);
for (int i = 0; i < batches.Count; ++i)
{
if (batches[i].enabled)
{
inputDeps = batches[i].AccumulateAnisotropy(inputDeps);
m_Solver.ScheduleBatchedJobsIfNeeded();
}
}
return AverageAnisotropy(inputDeps);
}
private JobHandle UpdateInteractions(JobHandle inputDeps)
{
// clear existing fluid data:
var clearData = new ClearFluidDataJob()
{
fluidParticles = fluidParticles.AsDeferredJobArray(),
fluidData = ((BurstSolverImpl)solver).abstraction.fluidData.AsNativeArray<float4>(),
};
inputDeps = clearData.Schedule(fluidParticles.Length, 64, inputDeps);
// update fluid interactions:
var updateInteractions = new UpdateInteractionsJob()
{
pairs = m_Solver.fluidInteractions,
positions = m_Solver.positions,
radii = m_Solver.smoothingRadii,
densityKernel = new Poly6Kernel(((BurstSolverImpl)solver).abstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
gradientKernel = new SpikyKernel(((BurstSolverImpl)solver).abstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
};
return updateInteractions.Schedule(((BurstSolverImpl)solver).fluidInteractions.Length, 64, inputDeps);
}
private JobHandle CalculateLambdas(JobHandle inputDeps, float deltaTime)
{
// calculate lagrange multipliers:
var calculateLambdas = new CalculateLambdasJob()
{
fluidParticles = fluidParticles.AsDeferredJobArray(),
invMasses = m_Solver.invMasses,
radii = m_Solver.smoothingRadii,
restDensities = m_Solver.restDensities,
surfaceTension = m_Solver.surfaceTension,
densityKernel = new Poly6Kernel(m_Solver.abstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
gradientKernel = new SpikyKernel(m_Solver.abstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
normals = m_Solver.normals,
vorticity = m_Solver.vorticities,
fluidData = m_Solver.fluidData
};
return calculateLambdas.Schedule(fluidParticles.Length,64,inputDeps);
}
private JobHandle ApplyVorticityAndAtmosphere(JobHandle inputDeps, float deltaTime)
{
// calculate lagrange multipliers:
var conf = new ApplyVorticityConfinementAndAtmosphere()
{
fluidParticles = fluidParticles.AsDeferredJobArray(),
wind = m_Solver.wind,
vorticities = m_Solver.vorticities,
eta = eta,
atmosphericDrag = m_Solver.athmosphericDrag,
atmosphericPressure = m_Solver.athmosphericPressure,
vorticityConfinement = m_Solver.vortConfinement,
restDensities = m_Solver.restDensities,
normals = m_Solver.normals,
fluidData = m_Solver.fluidData,
velocities = m_Solver.velocities,
dt = deltaTime
};
return conf.Schedule(fluidParticles.Length, 64, inputDeps);
}
private JobHandle IdentityAnisotropy(JobHandle inputDeps)
{
var idAnisotropy = new IdentityAnisotropyJob()
{
fluidParticles = fluidParticles.AsDeferredJobArray(),
principalAxes = m_Solver.anisotropies,
radii = m_Solver.principalRadii
};
return idAnisotropy.Schedule(fluidParticles.Length, 64, inputDeps);
}
private JobHandle AverageSmoothPositions(JobHandle inputDeps)
{
var average = new AverageSmoothPositionsJob()
{
fluidParticles = fluidParticles.AsDeferredJobArray(),
renderablePositions = m_Solver.renderablePositions,
smoothPositions = smoothPositions
};
return average.Schedule(fluidParticles.Length, 64, inputDeps);
}
private JobHandle AverageAnisotropy(JobHandle inputDeps)
{
var average = new AverageAnisotropyJob()
{
fluidParticles = fluidParticles.AsDeferredJobArray(),
renderablePositions = m_Solver.renderablePositions,
smoothPositions = smoothPositions,
principalRadii = m_Solver.principalRadii,
anisotropies = anisotropies,
maxAnisotropy = m_Solver.abstraction.parameters.maxAnisotropy,
principalAxes = m_Solver.anisotropies
};
return average.Schedule(fluidParticles.Length, 64, inputDeps);
}
[BurstCompile]
public struct ClearFluidDataJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> fluidParticles;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> fluidData;
public void Execute(int i)
{
fluidData[fluidParticles[i]] = float4.zero;
}
}
[BurstCompile]
public struct UpdateInteractionsJob : IJobParallelFor
{
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float> radii;
[ReadOnly] public Poly6Kernel densityKernel;
[ReadOnly] public SpikyKernel gradientKernel;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<FluidInteraction> pairs;
[ReadOnly] public BatchData batchData;
public void Execute(int i)
{
var pair = pairs[i];
// calculate normalized gradient vector:
pair.gradient = (positions[pair.particleA] - positions[pair.particleB]);
float distance = math.length(pair.gradient);
pair.gradient /= distance + math.FLT_MIN_NORMAL;
// calculate and store average density and gradient kernels:
pair.avgKernel = (densityKernel.W(distance, radii[pair.particleA]) +
densityKernel.W(distance, radii[pair.particleB])) * 0.5f;
pair.avgGradient = (gradientKernel.W(distance, radii[pair.particleA]) +
gradientKernel.W(distance, radii[pair.particleB])) * 0.5f;
pairs[i] = pair;
}
}
[BurstCompile]
public struct CalculateLambdasJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> fluidParticles;
[ReadOnly] public NativeArray<float> invMasses;
[ReadOnly] public NativeArray<float> radii;
[ReadOnly] public NativeArray<float> restDensities;
[ReadOnly] public NativeArray<float> surfaceTension;
[ReadOnly] public Poly6Kernel densityKernel;
[ReadOnly] public SpikyKernel gradientKernel;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> normals;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> vorticity;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> fluidData;
public void Execute(int p)
{
int i = fluidParticles[p];
normals[i] = float4.zero;
vorticity[i] = float4.zero;
float4 data = fluidData[i];
float grad = gradientKernel.W(0, radii[i]) / invMasses[i] / restDensities[i];
// self particle contribution to density and gradient:
data += new float4(densityKernel.W(0, radii[i]), 0, grad, grad * grad + data[2] * data[2]);
// weight by mass:
data[0] /= invMasses[i];
// evaluate density constraint (clamp pressure):
float constraint = math.max(-0.5f * surfaceTension[i], data[0] / restDensities[i] - 1);
// calculate lambda:
data[1] = -constraint / (invMasses[i] * data[3] + math.FLT_MIN_NORMAL);
fluidData[i] = data;
}
}
[BurstCompile]
public struct ApplyVorticityConfinementAndAtmosphere : IJobParallelFor
{
[ReadOnly] public NativeArray<int> fluidParticles;
[ReadOnly] public NativeArray<float4> wind;
[ReadOnly] public NativeArray<float4> vorticities;
[ReadOnly] public NativeArray<float> atmosphericDrag;
[ReadOnly] public NativeArray<float> atmosphericPressure;
[ReadOnly] public NativeArray<float> vorticityConfinement;
[ReadOnly] public NativeArray<float> restDensities;
[ReadOnly] public NativeArray<float4> normals;
[ReadOnly] public NativeArray<float4> fluidData;
[DeallocateOnJobCompletion] [ReadOnly] public NativeArray<float4> eta;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> velocities;
[ReadOnly] public float dt;
public void Execute(int p)
{
int i = fluidParticles[p];
//atmospheric drag:
float4 velocityDiff = velocities[i] - wind[i];
// particles near the surface should experience drag:
velocities[i] -= atmosphericDrag[i] * velocityDiff * math.max(0, 1 - fluidData[i][0] / restDensities[i]) * dt;
// ambient pressure:
velocities[i] += atmosphericPressure[i] * normals[i] * dt;
// apply vorticity confinement:
velocities[i] += new float4(math.cross(math.normalizesafe(eta[i]).xyz,vorticities[i].xyz), 0) * vorticityConfinement[i] * dt;
}
}
[BurstCompile]
public struct IdentityAnisotropyJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> fluidParticles;
[ReadOnly] public NativeArray<float4> radii;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> principalAxes;
public void Execute(int p)
{
int i = fluidParticles[p];
// align the principal axes of the particle with the solver axes:
principalAxes[i * 3] = new float4(1,0,0,radii[i].x);
principalAxes[i * 3 + 1] = new float4(0,1,0,radii[i].x);
principalAxes[i * 3 + 2] = new float4(0,0,1,radii[i].x);
}
}
[BurstCompile]
public struct AverageSmoothPositionsJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> fluidParticles;
[ReadOnly] public NativeArray<float4> renderablePositions;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> smoothPositions;
public void Execute(int p)
{
int i = fluidParticles[p];
if (smoothPositions[i].w > 0)
smoothPositions[i] /= smoothPositions[i].w;
else
smoothPositions[i] = renderablePositions[i];
}
}
[BurstCompile]
public struct AverageAnisotropyJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> fluidParticles;
[ReadOnly] public NativeArray<float4> principalRadii;
[ReadOnly] public float maxAnisotropy;
[ReadOnly]
[DeallocateOnJobCompletion]
public NativeArray<float4> smoothPositions;
[ReadOnly]
[DeallocateOnJobCompletion]
public NativeArray<float3x3> anisotropies;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> renderablePositions;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> principalAxes;
public void Execute(int p)
{
int i = fluidParticles[p];
if (smoothPositions[i].w > 0 && (anisotropies[i].c0[0] + anisotropies[i].c1[1] + anisotropies[i].c2[2]) > 0.01f)
{
float3 singularValues;
float3x3 u;
BurstMath.EigenSolve(anisotropies[i] / smoothPositions[i].w, out singularValues, out u);
float max = singularValues[0];
float3 s = math.max(singularValues,new float3(max / maxAnisotropy)) / max * principalRadii[i].x;
principalAxes[i * 3] = new float4(u.c0, s.x);
principalAxes[i * 3 + 1] = new float4(u.c1, s.y);
principalAxes[i * 3 + 2] = new float4(u.c2, s.z);
}
else
{
float radius = principalRadii[i].x / maxAnisotropy;
principalAxes[i * 3] = new float4(1, 0, 0, radius);
principalAxes[i * 3 + 1] = new float4(0, 1, 0, radius);
principalAxes[i * 3 + 2] = new float4(0, 0, 1, radius);
}
renderablePositions[i] = smoothPositions[i];
}
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,371 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
using System.Collections;
namespace Obi
{
public class BurstDensityConstraintsBatch : BurstConstraintsBatchImpl, IDensityConstraintsBatchImpl
{
public BatchData batchData;
public BurstDensityConstraintsBatch(BurstDensityConstraints constraints)
{
m_Constraints = constraints;
m_ConstraintType = Oni.ConstraintType.Density;
}
public override JobHandle Initialize(JobHandle inputDeps, float substepTime)
{
return inputDeps;
}
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
// update densities and gradients:
var updateDensities = new UpdateDensitiesJob()
{
pairs = ((BurstSolverImpl)constraints.solver).fluidInteractions,
positions = solverImplementation.positions,
invMasses = solverImplementation.invMasses,
restDensities = solverImplementation.restDensities,
diffusion = solverImplementation.diffusion,
userData = solverImplementation.userData,
fluidData = solverImplementation.fluidData,
batchData = batchData,
dt = substepTime
};
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
return updateDensities.Schedule(batchData.workItemCount, batchCount, inputDeps);
}
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
{
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
// update densities and gradients:
var apply = new ApplyDensityConstraintsJob()
{
invMasses = solverImplementation.invMasses,
radii = solverImplementation.smoothingRadii,
restDensities = solverImplementation.restDensities,
surfaceTension = solverImplementation.surfaceTension,
pairs = ((BurstSolverImpl)constraints.solver).fluidInteractions,
densityKernel = new Poly6Kernel(solverAbstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
positions = solverImplementation.positions,
fluidData = solverImplementation.fluidData,
batchData = batchData,
sorFactor = parameters.SORFactor
};
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
return apply.Schedule(batchData.workItemCount, batchCount, inputDeps);
}
public JobHandle CalculateViscosityAndNormals(JobHandle inputDeps, float deltaTime)
{
var viscosity = new NormalsViscosityAndVorticityJob()
{
positions = solverImplementation.positions,
invMasses = solverImplementation.invMasses,
radii = solverImplementation.smoothingRadii,
restDensities = solverImplementation.restDensities,
viscosities = solverImplementation.viscosities,
fluidData = solverImplementation.fluidData,
pairs = ((BurstSolverImpl)constraints.solver).fluidInteractions,
velocities = solverImplementation.velocities,
vorticities = solverImplementation.vorticities,
normals = solverImplementation.normals,
batchData = batchData
};
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
return viscosity.Schedule(batchData.workItemCount, batchCount, inputDeps);
}
public JobHandle CalculateVorticity(JobHandle inputDeps)
{
var eta = new CalculateVorticityEta()
{
invMasses = solverImplementation.invMasses,
restDensities = solverImplementation.restDensities,
pairs = ((BurstSolverImpl)constraints.solver).fluidInteractions,
vorticities = solverImplementation.vorticities,
eta = ((BurstDensityConstraints)this.constraints).eta,
batchData = batchData
};
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
return eta.Schedule(batchData.workItemCount, batchCount, inputDeps);
}
public JobHandle AccumulateSmoothPositions(JobHandle inputDeps)
{
var accumulateSmooth = new AccumulateSmoothPositionsJob()
{
renderablePositions = solverImplementation.renderablePositions,
smoothPositions = ((BurstDensityConstraints)this.constraints).smoothPositions,
radii = solverImplementation.smoothingRadii,
densityKernel = new Poly6Kernel(solverAbstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
pairs = ((BurstSolverImpl)constraints.solver).fluidInteractions,
batchData = batchData
};
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
return accumulateSmooth.Schedule(batchData.workItemCount, batchCount, inputDeps);
}
public JobHandle AccumulateAnisotropy(JobHandle inputDeps)
{
var accumulateAnisotropy = new AccumulateAnisotropyJob()
{
renderablePositions = solverImplementation.renderablePositions,
smoothPositions = ((BurstDensityConstraints)this.constraints).smoothPositions,
anisotropies = ((BurstDensityConstraints)this.constraints).anisotropies,
pairs = ((BurstSolverImpl)constraints.solver).fluidInteractions,
batchData = batchData
};
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
return accumulateAnisotropy.Schedule(batchData.workItemCount, batchCount, inputDeps);
}
[BurstCompile]
public struct UpdateDensitiesJob : IJobParallelFor
{
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float> invMasses;
[ReadOnly] public NativeArray<float> restDensities;
[ReadOnly] public NativeArray<float> diffusion;
[ReadOnly] public NativeArray<FluidInteraction> pairs;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> userData;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> fluidData;
[ReadOnly] public BatchData batchData;
[ReadOnly] public float dt;
public void Execute(int workItemIndex)
{
int start, end;
batchData.GetConstraintRange(workItemIndex, out start, out end);
for (int i = start; i < end; ++i)
{
var pair = pairs[i];
float restVolumeA = 1.0f / invMasses[pair.particleA] / restDensities[pair.particleA];
float restVolumeB = 1.0f / invMasses[pair.particleB] / restDensities[pair.particleB];
float gradA = restVolumeB * pair.avgGradient;
float gradB = restVolumeA * pair.avgGradient;
float vA = restVolumeB / restVolumeA;
float vB = restVolumeA / restVolumeB;
// accumulate pbf data (density, gradients):
fluidData[pair.particleA] += new float4(vA * pair.avgKernel, 0, gradA, gradA * gradA);
fluidData[pair.particleB] += new float4(vB * pair.avgKernel, 0, gradB, gradB * gradB);
// property diffusion:
float diffusionSpeed = (diffusion[pair.particleA] + diffusion[pair.particleB]) * pair.avgKernel * dt;
float4 userDelta = (userData[pair.particleB] - userData[pair.particleA]) * diffusionSpeed;
userData[pair.particleA] += vA * userDelta;
userData[pair.particleB] -= vB * userDelta;
}
}
}
[BurstCompile]
public struct ApplyDensityConstraintsJob : IJobParallelFor
{
[ReadOnly] public NativeArray<float> invMasses;
[ReadOnly] public NativeArray<float> radii;
[ReadOnly] public NativeArray<float> restDensities;
[ReadOnly] public NativeArray<float> surfaceTension;
[ReadOnly] public NativeArray<FluidInteraction> pairs;
[ReadOnly] public Poly6Kernel densityKernel;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> fluidData;
[ReadOnly] public BatchData batchData;
[ReadOnly] public float sorFactor;
public void Execute(int workItemIndex)
{
int start, end;
batchData.GetConstraintRange(workItemIndex, out start, out end);
for (int i = start; i < end; ++i)
{
var pair = pairs[i];
float restVolumeA = 1.0f / invMasses[pair.particleA] / restDensities[pair.particleA];
float restVolumeB = 1.0f / invMasses[pair.particleB] / restDensities[pair.particleB];
// calculate tensile instability correction factor:
float wAvg = pair.avgKernel / ((densityKernel.W(0, radii[pair.particleA]) + densityKernel.W(0, radii[pair.particleB])) * 0.5f);
float scorrA = -(0.001f + 0.2f * surfaceTension[pair.particleA]) * wAvg / (invMasses[pair.particleA] * fluidData[pair.particleA][3]);
float scorrB = -(0.001f + 0.2f * surfaceTension[pair.particleB]) * wAvg / (invMasses[pair.particleB] * fluidData[pair.particleB][3]);
// calculate position delta:
float4 delta = pair.gradient * pair.avgGradient * ((fluidData[pair.particleA][1] + scorrA) * restVolumeB + (fluidData[pair.particleB][1] + scorrB) * restVolumeA) * sorFactor;
positions[pair.particleA] += delta * invMasses[pair.particleA];
positions[pair.particleB] -= delta * invMasses[pair.particleB];
}
}
}
[BurstCompile]
public struct NormalsViscosityAndVorticityJob : IJobParallelFor
{
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float> invMasses;
[ReadOnly] public NativeArray<float> radii;
[ReadOnly] public NativeArray<float> restDensities;
[ReadOnly] public NativeArray<float> viscosities;
[ReadOnly] public NativeArray<float4> fluidData;
[ReadOnly] public NativeArray<FluidInteraction> pairs;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> velocities;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> vorticities;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> normals;
[ReadOnly] public BatchData batchData;
public void Execute(int workItemIndex)
{
int start, end;
batchData.GetConstraintRange(workItemIndex, out start, out end);
for (int i = start; i < end; ++i)
{
var pair = pairs[i];
float restVolumeA = 1.0f / invMasses[pair.particleA] / restDensities[pair.particleA];
float restVolumeB = 1.0f / invMasses[pair.particleB] / restDensities[pair.particleB];
// XSPH viscosity:
float viscosityCoeff = math.min(viscosities[pair.particleA], viscosities[pair.particleB]);
float4 relVelocity = velocities[pair.particleB] - velocities[pair.particleA];
float4 viscosity = viscosityCoeff * relVelocity * pair.avgKernel;
velocities[pair.particleA] += viscosity * restVolumeB;
velocities[pair.particleB] -= viscosity * restVolumeA;
// calculate vorticity:
float4 vgrad = pair.gradient * pair.avgGradient;
float4 vorticity = new float4(math.cross(relVelocity.xyz,vgrad.xyz),0);
vorticities[pair.particleA] += vorticity * restVolumeB;
vorticities[pair.particleB] += vorticity * restVolumeA;
// calculate color field normal:
float radius = (radii[pair.particleA] + radii[pair.particleB]) * 0.5f;
normals[pair.particleA] += vgrad * radius / invMasses[pair.particleB] / fluidData[pair.particleB][0];
normals[pair.particleB] -= vgrad * radius / invMasses[pair.particleA] / fluidData[pair.particleA][0];
}
}
}
[BurstCompile]
public struct CalculateVorticityEta : IJobParallelFor
{
[ReadOnly] public NativeArray<float4> vorticities;
[ReadOnly] public NativeArray<float> invMasses;
[ReadOnly] public NativeArray<float> restDensities;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<FluidInteraction> pairs;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> eta;
[ReadOnly] public BatchData batchData;
public void Execute(int workItemIndex)
{
int start, end;
batchData.GetConstraintRange(workItemIndex, out start, out end);
for (int i = start; i < end; ++i)
{
var pair = pairs[i];
float4 vgrad = pair.gradient * pair.avgGradient;
eta[pair.particleA] += math.length(vorticities[pair.particleA]) * vgrad / invMasses[pair.particleB] / restDensities[pair.particleB];
eta[pair.particleB] -= math.length(vorticities[pair.particleB]) * vgrad / invMasses[pair.particleA] / restDensities[pair.particleA];
}
}
}
[BurstCompile]
public struct AccumulateSmoothPositionsJob : IJobParallelFor
{
[ReadOnly] public NativeArray<float4> renderablePositions;
[ReadOnly] public NativeArray<float> radii;
[ReadOnly] public Poly6Kernel densityKernel;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> smoothPositions;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<FluidInteraction> pairs;
[ReadOnly] public BatchData batchData;
public void Execute(int workItemIndex)
{
int start, end;
batchData.GetConstraintRange(workItemIndex, out start, out end);
for (int i = start; i < end; ++i)
{
var pair = pairs[i];
float4 gradient = (renderablePositions[pair.particleA] - renderablePositions[pair.particleB]);
float distance = math.length(gradient);
pair.avgKernel = (densityKernel.W(distance, radii[pair.particleA]) +
densityKernel.W(distance, radii[pair.particleB])) * 0.5f;
smoothPositions[pair.particleA] += new float4(renderablePositions[pair.particleB].xyz,1) * pair.avgKernel;
smoothPositions[pair.particleB] += new float4(renderablePositions[pair.particleA].xyz,1) * pair.avgKernel;
pairs[i] = pair;
}
}
}
[BurstCompile]
public struct AccumulateAnisotropyJob : IJobParallelFor
{
[ReadOnly] public NativeArray<float4> renderablePositions;
[ReadOnly] public NativeArray<float4> smoothPositions;
[ReadOnly] public NativeArray<FluidInteraction> pairs;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float3x3> anisotropies;
[ReadOnly] public BatchData batchData;
public void Execute(int workItemIndex)
{
int start, end;
batchData.GetConstraintRange(workItemIndex, out start, out end);
for (int i = start; i < end; ++i)
{
var pair = pairs[i];
float4 distanceA = renderablePositions[pair.particleB] - smoothPositions[pair.particleA];
float4 distanceB = renderablePositions[pair.particleA] - smoothPositions[pair.particleB];
anisotropies[pair.particleA] += BurstMath.multrnsp(distanceA,distanceA) * pair.avgKernel;
anisotropies[pair.particleB] += BurstMath.multrnsp(distanceB,distanceB) * pair.avgKernel;
}
}
}
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,36 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
using Unity.Mathematics;
namespace Obi
{
public struct Poly6Kernel
{
public float norm;
public bool norm2D;
public Poly6Kernel(bool norm2D)
{
this.norm2D = norm2D;
if (norm2D)
norm = 4.0f / math.PI;
else
norm = 315.0f / (64.0f * math.PI);
}
public float W(float r, float h)
{
float h2 = h * h;
float h4 = h2 * h2;
float h8 = h4 * h4;
float rl = math.min(r, h);
float hr = h2 - rl * rl;
if (norm2D)
return norm / h8 * hr * hr * hr;
return norm / (h8 * h) * hr * hr * hr;
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,35 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
using Unity.Mathematics;
namespace Obi
{
public struct SpikyKernel
{
public float norm;
public bool norm2D;
public SpikyKernel(bool norm2D)
{
this.norm2D = norm2D;
if (norm2D)
norm = -30.0f / math.PI;
else
norm = -45.0f / math.PI;
}
public float W(float r, float h)
{
float h2 = h * h;
float h4 = h2 * h2;
float rl = math.min(r, h);
float hr = h - rl;
if (norm2D)
return norm / (h4 * h) * hr * hr;
return norm / (h4 * h2) * hr * hr;
}
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,26 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
namespace Obi
{
public class BurstDistanceConstraints : BurstConstraintsImpl<BurstDistanceConstraintsBatch>
{
public BurstDistanceConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.Distance)
{
}
public override IConstraintsBatchImpl CreateConstraintsBatch()
{
var dataBatch = new BurstDistanceConstraintsBatch(this);
batches.Add(dataBatch);
return dataBatch;
}
public override void RemoveBatch(IConstraintsBatchImpl batch)
{
batches.Remove(batch as BurstDistanceConstraintsBatch);
batch.Destroy();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,146 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
using System.Collections;
namespace Obi
{
public class BurstDistanceConstraintsBatch : BurstConstraintsBatchImpl, IDistanceConstraintsBatchImpl
{
private NativeArray<float> restLengths;
private NativeArray<float2> stiffnesses;
DistanceConstraintsBatchJob projectConstraints;
ApplyDistanceConstraintsBatchJob applyConstraints;
public BurstDistanceConstraintsBatch(BurstDistanceConstraints constraints)
{
m_Constraints = constraints;
m_ConstraintType = Oni.ConstraintType.Distance;
}
public void SetDistanceConstraints(ObiNativeIntList particleIndices, ObiNativeFloatList restLengths, ObiNativeVector2List stiffnesses, ObiNativeFloatList lambdas, int count)
{
this.particleIndices = particleIndices.AsNativeArray<int>();
this.restLengths = restLengths.AsNativeArray<float>();
this.stiffnesses = stiffnesses.AsNativeArray<float2>();
this.lambdas = lambdas.AsNativeArray<float>();
m_ConstraintCount = count;
projectConstraints.particleIndices = this.particleIndices;
projectConstraints.restLengths = this.restLengths;
projectConstraints.stiffnesses = this.stiffnesses;
projectConstraints.lambdas = this.lambdas;
applyConstraints.particleIndices = this.particleIndices;
}
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
projectConstraints.positions = solverImplementation.positions;
projectConstraints.invMasses = solverImplementation.invMasses;
projectConstraints.deltas = solverImplementation.positionDeltas;
projectConstraints.counts = solverImplementation.positionConstraintCounts;
projectConstraints.deltaTimeSqr = substepTime * substepTime;
return projectConstraints.Schedule(m_ConstraintCount, 32, inputDeps);
}
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
{
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
applyConstraints.positions = solverImplementation.positions;
applyConstraints.deltas = solverImplementation.positionDeltas;
applyConstraints.counts = solverImplementation.positionConstraintCounts;
applyConstraints.sorFactor = parameters.SORFactor;
return applyConstraints.Schedule(m_ConstraintCount, 64, inputDeps);
}
[BurstCompile]
public struct DistanceConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public NativeArray<float> restLengths;
[ReadOnly] public NativeArray<float2> stiffnesses;
public NativeArray<float> lambdas;
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float> invMasses;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<int> counts;
[ReadOnly] public float deltaTimeSqr;
public void Execute(int i)
{
int p1 = particleIndices[i * 2];
int p2 = particleIndices[i * 2 + 1];
float w1 = invMasses[p1];
float w2 = invMasses[p2];
// calculate time adjusted compliance
float compliance = stiffnesses[i].x / deltaTimeSqr;
// calculate position and lambda deltas:
float4 distance = positions[p1] - positions[p2];
float d = math.length(distance);
// calculate constraint value:
float constraint = d - restLengths[i];
constraint -= math.max(math.min(constraint, 0), -stiffnesses[i].y);
// calculate lambda and position deltas:
float dlambda = (-constraint - compliance * lambdas[i]) / (w1 + w2 + compliance + BurstMath.epsilon);
float4 delta = dlambda * distance / (d + BurstMath.epsilon);
lambdas[i] += dlambda;
deltas[p1] += delta * w1;
deltas[p2] -= delta * w2;
counts[p1]++;
counts[p2]++;
}
}
[BurstCompile]
public struct ApplyDistanceConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public float sorFactor;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<int> counts;
public void Execute(int i)
{
int p1 = particleIndices[i * 2];
int p2 = particleIndices[i * 2 + 1];
if (counts[p1] > 0)
{
positions[p1] += deltas[p1] * sorFactor / counts[p1];
deltas[p1] = float4.zero;
counts[p1] = 0;
}
if (counts[p2] > 0)
{
positions[p2] += deltas[p2] * sorFactor / counts[p2];
deltas[p2] = float4.zero;
counts[p2] = 0;
}
}
}
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,62 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Mathematics;
using Unity.Burst;
using System;
using System.Collections;
namespace Obi
{
[BurstCompile]
public struct ApplyBatchedCollisionConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<BurstContact> contacts;
[ReadOnly] public NativeArray<int> simplices;
[ReadOnly] public SimplexCounts simplexCounts;
[NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableParallelForRestriction] public NativeArray<int> counts;
[NativeDisableParallelForRestriction] public NativeArray<quaternion> orientations;
[NativeDisableParallelForRestriction] public NativeArray<quaternion> orientationDeltas;
[NativeDisableParallelForRestriction] public NativeArray<int> orientationCounts;
[ReadOnly] public Oni.ConstraintParameters constraintParameters;
[ReadOnly] public BatchData batchData;
public void Execute(int workItemIndex)
{
int start, end;
batchData.GetConstraintRange(workItemIndex, out start, out end);
for (int i = start; i < end; ++i)
{
int simplexStartA = simplexCounts.GetSimplexStartAndSize(contacts[i].bodyA, out int simplexSizeA);
int simplexStartB = simplexCounts.GetSimplexStartAndSize(contacts[i].bodyB, out int simplexSizeB);
for (int j = 0; j < simplexSizeA; ++j)
{
int particleIndex = simplices[simplexStartA + j];
BurstConstraintsBatchImpl.ApplyPositionDelta(particleIndex, constraintParameters.SORFactor, ref positions, ref deltas, ref counts);
BurstConstraintsBatchImpl.ApplyOrientationDelta(particleIndex, constraintParameters.SORFactor, ref orientations, ref orientationDeltas, ref orientationCounts);
}
for (int j = 0; j < simplexSizeB; ++j)
{
int particleIndex = simplices[simplexStartB + j];
BurstConstraintsBatchImpl.ApplyPositionDelta(particleIndex, constraintParameters.SORFactor, ref positions, ref deltas, ref counts);
BurstConstraintsBatchImpl.ApplyOrientationDelta(particleIndex, constraintParameters.SORFactor, ref orientations, ref orientationDeltas, ref orientationCounts);
}
}
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,34 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
using Unity.Jobs;
namespace Obi
{
public class BurstParticleCollisionConstraints : BurstConstraintsImpl<BurstParticleCollisionConstraintsBatch>
{
public BurstParticleCollisionConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.ParticleCollision)
{
}
public override IConstraintsBatchImpl CreateConstraintsBatch()
{
var dataBatch = new BurstParticleCollisionConstraintsBatch(this);
batches.Add(dataBatch);
return dataBatch;
}
public override void RemoveBatch(IConstraintsBatchImpl batch)
{
batches.Remove(batch as BurstParticleCollisionConstraintsBatch);
batch.Destroy();
}
public override int GetConstraintCount()
{
if (!((BurstSolverImpl)solver).particleContacts.IsCreated)
return 0;
return ((BurstSolverImpl)solver).particleContacts.Length;
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,335 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
using System.Collections;
namespace Obi
{
public class BurstParticleCollisionConstraintsBatch : BurstConstraintsBatchImpl, IParticleCollisionConstraintsBatchImpl
{
public BatchData batchData;
public BurstParticleCollisionConstraintsBatch(BurstParticleCollisionConstraints constraints)
{
m_Constraints = constraints;
m_ConstraintType = Oni.ConstraintType.ParticleCollision;
}
public BurstParticleCollisionConstraintsBatch(BatchData batchData) : base()
{
this.batchData = batchData;
}
public override JobHandle Initialize(JobHandle inputDeps, float substepTime)
{
var updateContacts = new UpdateParticleContactsJob()
{
prevPositions = solverImplementation.prevPositions,
prevOrientations = solverImplementation.prevOrientations,
velocities = solverImplementation.velocities,
radii = solverImplementation.principalRadii,
invMasses = solverImplementation.invMasses,
invInertiaTensors = solverImplementation.invInertiaTensors,
simplices = solverImplementation.simplices,
simplexCounts = solverImplementation.simplexCounts,
particleMaterialIndices = solverImplementation.collisionMaterials,
collisionMaterials = ObiColliderWorld.GetInstance().collisionMaterials.AsNativeArray<BurstCollisionMaterial>(),
contacts = ((BurstSolverImpl)constraints.solver).particleContacts,
batchData = batchData
};
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
return updateContacts.Schedule(batchData.workItemCount, batchCount, inputDeps);
}
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
var projectConstraints = new ParticleCollisionConstraintsBatchJob()
{
positions = solverImplementation.positions,
orientations = solverImplementation.orientations,
invMasses = solverImplementation.invMasses,
radii = solverImplementation.principalRadii,
particleMaterialIndices = solverImplementation.collisionMaterials,
collisionMaterials = ObiColliderWorld.GetInstance().collisionMaterials.AsNativeArray<BurstCollisionMaterial>(),
simplices = solverImplementation.simplices,
simplexCounts = solverImplementation.simplexCounts,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
contacts = ((BurstSolverImpl)constraints.solver).particleContacts,
batchData = batchData,
constraintParameters = parameters,
solverParameters = solverImplementation.abstraction.parameters,
gravity = new float4(solverImplementation.abstraction.parameters.gravity, 0),
substepTime = substepTime,
};
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
return projectConstraints.Schedule(batchData.workItemCount, batchCount, inputDeps);
}
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
{
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
var applyConstraints = new ApplyBatchedCollisionConstraintsBatchJob()
{
contacts = ((BurstSolverImpl)constraints.solver).particleContacts,
simplices = solverImplementation.simplices,
simplexCounts = solverImplementation.simplexCounts,
positions = solverImplementation.positions,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
orientations = solverImplementation.orientations,
orientationDeltas = solverImplementation.orientationDeltas,
orientationCounts = solverImplementation.orientationConstraintCounts,
batchData = batchData,
constraintParameters = parameters,
};
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
return applyConstraints.Schedule(batchData.workItemCount, batchCount, inputDeps);
}
/**
* Updates contact data (contact distance and frame) at the beginning of each substep. This is
* necessary because contacts are generated only once at the beginning of each step, not every substep.
*/
[BurstCompile]
public struct UpdateParticleContactsJob : IJobParallelFor
{
[ReadOnly] public NativeArray<float4> prevPositions;
[ReadOnly] public NativeArray<quaternion> prevOrientations;
[ReadOnly] public NativeArray<float4> velocities;
[ReadOnly] public NativeArray<float4> radii;
[ReadOnly] public NativeArray<float> invMasses;
[ReadOnly] public NativeArray<float4> invInertiaTensors;
[ReadOnly] public NativeArray<int> particleMaterialIndices;
[ReadOnly] public NativeArray<BurstCollisionMaterial> collisionMaterials;
// simplex arrays:
[ReadOnly] public NativeArray<int> simplices;
[ReadOnly] public SimplexCounts simplexCounts;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<BurstContact> contacts;
[ReadOnly] public BatchData batchData;
public void Execute(int workItemIndex)
{
int start, end;
batchData.GetConstraintRange(workItemIndex, out start, out end);
for (int i = start; i < end; ++i)
{
var contact = contacts[i];
int simplexStartA = simplexCounts.GetSimplexStartAndSize(contact.bodyA, out int simplexSizeA);
int simplexStartB = simplexCounts.GetSimplexStartAndSize(contact.bodyB, out int simplexSizeB);
float4 simplexVelocityA = float4.zero;
float4 simplexPrevPositionA = float4.zero;
quaternion simplexPrevOrientationA = new quaternion(0, 0, 0, 0);
float simplexRadiusA = 0;
float simplexInvMassA = 0;
float4 simplexInvInertiaA = float4.zero;
float4 simplexVelocityB = float4.zero;
float4 simplexPrevPositionB = float4.zero;
quaternion simplexPrevOrientationB = new quaternion(0, 0, 0, 0);
float simplexRadiusB = 0;
float simplexInvMassB = 0;
float4 simplexInvInertiaB = float4.zero;
for (int j = 0; j < simplexSizeA; ++j)
{
int particleIndex = simplices[simplexStartA + j];
simplexVelocityA += velocities[particleIndex] * contact.pointA[j];
simplexPrevPositionA += prevPositions[particleIndex] * contact.pointA[j];
simplexPrevOrientationA.value += prevOrientations[particleIndex].value * contact.pointA[j];
simplexInvMassA += invMasses[particleIndex] * contact.pointA[j];
simplexInvInertiaA += invInertiaTensors[particleIndex] * contact.pointA[j];
simplexRadiusA += BurstMath.EllipsoidRadius(contact.normal, prevOrientations[particleIndex], radii[particleIndex].xyz) * contact.pointA[j];
}
for (int j = 0; j < simplexSizeB; ++j)
{
int particleIndex = simplices[simplexStartB + j];
simplexVelocityB += velocities[particleIndex] * contact.pointB[j];
simplexPrevPositionB += prevPositions[particleIndex] * contact.pointB[j];
simplexPrevOrientationB.value += prevOrientations[particleIndex].value * contact.pointB[j];
simplexInvMassB += invMasses[particleIndex] * contact.pointB[j];
simplexInvInertiaB += invInertiaTensors[particleIndex] * contact.pointB[j];
simplexRadiusB += BurstMath.EllipsoidRadius(contact.normal, prevOrientations[particleIndex], radii[particleIndex].xyz) * contact.pointB[j];
}
// update contact distance
float dAB = math.dot(simplexPrevPositionA - simplexPrevPositionB, contact.normal);
contact.distance = dAB - (simplexRadiusA + simplexRadiusB);
// calculate contact points:
float4 contactPointA = simplexPrevPositionB + contact.normal * (contact.distance + simplexRadiusB);
float4 contactPointB = simplexPrevPositionA - contact.normal * (contact.distance + simplexRadiusA);
// update contact basis:
contact.CalculateBasis(simplexVelocityA - simplexVelocityB);
// update contact masses:
int aMaterialIndex = particleMaterialIndices[simplices[simplexStartA]];
int bMaterialIndex = particleMaterialIndices[simplices[simplexStartB]];
bool rollingContacts = (aMaterialIndex >= 0 ? collisionMaterials[aMaterialIndex].rollingContacts > 0 : false) |
(bMaterialIndex >= 0 ? collisionMaterials[bMaterialIndex].rollingContacts > 0 : false);
contact.CalculateContactMassesA(simplexInvMassA, simplexInvInertiaA, simplexPrevPositionA, simplexPrevOrientationA, contactPointA, rollingContacts);
contact.CalculateContactMassesB(simplexInvMassB, simplexInvInertiaB, simplexPrevPositionB, simplexPrevOrientationB, contactPointB, rollingContacts);
contacts[i] = contact;
}
}
}
[BurstCompile]
public struct ParticleCollisionConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<quaternion> orientations;
[ReadOnly] public NativeArray<float> invMasses;
[ReadOnly] public NativeArray<float4> radii;
[ReadOnly] public NativeArray<int> particleMaterialIndices;
[ReadOnly] public NativeArray<BurstCollisionMaterial> collisionMaterials;
// simplex arrays:
[ReadOnly] public NativeArray<int> simplices;
[ReadOnly] public SimplexCounts simplexCounts;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<BurstContact> contacts;
[ReadOnly] public Oni.ConstraintParameters constraintParameters;
[ReadOnly] public Oni.SolverParameters solverParameters;
[ReadOnly] public float4 gravity;
[ReadOnly] public float substepTime;
[ReadOnly] public BatchData batchData;
public void Execute(int workItemIndex)
{
int start, end;
batchData.GetConstraintRange(workItemIndex, out start, out end);
for (int i = start; i < end; ++i)
{
var contact = contacts[i];
int simplexStartA = simplexCounts.GetSimplexStartAndSize(contact.bodyA, out int simplexSizeA);
int simplexStartB = simplexCounts.GetSimplexStartAndSize(contact.bodyB, out int simplexSizeB);
// Combine collision materials:
BurstCollisionMaterial material = CombineCollisionMaterials(simplices[simplexStartA], simplices[simplexStartB]);
float4 simplexPositionA = float4.zero, simplexPositionB = float4.zero;
float simplexRadiusA = 0, simplexRadiusB = 0;
for (int j = 0; j < simplexSizeA; ++j)
{
int particleIndex = simplices[simplexStartA + j];
simplexPositionA += positions[particleIndex] * contact.pointA[j];
simplexRadiusA += BurstMath.EllipsoidRadius(contact.normal, orientations[particleIndex], radii[particleIndex].xyz) * contact.pointA[j];
}
for (int j = 0; j < simplexSizeB; ++j)
{
int particleIndex = simplices[simplexStartB + j];
simplexPositionB += positions[particleIndex] * contact.pointB[j];
simplexRadiusB += BurstMath.EllipsoidRadius(contact.normal, orientations[particleIndex], radii[particleIndex].xyz) * contact.pointA[j];
}
float4 posA = simplexPositionA - contact.normal * simplexRadiusA;
float4 posB = simplexPositionB + contact.normal * simplexRadiusB;
// adhesion:
float lambda = contact.SolveAdhesion(posA, posB, material.stickDistance, material.stickiness, substepTime);
// depenetration:
lambda += contact.SolvePenetration(posA, posB, solverParameters.maxDepenetration * substepTime);
// Apply normal impulse to both particles (w/ shock propagation):
if (math.abs(lambda) > BurstMath.epsilon)
{
float shock = solverParameters.shockPropagation * math.dot(contact.normal, math.normalizesafe(gravity));
float4 delta = lambda * contact.normal;
float baryScale = BurstMath.BaryScale(contact.pointA);
for (int j = 0; j < simplexSizeA; ++j)
{
int particleIndex = simplices[simplexStartA + j];
deltas[particleIndex] += delta * invMasses[particleIndex] * contact.pointA[j] * baryScale * (1 - shock);
counts[particleIndex]++;
}
baryScale = BurstMath.BaryScale(contact.pointB);
for (int j = 0; j < simplexSizeB; ++j)
{
int particleIndex = simplices[simplexStartB + j];
deltas[particleIndex] -= delta * invMasses[particleIndex] * contact.pointB[j] * baryScale * (1 + shock);
counts[particleIndex]++;
}
}
// Apply position deltas immediately, if using sequential evaluation:
if (constraintParameters.evaluationOrder == Oni.ConstraintParameters.EvaluationOrder.Sequential)
{
for (int j = 0; j < simplexSizeA; ++j)
{
int particleIndex = simplices[simplexStartA + j];
BurstConstraintsBatchImpl.ApplyPositionDelta(particleIndex, constraintParameters.SORFactor, ref positions, ref deltas, ref counts);
}
for (int j = 0; j < simplexSizeB; ++j)
{
int particleIndex = simplices[simplexStartB + j];
BurstConstraintsBatchImpl.ApplyPositionDelta(particleIndex, constraintParameters.SORFactor, ref positions, ref deltas, ref counts);
}
}
contacts[i] = contact;
}
}
private BurstCollisionMaterial CombineCollisionMaterials(int entityA, int entityB)
{
// Combine collision materials:
int aMaterialIndex = particleMaterialIndices[entityA];
int bMaterialIndex = particleMaterialIndices[entityB];
if (aMaterialIndex >= 0 && bMaterialIndex >= 0)
return BurstCollisionMaterial.CombineWith(collisionMaterials[aMaterialIndex], collisionMaterials[bMaterialIndex]);
else if (aMaterialIndex >= 0)
return collisionMaterials[aMaterialIndex];
else if (bMaterialIndex >= 0)
return collisionMaterials[bMaterialIndex];
return new BurstCollisionMaterial();
}
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,33 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
namespace Obi
{
public class BurstParticleFrictionConstraints : BurstConstraintsImpl<BurstParticleFrictionConstraintsBatch>
{
public BurstParticleFrictionConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.ParticleFriction)
{
}
public override IConstraintsBatchImpl CreateConstraintsBatch()
{
var dataBatch = new BurstParticleFrictionConstraintsBatch(this);
batches.Add(dataBatch);
return dataBatch;
}
public override void RemoveBatch(IConstraintsBatchImpl batch)
{
batches.Remove(batch as BurstParticleFrictionConstraintsBatch);
batch.Destroy();
}
public override int GetConstraintCount()
{
if (!((BurstSolverImpl)solver).particleContacts.IsCreated)
return 0;
return ((BurstSolverImpl)solver).particleContacts.Length;
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,288 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
using System.Collections;
namespace Obi
{
public class BurstParticleFrictionConstraintsBatch : BurstConstraintsBatchImpl, IParticleFrictionConstraintsBatchImpl
{
public BatchData batchData;
public BurstParticleFrictionConstraintsBatch(BurstParticleFrictionConstraints constraints)
{
m_Constraints = constraints;
m_ConstraintType = Oni.ConstraintType.ParticleFriction;
}
public BurstParticleFrictionConstraintsBatch(BatchData batchData) : base()
{
this.batchData = batchData;
}
public override JobHandle Initialize(JobHandle inputDeps, float substepTime)
{
return inputDeps;
}
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
if (!((BurstSolverImpl)constraints.solver).particleContacts.IsCreated)
return inputDeps;
var projectConstraints = new ParticleFrictionConstraintsBatchJob()
{
positions = solverImplementation.positions,
prevPositions = solverImplementation.prevPositions,
orientations = solverImplementation.orientations,
prevOrientations = solverImplementation.prevOrientations,
invMasses = solverImplementation.invMasses,
invInertiaTensors = solverImplementation.invInertiaTensors,
radii = solverImplementation.principalRadii,
particleMaterialIndices = solverImplementation.collisionMaterials,
collisionMaterials = ObiColliderWorld.GetInstance().collisionMaterials.AsNativeArray<BurstCollisionMaterial>(),
simplices = solverImplementation.simplices,
simplexCounts = solverImplementation.simplexCounts,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
orientationDeltas = solverImplementation.orientationDeltas,
orientationCounts = solverImplementation.orientationConstraintCounts,
contacts = ((BurstSolverImpl)constraints.solver).particleContacts,
batchData = batchData,
substepTime = substepTime,
};
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
return projectConstraints.Schedule(batchData.workItemCount, batchCount, inputDeps);
}
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
{
if (!((BurstSolverImpl)constraints.solver).particleContacts.IsCreated)
return inputDeps;
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
var applyConstraints = new ApplyBatchedCollisionConstraintsBatchJob()
{
contacts = ((BurstSolverImpl)constraints.solver).particleContacts,
simplices = solverImplementation.simplices,
simplexCounts = solverImplementation.simplexCounts,
positions = solverImplementation.positions,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
orientations = solverImplementation.orientations,
orientationDeltas = solverImplementation.orientationDeltas,
orientationCounts = solverImplementation.orientationConstraintCounts,
constraintParameters = parameters,
batchData = batchData
};
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
return applyConstraints.Schedule(batchData.workItemCount, batchCount, inputDeps);
}
[BurstCompile]
public struct ParticleFrictionConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float4> prevPositions;
[ReadOnly] public NativeArray<quaternion> orientations;
[ReadOnly] public NativeArray<quaternion> prevOrientations;
[ReadOnly] public NativeArray<float> invMasses;
[ReadOnly] public NativeArray<float4> invInertiaTensors;
[ReadOnly] public NativeArray<float4> radii;
[ReadOnly] public NativeArray<int> particleMaterialIndices;
[ReadOnly] public NativeArray<BurstCollisionMaterial> collisionMaterials;
// simplex arrays:
[ReadOnly] public NativeArray<int> simplices;
[ReadOnly] public SimplexCounts simplexCounts;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<quaternion> orientationDeltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> orientationCounts;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<BurstContact> contacts;
[ReadOnly] public BatchData batchData;
[ReadOnly] public float substepTime;
public void Execute(int workItemIndex)
{
int start, end;
batchData.GetConstraintRange(workItemIndex, out start, out end);
for (int i = start; i < end; ++i)
{
var contact = contacts[i];
int simplexStartA = simplexCounts.GetSimplexStartAndSize(contact.bodyA, out int simplexSizeA);
int simplexStartB = simplexCounts.GetSimplexStartAndSize(contact.bodyB, out int simplexSizeB);
// Combine collision materials:
BurstCollisionMaterial material = CombineCollisionMaterials(simplices[simplexStartA], simplices[simplexStartB]);
float4 prevPositionA = float4.zero;
float4 linearVelocityA = float4.zero;
float4 angularVelocityA = float4.zero;
float4 invInertiaTensorA = float4.zero;
quaternion orientationA = new quaternion(0, 0, 0, 0);
float simplexRadiusA = 0;
float4 prevPositionB = float4.zero;
float4 linearVelocityB = float4.zero;
float4 angularVelocityB = float4.zero;
float4 invInertiaTensorB = float4.zero;
quaternion orientationB = new quaternion(0, 0, 0, 0);
float simplexRadiusB = 0;
for (int j = 0; j < simplexSizeA; ++j)
{
int particleIndex = simplices[simplexStartA + j];
prevPositionA += prevPositions[particleIndex] * contact.pointA[j];
linearVelocityA += BurstIntegration.DifferentiateLinear(positions[particleIndex], prevPositions[particleIndex], substepTime) * contact.pointA[j];
angularVelocityA += BurstIntegration.DifferentiateAngular(orientations[particleIndex], prevOrientations[particleIndex], substepTime) * contact.pointA[j];
invInertiaTensorA += invInertiaTensors[particleIndex] * contact.pointA[j];
orientationA.value += orientations[particleIndex].value * contact.pointA[j];
simplexRadiusA += BurstMath.EllipsoidRadius(contact.normal, prevOrientations[particleIndex], radii[particleIndex].xyz) * contact.pointA[j];
}
for (int j = 0; j < simplexSizeB; ++j)
{
int particleIndex = simplices[simplexStartB + j];
prevPositionB += prevPositions[particleIndex] * contact.pointB[j];
linearVelocityB += BurstIntegration.DifferentiateLinear(positions[particleIndex], prevPositions[particleIndex], substepTime) * contact.pointB[j];
angularVelocityB += BurstIntegration.DifferentiateAngular(orientations[particleIndex], prevOrientations[particleIndex], substepTime) * contact.pointB[j];
invInertiaTensorB += invInertiaTensors[particleIndex] * contact.pointB[j];
orientationB.value += orientations[particleIndex].value * contact.pointB[j];
simplexRadiusB += BurstMath.EllipsoidRadius(contact.normal, prevOrientations[particleIndex], radii[particleIndex].xyz) * contact.pointB[j];
}
float4 rA = float4.zero, rB = float4.zero;
// Consider angular velocities if rolling contacts are enabled:
if (material.rollingContacts > 0)
{
rA = -contact.normal * simplexRadiusA;
rB = contact.normal * simplexRadiusB;
linearVelocityA += new float4(math.cross(angularVelocityA.xyz, rA.xyz), 0);
linearVelocityB += new float4(math.cross(angularVelocityB.xyz, rB.xyz), 0);
}
// Calculate relative velocity:
float4 relativeVelocity = linearVelocityA - linearVelocityB;
// Calculate friction impulses (in the tangent and bitangent ddirections):
float2 impulses = contact.SolveFriction(relativeVelocity, material.staticFriction, material.dynamicFriction, substepTime);
// Apply friction impulses to both particles:
if (math.abs(impulses.x) > BurstMath.epsilon || math.abs(impulses.y) > BurstMath.epsilon)
{
float4 tangentImpulse = impulses.x * contact.tangent;
float4 bitangentImpulse = impulses.y * contact.bitangent;
float4 totalImpulse = tangentImpulse + bitangentImpulse;
float baryScale = BurstMath.BaryScale(contact.pointA);
for (int j = 0; j < simplexSizeA; ++j)
{
int particleIndex = simplices[simplexStartA + j];
deltas[particleIndex] += (tangentImpulse * contact.tangentInvMassA + bitangentImpulse * contact.bitangentInvMassA) * substepTime * contact.pointA[j] * baryScale;
counts[particleIndex]++;
}
baryScale = BurstMath.BaryScale(contact.pointB);
for (int j = 0; j < simplexSizeB; ++j)
{
int particleIndex = simplices[simplexStartB + j];
deltas[particleIndex] -= (tangentImpulse * contact.tangentInvMassB + bitangentImpulse * contact.bitangentInvMassB) * substepTime * contact.pointB[j] * baryScale;
counts[particleIndex]++;
}
// Rolling contacts:
if (material.rollingContacts > 0)
{
// Calculate angular velocity deltas due to friction impulse:
float4x4 solverInertiaA = BurstMath.TransformInertiaTensor(invInertiaTensorA, orientationA);
float4x4 solverInertiaB = BurstMath.TransformInertiaTensor(invInertiaTensorB, orientationB);
float4 angVelDeltaA = math.mul(solverInertiaA, new float4(math.cross(rA.xyz, totalImpulse.xyz), 0));
float4 angVelDeltaB = -math.mul(solverInertiaB, new float4(math.cross(rB.xyz, totalImpulse.xyz), 0));
// Final angular velocities, after adding the deltas:
angularVelocityA += angVelDeltaA;
angularVelocityB += angVelDeltaB;
// Calculate weights (inverse masses):
float invMassA = math.length(math.mul(solverInertiaA, math.normalizesafe(angularVelocityA)));
float invMassB = math.length(math.mul(solverInertiaB, math.normalizesafe(angularVelocityB)));
// Calculate rolling axis and angular velocity deltas:
float4 rollAxis = float4.zero;
float rollingImpulse = contact.SolveRollingFriction(angularVelocityA, angularVelocityB, material.rollingFriction, invMassA, invMassB, ref rollAxis);
angVelDeltaA += rollAxis * rollingImpulse * invMassA;
angVelDeltaB -= rollAxis * rollingImpulse * invMassB;
// Apply orientation deltas to particles:
quaternion orientationDeltaA = BurstIntegration.AngularVelocityToSpinQuaternion(orientationA, angVelDeltaA, substepTime);
quaternion orientationDeltaB = BurstIntegration.AngularVelocityToSpinQuaternion(orientationB, angVelDeltaB, substepTime);
for (int j = 0; j < simplexSizeA; ++j)
{
int particleIndex = simplices[simplexStartA + j];
quaternion qA = orientationDeltas[particleIndex];
qA.value += orientationDeltaA.value;
orientationDeltas[particleIndex] = qA;
orientationCounts[particleIndex]++;
}
for (int j = 0; j < simplexSizeB; ++j)
{
int particleIndex = simplices[simplexStartB+ j];
quaternion qB = orientationDeltas[particleIndex];
qB.value += orientationDeltaB.value;
orientationDeltas[particleIndex] = qB;
orientationCounts[particleIndex]++;
}
}
}
contacts[i] = contact;
}
}
private BurstCollisionMaterial CombineCollisionMaterials(int entityA, int entityB)
{
// Combine collision materials:
int aMaterialIndex = particleMaterialIndices[entityA];
int bMaterialIndex = particleMaterialIndices[entityB];
if (aMaterialIndex >= 0 && bMaterialIndex >= 0)
return BurstCollisionMaterial.CombineWith(collisionMaterials[aMaterialIndex], collisionMaterials[bMaterialIndex]);
else if (aMaterialIndex >= 0)
return collisionMaterials[aMaterialIndex];
else if (bMaterialIndex >= 0)
return collisionMaterials[bMaterialIndex];
return new BurstCollisionMaterial();
}
}
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,26 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
namespace Obi
{
public class BurstPinConstraints : BurstConstraintsImpl<BurstPinConstraintsBatch>
{
public BurstPinConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.Pin)
{
}
public override IConstraintsBatchImpl CreateConstraintsBatch()
{
var dataBatch = new BurstPinConstraintsBatch(this);
batches.Add(dataBatch);
return dataBatch;
}
public override void RemoveBatch(IConstraintsBatchImpl batch)
{
batches.Remove(batch as BurstPinConstraintsBatch);
batch.Destroy();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,280 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
using System.Collections.Generic;
namespace Obi
{
public class BurstPinConstraintsBatch : BurstConstraintsBatchImpl, IPinConstraintsBatchImpl
{
private NativeArray<int> colliderIndices;
private NativeArray<float4> offsets;
private NativeArray<quaternion> restDarbouxVectors;
private NativeArray<float2> stiffnesses;
public BurstPinConstraintsBatch(BurstPinConstraints constraints)
{
m_Constraints = constraints;
m_ConstraintType = Oni.ConstraintType.Pin;
}
public void SetPinConstraints(ObiNativeIntList particleIndices, ObiNativeIntList colliderIndices, ObiNativeVector4List offsets, ObiNativeQuaternionList restDarbouxVectors, ObiNativeFloatList stiffnesses, ObiNativeFloatList lambdas, int count)
{
this.particleIndices = particleIndices.AsNativeArray<int>();
this.colliderIndices = colliderIndices.AsNativeArray<int>();
this.offsets = offsets.AsNativeArray<float4>();
this.restDarbouxVectors = restDarbouxVectors.AsNativeArray<quaternion>();
this.stiffnesses = stiffnesses.AsNativeArray<float2>();
this.lambdas = lambdas.AsNativeArray<float>();
m_ConstraintCount = count;
}
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
var projectConstraints = new PinConstraintsBatchJob()
{
particleIndices = particleIndices,
colliderIndices = colliderIndices,
offsets = offsets,
stiffnesses = stiffnesses,
restDarboux = restDarbouxVectors,
lambdas = lambdas.Reinterpret<float, float4>(),
positions = solverImplementation.positions,
prevPositions = solverImplementation.prevPositions,
invMasses = solverImplementation.invMasses,
orientations = solverImplementation.orientations,
invRotationalMasses = solverImplementation.invRotationalMasses,
shapes = ObiColliderWorld.GetInstance().colliderShapes.AsNativeArray<BurstColliderShape>(),
transforms = ObiColliderWorld.GetInstance().colliderTransforms.AsNativeArray<BurstAffineTransform>(),
rigidbodies = ObiColliderWorld.GetInstance().rigidbodies.AsNativeArray<BurstRigidbody>(),
rigidbodyLinearDeltas = solverImplementation.abstraction.rigidbodyLinearDeltas.AsNativeArray<float4>(),
rigidbodyAngularDeltas = solverImplementation.abstraction.rigidbodyAngularDeltas.AsNativeArray<float4>(),
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
orientationDeltas = solverImplementation.orientationDeltas,
orientationCounts = solverImplementation.orientationConstraintCounts,
inertialFrame = ((BurstSolverImpl)constraints.solver).inertialFrame,
stepTime = stepTime,
substepTime = substepTime,
substeps = substeps,
activeConstraintCount = m_ConstraintCount
};
return projectConstraints.Schedule(inputDeps);
}
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
{
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
var applyConstraints = new ApplyPinConstraintsBatchJob()
{
particleIndices = particleIndices,
positions = solverImplementation.positions,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
orientations = solverImplementation.orientations,
orientationDeltas = solverImplementation.orientationDeltas,
orientationCounts = solverImplementation.orientationConstraintCounts,
sorFactor = parameters.SORFactor,
activeConstraintCount = m_ConstraintCount,
};
return applyConstraints.Schedule(inputDeps);
}
[BurstCompile]
public unsafe struct PinConstraintsBatchJob : IJob
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public NativeArray<int> colliderIndices;
[ReadOnly] public NativeArray<float4> offsets;
[ReadOnly] public NativeArray<float2> stiffnesses;
[ReadOnly] public NativeArray<quaternion> restDarboux;
public NativeArray<float4> lambdas;
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float4> prevPositions;
[ReadOnly] public NativeArray<float> invMasses;
[ReadOnly] public NativeArray<quaternion> orientations;
[ReadOnly] public NativeArray<float> invRotationalMasses;
[ReadOnly] public NativeArray<BurstColliderShape> shapes;
[ReadOnly] public NativeArray<BurstAffineTransform> transforms;
[ReadOnly] public NativeArray<BurstRigidbody> rigidbodies;
public NativeArray<float4> rigidbodyLinearDeltas;
public NativeArray<float4> rigidbodyAngularDeltas;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<int> counts;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<quaternion> orientationDeltas;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<int> orientationCounts;
[ReadOnly] public BurstInertialFrame inertialFrame;
[ReadOnly] public float stepTime;
[ReadOnly] public float substepTime;
[ReadOnly] public int substeps;
[ReadOnly] public int activeConstraintCount;
public void Execute()
{
for (int i = 0; i < activeConstraintCount; ++i)
{
int particleIndex = particleIndices[i];
int colliderIndex = colliderIndices[i];
// no collider to pin to, so ignore the constraint.
if (colliderIndex < 0)
continue;
int rigidbodyIndex = shapes[colliderIndex].rigidbodyIndex;
// calculate time adjusted compliances
float2 compliances = stiffnesses[i].xy / (substepTime * substepTime);
// project particle position to the end of the full step:
float4 particlePosition = math.lerp(prevPositions[particleIndex], positions[particleIndex], substeps);
// express pin offset in world space:
float4 worldPinOffset = transforms[colliderIndex].TransformPoint(offsets[i]);
float4 predictedPinOffset = worldPinOffset;
quaternion predictedRotation = transforms[colliderIndex].rotation;
float rigidbodyLinearW = 0;
float rigidbodyAngularW = 0;
if (rigidbodyIndex >= 0)
{
var rigidbody = rigidbodies[rigidbodyIndex];
// predict offset point position:
float4 velocityAtPoint = BurstMath.GetRigidbodyVelocityAtPoint(rigidbodyIndex, inertialFrame.frame.InverseTransformPoint(worldPinOffset), rigidbodies, rigidbodyLinearDeltas, rigidbodyAngularDeltas, inertialFrame.frame);
predictedPinOffset = BurstIntegration.IntegrateLinear(predictedPinOffset, inertialFrame.frame.TransformVector(velocityAtPoint), stepTime);
// predict rotation at the end of the step:
predictedRotation = BurstIntegration.IntegrateAngular(predictedRotation, rigidbody.angularVelocity + rigidbodyAngularDeltas[rigidbodyIndex], stepTime);
// calculate linear and angular rigidbody weights:
rigidbodyLinearW = rigidbody.inverseMass;
rigidbodyAngularW = BurstMath.RotationalInvMass(rigidbody.inverseInertiaTensor,
worldPinOffset - rigidbody.com,
math.normalizesafe(inertialFrame.frame.TransformPoint(particlePosition) - predictedPinOffset));
}
// Transform pin position to solver space for constraint solving:
predictedPinOffset = inertialFrame.frame.InverseTransformPoint(predictedPinOffset);
predictedRotation = math.mul(math.conjugate(inertialFrame.frame.rotation), predictedRotation);
float4 gradient = particlePosition - predictedPinOffset;
float constraint = math.length(gradient);
float4 gradientDir = gradient / (constraint + BurstMath.epsilon);
float4 lambda = lambdas[i];
float linearDLambda = (-constraint - compliances.x * lambda.w) / (invMasses[particleIndex] + rigidbodyLinearW + rigidbodyAngularW + compliances.x + BurstMath.epsilon);
lambda.w += linearDLambda;
float4 correction = linearDLambda * gradientDir;
deltas[particleIndex] += correction * invMasses[particleIndex] / substeps;
counts[particleIndex]++;
if (rigidbodyIndex >= 0)
{
BurstMath.ApplyImpulse(rigidbodyIndex,
-correction / stepTime * 1,
inertialFrame.frame.InverseTransformPoint(worldPinOffset),
rigidbodies, rigidbodyLinearDeltas, rigidbodyAngularDeltas, inertialFrame.frame);
}
if (rigidbodyAngularW > 0 || invRotationalMasses[particleIndex] > 0)
{
// bend/twist constraint:
quaternion omega = math.mul(math.conjugate(orientations[particleIndex]), predictedRotation); //darboux vector
quaternion omega_plus;
omega_plus.value = omega.value + restDarboux[i].value; //delta Omega with - omega_0
omega.value -= restDarboux[i].value; //delta Omega with + omega_0
if (math.lengthsq(omega.value) > math.lengthsq(omega_plus.value))
omega = omega_plus;
float3 dlambda = (omega.value.xyz - compliances.y * lambda.xyz) / new float3(compliances.y + invRotationalMasses[particleIndex] + rigidbodyAngularW + BurstMath.epsilon);
lambda.xyz += dlambda;
//discrete Darboux vector does not have vanishing scalar part
quaternion dlambdaQ = new quaternion(dlambda[0], dlambda[1], dlambda[2], 0);
quaternion orientDelta = orientationDeltas[particleIndex];
orientDelta.value += math.mul(predictedRotation, dlambdaQ).value * invRotationalMasses[particleIndex] / substeps;
orientationDeltas[particleIndex] = orientDelta;
orientationCounts[particleIndex]++;
if (rigidbodyIndex >= 0)
{
BurstMath.ApplyDeltaQuaternion(rigidbodyIndex,
predictedRotation,
-math.mul(orientations[particleIndex], dlambdaQ).value * rigidbodyAngularW,
rigidbodyAngularDeltas, inertialFrame.frame, stepTime);
}
}
lambdas[i] = lambda;
}
}
}
[BurstCompile]
public struct ApplyPinConstraintsBatchJob : IJob
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public float sorFactor;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<quaternion> orientations;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<quaternion> orientationDeltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> orientationCounts;
[ReadOnly] public int activeConstraintCount;
public void Execute()
{
for (int i = 0; i < activeConstraintCount; ++i)
{
int p1 = particleIndices[i];
if (counts[p1] > 0)
{
positions[p1] += deltas[p1] * sorFactor / counts[p1];
deltas[p1] = float4.zero;
counts[p1] = 0;
}
if (orientationCounts[p1] > 0)
{
quaternion q = orientations[p1];
q.value += orientationDeltas[p1].value * sorFactor / orientationCounts[p1];
orientations[p1] = math.normalize(q);
orientationDeltas[p1] = new quaternion(0, 0, 0, 0);
orientationCounts[p1] = 0;
}
}
}
}
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,26 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
namespace Obi
{
public class BurstShapeMatchingConstraints : BurstConstraintsImpl<BurstShapeMatchingConstraintsBatch>
{
public BurstShapeMatchingConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.ShapeMatching)
{
}
public override IConstraintsBatchImpl CreateConstraintsBatch()
{
var dataBatch = new BurstShapeMatchingConstraintsBatch(this);
batches.Add(dataBatch);
return dataBatch;
}
public override void RemoveBatch(IConstraintsBatchImpl batch)
{
batches.Remove(batch as BurstShapeMatchingConstraintsBatch);
batch.Destroy();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,459 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
using System.Collections;
namespace Obi
{
public class BurstShapeMatchingConstraintsBatch : BurstConstraintsBatchImpl, IShapeMatchingConstraintsBatchImpl
{
private NativeArray<int> firstIndex;
private NativeArray<int> numIndices;
private NativeArray<int> explicitGroup;
private NativeArray<float> shapeMaterialParameters;
private NativeArray<float4> restComs;
private NativeArray<float4> coms;
private NativeArray<quaternion> constraintOrientations;
private NativeArray<float4x4> Aqq;
private NativeArray<float4x4> linearTransforms;
private NativeArray<float4x4> plasticDeformations;
public BurstShapeMatchingConstraintsBatch(BurstShapeMatchingConstraints constraints)
{
m_Constraints = constraints;
m_ConstraintType = Oni.ConstraintType.ShapeMatching;
}
public void SetShapeMatchingConstraints(ObiNativeIntList particleIndices,
ObiNativeIntList firstIndex,
ObiNativeIntList numIndices,
ObiNativeIntList explicitGroup,
ObiNativeFloatList shapeMaterialParameters,
ObiNativeVector4List restComs,
ObiNativeVector4List coms,
ObiNativeQuaternionList constraintOrientations,
ObiNativeMatrix4x4List linearTransforms,
ObiNativeMatrix4x4List plasticDeformations,
ObiNativeFloatList lambdas,
int count)
{
this.particleIndices = particleIndices.AsNativeArray<int>();
this.firstIndex = firstIndex.AsNativeArray<int>();
this.numIndices = numIndices.AsNativeArray<int>();
this.explicitGroup = explicitGroup.AsNativeArray<int>();
this.shapeMaterialParameters = shapeMaterialParameters.AsNativeArray<float>();
this.restComs = restComs.AsNativeArray<float4>();
this.coms = coms.AsNativeArray<float4>();
this.constraintOrientations = constraintOrientations.AsNativeArray<quaternion>();
this.linearTransforms = linearTransforms.AsNativeArray<float4x4>();
this.plasticDeformations = plasticDeformations.AsNativeArray<float4x4>();
if (Aqq.IsCreated)
Aqq.Dispose();
Aqq = new NativeArray<float4x4>(count,Allocator.Persistent);
m_ConstraintCount = count;
}
public override void Destroy()
{
if (Aqq.IsCreated)
Aqq.Dispose();
}
public override JobHandle Initialize(JobHandle inputDeps, float substepTime)
{
return inputDeps;
}
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
var projectConstraints = new ShapeMatchingConstraintsBatchJob()
{
particleIndices = particleIndices,
firstIndex = firstIndex,
numIndices = numIndices,
explicitGroup = explicitGroup,
shapeMaterialParameters = shapeMaterialParameters,
restComs = restComs,
coms = coms,
constraintOrientations = constraintOrientations,
Aqq = Aqq,
linearTransforms = linearTransforms,
deformation = plasticDeformations,
positions = solverImplementation.positions,
restPositions = solverImplementation.restPositions,
orientations = solverImplementation.orientations,
restOrientations = solverImplementation.restOrientations,
invMasses = solverImplementation.invMasses,
invRotationalMasses = solverImplementation.invRotationalMasses,
invInertiaTensors = solverImplementation.invInertiaTensors,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
deltaTime = substepTime
};
return projectConstraints.Schedule(m_ConstraintCount, 4, inputDeps);
}
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
{
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
var applyConstraints = new ApplyShapeMatchingConstraintsBatchJob()
{
particleIndices = particleIndices,
firstIndex = firstIndex,
numIndices = numIndices,
positions = solverImplementation.positions,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
sorFactor = parameters.SORFactor
};
return applyConstraints.Schedule(m_ConstraintCount, 8, inputDeps);
}
public void CalculateRestShapeMatching()
{
var deps = ((BurstSolverImpl)constraints.solver).RecalculateInertiaTensors(new JobHandle());
var calculateRest = new ShapeMatchingCalculateRestJob()
{
particleIndices = particleIndices,
firstIndex = firstIndex,
numIndices = numIndices,
restComs = restComs,
coms = coms,
Aqq = Aqq,
deformation = plasticDeformations,
restPositions = solverAbstraction.restPositions.AsNativeArray<float4>(),
restOrientations = solverAbstraction.restOrientations.AsNativeArray<quaternion>(),
invMasses = solverAbstraction.invMasses.AsNativeArray<float>(),
invInertiaTensors = solverAbstraction.invInertiaTensors.AsNativeArray<float4>(),
};
calculateRest.Schedule(numIndices.Length, 64, deps).Complete();
}
protected static void RecalculateRestData(int i,
ref NativeArray<int> particleIndices,
ref NativeArray<int> firstIndex,
ref NativeArray<float4> restComs,
ref NativeArray<float4x4> Aqq,
ref NativeArray<float4x4> deformation,
ref NativeArray<int> numIndices,
ref NativeArray<float> invMasses,
ref NativeArray<float4> restPositions,
ref NativeArray<quaternion> restOrientations,
ref NativeArray<float4> invInertiaTensors)
{
int k = 0;
float maximumMass = 10000;
// initialize rest center of mass and shape matrix:
restComs[i] = float4.zero;
Aqq[i] = float4x4.zero;
float4 restCom = float4.zero;
float4x4 _Aqq = float4x4.zero, _Rqq = float4x4.zero;
// calculate rest center of mass, shape mass and Aqq matrix.
for (int j = 0; j < numIndices[i]; ++j)
{
k = particleIndices[firstIndex[i] + j];
float mass = maximumMass;
if (invMasses[k] > 1.0f / maximumMass)
mass = 1.0f / invMasses[k];
restCom += restPositions[k] * mass;
float4x4 particleR = restOrientations[k].toMatrix();
particleR[3][3] = 0;
_Rqq += math.mul(particleR,
math.mul(math.rcp(invInertiaTensors[k] + new float4(BurstMath.epsilon)).asDiagonal(),
math.transpose(particleR))
);
float4 restPosition = restPositions[k];
restPosition[3] = 0;
_Aqq += mass * BurstMath.multrnsp4(restPosition, restPosition);
}
if (restCom[3] < BurstMath.epsilon)
return;
restCom.xyz /= restCom[3];
restComs[i] = restCom;
restCom[3] = 0;
_Aqq -= restComs[i][3] * BurstMath.multrnsp4(restCom, restCom);
_Aqq[3][3] = 1; // so that the determinant is never 0 due to all-zeros row/column.
Aqq[i] = math.inverse(_Rqq + math.mul(deformation[i], math.mul(_Aqq, math.transpose(deformation[i]))));
}
[BurstCompile]
public struct ShapeMatchingCalculateRestJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public NativeArray<int> firstIndex;
[ReadOnly] public NativeArray<int> numIndices;
public NativeArray<float4> restComs;
[ReadOnly] public NativeArray<float4> coms;
public NativeArray<float4x4> Aqq;
[ReadOnly] public NativeArray<float4x4> deformation;
[ReadOnly] public NativeArray<float4> restPositions;
[ReadOnly] public NativeArray<quaternion> restOrientations;
[ReadOnly] public NativeArray<float> invMasses;
[ReadOnly] public NativeArray<float4> invInertiaTensors;
public void Execute(int i)
{
RecalculateRestData(i,
ref particleIndices,
ref firstIndex,
ref restComs,
ref Aqq,
ref deformation,
ref numIndices,
ref invMasses,
ref restPositions,
ref restOrientations,
ref invInertiaTensors);
}
}
[BurstCompile]
public struct ShapeMatchingConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public NativeArray<int> firstIndex;
[ReadOnly] public NativeArray<int> numIndices;
[ReadOnly] public NativeArray<int> explicitGroup;
[ReadOnly] public NativeArray<float> shapeMaterialParameters;
public NativeArray<float4> restComs;
public NativeArray<float4> coms;
public NativeArray<quaternion> constraintOrientations;
public NativeArray<float4x4> Aqq;
public NativeArray<float4x4> linearTransforms;
public NativeArray<float4x4> deformation;
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float4> restPositions;
[ReadOnly] public NativeArray<quaternion> restOrientations;
[ReadOnly] public NativeArray<float> invMasses;
[ReadOnly] public NativeArray<float> invRotationalMasses;
[ReadOnly] public NativeArray<float4> invInertiaTensors;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<quaternion> orientations;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<int> counts;
[ReadOnly] public float deltaTime;
public void Execute(int i)
{
int k;
float maximumMass = 10000;
coms[i] = float4.zero;
float4x4 Apq = float4x4.zero, Rpq = float4x4.zero;
// calculate shape mass, center of mass, and moment matrix:
for (int j = 0; j < numIndices[i]; ++j)
{
k = particleIndices[firstIndex[i] + j];
float mass = maximumMass;
if (invMasses[k] > 1.0f / maximumMass)
mass = 1.0f / invMasses[k];
coms[i] += positions[k] * mass;
float4x4 particleR = orientations[k].toMatrix();
float4x4 particleRT = restOrientations[k].toMatrix();
particleR[3][3] = 0;
particleRT[3][3] = 0;
Rpq += math.mul(particleR,
math.mul(math.rcp(invInertiaTensors[k] + new float4(BurstMath.epsilon)).asDiagonal(),
math.transpose(particleRT))
);
float4 restPosition = restPositions[k];
restPosition[3] = 0;
Apq += mass * BurstMath.multrnsp4(positions[k], restPosition);
}
if (restComs[i][3] < BurstMath.epsilon)
return;
coms[i] /= restComs[i][3];
// subtract global shape moment:
float4 restCom = restComs[i];
restCom[3] = 0;
Apq -= restComs[i][3] * BurstMath.multrnsp4(coms[i], restCom);
// calculate optimal transform including plastic deformation:
float4x4 Apq_def = Rpq + math.mul(Apq , math.transpose(deformation[i]));
Apq_def[3][3] = 1;
// reconstruct full best-matching linear transform:
linearTransforms[i] = math.mul(Apq_def, Aqq[i]);
// extract rotation from transform matrix, using warmstarting and few iterations:
constraintOrientations[i] = BurstMath.ExtractRotation(Apq_def, constraintOrientations[i], 2);
// finally, obtain rotation matrix:
float4x4 R = constraintOrientations[i].toMatrix();
R[3][3] = 0;
// calculate particle orientations:
if (explicitGroup[i] > 0)
{
// if the group is explicit, set the orientation for all particles:
for (int j = 0; j < numIndices[i]; ++j)
{
k = particleIndices[firstIndex[i] + j];
orientations[k] = math.mul(constraintOrientations[i], restOrientations[k]);
}
}
else
{
// set orientation of center particle only:
int centerIndex = particleIndices[firstIndex[i]];
orientations[centerIndex] = math.mul(constraintOrientations[i], restOrientations[centerIndex]);
}
// calculate and accumulate particle goal positions:
float4 goal;
float4x4 transform = math.mul(R,deformation[i]);
for (int j = 0; j < numIndices[i]; ++j)
{
k = particleIndices[firstIndex[i] + j];
goal = coms[i] + math.mul(transform, restPositions[k] - restComs[i]);
deltas[k] += (goal - positions[k]) * shapeMaterialParameters[i * 5];
counts[k]++;
}
// update plastic deformation:
float plastic_yield = shapeMaterialParameters[i * 5 + 1];
float plastic_creep = shapeMaterialParameters[i * 5 + 2];
float plastic_recovery = shapeMaterialParameters[i * 5 + 3];
float max_deform = shapeMaterialParameters[i * 5 + 4];
// if we are allowed to absorb deformation:
if (plastic_creep > 0)
{
R[3][3] = 1;
// get scale matrix (A = RS so S = Rt * A) and its deviation from the identity matrix:
float4x4 deform_matrix = math.mul(math.transpose(R), linearTransforms[i]) - float4x4.identity;
// if the amount of deformation exceeds the yield threshold:
float norm = deform_matrix.frobeniusNorm();
if (norm > plastic_yield)
{
// deform the shape permanently:
deformation[i] = math.mul(float4x4.identity + plastic_creep * deform_matrix, deformation[i]);
// clamp deformation so that it does not exceed a percentage;
deform_matrix = deformation[i] - float4x4.identity;
norm = deform_matrix.frobeniusNorm();
if (norm > max_deform)
{
deformation[i] = float4x4.identity + max_deform * deform_matrix / norm;
}
// if we cannot recover from plastic deformation, recalculate rest shape now:
if (plastic_recovery == 0)
RecalculateRestData(i,
ref particleIndices,
ref firstIndex,
ref restComs,
ref Aqq,
ref deformation,
ref numIndices,
ref invMasses,
ref restPositions,
ref restOrientations,
ref invInertiaTensors);
}
}
// if we can recover from plastic deformation, lerp towards non-deformed shape and recalculate rest shape:
if (plastic_recovery > 0)
{
deformation[i] += (float4x4.identity - deformation[i]) * math.min(plastic_recovery * deltaTime, 1.0f);
RecalculateRestData(i,
ref particleIndices,
ref firstIndex,
ref restComs,
ref Aqq,
ref deformation,
ref numIndices,
ref invMasses,
ref restPositions,
ref restOrientations,
ref invInertiaTensors);
}
}
}
[BurstCompile]
public struct ApplyShapeMatchingConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public NativeArray<int> firstIndex;
[ReadOnly] public NativeArray<int> numIndices;
[ReadOnly] public float sorFactor;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
public void Execute(int i)
{
int first = firstIndex[i];
int last = first + numIndices[i];
for (int k = first; k < last; ++k)
{
int p = particleIndices[k];
if (counts[p] > 0)
{
positions[p] += deltas[p] * sorFactor / counts[p];
deltas[p] = float4.zero;
counts[p] = 0;
}
}
}
}
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,26 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
namespace Obi
{
public class BurstSkinConstraints : BurstConstraintsImpl<BurstSkinConstraintsBatch>
{
public BurstSkinConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.Skin)
{
}
public override IConstraintsBatchImpl CreateConstraintsBatch()
{
var dataBatch = new BurstSkinConstraintsBatch(this);
batches.Add(dataBatch);
return dataBatch;
}
public override void RemoveBatch(IConstraintsBatchImpl batch)
{
batches.Remove(batch as BurstSkinConstraintsBatch);
batch.Destroy();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,151 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
using System.Collections;
namespace Obi
{
public class BurstSkinConstraintsBatch : BurstConstraintsBatchImpl, ISkinConstraintsBatchImpl
{
private NativeArray<float4> skinPoints;
private NativeArray<float4> skinNormals;
private NativeArray<float> skinRadiiBackstop;
private NativeArray<float> skinCompliance;
public BurstSkinConstraintsBatch(BurstSkinConstraints constraints)
{
m_Constraints = constraints;
m_ConstraintType = Oni.ConstraintType.Skin;
}
public void SetSkinConstraints(ObiNativeIntList particleIndices, ObiNativeVector4List skinPoints, ObiNativeVector4List skinNormals, ObiNativeFloatList skinRadiiBackstop, ObiNativeFloatList skinCompliance, ObiNativeFloatList lambdas, int count)
{
this.particleIndices = particleIndices.AsNativeArray<int>();
this.skinPoints = skinPoints.AsNativeArray<float4>();
this.skinNormals = skinNormals.AsNativeArray<float4>();
this.skinRadiiBackstop = skinRadiiBackstop.AsNativeArray<float>();
this.skinCompliance = skinCompliance.AsNativeArray<float>();
this.lambdas = lambdas.AsNativeArray<float>();
m_ConstraintCount = count;
}
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
var projectConstraints = new SkinConstraintsBatchJob()
{
particleIndices = particleIndices,
skinPoints = skinPoints,
skinNormals = skinNormals,
skinRadiiBackstop = skinRadiiBackstop.Reinterpret<float, float3>(),
skinCompliance = skinCompliance,
lambdas = lambdas,
positions = solverImplementation.positions,
invMasses = solverImplementation.invMasses,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
deltaTimeSqr = substepTime * substepTime
};
return projectConstraints.Schedule(m_ConstraintCount, 32, inputDeps);
}
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
{
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
var applyConstraints = new ApplySkinConstraintsBatchJob()
{
particleIndices = particleIndices,
positions = solverImplementation.positions,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
sorFactor = parameters.SORFactor
};
return applyConstraints.Schedule(m_ConstraintCount, 64, inputDeps);
}
[BurstCompile]
public struct SkinConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public NativeArray<float4> skinPoints;
[ReadOnly] public NativeArray<float4> skinNormals;
[ReadOnly] public NativeArray<float3> skinRadiiBackstop;
[ReadOnly] public NativeArray<float> skinCompliance;
public NativeArray<float> lambdas;
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float> invMasses;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<int> counts;
[ReadOnly] public float deltaTimeSqr;
public void Execute(int i)
{
float radius = skinRadiiBackstop[i].x;
float collisionRadius = skinRadiiBackstop[i].y;
float backstopDistance = collisionRadius + skinRadiiBackstop[i].z;
float compliance = skinCompliance[i] / deltaTimeSqr;
int p = particleIndices[i];
if (invMasses[p] > 0)
{
float4 toSkin = positions[p] - skinPoints[i];
float4 toBackstop = positions[p] - (skinPoints[i] - skinNormals[i] * backstopDistance);
// distance to skin and backstop sphere centers:
float d = math.length(toSkin);
float b = math.length(toBackstop);
// constrain particle within skin radius.
// ignore mass in the equations (use 1), as we don't want particle mass to interfere with skin compliance.
// We should be able to adjust skin properties and particle mass (for collisions) independently.
float constraint = math.max(0,d - radius);
float dlambda = (-constraint - compliance * lambdas[i]) / (1 + compliance);
lambdas[i] += dlambda;
deltas[p] += dlambda * toSkin / (d + BurstMath.epsilon);
counts[p]++;
// constrain particle outside the backstop sphere (0 compliance):
constraint = math.min(0, b - collisionRadius);
deltas[p] -= constraint * toBackstop / (b + BurstMath.epsilon);
}
}
}
[BurstCompile]
public struct ApplySkinConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public float sorFactor;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
public void Execute(int i)
{
int p1 = particleIndices[i];
if (counts[p1] > 0)
{
positions[p1] += deltas[p1] * sorFactor / counts[p1];
deltas[p1] = float4.zero;
counts[p1] = 0;
}
}
}
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,26 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
namespace Obi
{
public class BurstStitchConstraints : BurstConstraintsImpl<BurstStitchConstraintsBatch>
{
public BurstStitchConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.Stitch)
{
}
public override IConstraintsBatchImpl CreateConstraintsBatch()
{
var dataBatch = new BurstStitchConstraintsBatch(this);
batches.Add(dataBatch);
return dataBatch;
}
public override void RemoveBatch(IConstraintsBatchImpl batch)
{
batches.Remove(batch as BurstStitchConstraintsBatch);
batch.Destroy();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,152 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
using System.Collections;
namespace Obi
{
public class BurstStitchConstraintsBatch : BurstConstraintsBatchImpl, IStitchConstraintsBatchImpl
{
private NativeArray<float> stiffnesses;
public BurstStitchConstraintsBatch(BurstStitchConstraints constraints)
{
m_Constraints = constraints;
m_ConstraintType = Oni.ConstraintType.Stitch;
}
public void SetStitchConstraints(ObiNativeIntList particleIndices, ObiNativeFloatList stiffnesses, ObiNativeFloatList lambdas, int count)
{
this.particleIndices = particleIndices.AsNativeArray<int>();
this.stiffnesses = stiffnesses.AsNativeArray<float>();
this.lambdas = lambdas.AsNativeArray<float>();
m_ConstraintCount = count;
}
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
var projectConstraints = new StitchConstraintsBatchJob()
{
particleIndices = particleIndices,
stiffnesses = stiffnesses,
lambdas = lambdas,
positions = solverImplementation.positions,
invMasses = solverImplementation.invMasses,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
deltaTimeSqr = substepTime * substepTime,
activeConstraintCount = m_ConstraintCount
};
return projectConstraints.Schedule(inputDeps);
}
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
{
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
var applyConstraints = new ApplyStitchConstraintsBatchJob()
{
particleIndices = particleIndices,
positions = solverImplementation.positions,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
sorFactor = parameters.SORFactor,
activeConstraintCount = m_ConstraintCount
};
return applyConstraints.Schedule(inputDeps);
}
[BurstCompile]
public struct StitchConstraintsBatchJob : IJob
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public NativeArray<float> stiffnesses;
public NativeArray<float> lambdas;
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float> invMasses;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<int> counts;
[ReadOnly] public float deltaTimeSqr;
[ReadOnly] public int activeConstraintCount;
public void Execute()
{
for (int i = 0; i < activeConstraintCount; ++i)
{
int p1 = particleIndices[i * 2];
int p2 = particleIndices[i * 2 + 1];
float w1 = invMasses[p1];
float w2 = invMasses[p2];
// calculate time adjusted compliance
float compliance = stiffnesses[i] / deltaTimeSqr;
// calculate position and lambda deltas:
float4 distance = positions[p1] - positions[p2];
float constraint = math.length(distance);
// calculate lambda and position deltas:
float dlambda = (-constraint - compliance * lambdas[i]) / (w1 + w2 + compliance + BurstMath.epsilon);
float4 delta = dlambda * distance / (constraint + BurstMath.epsilon);
lambdas[i] += dlambda;
deltas[p1] += delta * w1;
deltas[p2] -= delta * w2;
counts[p1]++;
counts[p2]++;
}
}
}
[BurstCompile]
public struct ApplyStitchConstraintsBatchJob : IJob
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public float sorFactor;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
[ReadOnly] public int activeConstraintCount;
public void Execute()
{
for (int i = 0; i < activeConstraintCount; ++i)
{
int p1 = particleIndices[i * 2];
int p2 = particleIndices[i * 2 + 1];
if (counts[p1] > 0)
{
positions[p1] += deltas[p1] * sorFactor / counts[p1];
deltas[p1] = float4.zero;
counts[p1] = 0;
}
if (counts[p2] > 0)
{
positions[p2] += deltas[p2] * sorFactor / counts[p2];
deltas[p2] = float4.zero;
counts[p2] = 0;
}
}
}
}
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,26 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
namespace Obi
{
public class BurstStretchShearConstraints : BurstConstraintsImpl<BurstStretchShearConstraintsBatch>
{
public BurstStretchShearConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.StretchShear)
{
}
public override IConstraintsBatchImpl CreateConstraintsBatch()
{
var dataBatch = new BurstStretchShearConstraintsBatch(this);
batches.Add(dataBatch);
return dataBatch;
}
public override void RemoveBatch(IConstraintsBatchImpl batch)
{
batches.Remove(batch as BurstStretchShearConstraintsBatch);
batch.Destroy();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,203 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
using System.Collections;
namespace Obi
{
public class BurstStretchShearConstraintsBatch : BurstConstraintsBatchImpl, IStretchShearConstraintsBatchImpl
{
private NativeArray<int> orientationIndices;
private NativeArray<float> restLengths;
private NativeArray<quaternion> restOrientations;
private NativeArray<float3> stiffnesses;
public BurstStretchShearConstraintsBatch(BurstStretchShearConstraints constraints)
{
m_Constraints = constraints;
m_ConstraintType = Oni.ConstraintType.StretchShear;
}
public void SetStretchShearConstraints(ObiNativeIntList particleIndices, ObiNativeIntList orientationIndices, ObiNativeFloatList restLengths, ObiNativeQuaternionList restOrientations, ObiNativeVector3List stiffnesses, ObiNativeFloatList lambdas, int count)
{
this.particleIndices = particleIndices.AsNativeArray<int>();
this.orientationIndices = orientationIndices.AsNativeArray<int>();
this.restLengths = restLengths.AsNativeArray<float>();
this.restOrientations = restOrientations.AsNativeArray<quaternion>();
this.stiffnesses = stiffnesses.AsNativeArray<float3>();
this.lambdas = lambdas.AsNativeArray<float>();
m_ConstraintCount = count;
}
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
var projectConstraints = new StretchShearConstraintsBatchJob()
{
particleIndices = particleIndices,
orientationIndices = orientationIndices,
restLengths = restLengths,
restOrientations = restOrientations,
stiffnesses = stiffnesses,
lambdas = lambdas.Reinterpret<float, float3>(),
positions = solverImplementation.positions,
orientations = solverImplementation.orientations,
invMasses = solverImplementation.invMasses,
invRotationalMasses = solverImplementation.invRotationalMasses,
deltas = solverImplementation.positionDeltas,
orientationDeltas = solverImplementation.orientationDeltas,
counts = solverImplementation.positionConstraintCounts,
orientationCounts = solverImplementation.orientationConstraintCounts,
deltaTimeSqr = substepTime * substepTime
};
return projectConstraints.Schedule(m_ConstraintCount, 32, inputDeps);
}
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
{
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
var applyConstraints = new ApplyStretchShearConstraintsBatchJob()
{
particleIndices = particleIndices,
orientationIndices = orientationIndices,
positions = solverImplementation.positions,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
orientations = solverImplementation.orientations,
orientationDeltas = solverImplementation.orientationDeltas,
orientationCounts = solverImplementation.orientationConstraintCounts,
sorFactor = parameters.SORFactor
};
return applyConstraints.Schedule(m_ConstraintCount, 64, inputDeps);
}
[BurstCompile]
public struct StretchShearConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public NativeArray<int> orientationIndices;
[ReadOnly] public NativeArray<float> restLengths;
[ReadOnly] public NativeArray<quaternion> restOrientations;
[ReadOnly] public NativeArray<float3> stiffnesses;
public NativeArray<float3> lambdas;
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<quaternion> orientations;
[ReadOnly] public NativeArray<float> invMasses;
[ReadOnly] public NativeArray<float> invRotationalMasses;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<quaternion> orientationDeltas;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<int> counts;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<int> orientationCounts;
[ReadOnly] public float deltaTimeSqr;
public void Execute(int i)
{
int p1 = particleIndices[i * 2];
int p2 = particleIndices[i * 2 + 1];
int q = orientationIndices[i];
float w1 = invMasses[p1];
float w2 = invMasses[p2];
// calculate time adjusted compliance
float3 compliances = stiffnesses[i] / deltaTimeSqr;
float3 e = math.rotate(restOrientations[i],new float3(0, 0, 1));
quaternion basis = math.mul(orientations[q],restOrientations[i]);
// calculate rod vector in local element space:
float3 gamma = math.rotate(math.conjugate(basis), (positions[p2] - positions[p1]).xyz) / (restLengths[i] + BurstMath.epsilon);
// subtract third director vector (0,0,1):
gamma[2] -= 1;
float3 W = new float3((w1 + w2) / (restLengths[i] + BurstMath.epsilon) + invRotationalMasses[q] * 4.0f * restLengths[i] + BurstMath.epsilon);
float3 dlambda = (gamma - compliances * lambdas[i]) / (compliances + W);
lambdas[i] += dlambda;
// convert lambda delta lambda back to world space:
dlambda = math.mul(basis, dlambda);
deltas[p1] += new float4(dlambda, 0) * w1;
deltas[p2] -= new float4(dlambda, 0) * w2;
quaternion e_3 = new quaternion(e.x,e.y,e.z,0);
quaternion q_e_3_bar = math.mul(orientations[q],math.conjugate(e_3));
// calculate rotation delta:
quaternion rotDelta = math.mul(new quaternion(dlambda[0], dlambda[1], dlambda[2], 0.0f),q_e_3_bar);
rotDelta.value *= 2.0f * invRotationalMasses[q] * restLengths[i];
orientationDeltas[q] = rotDelta;
counts[p1]++;
counts[p2]++;
orientationCounts[q]++;
}
}
[BurstCompile]
public struct ApplyStretchShearConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public NativeArray<int> orientationIndices;
[ReadOnly] public float sorFactor;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<quaternion> orientations;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<quaternion> orientationDeltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> orientationCounts;
public void Execute(int i)
{
int p1 = particleIndices[i * 2];
int p2 = particleIndices[i * 2 + 1];
int q1 = orientationIndices[i];
if (counts[p1] > 0)
{
positions[p1] += deltas[p1] * sorFactor / counts[p1];
deltas[p1] = float4.zero;
counts[p1] = 0;
}
if (counts[p2] > 0)
{
positions[p2] += deltas[p2] * sorFactor / counts[p2];
deltas[p2] = float4.zero;
counts[p2] = 0;
}
if (orientationCounts[q1] > 0)
{
quaternion q = orientations[q1];
q.value += orientationDeltas[q1].value * sorFactor / orientationCounts[q1];
orientations[q1] = math.normalize(q);
orientationDeltas[q1] = new quaternion(0, 0, 0, 0);
orientationCounts[q1] = 0;
}
}
}
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,26 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
namespace Obi
{
public class BurstTetherConstraints : BurstConstraintsImpl<BurstTetherConstraintsBatch>
{
public BurstTetherConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.Distance)
{
}
public override IConstraintsBatchImpl CreateConstraintsBatch()
{
var dataBatch = new BurstTetherConstraintsBatch(this);
batches.Add(dataBatch);
return dataBatch;
}
public override void RemoveBatch(IConstraintsBatchImpl batch)
{
batches.Remove(batch as BurstTetherConstraintsBatch);
batch.Destroy();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,141 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
using System.Collections;
namespace Obi
{
public class BurstTetherConstraintsBatch : BurstConstraintsBatchImpl, ITetherConstraintsBatchImpl
{
private NativeArray<float2> maxLengthScale;
private NativeArray<float> stiffnesses;
public BurstTetherConstraintsBatch(BurstTetherConstraints constraints)
{
m_Constraints = constraints;
m_ConstraintType = Oni.ConstraintType.Tether;
}
public void SetTetherConstraints(ObiNativeIntList particleIndices, ObiNativeVector2List maxLengthScale, ObiNativeFloatList stiffnesses, ObiNativeFloatList lambdas, int count)
{
this.particleIndices = particleIndices.AsNativeArray<int>();
this.maxLengthScale = maxLengthScale.AsNativeArray<float2>();
this.stiffnesses = stiffnesses.AsNativeArray<float>();
this.lambdas = lambdas.AsNativeArray<float>();
m_ConstraintCount = count;
}
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
var projectConstraints = new TetherConstraintsBatchJob()
{
particleIndices = particleIndices,
maxLengthScale = maxLengthScale,
stiffnesses = stiffnesses,
lambdas = lambdas,
positions = solverImplementation.positions,
invMasses = solverImplementation.invMasses,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
deltaTimeSqr = substepTime * substepTime
};
return projectConstraints.Schedule(m_ConstraintCount, 32, inputDeps);
}
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
{
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
var applyConstraints = new ApplyTetherConstraintsBatchJob()
{
particleIndices = particleIndices,
positions = solverImplementation.positions,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
sorFactor = parameters.SORFactor
};
return applyConstraints.Schedule(m_ConstraintCount, 64, inputDeps);
}
[BurstCompile]
public struct TetherConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> particleIndices;
[ReadOnly] public NativeArray<float2> maxLengthScale;
[ReadOnly] public NativeArray<float> stiffnesses;
public NativeArray<float> lambdas;
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float> invMasses;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<int> counts;
[ReadOnly] public float deltaTimeSqr;
public void Execute(int i)
{
int p1 = particleIndices[i * 2];
int p2 = particleIndices[i * 2 + 1];
float w1 = invMasses[p1];
float w2 = invMasses[p2];
// calculate time adjusted compliance
float compliance = stiffnesses[i] / deltaTimeSqr;
// calculate position and lambda deltas:
float4 distance = positions[p1] - positions[p2];
float d = math.length(distance);
// calculate constraint value (distance - rest length)
float constraint = d - (maxLengthScale[i].x * maxLengthScale[i].y);
if (constraint > 0)
{
// calculate lambda and position deltas:
float dlambda = (-constraint - compliance * lambdas[i]) / (w1 + w2 + compliance + BurstMath.epsilon);
float4 delta = dlambda * distance / (d + BurstMath.epsilon);
lambdas[i] += dlambda;
deltas[p1] += delta * w1;
counts[p1]++;
}
}
}
[BurstCompile]
public struct ApplyTetherConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeSlice<int> particleIndices;
// linear/position properties:
[NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableParallelForRestriction] public NativeArray<int> counts;
[ReadOnly] public float sorFactor;
public void Execute(int index)
{
// only the first particle out of each pair is affected:
int i = particleIndices[index * 2];
if (counts[i] > 0)
{
positions[i] += deltas[i] * sorFactor / counts[i];
deltas[i] = float4.zero;
counts[i] = 0;
}
}
}
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,26 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
namespace Obi
{
public class BurstVolumeConstraints : BurstConstraintsImpl<BurstVolumeConstraintsBatch>
{
public BurstVolumeConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.Volume)
{
}
public override IConstraintsBatchImpl CreateConstraintsBatch()
{
var dataBatch = new BurstVolumeConstraintsBatch(this);
batches.Add(dataBatch);
return dataBatch;
}
public override void RemoveBatch(IConstraintsBatchImpl batch)
{
batches.Remove(batch as BurstVolumeConstraintsBatch);
batch.Destroy();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,220 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
using System.Collections;
namespace Obi
{
public class BurstVolumeConstraintsBatch : BurstConstraintsBatchImpl, IVolumeConstraintsBatchImpl
{
private NativeArray<int> firstTriangle;
private NativeArray<int> numTriangles;
private NativeArray<float> restVolumes;
private NativeArray<float2> pressureStiffness;
public BurstVolumeConstraintsBatch(BurstVolumeConstraints constraints)
{
m_Constraints = constraints;
m_ConstraintType = Oni.ConstraintType.Volume;
}
public void SetVolumeConstraints(ObiNativeIntList triangles,
ObiNativeIntList firstTriangle,
ObiNativeIntList numTriangles,
ObiNativeFloatList restVolumes,
ObiNativeVector2List pressureStiffness,
ObiNativeFloatList lambdas,
int count)
{
this.particleIndices = triangles.AsNativeArray<int>();
this.firstTriangle = firstTriangle.AsNativeArray<int>();
this.numTriangles = numTriangles.AsNativeArray<int>();
this.restVolumes = restVolumes.AsNativeArray<float>();
this.pressureStiffness = pressureStiffness.AsNativeArray<float2>();
this.lambdas = lambdas.AsNativeArray<float>();
m_ConstraintCount = count;
}
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
var projectConstraints = new VolumeConstraintsBatchJob()
{
triangles = particleIndices,
firstTriangle = firstTriangle,
numTriangles = numTriangles,
restVolumes = restVolumes,
pressureStiffness = pressureStiffness,
lambdas = lambdas,
positions = solverImplementation.positions,
invMasses = solverImplementation.invMasses,
gradients = solverImplementation.fluidData, // reuse fluidData for temp gradients.
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
deltaTimeSqr = substepTime * substepTime
};
return projectConstraints.Schedule(m_ConstraintCount, 4, inputDeps);
}
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
{
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
var applyConstraints = new ApplyVolumeConstraintsBatchJob()
{
triangles = particleIndices,
firstTriangle = firstTriangle,
numTriangles = numTriangles,
positions = solverImplementation.positions,
deltas = solverImplementation.positionDeltas,
counts = solverImplementation.positionConstraintCounts,
sorFactor = parameters.SORFactor
};
return applyConstraints.Schedule(m_ConstraintCount, 8, inputDeps);
}
[BurstCompile]
public struct VolumeConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> triangles;
[ReadOnly] public NativeArray<int> firstTriangle;
[ReadOnly] public NativeArray<int> numTriangles;
[ReadOnly] public NativeArray<float> restVolumes;
[ReadOnly] public NativeArray<float2> pressureStiffness;
public NativeArray<float> lambdas;
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float> invMasses;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> gradients;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<int> counts;
[ReadOnly] public float deltaTimeSqr;
public void Execute(int i)
{
float compliance = pressureStiffness[i].y / deltaTimeSqr;
NativeList<int> particleIndices = new NativeList<int>(numTriangles[i] * 3, Allocator.Temp);
// calculate volume:
float volume = 0;
for (int j = 0; j < numTriangles[i]; ++j)
{
int v = (firstTriangle[i] + j) * 3;
int i1 = triangles[v];
int i2 = triangles[v + 1];
int i3 = triangles[v + 2];
particleIndices.Add(i1);
particleIndices.Add(i2);
particleIndices.Add(i3);
//calculate this triangle's volume contribution:
volume += math.dot(math.cross(positions[i1].xyz, positions[i2].xyz), positions[i3].xyz) / 6.0f;
}
particleIndices.Sort();
int particleCount = particleIndices.AsArray().Unique();
// accumulate particle gradients:
for (int j = 0; j < particleCount; ++j)
gradients[particleIndices[j]] = float4.zero;
for (int j = 0; j < numTriangles[i]; ++j)
{
int v = (firstTriangle[i] + j) * 3;
int i1 = triangles[v];
int i2 = triangles[v + 1];
int i3 = triangles[v + 2];
//accumulate gradient for each particle:
gradients[i1] += new float4(math.cross(positions[i2].xyz, positions[i3].xyz), 0);
gradients[i2] += new float4(math.cross(positions[i3].xyz, positions[i1].xyz), 0);
gradients[i3] += new float4(math.cross(positions[i1].xyz, positions[i2].xyz), 0);
}
// calculate constraint denominator (G(Cj)*inv(M)):
float denominator = 0;
for (int j = 0; j < particleCount; ++j)
{
int p = particleIndices[j];
denominator += invMasses[p] * math.lengthsq(gradients[p]);
}
// equality constraint: volume - pressure * rest volume = 0
float constraint = volume - pressureStiffness[i].x * restVolumes[i];
// calculate lagrange multiplier delta:
float dlambda = (-constraint - compliance * lambdas[i]) / (denominator + compliance + BurstMath.epsilon);
lambdas[i] += dlambda;
// calculate position deltas:
for (int j = 0; j < particleCount; ++j)
{
int p = particleIndices[j];
deltas[p] += dlambda * invMasses[p] * gradients[p];
counts[p]++;
}
}
}
[BurstCompile]
public struct ApplyVolumeConstraintsBatchJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> triangles;
[ReadOnly] public NativeArray<int> firstTriangle;
[ReadOnly] public NativeArray<int> numTriangles;
[ReadOnly] public float sorFactor;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
public void Execute(int i)
{
for (int j = 0; j < numTriangles[i]; ++j)
{
int v = (firstTriangle[i] + j) * 3;
int p1 = triangles[v];
int p2 = triangles[v + 1];
int p3 = triangles[v + 2];
if (counts[p1] > 0)
{
positions[p1] += deltas[p1] * sorFactor / counts[p1];
deltas[p1] = float4.zero;
counts[p1] = 0;
}
if (counts[p2] > 0)
{
positions[p2] += deltas[p2] * sorFactor / counts[p2];
deltas[p2] = float4.zero;
counts[p2] = 0;
}
if (counts[p3] > 0)
{
positions[p3] += deltas[p3] * sorFactor / counts[p3];
deltas[p3] = float4.zero;
counts[p3] = 0;
}
}
}
}
}
}
#endif

View File

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