去掉obi,使用自写绳索
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4c2af25bbe8a4c44941ea5486c18f71
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,26 +0,0 @@
|
||||
#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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 64e54848bb85248c8b0c31991ef094e0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,112 +0,0 @@
|
||||
#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 stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
return inputDeps;
|
||||
}
|
||||
|
||||
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9db1828d66ec4f65aa37304663982af
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93818b1e63d1143c580b09480a2c0a1c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,26 +0,0 @@
|
||||
#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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c5e3cbf9187d4d39a1bc1a2e2386b00
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,168 +0,0 @@
|
||||
#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 steps, float timeLeft)
|
||||
{
|
||||
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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3ca9c1fed63774363964743eb64fb68b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e62fc9e22b02847ba86a32d3d0f375da
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,26 +0,0 @@
|
||||
#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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59166e10c311e43e283064f9c03b525c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,181 +0,0 @@
|
||||
#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 steps, float timeLeft)
|
||||
{
|
||||
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.xyz) > 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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6235d2e315a94287ab8a219496d7961
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,110 +0,0 @@
|
||||
#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 { 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 stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
if (lambdas.IsCreated)
|
||||
{
|
||||
inputDeps = new ClearLambdasJob {lambdas = lambdas}.Schedule(lambdas.Length, 256, inputDeps);
|
||||
}
|
||||
return inputDeps;
|
||||
}
|
||||
|
||||
// implemented by concrete constraint subclasses.
|
||||
public abstract JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int steps, float timeLeft);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct ClearLambdasJob : IJobParallelFor
|
||||
{
|
||||
public NativeArray<float> lambdas;
|
||||
public void Execute(int i)
|
||||
{
|
||||
lambdas[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09a081eed828341979cf470e2eca6ee0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,145 +0,0 @@
|
||||
#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 stepTime, float substepTime, int steps, float timeLeft);
|
||||
JobHandle Project(JobHandle inputDeps, float stepTime, float substepTime, int steps, float timeLeft);
|
||||
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 stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
// 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, stepTime, substepTime, steps, timeLeft) : inputDeps;
|
||||
|
||||
JobHandle result = JobHandle.CombineDependencies(deps);
|
||||
deps.Dispose();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return inputDeps;
|
||||
}
|
||||
|
||||
public JobHandle Project(JobHandle inputDeps, float stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
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, steps, timeLeft);
|
||||
break;
|
||||
|
||||
case Oni.ConstraintParameters.EvaluationOrder.Parallel:
|
||||
inputDeps = EvaluateParallel(inputDeps, stepTime, substepTime, steps, timeLeft);
|
||||
break;
|
||||
}
|
||||
|
||||
UnityEngine.Profiling.Profiler.EndSample();
|
||||
|
||||
return inputDeps;
|
||||
}
|
||||
|
||||
protected virtual JobHandle EvaluateSequential(JobHandle inputDeps, float stepTime, float substepTime,int steps, float timeLeft)
|
||||
{
|
||||
// evaluate and apply all batches:
|
||||
for (int i = 0; i < batches.Count; ++i)
|
||||
{
|
||||
if (batches[i].enabled)
|
||||
{
|
||||
inputDeps = batches[i].Evaluate(inputDeps, stepTime, substepTime, steps, timeLeft);
|
||||
inputDeps = batches[i].Apply(inputDeps, substepTime);
|
||||
m_Solver.ScheduleBatchedJobsIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
return inputDeps;
|
||||
}
|
||||
|
||||
protected virtual JobHandle EvaluateParallel(JobHandle inputDeps, float stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
// evaluate all batches:
|
||||
for (int i = 0; i < batches.Count; ++i)
|
||||
if (batches[i].enabled)
|
||||
{
|
||||
inputDeps = batches[i].Evaluate(inputDeps, stepTime, substepTime, steps, timeLeft);
|
||||
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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c1b834b5430e4d3790a5979367cd915
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60c7b29b5d2db47a68bfc9b00847af01
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,26 +0,0 @@
|
||||
#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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea608f10fe5d24cb392ca8dcd960a920
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,222 +0,0 @@
|
||||
#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 steps, float timeLeft)
|
||||
{
|
||||
|
||||
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].x;
|
||||
float maxLength = restLengths[c].y;
|
||||
|
||||
// (ni:constraint gradient, di:desired lenght)
|
||||
NativeArray<float4> ni = new NativeArray<float4>(numEdges, Allocator.Temp);
|
||||
|
||||
// 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;
|
||||
|
||||
float4 p1 = positions[particleIndices[edge]];
|
||||
float4 p2 = positions[particleIndices[edge+1]];
|
||||
float4 diff = p1 - p2;
|
||||
|
||||
float distance = math.length(diff);
|
||||
ni[i] = new float4(diff/(distance + BurstMath.epsilon));
|
||||
}
|
||||
|
||||
// calculate ai, bi and ci (superdiagonals):
|
||||
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
|
||||
}
|
||||
|
||||
// solve step #1, forward sweep:
|
||||
// reuse diagonals.xy to store sweep results ci_ and di_:
|
||||
for (int i = 0; i < numEdges; ++i)
|
||||
{
|
||||
int edge = first + i;
|
||||
float4 p1 = positions[particleIndices[edge]];
|
||||
float4 p2 = positions[particleIndices[edge + 1]];
|
||||
|
||||
float cip_ = (i > 0) ? diagonals[i - 1].x : 0;
|
||||
float dip_ = (i > 0) ? diagonals[i - 1].y : 0;
|
||||
float den = diagonals[i].y - cip_ * diagonals[i].x;
|
||||
|
||||
float3 d = diagonals[i];
|
||||
if (math.abs(den) > BurstMath.epsilon)
|
||||
{
|
||||
float distance = math.distance(p1, p2);
|
||||
float correction = 0;
|
||||
|
||||
if (distance >= maxLength)
|
||||
correction = distance - maxLength;
|
||||
else if (distance <= minLength)
|
||||
correction = distance - minLength;
|
||||
|
||||
d.xy = new float2(d.z / den,
|
||||
(correction - dip_ * d.x) / den);
|
||||
|
||||
}
|
||||
else
|
||||
d.xy = float2.zero;
|
||||
|
||||
diagonals[i] = d;
|
||||
}
|
||||
|
||||
// solve step #2, backward sweep. reuse diagonals.z to store solution xi:
|
||||
for (int i = numEdges - 1; i >= 0; --i)
|
||||
{
|
||||
float xi_ = (i < numEdges - 1) ? diagonals[i + 1].z : 0;
|
||||
|
||||
float3 d = diagonals[i];
|
||||
d.z = d.y - d.x * xi_;
|
||||
diagonals[i] = d;
|
||||
}
|
||||
|
||||
// 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) ? diagonals[i - 1].z : 0;
|
||||
float nxi = (i < numIndices[c] - 1) ? diagonals[i].z : 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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 832ac0a67ec764ee6a1e9a69fc1092e0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d7d6ac7f5b664d5cb7860b843e47fff
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,49 +0,0 @@
|
||||
#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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f97613844b24a40899f10722bcfc4cf8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,31 +0,0 @@
|
||||
#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()
|
||||
{
|
||||
return ((BurstSolverImpl)solver).abstraction.colliderContacts.count;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e31847a0e619545c0bc70258b413a42e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,344 +0,0 @@
|
||||
#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 stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
var updateContacts = new UpdateContactsJob()
|
||||
{
|
||||
prevPositions = solverImplementation.prevPositions,
|
||||
prevOrientations = solverImplementation.prevOrientations,
|
||||
velocities = solverImplementation.velocities,
|
||||
radii = solverImplementation.principalRadii,
|
||||
invMasses = solverImplementation.invMasses,
|
||||
invRotationalMasses = solverImplementation.invRotationalMasses,
|
||||
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).abstraction.colliderContacts.AsNativeArray<BurstContact>(),
|
||||
effectiveMasses = ((BurstSolverImpl)constraints.solver).abstraction.contactEffectiveMasses.AsNativeArray<ContactEffectiveMasses>(),
|
||||
inertialFrame = ((BurstSolverImpl)constraints.solver).inertialFrame
|
||||
};
|
||||
return updateContacts.Schedule(((BurstSolverImpl)constraints.solver).abstraction.colliderContacts.count, 128, inputDeps);
|
||||
}
|
||||
|
||||
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
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).abstraction.colliderContacts.AsNativeArray<BurstContact>(),
|
||||
effectiveMasses = ((BurstSolverImpl)constraints.solver).abstraction.contactEffectiveMasses.AsNativeArray<ContactEffectiveMasses>(),
|
||||
inertialFrame = ((BurstSolverImpl)constraints.solver).inertialFrame,
|
||||
constraintParameters = parameters,
|
||||
solverParameters = solverAbstraction.parameters,
|
||||
steps = steps,
|
||||
timeLeft = timeLeft,
|
||||
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).abstraction.colliderContacts.AsNativeArray<BurstContact>(),
|
||||
|
||||
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 generated 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<float> invRotationalMasses;
|
||||
|
||||
[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<ContactEffectiveMasses> effectiveMasses;
|
||||
public NativeArray<BurstContact> contacts;
|
||||
[ReadOnly] public BurstInertialFrame inertialFrame;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
var contact = contacts[i];
|
||||
var efMasses = effectiveMasses[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;
|
||||
float simplexInvRotationalMass = 0;
|
||||
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];
|
||||
simplexInvRotationalMass = invRotationalMasses[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);
|
||||
|
||||
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;
|
||||
|
||||
// calculate contact tangent (first friction direction) using relative velocity:
|
||||
contact.CalculateTangent(relativeVelocity);
|
||||
|
||||
// calculate A's contact mass.
|
||||
float4 invInertiaTensor = math.rcp(BurstMath.GetParticleInertiaTensor(simplexRadius, simplexInvRotationalMass) + new float4(BurstMath.epsilon));
|
||||
efMasses.CalculateContactMassesA(simplexInvMass, invInertiaTensor, simplexPrevPosition, simplexPrevOrientation, contactPoint, contact.normal, contact.tangent, contact.bitangent, rollingContacts);
|
||||
|
||||
// calculate B's contact mass.
|
||||
if (rigidbodyIndex >= 0)
|
||||
efMasses.CalculateContactMassesB(rigidbodies[rigidbodyIndex], inertialFrame.frame, contact.pointB, contact.normal, contact.tangent, contact.bitangent);
|
||||
else
|
||||
efMasses.ClearContactMassesB();
|
||||
|
||||
contacts[i] = contact;
|
||||
effectiveMasses[i] = efMasses;
|
||||
}
|
||||
}
|
||||
|
||||
[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 NativeArray<ContactEffectiveMasses> effectiveMasses;
|
||||
[ReadOnly] public BurstInertialFrame inertialFrame;
|
||||
[ReadOnly] public Oni.ConstraintParameters constraintParameters;
|
||||
[ReadOnly] public Oni.SolverParameters solverParameters;
|
||||
[ReadOnly] public float stepTime;
|
||||
[ReadOnly] public float substepTime;
|
||||
[ReadOnly] public float timeLeft;
|
||||
[ReadOnly] public int steps;
|
||||
|
||||
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].isTrigger)
|
||||
continue;
|
||||
|
||||
// Get the rigidbody index (might be < 0, in that case there's no rigidbody present)
|
||||
int rigidbodyIndex = shapes[colliderIndex].rigidbodyIndex;
|
||||
|
||||
float frameEnd = stepTime * steps;
|
||||
float substepsToEnd = timeLeft / substepTime;
|
||||
|
||||
// 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, substepsToEnd);
|
||||
posA += -contact.normal * simplexRadius;
|
||||
|
||||
float4 posB = contact.pointB;
|
||||
|
||||
if (rigidbodyIndex >= 0)
|
||||
posB += BurstMath.GetRigidbodyVelocityAtPoint(rigidbodyIndex, contact.pointB, rigidbodies, rigidbodyLinearDeltas, rigidbodyAngularDeltas, inertialFrame) * frameEnd;
|
||||
|
||||
// adhesion:
|
||||
float lambda = contact.SolveAdhesion(effectiveMasses[i].TotalNormalInvMass, posA, posB, material.stickDistance, material.stickiness, stepTime);
|
||||
|
||||
// depenetration:
|
||||
lambda += contact.SolvePenetration(effectiveMasses[i].TotalNormalInvMass, 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) / substepsToEnd;
|
||||
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 / frameEnd * 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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 273c5561da8534560bb9b9e8d32ae092
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,33 +0,0 @@
|
||||
#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()
|
||||
{
|
||||
return ((BurstSolverImpl)solver).abstraction.colliderContacts.count;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00f91403e75564dc6ace566943caa172
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,280 +0,0 @@
|
||||
#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 stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
return inputDeps;
|
||||
}
|
||||
|
||||
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
var projectConstraints = new FrictionConstraintsBatchJob()
|
||||
{
|
||||
positions = solverImplementation.positions,
|
||||
prevPositions = solverImplementation.prevPositions,
|
||||
orientations = solverImplementation.orientations,
|
||||
prevOrientations = solverImplementation.prevOrientations,
|
||||
|
||||
invMasses = solverImplementation.invMasses,
|
||||
invRotationalMasses = solverImplementation.invRotationalMasses,
|
||||
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).abstraction.colliderContacts.AsNativeArray<BurstContact>(),
|
||||
effectiveMasses = ((BurstSolverImpl)constraints.solver).abstraction.contactEffectiveMasses.AsNativeArray<ContactEffectiveMasses>(),
|
||||
inertialFrame = ((BurstSolverImpl)constraints.solver).inertialFrame,
|
||||
steps = steps,
|
||||
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).abstraction.colliderContacts.AsNativeArray<BurstContact>(),
|
||||
|
||||
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<float> invRotationalMasses;
|
||||
[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 NativeArray<ContactEffectiveMasses> effectiveMasses;
|
||||
[ReadOnly] public BurstInertialFrame inertialFrame;
|
||||
[ReadOnly] public float stepTime;
|
||||
[ReadOnly] public float substepTime;
|
||||
[ReadOnly] public int steps;
|
||||
|
||||
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].isTrigger)
|
||||
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;
|
||||
float invRotationalMassA = 0;
|
||||
quaternion orientationA = new quaternion(0, 0, 0, 0);
|
||||
float4 simplexRadiiA = float4.zero;
|
||||
|
||||
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];
|
||||
invRotationalMassA += invRotationalMasses[particleIndex] * contact.pointA[j];
|
||||
orientationA.value += orientations[particleIndex].value * contact.pointA[j];
|
||||
simplexRadiiA += radii[particleIndex] * contact.pointA[j];
|
||||
}
|
||||
|
||||
float4 relativeVelocity = linearVelocityA;
|
||||
|
||||
// Add particle angular velocity if rolling contacts are enabled:
|
||||
if (material.rollingContacts > 0)
|
||||
{
|
||||
rA = -contact.normal * BurstMath.EllipsoidRadius(contact.normal, orientationA, simplexRadiiA.xyz);
|
||||
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);
|
||||
}
|
||||
|
||||
// Determine impulse magnitude:
|
||||
float2 impulses = contact.SolveFriction(effectiveMasses[i].TotalTangentInvMass, effectiveMasses[i].TotalBitangentInvMass, 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];
|
||||
deltas[particleIndex] += (tangentImpulse * effectiveMasses[i].tangentInvMassA + bitangentImpulse * effectiveMasses[i].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:
|
||||
float4 invInertiaTensor = math.rcp(BurstMath.GetParticleInertiaTensor(simplexRadiiA, invRotationalMassA) + new float4(BurstMath.epsilon));
|
||||
float4x4 solverInertiaA = BurstMath.TransformInertiaTensor(invInertiaTensor, 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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9abf9b1d2ee1a4d09b965103ae78fe53
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d2e0de656b27431f9501fe6ffacff67
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,553 +0,0 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public class BurstDensityConstraints : BurstConstraintsImpl<BurstDensityConstraintsBatch>
|
||||
{
|
||||
public NativeList<int> fluidParticles;
|
||||
|
||||
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 steps, float timeLeft)
|
||||
{
|
||||
return EvaluateParallel(inputDeps, stepTime, substepTime, steps, timeLeft);
|
||||
}
|
||||
|
||||
protected override JobHandle EvaluateParallel(JobHandle inputDeps, float stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
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, steps, timeLeft);
|
||||
m_Solver.ScheduleBatchedJobsIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
// calculate per-particle density lambdas:
|
||||
inputDeps = CalculateLambdas(inputDeps, substepTime);
|
||||
|
||||
// calculate viscosity/vorticity:
|
||||
for (int i = 0; i < batches.Count; ++i)
|
||||
{
|
||||
if (batches[i].enabled)
|
||||
{
|
||||
inputDeps = batches[i].ViscosityAndVorticity(inputDeps);
|
||||
m_Solver.ScheduleBatchedJobsIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
// apply viscosity/vorticity positional deltas:
|
||||
var app = new ApplyPositionDeltasJob()
|
||||
{
|
||||
fluidParticles = fluidParticles,
|
||||
positions = m_Solver.positions,
|
||||
deltas = m_Solver.positionDeltas,
|
||||
counts = m_Solver.positionConstraintCounts,
|
||||
anisotropies = m_Solver.anisotropies,
|
||||
normals = m_Solver.normals,
|
||||
fluidData = m_Solver.fluidData,
|
||||
matchingRotations = m_Solver.orientationDeltas,
|
||||
linearFromAngular = m_Solver.restPositions,
|
||||
};
|
||||
|
||||
inputDeps = app.Schedule(fluidParticles.Length, 64, inputDeps);
|
||||
|
||||
// apply density positional deltas:
|
||||
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 CalculateVelocityCorrections(JobHandle inputDeps, float deltaTime)
|
||||
{
|
||||
for (int i = 0; i < batches.Count; ++i)
|
||||
{
|
||||
if (batches[i].enabled)
|
||||
{
|
||||
inputDeps = batches[i].CalculateNormals(inputDeps, deltaTime);
|
||||
m_Solver.ScheduleBatchedJobsIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
return inputDeps;
|
||||
}
|
||||
|
||||
public JobHandle ApplyVelocityCorrections(JobHandle inputDeps, float deltaTime)
|
||||
{
|
||||
inputDeps = ApplyAtmosphere(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 inputDeps;
|
||||
|
||||
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,
|
||||
fluidData = m_Solver.fluidData,
|
||||
massCenters = m_Solver.normals,
|
||||
prevMassCenters = m_Solver.renderablePositions,
|
||||
moments = m_Solver.anisotropies
|
||||
};
|
||||
|
||||
inputDeps = clearData.Schedule(fluidParticles.Length, 64, inputDeps);
|
||||
|
||||
// update fluid interactions:
|
||||
var updateInteractions = new UpdateInteractionsJob()
|
||||
{
|
||||
pairs = m_Solver.fluidInteractions,
|
||||
positions = m_Solver.positions,
|
||||
fluidMaterials = m_Solver.fluidMaterials,
|
||||
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,
|
||||
positions = m_Solver.positions,
|
||||
prevPositions = m_Solver.prevPositions,
|
||||
matchingRotations = m_Solver.restPositions.Reinterpret<quaternion>(),
|
||||
principalRadii = m_Solver.principalRadii,
|
||||
fluidMaterials = m_Solver.fluidMaterials,
|
||||
densityKernel = new Poly6Kernel(m_Solver.abstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
|
||||
gradientKernel = new SpikyKernel(m_Solver.abstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
|
||||
fluidData = m_Solver.fluidData,
|
||||
|
||||
massCenters = m_Solver.normals,
|
||||
prevMassCenters = m_Solver.renderablePositions,
|
||||
moments = m_Solver.anisotropies,
|
||||
|
||||
deltas = m_Solver.positionDeltas,
|
||||
counts = m_Solver.positionConstraintCounts,
|
||||
|
||||
solverParams = m_Solver.abstraction.parameters
|
||||
};
|
||||
|
||||
return calculateLambdas.Schedule(fluidParticles.Length,64,inputDeps);
|
||||
}
|
||||
|
||||
private JobHandle ApplyAtmosphere(JobHandle inputDeps, float deltaTime)
|
||||
{
|
||||
var conf = new ApplyAtmosphereJob
|
||||
{
|
||||
fluidParticles = fluidParticles,
|
||||
wind = m_Solver.wind,
|
||||
fluidInterface = m_Solver.fluidInterface,
|
||||
fluidMaterials2 = m_Solver.fluidMaterials2,
|
||||
principalRadii = m_Solver.principalRadii,
|
||||
normals = m_Solver.normals,
|
||||
fluidData = m_Solver.fluidData,
|
||||
velocities = m_Solver.velocities,
|
||||
angularVelocities = m_Solver.angularVelocities,
|
||||
vorticity = m_Solver.restOrientations.Reinterpret<float4>(),
|
||||
vorticityAccelerations = m_Solver.orientationDeltas.Reinterpret<float4>(),
|
||||
linearAccelerations = m_Solver.positionDeltas,
|
||||
linearFromAngular = m_Solver.restPositions,
|
||||
angularDiffusion = m_Solver.anisotropies,
|
||||
positions = m_Solver.positions,
|
||||
prevPositions = m_Solver.prevPositions,
|
||||
dt = deltaTime,
|
||||
solverParams = m_Solver.abstraction.parameters
|
||||
};
|
||||
|
||||
return conf.Schedule(fluidParticles.Length, 64, inputDeps);
|
||||
}
|
||||
|
||||
private JobHandle AverageSmoothPositions(JobHandle inputDeps)
|
||||
{
|
||||
var average = new AverageSmoothPositionsJob()
|
||||
{
|
||||
fluidParticles = fluidParticles,
|
||||
renderablePositions = m_Solver.renderablePositions,
|
||||
anisotropies = m_Solver.anisotropies
|
||||
};
|
||||
|
||||
return average.Schedule(fluidParticles.Length, 64, inputDeps);
|
||||
}
|
||||
|
||||
private JobHandle AverageAnisotropy(JobHandle inputDeps)
|
||||
{
|
||||
var average = new AverageAnisotropyJob()
|
||||
{
|
||||
fluidParticles = fluidParticles,
|
||||
renderablePositions = m_Solver.renderablePositions,
|
||||
renderableOrientations = m_Solver.renderableOrientations,
|
||||
principalRadii = m_Solver.principalRadii,
|
||||
anisotropies = m_Solver.anisotropies,
|
||||
maxAnisotropy = m_Solver.abstraction.parameters.maxAnisotropy,
|
||||
renderableRadii = m_Solver.renderableRadii,
|
||||
fluidData = m_Solver.fluidData,
|
||||
life = m_Solver.life,
|
||||
solverParams = m_Solver.abstraction.parameters
|
||||
};
|
||||
|
||||
return average.Schedule(fluidParticles.Length, 64, inputDeps);
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct ClearFluidDataJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeList<int> fluidParticles;
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> fluidData;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> massCenters;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> prevMassCenters;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4x4> moments;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
int p = fluidParticles[i];
|
||||
fluidData[p] = float4.zero;
|
||||
massCenters[p] = float4.zero;
|
||||
prevMassCenters[p] = float4.zero;
|
||||
moments[p] = float4x4.zero;
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct UpdateInteractionsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<float4> positions;
|
||||
[ReadOnly] public NativeArray<float4> fluidMaterials;
|
||||
[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 = new float4((positions[pair.particleA] - positions[pair.particleB]).xyz,0);
|
||||
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, fluidMaterials[pair.particleA].x) +
|
||||
densityKernel.W(distance, fluidMaterials[pair.particleB].x)) * 0.5f;
|
||||
|
||||
pair.avgGradient = (gradientKernel.W(distance, fluidMaterials[pair.particleA].x) +
|
||||
gradientKernel.W(distance, fluidMaterials[pair.particleB].x)) * 0.5f;
|
||||
|
||||
pairs[i] = pair;
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct CalculateLambdasJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeList<int> fluidParticles;
|
||||
[ReadOnly] public NativeArray<float4> positions;
|
||||
[ReadOnly] public NativeArray<float4> prevPositions;
|
||||
[ReadOnly] public NativeArray<float4> principalRadii;
|
||||
[ReadOnly] public NativeArray<float4> fluidMaterials;
|
||||
[ReadOnly] public Poly6Kernel densityKernel;
|
||||
[ReadOnly] public SpikyKernel gradientKernel;
|
||||
|
||||
[ReadOnly] public Oni.SolverParameters solverParams;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> fluidData;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> massCenters;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> prevMassCenters;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4x4> moments;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<quaternion> matchingRotations;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
|
||||
|
||||
public void Execute(int p)
|
||||
{
|
||||
int i = fluidParticles[p];
|
||||
|
||||
float restVolume = math.pow(principalRadii[i].x * 2, 3 - (int)solverParams.mode);
|
||||
float4 data = fluidData[i];
|
||||
|
||||
float grad = restVolume * gradientKernel.W(0, fluidMaterials[i].x);
|
||||
|
||||
// self particle contribution to density, gradient and mass centers:
|
||||
data += new float4(densityKernel.W(0, fluidMaterials[i].x), 0, grad, grad * grad + data[2] * data[2]);
|
||||
massCenters[i] += new float4(positions[i].xyz, 1) / positions[i].w;
|
||||
prevMassCenters[i] += new float4(prevPositions[i].xyz, 1) / positions[i].w;
|
||||
|
||||
// usually, we'd weight density by mass (density contrast formulation) by dividing by invMass. Then, multiply by invMass when
|
||||
// calculating the state equation (density / restDensity - 1, restDensity = mass / volume, so density * invMass * restVolume - 1
|
||||
// We end up with density / invMass * invMass * restVolume - 1, invMass cancels out.
|
||||
float constraint = math.max(0, data[0] * restVolume - 1) * fluidMaterials[i].w;
|
||||
|
||||
// calculate lambda:
|
||||
data[1] = -constraint / (positions[i].w * data[3] + math.FLT_MIN_NORMAL);
|
||||
|
||||
fluidData[i] = data;
|
||||
|
||||
// get total neighborhood mass:
|
||||
float M = massCenters[i][3];
|
||||
massCenters[i] /= massCenters[i][3];
|
||||
prevMassCenters[i] /= prevMassCenters[i][3];
|
||||
|
||||
// update moments:
|
||||
moments[i] += (BurstMath.multrnsp4(positions[i], prevPositions[i]) + float4x4.identity * math.pow(principalRadii[i].x, 2) * 0.001f) / positions[i].w;
|
||||
moments[i] -= M * BurstMath.multrnsp4(massCenters[i], prevMassCenters[i]);
|
||||
|
||||
// extract neighborhood orientation delta:
|
||||
matchingRotations[i] = BurstMath.ExtractRotation(moments[i], quaternion.identity, 5);
|
||||
|
||||
// viscosity and vorticity:
|
||||
float4 viscGoal = new float4(massCenters[i].xyz + math.rotate(matchingRotations[i], (prevPositions[i] - prevMassCenters[i]).xyz), 0);
|
||||
deltas[i] += (viscGoal - positions[i]) * fluidMaterials[i].z;
|
||||
|
||||
counts[i]++;
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct ApplyPositionDeltasJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeList<int> fluidParticles;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> positions;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> normals;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4x4> anisotropies;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<quaternion> matchingRotations;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> linearFromAngular;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> fluidData;
|
||||
|
||||
public void Execute(int p)
|
||||
{
|
||||
int i = fluidParticles[p];
|
||||
|
||||
if (counts[i] > 0)
|
||||
{
|
||||
positions[i] += new float4(deltas[i].xyz,0) / counts[i];
|
||||
deltas[i] = float4.zero;
|
||||
counts[i] = 0;
|
||||
}
|
||||
|
||||
normals[i] = float4.zero;
|
||||
anisotropies[i] = float4x4.zero;
|
||||
linearFromAngular[i] = float4.zero;
|
||||
matchingRotations[i] = new quaternion(0, 0, 0, 0);
|
||||
|
||||
// zero out fluidData.z in preparation to accumulate relative velocity.
|
||||
float4 data = fluidData[i];
|
||||
data.z = 0;
|
||||
fluidData[i] = data;
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct ApplyAtmosphereJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeList<int> fluidParticles;
|
||||
[ReadOnly] public NativeArray<float4> wind;
|
||||
[ReadOnly] public NativeArray<float4> fluidInterface;
|
||||
[ReadOnly] public NativeArray<float4> fluidMaterials2;
|
||||
[ReadOnly] public NativeArray<float4> principalRadii;
|
||||
[ReadOnly] public NativeArray<float4> normals;
|
||||
[ReadOnly] public NativeArray<float4> fluidData;
|
||||
[ReadOnly] public NativeArray<float4> linearFromAngular;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> positions;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> prevPositions;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> linearAccelerations;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> vorticityAccelerations;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> vorticity;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4x4> angularDiffusion;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> angularVelocities;
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> velocities;
|
||||
|
||||
[ReadOnly] public float dt;
|
||||
[ReadOnly] public Oni.SolverParameters solverParams;
|
||||
|
||||
public void Execute(int p)
|
||||
{
|
||||
int i = fluidParticles[p];
|
||||
|
||||
float restVolume = math.pow(principalRadii[i].x * 2, 3 - (int)solverParams.mode);
|
||||
|
||||
//atmospheric drag:
|
||||
float4 velocityDiff = velocities[i] - wind[i];
|
||||
|
||||
// particles near the surface should experience drag:
|
||||
velocities[i] -= fluidInterface[i].x * velocityDiff * math.max(0, 1 - fluidData[i][0] * restVolume) * dt;
|
||||
|
||||
// ambient pressure:
|
||||
velocities[i] += fluidInterface[i].y * normals[i] * dt;
|
||||
|
||||
// angular accel due to baroclinity:
|
||||
angularVelocities[i] += new float4(fluidMaterials2[i].z * math.cross(-normals[i].xyz, -velocityDiff.xyz), 0) * dt;
|
||||
angularVelocities[i] -= fluidMaterials2[i].w * angularDiffusion[i].c0;
|
||||
|
||||
// micropolar vorticity:
|
||||
velocities[i] += fluidMaterials2[i].x * linearAccelerations[i] * dt;
|
||||
vorticity[i] += fluidMaterials2[i].x * (vorticityAccelerations[i] * 0.5f - vorticity[i]) * dt;
|
||||
vorticity[i] -= fluidMaterials2[i].y * angularDiffusion[i].c1;
|
||||
|
||||
linearAccelerations[i] = float4.zero;
|
||||
vorticityAccelerations[i] = float4.zero;
|
||||
angularDiffusion[i] = float4x4.zero;
|
||||
|
||||
// we want to add together linear and angular velocity fields and use result to advect particles without modifying either field:
|
||||
positions[i] += new float4(linearFromAngular[i].xyz * dt,0);
|
||||
prevPositions[i] += new float4(linearFromAngular[i].xyz * dt, 0);
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct AverageSmoothPositionsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeList<int> fluidParticles;
|
||||
[ReadOnly] public NativeArray<float4> renderablePositions;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4x4> anisotropies;
|
||||
|
||||
public void Execute(int p)
|
||||
{
|
||||
int i = fluidParticles[p];
|
||||
|
||||
var smoothPos = anisotropies[i];
|
||||
|
||||
if (smoothPos.c3.w > 0)
|
||||
smoothPos.c3 /= smoothPos.c3.w;
|
||||
else
|
||||
smoothPos.c3.xyz = renderablePositions[i].xyz;
|
||||
|
||||
anisotropies[i] = smoothPos;
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct AverageAnisotropyJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeList<int> fluidParticles;
|
||||
[ReadOnly] public NativeArray<float4> principalRadii;
|
||||
[ReadOnly] public float maxAnisotropy;
|
||||
[ReadOnly] public NativeArray<float4x4> anisotropies;
|
||||
[ReadOnly] public NativeArray<float> life;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> fluidData;
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> renderablePositions;
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<quaternion> renderableOrientations;
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> renderableRadii;
|
||||
|
||||
[ReadOnly] public Oni.SolverParameters solverParams;
|
||||
|
||||
public void Execute(int p)
|
||||
{
|
||||
int i = fluidParticles[p];
|
||||
|
||||
if (anisotropies[i].c3.w > 0 && (anisotropies[i].c0[0] + anisotropies[i].c1[1] + anisotropies[i].c2[2]) > 0.01f)
|
||||
{
|
||||
float3 singularValues;
|
||||
float3x3 u;
|
||||
BurstMath.EigenSolve(math.float3x3(anisotropies[i] / anisotropies[i].c3.w), out singularValues, out u);
|
||||
|
||||
float max = singularValues[0];
|
||||
float3 s = math.max(singularValues,new float3(max / maxAnisotropy)) / max * principalRadii[i].x;
|
||||
|
||||
renderableOrientations[i] = quaternion.LookRotationSafe(u.c2,u.c1);
|
||||
renderableRadii[i] = new float4(s.xyz,1);
|
||||
}
|
||||
else
|
||||
{
|
||||
float radius = principalRadii[i].x / maxAnisotropy;
|
||||
renderableOrientations[i] = quaternion.identity;
|
||||
renderableRadii[i] = new float4(radius,radius,radius,1);
|
||||
|
||||
float4 data = fluidData[i];
|
||||
data.x = 1 / math.pow(math.abs(radius * 2), 3 - (int)solverParams.mode); // normal volume of an isolated particle.
|
||||
fluidData[i] = data;
|
||||
}
|
||||
|
||||
renderablePositions[i] = math.lerp(renderablePositions[i], anisotropies[i].c3, math.min((maxAnisotropy - 1)/3.0f,1));
|
||||
|
||||
// inactive particles have radii.w == 0, set it right away for particles killed during this frame
|
||||
// to keep them from being rendered during this frame instead of waiting to do it at the start of next sim step:
|
||||
float4 radii = renderableRadii[i];
|
||||
radii.w = life[i] <= 0 ? 0 : radii.w;
|
||||
renderableRadii[i] = radii;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df96ac4db14c846ea99a6ebc5771098f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,477 +0,0 @@
|
||||
#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 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 stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
return inputDeps;
|
||||
}
|
||||
|
||||
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
|
||||
// update densities and gradients:
|
||||
var updateDensities = new UpdateDensitiesJob()
|
||||
{
|
||||
pairs = ((BurstSolverImpl)constraints.solver).fluidInteractions,
|
||||
positions = solverImplementation.positions,
|
||||
prevPositions = solverImplementation.prevPositions,
|
||||
principalRadii = solverImplementation.principalRadii,
|
||||
fluidMaterials = solverImplementation.fluidMaterials,
|
||||
fluidData = solverImplementation.fluidData,
|
||||
moments = solverImplementation.anisotropies,
|
||||
massCenters = solverImplementation.normals,
|
||||
prevMassCenters = solverImplementation.renderablePositions,
|
||||
densityKernel = new Poly6Kernel(solverAbstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
|
||||
batchData = batchData,
|
||||
solverParams = solverAbstraction.parameters
|
||||
};
|
||||
|
||||
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()
|
||||
{
|
||||
principalRadii = solverImplementation.principalRadii,
|
||||
fluidMaterials = solverImplementation.fluidMaterials,
|
||||
pairs = ((BurstSolverImpl)constraints.solver).fluidInteractions,
|
||||
densityKernel = new Poly6Kernel(solverAbstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
|
||||
positions = solverImplementation.positions,
|
||||
fluidData = solverImplementation.fluidData,
|
||||
batchData = batchData,
|
||||
solverParams = solverAbstraction.parameters,
|
||||
sorFactor = parameters.SORFactor
|
||||
};
|
||||
|
||||
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
|
||||
return apply.Schedule(batchData.workItemCount, batchCount, inputDeps);
|
||||
}
|
||||
|
||||
public JobHandle CalculateNormals(JobHandle inputDeps, float deltaTime)
|
||||
{
|
||||
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
|
||||
|
||||
var vorticity = new NormalsJob()
|
||||
{
|
||||
invMasses = solverImplementation.invMasses,
|
||||
positions = solverImplementation.positions,
|
||||
principalRadii = solverImplementation.principalRadii,
|
||||
fluidMaterials = solverImplementation.fluidMaterials,
|
||||
fluidMaterials2 = solverImplementation.fluidMaterials2,
|
||||
fluidData = solverImplementation.fluidData,
|
||||
fluidInterface = solverImplementation.fluidInterface,
|
||||
velocities = solverImplementation.velocities,
|
||||
angularVelocities = solverImplementation.angularVelocities,
|
||||
|
||||
vorticityAccelerations = solverImplementation.orientationDeltas.Reinterpret<float4>(),
|
||||
vorticity = solverImplementation.restOrientations.Reinterpret<float4>(),
|
||||
linearAccelerations = solverImplementation.positionDeltas,
|
||||
linearFromAngular = solverImplementation.restPositions,
|
||||
angularDiffusion = solverImplementation.anisotropies,
|
||||
|
||||
userData = solverImplementation.userData,
|
||||
pairs = ((BurstSolverImpl)constraints.solver).fluidInteractions,
|
||||
normals = solverImplementation.normals,
|
||||
densityKernel = new Poly6Kernel(solverAbstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
|
||||
gradKernel = new SpikyKernel(solverAbstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
|
||||
solverParams = solverAbstraction.parameters,
|
||||
batchData = batchData,
|
||||
dt = deltaTime,
|
||||
};
|
||||
|
||||
return vorticity.Schedule(batchData.workItemCount, batchCount, inputDeps);
|
||||
}
|
||||
|
||||
public JobHandle ViscosityAndVorticity(JobHandle inputDeps)
|
||||
{
|
||||
var eta = new ViscosityVorticityJob()
|
||||
{
|
||||
positions = solverImplementation.positions,
|
||||
prevPositions = solverImplementation.prevPositions,
|
||||
matchingRotations = solverImplementation.restPositions.Reinterpret<quaternion>(),
|
||||
pairs = ((BurstSolverImpl)constraints.solver).fluidInteractions,
|
||||
massCenters = solverImplementation.normals,
|
||||
prevMassCenters = solverImplementation.renderablePositions,
|
||||
fluidParams = solverImplementation.fluidMaterials,
|
||||
deltas = solverImplementation.positionDeltas,
|
||||
counts = solverImplementation.positionConstraintCounts,
|
||||
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,
|
||||
anisotropies = solverImplementation.anisotropies,
|
||||
fluidMaterials = solverImplementation.fluidMaterials,
|
||||
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,
|
||||
anisotropies = solverImplementation.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<float4> prevPositions;
|
||||
[ReadOnly] public NativeArray<float4> fluidMaterials;
|
||||
[ReadOnly] public NativeArray<float4> principalRadii;
|
||||
[ReadOnly] public NativeArray<FluidInteraction> pairs;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> fluidData;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4x4> moments;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> massCenters;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> prevMassCenters;
|
||||
|
||||
[ReadOnly] public Poly6Kernel densityKernel;
|
||||
[ReadOnly] public BatchData batchData;
|
||||
|
||||
[ReadOnly] public Oni.SolverParameters solverParams;
|
||||
|
||||
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 = math.pow(principalRadii[pair.particleA].x * 2, 3 - (int)solverParams.mode);
|
||||
float restVolumeB = math.pow(principalRadii[pair.particleB].x * 2, 3 - (int)solverParams.mode);
|
||||
|
||||
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);
|
||||
|
||||
// accumulate masses for COMs and moment matrices:
|
||||
float wAvg = pair.avgKernel / ((densityKernel.W(0, fluidMaterials[pair.particleA].x) + densityKernel.W(0, fluidMaterials[pair.particleB].x)) * 0.5f);
|
||||
|
||||
massCenters[pair.particleA] += wAvg * new float4(positions[pair.particleB].xyz, 1) / positions[pair.particleB].w;
|
||||
massCenters[pair.particleB] += wAvg * new float4(positions[pair.particleA].xyz, 1) / positions[pair.particleA].w;
|
||||
|
||||
prevMassCenters[pair.particleA] += wAvg * new float4(prevPositions[pair.particleB].xyz, 1) / positions[pair.particleB].w;
|
||||
prevMassCenters[pair.particleB] += wAvg * new float4(prevPositions[pair.particleA].xyz, 1) / positions[pair.particleA].w;
|
||||
|
||||
moments[pair.particleA] += wAvg * (BurstMath.multrnsp4(positions[pair.particleB], prevPositions[pair.particleB]) + float4x4.identity * math.pow(principalRadii[pair.particleB].x, 2) * 0.001f) / positions[pair.particleB].w;
|
||||
moments[pair.particleB] += wAvg * (BurstMath.multrnsp4(positions[pair.particleA], prevPositions[pair.particleA]) + float4x4.identity * math.pow(principalRadii[pair.particleA].x, 2) * 0.001f) / positions[pair.particleA].w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct ApplyDensityConstraintsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<float4> principalRadii;
|
||||
[ReadOnly] public NativeArray<float4> fluidMaterials;
|
||||
[ReadOnly] public NativeArray<FluidInteraction> pairs;
|
||||
[ReadOnly] public Poly6Kernel densityKernel;
|
||||
[ReadOnly] public CohesionKernel cohesionKernel;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> positions;
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> fluidData;
|
||||
|
||||
[ReadOnly] public BatchData batchData;
|
||||
[ReadOnly] public float sorFactor;
|
||||
[ReadOnly] public Oni.SolverParameters solverParams;
|
||||
|
||||
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 = math.pow(principalRadii[pair.particleA].x * 2, 3 - (int)solverParams.mode);
|
||||
float restVolumeB = math.pow(principalRadii[pair.particleB].x * 2, 3 - (int)solverParams.mode);
|
||||
|
||||
float dist = math.length(positions[pair.particleA].xyz - positions[pair.particleB].xyz); // TODO: FIX! we cant read positions while we are writing to them.
|
||||
|
||||
// calculate tensile instability correction factor:
|
||||
float cAvg = (cohesionKernel.W(dist, fluidMaterials[pair.particleA].x * 1.4f) + cohesionKernel.W(dist, fluidMaterials[pair.particleB].x * 1.4f)) * 0.5f;
|
||||
float st = 0.2f * cAvg * (1 - math.saturate(math.abs(fluidMaterials[pair.particleA].y - fluidMaterials[pair.particleB].y))) * (fluidMaterials[pair.particleA].y + fluidMaterials[pair.particleB].y) * 0.5f;
|
||||
float scorrA = -st / (positions[pair.particleA].w * fluidData[pair.particleA][3] + math.FLT_MIN_NORMAL);
|
||||
float scorrB = -st / (positions[pair.particleB].w * fluidData[pair.particleB][3] + math.FLT_MIN_NORMAL);
|
||||
|
||||
// calculate position delta:
|
||||
float4 delta = pair.gradient * pair.avgGradient * ((fluidData[pair.particleA][1] + scorrA) * restVolumeB + (fluidData[pair.particleB][1] + scorrB) * restVolumeA) * sorFactor;
|
||||
delta.w = 0;
|
||||
positions[pair.particleA] += delta * positions[pair.particleA].w;
|
||||
positions[pair.particleB] -= delta * positions[pair.particleB].w;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct ViscosityVorticityJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<float4> positions;
|
||||
[ReadOnly] public NativeArray<float4> prevPositions;
|
||||
[ReadOnly] public NativeArray<quaternion> matchingRotations;
|
||||
[ReadOnly] public NativeArray<float4> fluidParams;
|
||||
[ReadOnly] public NativeArray<FluidInteraction> pairs;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> massCenters;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> prevMassCenters;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
|
||||
|
||||
[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 visc = math.min(fluidParams[pair.particleA].z, fluidParams[pair.particleB].z);
|
||||
|
||||
// viscosity:
|
||||
float4 goalA = new float4(massCenters[pair.particleB].xyz + math.rotate(matchingRotations[pair.particleB], (prevPositions[pair.particleA] - prevMassCenters[pair.particleB]).xyz), 0);
|
||||
float4 goalB = new float4(massCenters[pair.particleA].xyz + math.rotate(matchingRotations[pair.particleA], (prevPositions[pair.particleB] - prevMassCenters[pair.particleA]).xyz), 0);
|
||||
deltas[pair.particleA] += (goalA - positions[pair.particleA]) * visc;
|
||||
deltas[pair.particleB] += (goalB - positions[pair.particleB]) * visc;
|
||||
|
||||
counts[pair.particleA]++;
|
||||
counts[pair.particleB]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct NormalsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<float> invMasses;
|
||||
[ReadOnly] public NativeArray<float4> velocities;
|
||||
[ReadOnly] public NativeArray<float4> angularVelocities;
|
||||
[ReadOnly] public NativeArray<float4> positions;
|
||||
[ReadOnly] public NativeArray<float4> vorticity;
|
||||
|
||||
[ReadOnly] public NativeArray<float4> principalRadii;
|
||||
[ReadOnly] public NativeArray<float4> fluidMaterials;
|
||||
[ReadOnly] public NativeArray<float4> fluidMaterials2;
|
||||
[ReadOnly] public NativeArray<float4> fluidInterface;
|
||||
[ReadOnly] public NativeArray<FluidInteraction> pairs;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> fluidData;
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> userData;
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> normals;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> linearAccelerations;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> vorticityAccelerations;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> linearFromAngular;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4x4> angularDiffusion;
|
||||
|
||||
[ReadOnly] public Poly6Kernel densityKernel;
|
||||
[ReadOnly] public SpikyKernel gradKernel;
|
||||
[ReadOnly] public BatchData batchData;
|
||||
[ReadOnly] public Oni.SolverParameters solverParams;
|
||||
[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 = math.pow(principalRadii[pair.particleA].x * 2, 3 - (int)solverParams.mode);
|
||||
float restVolumeB = math.pow(principalRadii[pair.particleB].x * 2, 3 - (int)solverParams.mode);
|
||||
|
||||
float invDensityA = invMasses[pair.particleA] / fluidData[pair.particleA].x;
|
||||
float invDensityB = invMasses[pair.particleB] / fluidData[pair.particleB].x;
|
||||
|
||||
float3 relVel = velocities[pair.particleA].xyz - velocities[pair.particleB].xyz;
|
||||
float3 relAng = angularVelocities[pair.particleA].xyz - angularVelocities[pair.particleB].xyz;
|
||||
float3 relVort = vorticity[pair.particleA].xyz - vorticity[pair.particleB].xyz;
|
||||
float4 d = new float4((positions[pair.particleA] - positions[pair.particleB]).xyz,0);
|
||||
float dist = math.length(d);
|
||||
|
||||
float avgGrad = (gradKernel.W(dist, fluidMaterials[pair.particleA].x) +
|
||||
gradKernel.W(dist, fluidMaterials[pair.particleB].x)) * 0.5f;
|
||||
float avgKern = (densityKernel.W(dist, fluidMaterials[pair.particleA].x) +
|
||||
densityKernel.W(dist, fluidMaterials[pair.particleB].x)) * 0.5f;
|
||||
float avgNorm = (densityKernel.W(0, fluidMaterials[pair.particleA].x) +
|
||||
densityKernel.W(0, fluidMaterials[pair.particleB].x)) * 0.5f;
|
||||
|
||||
// property diffusion:
|
||||
float diffusionSpeed = (fluidInterface[pair.particleA].w + fluidInterface[pair.particleB].w) * avgKern * dt;
|
||||
float4 userDelta = (userData[pair.particleB] - userData[pair.particleA]) * solverParams.diffusionMask * diffusionSpeed;
|
||||
userData[pair.particleA] += restVolumeB / restVolumeA * userDelta;
|
||||
userData[pair.particleB] -= restVolumeA / restVolumeB * userDelta;
|
||||
|
||||
// calculate color field normal:
|
||||
float4 normGrad = d / (dist + BurstMath.epsilon);
|
||||
float4 vgrad = normGrad * avgGrad;
|
||||
float radius = (fluidMaterials[pair.particleA].x + fluidMaterials[pair.particleB].x) * 0.5f;
|
||||
normals[pair.particleA] += vgrad * radius * restVolumeB;
|
||||
normals[pair.particleB] -= vgrad * radius * restVolumeA;
|
||||
|
||||
// measure relative velocity for foam generation:
|
||||
float4 dataA = fluidData[pair.particleA];
|
||||
float4 dataB = fluidData[pair.particleB];
|
||||
float relVelMag = math.length(relVel) + BurstMath.epsilon;
|
||||
float avgVelDiffKernel = 1 - math.min(1, dist / (radius + BurstMath.epsilon));
|
||||
float rv = relVelMag * (1 - math.dot(relVel / relVelMag, normGrad.xyz)) * avgVelDiffKernel;
|
||||
dataA.z += rv;
|
||||
dataB.z += rv;
|
||||
fluidData[pair.particleA] = dataA;
|
||||
fluidData[pair.particleB] = dataB;
|
||||
|
||||
// micropolar: curl of linear/angular velocity:
|
||||
float3 velCross = math.cross(relVel, vgrad.xyz);
|
||||
float3 vortCross = math.cross(relVort, vgrad.xyz);
|
||||
linearAccelerations[pair.particleA] += new float4(vortCross / invMasses[pair.particleB] * invDensityA, 0);
|
||||
linearAccelerations[pair.particleB] += new float4(vortCross / invMasses[pair.particleA] * invDensityB, 0);
|
||||
vorticityAccelerations[pair.particleA] += new float4(velCross / invMasses[pair.particleB] * invDensityA, 0);
|
||||
vorticityAccelerations[pair.particleB] += new float4(velCross / invMasses[pair.particleA] * invDensityB, 0);
|
||||
|
||||
// angular diffusion:
|
||||
float4x4 diffA = angularDiffusion[pair.particleA];
|
||||
float4x4 diffB = angularDiffusion[pair.particleB];
|
||||
diffA.c0 += new float4(relAng * avgKern / invMasses[pair.particleB] * invDensityA, 0);
|
||||
diffB.c0 -= new float4(relAng * avgKern / invMasses[pair.particleA] * invDensityB, 0);
|
||||
diffA.c1 += new float4(relVort * avgKern / invMasses[pair.particleB] * invDensityA, 0);
|
||||
diffB.c1 -= new float4(relVort * avgKern / invMasses[pair.particleA] * invDensityB, 0);
|
||||
angularDiffusion[pair.particleA] = diffA;
|
||||
angularDiffusion[pair.particleB] = diffB;
|
||||
|
||||
// linear velocity due to baroclinity:
|
||||
linearFromAngular[pair.particleA] += new float4(math.cross(angularVelocities[pair.particleB].xyz, d.xyz) * avgKern / avgNorm, 0);
|
||||
linearFromAngular[pair.particleB] -= new float4(math.cross(angularVelocities[pair.particleA].xyz, d.xyz) * avgKern / avgNorm, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct AccumulateSmoothPositionsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<float4> renderablePositions;
|
||||
[ReadOnly] public NativeArray<float4> fluidMaterials;
|
||||
[ReadOnly] public Poly6Kernel densityKernel;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4x4> anisotropies;
|
||||
[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];
|
||||
|
||||
float distance = math.length((renderablePositions[pair.particleA] - renderablePositions[pair.particleB]).xyz);
|
||||
|
||||
pair.avgKernel = (densityKernel.W(distance, fluidMaterials[pair.particleA].x) +
|
||||
densityKernel.W(distance, fluidMaterials[pair.particleB].x)) * 0.5f;
|
||||
|
||||
var A = anisotropies[pair.particleA];
|
||||
var B = anisotropies[pair.particleB];
|
||||
|
||||
A.c3 += new float4(renderablePositions[pair.particleB].xyz,1) * pair.avgKernel;
|
||||
B.c3 += new float4(renderablePositions[pair.particleA].xyz,1) * pair.avgKernel;
|
||||
|
||||
anisotropies[pair.particleA] = A;
|
||||
anisotropies[pair.particleB] = B;
|
||||
|
||||
pairs[i] = pair;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct AccumulateAnisotropyJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<float4> renderablePositions;
|
||||
[ReadOnly] public NativeArray<FluidInteraction> pairs;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4x4> 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] - anisotropies[pair.particleA].c3) * pair.avgKernel;
|
||||
float4 distanceB = (renderablePositions[pair.particleA] - anisotropies[pair.particleB].c3) * pair.avgKernel;
|
||||
|
||||
anisotropies[pair.particleA] += BurstMath.multrnsp4(distanceA,distanceA);
|
||||
anisotropies[pair.particleB] += BurstMath.multrnsp4(distanceB,distanceB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8292e6ef6129f47abaee4fb2cb49055e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a128a7c745c84794a944362f49011fc
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,15 +0,0 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using System;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public struct CohesionKernel
|
||||
{
|
||||
public float W(float r, float h)
|
||||
{
|
||||
return math.cos(math.min(r, h) * 3 * math.PI / (2 * h));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2bcf975ae59e4fcf9412ec328a3e2b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,36 +0,0 @@
|
||||
#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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a3990134524143ac852b488554f6d4e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,35 +0,0 @@
|
||||
#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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a407989bfa0664e9ab75773d1808f549
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 725436c3a327442cd8b06889111f9b8f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,26 +0,0 @@
|
||||
#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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af06abf9c29a04274842dbcb65a2a753
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,146 +0,0 @@
|
||||
#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 steps, float timeLeft)
|
||||
{
|
||||
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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31ee5bf24da6847f0b93a69dbbdecf25
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66103ca5acc86407cab9aa94d1e6d1fd
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,62 +0,0 @@
|
||||
#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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 96623cff9b30e4504a4a6dbfe3d19ace
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,32 +0,0 @@
|
||||
#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()
|
||||
{
|
||||
return ((BurstSolverImpl)solver).abstraction.particleContacts.count;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8ef36a05943714c1db8f9ee0b28e9c51
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,364 +0,0 @@
|
||||
#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 stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
var updateContacts = new UpdateParticleContactsJob()
|
||||
{
|
||||
prevPositions = solverImplementation.prevPositions,
|
||||
prevOrientations = solverImplementation.prevOrientations,
|
||||
velocities = solverImplementation.velocities,
|
||||
radii = solverImplementation.principalRadii,
|
||||
invMasses = solverImplementation.invMasses,
|
||||
invRotationalMasses = solverImplementation.invRotationalMasses,
|
||||
|
||||
simplices = solverImplementation.simplices,
|
||||
simplexCounts = solverImplementation.simplexCounts,
|
||||
|
||||
particleMaterialIndices = solverImplementation.collisionMaterials,
|
||||
collisionMaterials = ObiColliderWorld.GetInstance().collisionMaterials.AsNativeArray<BurstCollisionMaterial>(),
|
||||
|
||||
contacts = ((BurstSolverImpl)constraints.solver).abstraction.particleContacts.AsNativeArray<BurstContact>(),
|
||||
effectiveMasses = ((BurstSolverImpl)constraints.solver).abstraction.particleContactEffectiveMasses.AsNativeArray<ContactEffectiveMasses>(),
|
||||
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 steps, float timeLeft)
|
||||
{
|
||||
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,
|
||||
fluidInterface = solverImplementation.fluidInterface,
|
||||
collisionMaterials = ObiColliderWorld.GetInstance().collisionMaterials.AsNativeArray<BurstCollisionMaterial>(),
|
||||
|
||||
simplices = solverImplementation.simplices,
|
||||
simplexCounts = solverImplementation.simplexCounts,
|
||||
|
||||
deltas = solverImplementation.positionDeltas,
|
||||
counts = solverImplementation.positionConstraintCounts,
|
||||
userData = solverImplementation.userData,
|
||||
contacts = solverAbstraction.particleContacts.AsNativeArray<BurstContact>(),
|
||||
effectiveMasses = ((BurstSolverImpl)constraints.solver).abstraction.particleContactEffectiveMasses.AsNativeArray<ContactEffectiveMasses>(),
|
||||
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 = solverAbstraction.particleContacts.AsNativeArray<BurstContact>(),
|
||||
|
||||
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<float> invRotationalMasses;
|
||||
|
||||
[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<ContactEffectiveMasses> effectiveMasses;
|
||||
[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];
|
||||
var efMasses = effectiveMasses[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;
|
||||
float simplexInvRotationalMassA = 0;
|
||||
|
||||
float4 simplexVelocityB = float4.zero;
|
||||
float4 simplexPrevPositionB = float4.zero;
|
||||
quaternion simplexPrevOrientationB = new quaternion(0, 0, 0, 0);
|
||||
float simplexRadiusB = 0;
|
||||
float simplexInvMassB = 0;
|
||||
float simplexInvRotationalMassB = 0;
|
||||
|
||||
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];
|
||||
simplexInvRotationalMassA += invRotationalMasses[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];
|
||||
simplexInvRotationalMassB += invRotationalMasses[particleIndex] * contact.pointB[j];
|
||||
simplexRadiusB += BurstMath.EllipsoidRadius(contact.normal, prevOrientations[particleIndex], radii[particleIndex].xyz) * contact.pointB[j];
|
||||
}
|
||||
|
||||
simplexPrevPositionA.w = 0;
|
||||
simplexPrevPositionB.w = 0;
|
||||
|
||||
// update contact distance
|
||||
float4 contactPointA = simplexPrevPositionA - contact.normal * simplexRadiusA;
|
||||
float4 contactPointB = simplexPrevPositionB + contact.normal * simplexRadiusB;
|
||||
|
||||
contact.distance = math.dot(contactPointA - contactPointB, contact.normal);
|
||||
|
||||
// update contact basis:
|
||||
contact.CalculateTangent(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);
|
||||
|
||||
float4 invInertiaTensorA = math.rcp(BurstMath.GetParticleInertiaTensor(simplexRadiusA, simplexInvRotationalMassA) + new float4(BurstMath.epsilon));
|
||||
float4 invInertiaTensorB = math.rcp(BurstMath.GetParticleInertiaTensor(simplexRadiusB, simplexInvRotationalMassB) + new float4(BurstMath.epsilon));
|
||||
|
||||
efMasses.CalculateContactMassesA(simplexInvMassA, invInertiaTensorA, simplexPrevPositionA, simplexPrevOrientationA, contactPointA, contact.normal, contact.tangent, contact.bitangent, rollingContacts);
|
||||
efMasses.CalculateContactMassesB(simplexInvMassB, invInertiaTensorB, simplexPrevPositionB, simplexPrevOrientationB, contactPointB, contact.normal, contact.tangent, contact.bitangent, rollingContacts);
|
||||
|
||||
contacts[i] = contact;
|
||||
effectiveMasses[i] = efMasses;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[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<float4> fluidInterface;
|
||||
[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<float4> userData;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<BurstContact> contacts;
|
||||
[ReadOnly] public NativeArray<ContactEffectiveMasses> effectiveMasses;
|
||||
|
||||
[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;
|
||||
float4 simplexUserDataA = float4.zero, simplexUserDataB = float4.zero;
|
||||
float miscibility = 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];
|
||||
simplexUserDataA += userData[particleIndex] * contact.pointA[j];
|
||||
miscibility += fluidInterface[particleIndex].w * 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];
|
||||
simplexUserDataB += userData[particleIndex] * contact.pointB[j];
|
||||
miscibility += fluidInterface[particleIndex].w * contact.pointB[j];
|
||||
}
|
||||
|
||||
simplexPositionA.w = 0;
|
||||
simplexPositionB.w = 0;
|
||||
|
||||
float4 posA = simplexPositionA - contact.normal * simplexRadiusA;
|
||||
float4 posB = simplexPositionB + contact.normal * simplexRadiusB;
|
||||
|
||||
// adhesion:
|
||||
float lambda = contact.SolveAdhesion(effectiveMasses[i].TotalNormalInvMass, posA, posB, material.stickDistance, material.stickiness, substepTime);
|
||||
|
||||
// depenetration:
|
||||
lambda += contact.SolvePenetration(effectiveMasses[i].TotalNormalInvMass, 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]++;
|
||||
}
|
||||
}
|
||||
|
||||
// property diffusion:
|
||||
if (contact.distance < solverParameters.collisionMargin)
|
||||
{
|
||||
float diffusionSpeed = miscibility * 0.5f * substepTime;
|
||||
float4 userDelta = (simplexUserDataB - simplexUserDataA) * solverParameters.diffusionMask * diffusionSpeed;
|
||||
|
||||
for (int j = 0; j < simplexSizeA; ++j)
|
||||
userData[simplices[simplexStartA + j]] += userDelta * contact.pointA[j];
|
||||
|
||||
for (int j = 0; j < simplexSizeB; ++j)
|
||||
userData[simplices[simplexStartB + j]] -= userDelta * contact.pointB[j];
|
||||
}
|
||||
|
||||
// Apply position deltas immediately, if using sequential evaluation:
|
||||
if (constraintParameters.evaluationOrder == Oni.ConstraintParameters.EvaluationOrder.Sequential)
|
||||
{
|
||||
for (int j = 0; j < simplexSizeA; ++j)
|
||||
ApplyPositionDelta(simplices[simplexStartA + j], constraintParameters.SORFactor, ref positions, ref deltas, ref counts);
|
||||
|
||||
for (int j = 0; j < simplexSizeB; ++j)
|
||||
ApplyPositionDelta(simplices[simplexStartB + j], 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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 61f5c3e93290646948b251d617f01c8d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,31 +0,0 @@
|
||||
#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()
|
||||
{
|
||||
return ((BurstSolverImpl)solver).abstraction.particleContacts.count;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 63dade0c384ee4c1398ddf4d60038764
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,289 +0,0 @@
|
||||
#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 stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
return inputDeps;
|
||||
}
|
||||
|
||||
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
|
||||
var projectConstraints = new ParticleFrictionConstraintsBatchJob()
|
||||
{
|
||||
positions = solverImplementation.positions,
|
||||
prevPositions = solverImplementation.prevPositions,
|
||||
orientations = solverImplementation.orientations,
|
||||
prevOrientations = solverImplementation.prevOrientations,
|
||||
|
||||
invMasses = solverImplementation.invMasses,
|
||||
invRotationalMasses = solverImplementation.invRotationalMasses,
|
||||
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).abstraction.particleContacts.AsNativeArray<BurstContact>(),
|
||||
effectiveMasses = ((BurstSolverImpl)constraints.solver).abstraction.particleContactEffectiveMasses.AsNativeArray<ContactEffectiveMasses>(),
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
|
||||
|
||||
var applyConstraints = new ApplyBatchedCollisionConstraintsBatchJob()
|
||||
{
|
||||
contacts = solverAbstraction.particleContacts.AsNativeArray<BurstContact>(),
|
||||
|
||||
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<float> invRotationalMasses;
|
||||
[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 NativeArray<ContactEffectiveMasses> effectiveMasses;
|
||||
|
||||
[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;
|
||||
float invRotationalMassA = 0;
|
||||
quaternion orientationA = new quaternion(0, 0, 0, 0);
|
||||
float4 simplexRadiiA = float4.zero;
|
||||
|
||||
float4 prevPositionB = float4.zero;
|
||||
float4 linearVelocityB = float4.zero;
|
||||
float4 angularVelocityB = float4.zero;
|
||||
float invRotationalMassB = 0;
|
||||
quaternion orientationB = new quaternion(0, 0, 0, 0);
|
||||
float4 simplexRadiiB = float4.zero;
|
||||
|
||||
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];
|
||||
invRotationalMassA += invRotationalMasses[particleIndex] * contact.pointA[j];
|
||||
orientationA.value += orientations[particleIndex].value * contact.pointA[j];
|
||||
simplexRadiiA += radii[particleIndex] * 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];
|
||||
invRotationalMassB += invRotationalMasses[particleIndex] * contact.pointB[j];
|
||||
orientationB.value += orientations[particleIndex].value * contact.pointB[j];
|
||||
simplexRadiiB += radii[particleIndex] * 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 * BurstMath.EllipsoidRadius(contact.normal, orientationA, simplexRadiiA.xyz);
|
||||
rB = contact.normal * BurstMath.EllipsoidRadius(contact.normal, orientationB, simplexRadiiB.xyz);
|
||||
|
||||
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 directions):
|
||||
float2 impulses = contact.SolveFriction(effectiveMasses[i].TotalTangentInvMass, effectiveMasses[i].TotalBitangentInvMass, 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 * effectiveMasses[i].tangentInvMassA + bitangentImpulse * effectiveMasses[i].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 * effectiveMasses[i].tangentInvMassB + bitangentImpulse * effectiveMasses[i].bitangentInvMassB) * substepTime * contact.pointB[j] * baryScale;
|
||||
counts[particleIndex]++;
|
||||
}
|
||||
|
||||
// Rolling contacts:
|
||||
if (material.rollingContacts > 0)
|
||||
{
|
||||
float4 invInertiaTensorA = math.rcp(BurstMath.GetParticleInertiaTensor(simplexRadiiA, invRotationalMassA) + new float4(BurstMath.epsilon));
|
||||
float4 invInertiaTensorB = math.rcp(BurstMath.GetParticleInertiaTensor(simplexRadiiB, invRotationalMassB) + new float4(BurstMath.epsilon));
|
||||
|
||||
// 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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9a942dd261ea741b69997eba73462034
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dcbc7b9bf37704bd3945f0fb82506bfb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,41 +0,0 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using System;
|
||||
using Unity.Jobs;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public JobHandle ProjectRenderablePositions(JobHandle inputDeps)
|
||||
{
|
||||
for (int i = 0; i < batches.Count; ++i)
|
||||
{
|
||||
if (batches[i].enabled)
|
||||
{
|
||||
inputDeps = batches[i].ProjectRenderablePositions(inputDeps);
|
||||
m_Solver.ScheduleBatchedJobsIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
return inputDeps;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73ae545b061fa4db988fd3b64410fc6d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,409 +0,0 @@
|
||||
#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;
|
||||
using System.Threading;
|
||||
|
||||
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 Initialize(JobHandle inputDeps, float stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
var clearPins = new ClearPinsJob
|
||||
{
|
||||
colliderIndices = colliderIndices,
|
||||
shapes = ObiColliderWorld.GetInstance().colliderShapes.AsNativeArray<BurstColliderShape>(),
|
||||
rigidbodies = ObiColliderWorld.GetInstance().rigidbodies.AsNativeArray<BurstRigidbody>(),
|
||||
};
|
||||
inputDeps = clearPins.Schedule(m_ConstraintCount, 128, inputDeps);
|
||||
|
||||
var updatePins = new UpdatePinsJob
|
||||
{
|
||||
colliderIndices = colliderIndices,
|
||||
shapes = ObiColliderWorld.GetInstance().colliderShapes.AsNativeArray<BurstColliderShape>(),
|
||||
rigidbodies = ObiColliderWorld.GetInstance().rigidbodies.AsNativeArray<BurstRigidbody>(),
|
||||
};
|
||||
inputDeps = updatePins.Schedule(m_ConstraintCount, 128, inputDeps);
|
||||
|
||||
// clear lambdas:
|
||||
return base.Initialize(inputDeps, stepTime, substepTime, steps, timeLeft);
|
||||
}
|
||||
|
||||
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
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,
|
||||
steps = steps,
|
||||
substepTime = substepTime,
|
||||
timeLeft = timeLeft,
|
||||
activeConstraintCount = m_ConstraintCount
|
||||
};
|
||||
|
||||
return projectConstraints.Schedule(m_ConstraintCount, 16, 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);
|
||||
}
|
||||
|
||||
public JobHandle ProjectRenderablePositions(JobHandle inputDeps)
|
||||
{
|
||||
var project = new ProjectRenderablePositionsJob()
|
||||
{
|
||||
particleIndices = particleIndices,
|
||||
colliderIndices = colliderIndices,
|
||||
offsets = offsets,
|
||||
stiffnesses = stiffnesses,
|
||||
restDarboux = restDarbouxVectors,
|
||||
|
||||
transforms = ObiColliderWorld.GetInstance().colliderTransforms.AsNativeArray<BurstAffineTransform>(),
|
||||
|
||||
renderablePositions = solverImplementation.renderablePositions,
|
||||
renderableOrientations = solverImplementation.renderableOrientations,
|
||||
|
||||
inertialFrame = ((BurstSolverImpl)constraints.solver).inertialFrame,
|
||||
};
|
||||
|
||||
return project.Schedule(m_ConstraintCount, 16, inputDeps);
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public unsafe struct ClearPinsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> colliderIndices;
|
||||
[ReadOnly] public NativeArray<BurstColliderShape> shapes;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<BurstRigidbody> rigidbodies;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
int colliderIndex = colliderIndices[i];
|
||||
|
||||
// no collider to pin to, so ignore the constraint.
|
||||
if (colliderIndex < 0)
|
||||
return;
|
||||
|
||||
int rigidbodyIndex = shapes[colliderIndex].rigidbodyIndex;
|
||||
if (rigidbodyIndex >= 0)
|
||||
{
|
||||
BurstRigidbody* arr = (BurstRigidbody*)rigidbodies.GetUnsafePtr();
|
||||
Interlocked.Exchange(ref arr[rigidbodyIndex].constraintCount, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public unsafe struct UpdatePinsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> colliderIndices;
|
||||
[ReadOnly] public NativeArray<BurstColliderShape> shapes;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<BurstRigidbody> rigidbodies;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
int colliderIndex = colliderIndices[i];
|
||||
|
||||
// no collider to pin to, so ignore the constraint.
|
||||
if (colliderIndex < 0)
|
||||
return;
|
||||
|
||||
// Increment the amount of constraints affecting this rigidbody for mass splitting:
|
||||
int rigidbodyIndex = shapes[colliderIndex].rigidbodyIndex;
|
||||
if (rigidbodyIndex >= 0)
|
||||
{
|
||||
BurstRigidbody* arr = (BurstRigidbody*)rigidbodies.GetUnsafePtr();
|
||||
Interlocked.Increment(ref arr[rigidbodyIndex].constraintCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public unsafe struct PinConstraintsBatchJob : IJobParallelFor
|
||||
{
|
||||
[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;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] 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;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> rigidbodyLinearDeltas;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] 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 float timeLeft;
|
||||
[ReadOnly] public int steps;
|
||||
[ReadOnly] public int activeConstraintCount;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
int particleIndex = particleIndices[i];
|
||||
int colliderIndex = colliderIndices[i];
|
||||
|
||||
// no collider to pin to, so ignore the constraint.
|
||||
if (colliderIndex < 0)
|
||||
return;
|
||||
|
||||
int rigidbodyIndex = shapes[colliderIndex].rigidbodyIndex;
|
||||
|
||||
float frameEnd = stepTime * steps;
|
||||
float substepsToEnd = timeLeft / substepTime;
|
||||
|
||||
// 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], substepsToEnd);
|
||||
|
||||
// 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 using rb velocity at that point (can't integrate transform since position != center of mass)
|
||||
float4 velocityAtPoint = BurstMath.GetRigidbodyVelocityAtPoint(rigidbodyIndex, inertialFrame.frame.InverseTransformPoint(worldPinOffset), rigidbodies, rigidbodyLinearDeltas, rigidbodyAngularDeltas, inertialFrame);
|
||||
predictedPinOffset = BurstIntegration.IntegrateLinear(predictedPinOffset, inertialFrame.frame.TransformVector(velocityAtPoint), frameEnd);
|
||||
|
||||
// predict rotation at the end of the step:
|
||||
predictedRotation = BurstIntegration.IntegrateAngular(predictedRotation, rigidbody.angularVelocity + rigidbodyAngularDeltas[rigidbodyIndex], stepTime);
|
||||
|
||||
// calculate linear and angular rigidbody effective masses (mass splitting: multiply by constraint count)
|
||||
rigidbodyLinearW = rigidbody.inverseMass * rigidbody.constraintCount;
|
||||
rigidbodyAngularW = BurstMath.RotationalInvMass(rigidbody.inverseInertiaTensor,
|
||||
worldPinOffset - rigidbody.com,
|
||||
math.normalizesafe(inertialFrame.frame.TransformPoint(particlePosition) - predictedPinOffset)) * rigidbody.constraintCount;
|
||||
|
||||
}
|
||||
|
||||
// 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] / substepsToEnd;
|
||||
counts[particleIndex]++;
|
||||
|
||||
if (rigidbodyIndex >= 0)
|
||||
{
|
||||
BurstMath.ApplyImpulse(rigidbodyIndex,
|
||||
-correction / frameEnd,
|
||||
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) / (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] / substepsToEnd;
|
||||
orientationDeltas[particleIndex] = orientDelta;
|
||||
orientationCounts[particleIndex]++;
|
||||
|
||||
if (rigidbodyIndex >= 0)
|
||||
{
|
||||
BurstMath.ApplyDeltaQuaternion(rigidbodyIndex,
|
||||
predictedRotation,
|
||||
-math.mul(orientations[particleIndex], dlambdaQ).value * rigidbodyAngularW,
|
||||
rigidbodyAngularDeltas, inertialFrame.frame, frameEnd);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct ProjectRenderablePositionsJob : IJobParallelFor
|
||||
{
|
||||
[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;
|
||||
|
||||
[ReadOnly] public NativeArray<BurstAffineTransform> transforms;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> renderablePositions;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<quaternion> renderableOrientations;
|
||||
|
||||
[ReadOnly] public BurstInertialFrame inertialFrame;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
int particleIndex = particleIndices[i];
|
||||
int colliderIndex = colliderIndices[i];
|
||||
|
||||
// no collider to pin to or projection deactivated, so ignore the constraint.
|
||||
if (colliderIndex < 0 || offsets[i].w < 0.5f)
|
||||
return;
|
||||
|
||||
BurstAffineTransform attachmentMatrix = inertialFrame.frame.Inverse() * transforms[colliderIndex];
|
||||
|
||||
renderablePositions[particleIndex] = attachmentMatrix.TransformPoint(offsets[i]);
|
||||
if (stiffnesses[i].y < 10000)
|
||||
renderableOrientations[particleIndex] = math.mul(attachmentMatrix.rotation, restDarboux[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a383dd79fc24448059bb45283b12a52b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 744a58a1ca5364e0a86c93e04770c0b8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,26 +0,0 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using System;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public class BurstPinholeConstraints : BurstConstraintsImpl<BurstPinholeConstraintsBatch>
|
||||
{
|
||||
public BurstPinholeConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.Pinhole)
|
||||
{
|
||||
}
|
||||
|
||||
public override IConstraintsBatchImpl CreateConstraintsBatch()
|
||||
{
|
||||
var dataBatch = new BurstPinholeConstraintsBatch(this);
|
||||
batches.Add(dataBatch);
|
||||
return dataBatch;
|
||||
}
|
||||
|
||||
public override void RemoveBatch(IConstraintsBatchImpl batch)
|
||||
{
|
||||
batches.Remove(batch as BurstPinholeConstraintsBatch);
|
||||
batch.Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71db1a3a2698147deb04f0264e4a728f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,490 +0,0 @@
|
||||
#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;
|
||||
using System.Threading;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public class BurstPinholeConstraintsBatch : BurstConstraintsBatchImpl, IPinholeConstraintsBatchImpl
|
||||
{
|
||||
private NativeArray<int> colliderIndices;
|
||||
private NativeArray<float4> offsets;
|
||||
private NativeArray<float> edgeMus;
|
||||
private NativeArray<int2> edgeRanges;
|
||||
private NativeArray<float2> edgeRangeMus;
|
||||
private NativeArray<float> parameters;
|
||||
private NativeArray<float> relativeVelocities;
|
||||
|
||||
public BurstPinholeConstraintsBatch(BurstPinholeConstraints constraints)
|
||||
{
|
||||
m_Constraints = constraints;
|
||||
m_ConstraintType = Oni.ConstraintType.Pinhole;
|
||||
}
|
||||
|
||||
public void SetPinholeConstraints(ObiNativeIntList particleIndices, ObiNativeIntList colliderIndices, ObiNativeVector4List offsets, ObiNativeFloatList edgeMus, ObiNativeIntList edgeRanges, ObiNativeFloatList edgeRangeMus, ObiNativeFloatList parameters, ObiNativeFloatList relativeVelocities, ObiNativeFloatList lambdas, int count)
|
||||
{
|
||||
this.particleIndices = particleIndices.AsNativeArray<int>();
|
||||
this.colliderIndices = colliderIndices.AsNativeArray<int>();
|
||||
this.offsets = offsets.AsNativeArray<float4>();
|
||||
this.edgeMus = edgeMus.AsNativeArray<float>();
|
||||
this.edgeRanges = edgeRanges.AsNativeArray<int2>();
|
||||
this.edgeRangeMus = edgeRangeMus.AsNativeArray<float2>();
|
||||
this.parameters = parameters.AsNativeArray<float>();
|
||||
this.relativeVelocities = relativeVelocities.AsNativeArray<float>();
|
||||
this.lambdas = lambdas.AsNativeArray<float>();
|
||||
m_ConstraintCount = count;
|
||||
}
|
||||
|
||||
public override JobHandle Initialize(JobHandle inputDeps, float stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
var clearPins = new ClearPinsJob
|
||||
{
|
||||
colliderIndices = colliderIndices,
|
||||
shapes = ObiColliderWorld.GetInstance().colliderShapes.AsNativeArray<BurstColliderShape>(),
|
||||
rigidbodies = ObiColliderWorld.GetInstance().rigidbodies.AsNativeArray<BurstRigidbody>(),
|
||||
};
|
||||
inputDeps = clearPins.Schedule(m_ConstraintCount, 128, inputDeps);
|
||||
|
||||
var updatePins = new UpdatePinsJob
|
||||
{
|
||||
particleIndices = particleIndices,
|
||||
colliderIndices = colliderIndices,
|
||||
offsets = offsets,
|
||||
edgeMus = edgeMus,
|
||||
edgeRangeMus = edgeRangeMus,
|
||||
relativeVelocities = relativeVelocities,
|
||||
parameters = parameters,
|
||||
edgeRanges = edgeRanges,
|
||||
|
||||
positions = solverImplementation.positions,
|
||||
prevPositions = solverImplementation.prevPositions,
|
||||
invMasses = solverImplementation.invMasses,
|
||||
|
||||
deformableEdges = solverImplementation.abstraction.deformableEdges.AsNativeArray<int>(),
|
||||
|
||||
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>(),
|
||||
|
||||
inertialFrame = ((BurstSolverImpl)constraints.solver).inertialFrame,
|
||||
stepTime = stepTime,
|
||||
steps = steps,
|
||||
substepTime = substepTime,
|
||||
timeLeft = timeLeft,
|
||||
activeConstraintCount = m_ConstraintCount
|
||||
};
|
||||
inputDeps = updatePins.Schedule(m_ConstraintCount, 128, inputDeps);
|
||||
|
||||
// clear lambdas:
|
||||
return base.Initialize(inputDeps, stepTime, substepTime, steps, timeLeft);
|
||||
}
|
||||
|
||||
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
var projectConstraints = new PinholeConstraintsBatchJob()
|
||||
{
|
||||
particleIndices = particleIndices,
|
||||
colliderIndices = colliderIndices,
|
||||
offsets = offsets,
|
||||
edgeMus = edgeMus,
|
||||
parameters = parameters,
|
||||
lambdas = lambdas,
|
||||
|
||||
positions = solverImplementation.positions,
|
||||
prevPositions = solverImplementation.prevPositions,
|
||||
invMasses = solverImplementation.invMasses,
|
||||
|
||||
deformableEdges = solverImplementation.abstraction.deformableEdges.AsNativeArray<int>(),
|
||||
|
||||
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,
|
||||
|
||||
inertialFrame = ((BurstSolverImpl)constraints.solver).inertialFrame,
|
||||
stepTime = stepTime,
|
||||
steps = steps,
|
||||
substepTime = substepTime,
|
||||
timeLeft = timeLeft,
|
||||
activeConstraintCount = m_ConstraintCount
|
||||
};
|
||||
|
||||
return projectConstraints.Schedule(m_ConstraintCount, 16, inputDeps);
|
||||
}
|
||||
|
||||
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
|
||||
{
|
||||
var cparameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
|
||||
|
||||
var applyConstraints = new ApplyPinholeConstraintsBatchJob()
|
||||
{
|
||||
particleIndices = particleIndices,
|
||||
deformableEdges = solverImplementation.abstraction.deformableEdges.AsNativeArray<int>(),
|
||||
|
||||
positions = solverImplementation.positions,
|
||||
deltas = solverImplementation.positionDeltas,
|
||||
counts = solverImplementation.positionConstraintCounts,
|
||||
|
||||
sorFactor = cparameters.SORFactor,
|
||||
activeConstraintCount = m_ConstraintCount,
|
||||
};
|
||||
|
||||
return applyConstraints.Schedule(inputDeps);
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public unsafe struct ClearPinsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> colliderIndices;
|
||||
[ReadOnly] public NativeArray<BurstColliderShape> shapes;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<BurstRigidbody> rigidbodies;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
int colliderIndex = colliderIndices[i];
|
||||
|
||||
// no collider to pin to, so ignore the constraint.
|
||||
if (colliderIndex < 0)
|
||||
return;
|
||||
|
||||
int rigidbodyIndex = shapes[colliderIndex].rigidbodyIndex;
|
||||
if (rigidbodyIndex >= 0)
|
||||
{
|
||||
BurstRigidbody* arr = (BurstRigidbody*)rigidbodies.GetUnsafePtr();
|
||||
Interlocked.Exchange(ref arr[rigidbodyIndex].constraintCount, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public unsafe struct UpdatePinsJob : IJobParallelFor
|
||||
{
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> particleIndices;
|
||||
|
||||
[ReadOnly] public NativeArray<int2> edgeRanges;
|
||||
[ReadOnly] public NativeArray<float2> edgeRangeMus;
|
||||
[ReadOnly] public NativeArray<float4> offsets;
|
||||
[ReadOnly] public NativeArray<float> parameters; // compliance, friction, motor speed, motor force, clamp behavior.
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float> edgeMus;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float> relativeVelocities;
|
||||
|
||||
[ReadOnly] public NativeArray<float4> positions;
|
||||
[ReadOnly] public NativeArray<float4> prevPositions;
|
||||
[ReadOnly] public NativeArray<float> invMasses;
|
||||
|
||||
[ReadOnly] public NativeArray<int> deformableEdges;
|
||||
|
||||
[ReadOnly] public NativeArray<int> colliderIndices;
|
||||
[ReadOnly] public NativeArray<BurstColliderShape> shapes;
|
||||
[ReadOnly] public NativeArray<BurstAffineTransform> transforms;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<BurstRigidbody> rigidbodies;
|
||||
|
||||
[ReadOnly] public NativeArray<float4> rigidbodyLinearDeltas;
|
||||
[ReadOnly] public NativeArray<float4> rigidbodyAngularDeltas;
|
||||
|
||||
[ReadOnly] public BurstInertialFrame inertialFrame;
|
||||
[ReadOnly] public float stepTime;
|
||||
[ReadOnly] public float substepTime;
|
||||
[ReadOnly] public float timeLeft;
|
||||
[ReadOnly] public int steps;
|
||||
[ReadOnly] public int activeConstraintCount;
|
||||
|
||||
private bool IsEdgeValid(int edgeIndex, int nextEdgeIndex, float mix)
|
||||
{
|
||||
return mix < 0 ? deformableEdges[nextEdgeIndex * 2 + 1] == deformableEdges[edgeIndex * 2] :
|
||||
deformableEdges[nextEdgeIndex * 2] == deformableEdges[edgeIndex * 2 + 1];
|
||||
}
|
||||
|
||||
private bool ClampToRange(int i, int edgeIndex, ref float mix)
|
||||
{
|
||||
bool clamped = false;
|
||||
if (edgeIndex == edgeRanges[i].x && mix < edgeRangeMus[i].x)
|
||||
{
|
||||
mix = edgeRangeMus[i].x;
|
||||
clamped = true;
|
||||
}
|
||||
if (edgeIndex == edgeRanges[i].y && mix > edgeRangeMus[i].y)
|
||||
{
|
||||
mix = edgeRangeMus[i].y;
|
||||
clamped = true;
|
||||
}
|
||||
return clamped;
|
||||
}
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
int edgeIndex = particleIndices[i];
|
||||
int colliderIndex = colliderIndices[i];
|
||||
|
||||
// if no collider or edge, ignore the constraint.
|
||||
if (colliderIndex < 0 || edgeIndex < 0)
|
||||
return;
|
||||
|
||||
// Increment the amount of constraints affecting this rigidbody for mass splitting:
|
||||
int rigidbodyIndex = shapes[colliderIndex].rigidbodyIndex;
|
||||
if (rigidbodyIndex >= 0)
|
||||
{
|
||||
BurstRigidbody* arr = (BurstRigidbody*)rigidbodies.GetUnsafePtr();
|
||||
Interlocked.Increment(ref arr[rigidbodyIndex].constraintCount);
|
||||
}
|
||||
|
||||
float frameEnd = stepTime * steps;
|
||||
float substepsToEnd = timeLeft / substepTime;
|
||||
|
||||
int p1 = deformableEdges[edgeIndex * 2];
|
||||
int p2 = deformableEdges[edgeIndex * 2 + 1];
|
||||
int edgeCount = math.max(0, edgeRanges[i].y - edgeRanges[i].x + 1);
|
||||
|
||||
// express pin offset in world space:
|
||||
float4 worldPinOffset = transforms[colliderIndex].TransformPoint(offsets[i]);
|
||||
float4 predictedPinOffset = worldPinOffset;
|
||||
|
||||
if (rigidbodyIndex >= 0)
|
||||
{
|
||||
// predict offset point position using rb velocity at that point (can't integrate transform since position != center of mass)
|
||||
float4 pointVelocity = BurstMath.GetRigidbodyVelocityAtPoint(rigidbodyIndex, inertialFrame.frame.InverseTransformPoint(worldPinOffset), rigidbodies, rigidbodyLinearDeltas, rigidbodyAngularDeltas, inertialFrame);
|
||||
predictedPinOffset = BurstIntegration.IntegrateLinear(predictedPinOffset, inertialFrame.frame.TransformVector(pointVelocity), frameEnd);
|
||||
}
|
||||
|
||||
// transform pinhole position to solver space for constraint solving:
|
||||
float4 solverPredictedOffset = inertialFrame.frame.InverseTransformPoint(predictedPinOffset);
|
||||
|
||||
// get current edge data:
|
||||
float4 particlePosition1 = math.lerp(prevPositions[p1], positions[p1], substepsToEnd);
|
||||
float4 particlePosition2 = math.lerp(prevPositions[p2], positions[p2], substepsToEnd);
|
||||
float edgeLength = math.length(particlePosition1 - particlePosition2) + BurstMath.epsilon;
|
||||
BurstMath.NearestPointOnEdge(particlePosition1, particlePosition2, solverPredictedOffset, out float mix, false);
|
||||
|
||||
// calculate current relative velocity between rope and pinhole:
|
||||
float velocity = (mix - edgeMus[i]) / substepTime * edgeLength; // vel = pos / time.
|
||||
relativeVelocities[i] = velocity;
|
||||
|
||||
//apply motor force:
|
||||
float targetAccel = (parameters[i * 5 + 2] - velocity) / substepTime; // accel = vel / time.
|
||||
float maxAccel = parameters[i * 5 + 3] * math.max(math.lerp(invMasses[p1], invMasses[p2], mix), BurstMath.epsilon); // accel = force / mass. Guard against inf*0
|
||||
velocity += math.clamp(targetAccel, -maxAccel, maxAccel) * substepTime;
|
||||
|
||||
// calculate new position by adding motor acceleration:
|
||||
float corrMix = edgeMus[i] + velocity * substepTime / edgeLength;
|
||||
|
||||
// apply artificial friction by interpolating predicted position and corrected position.
|
||||
mix = math.lerp(mix, corrMix, parameters[i * 5 + 1]);
|
||||
|
||||
// move to an adjacent edge if needed:
|
||||
if (!ClampToRange(i, edgeIndex, ref mix) && (mix < 0 || mix > 1))
|
||||
{
|
||||
bool clampOnEnd = parameters[i * 5 + 4] > 0.5f;
|
||||
|
||||
// calculate distance we need to travel along edge chain:
|
||||
float distToTravel = math.length(particlePosition1 - particlePosition2) * (mix < 0 ? -mix : mix - 1);
|
||||
|
||||
int nextEdgeIndex;
|
||||
for (int k = 0; k < 10; ++k) // look up to 10 edges away.
|
||||
{
|
||||
// calculate index of next edge:
|
||||
nextEdgeIndex = mix < 0 ? edgeIndex - 1 : edgeIndex + 1;
|
||||
nextEdgeIndex = edgeRanges[i].x + (int)BurstMath.nfmod(nextEdgeIndex - edgeRanges[i].x, edgeCount);
|
||||
|
||||
// see if it's valid
|
||||
if (!IsEdgeValid(edgeIndex, nextEdgeIndex, mix))
|
||||
{
|
||||
// disable constraint if needed
|
||||
if (!clampOnEnd) { particleIndices[i] = -1; return; }
|
||||
|
||||
// otherwise clamp:
|
||||
mix = math.saturate(mix);
|
||||
break;
|
||||
}
|
||||
|
||||
// advance to next edge:
|
||||
edgeIndex = nextEdgeIndex;
|
||||
p1 = deformableEdges[edgeIndex * 2];
|
||||
p2 = deformableEdges[edgeIndex * 2 + 1];
|
||||
particlePosition1 = math.lerp(prevPositions[p1], positions[p1], substepsToEnd);
|
||||
particlePosition2 = math.lerp(prevPositions[p2], positions[p2], substepsToEnd);
|
||||
edgeLength = math.length(particlePosition1 - particlePosition2) + BurstMath.epsilon;
|
||||
|
||||
// stop if we reached target edge:
|
||||
if (distToTravel <= edgeLength)
|
||||
{
|
||||
mix = mix < 0 ? 1 - math.saturate(distToTravel / edgeLength) : math.saturate(distToTravel / edgeLength);
|
||||
ClampToRange(i, edgeIndex, ref mix);
|
||||
break;
|
||||
}
|
||||
|
||||
// stop if we reached end of range:
|
||||
if (ClampToRange(i, edgeIndex, ref mix))
|
||||
break;
|
||||
|
||||
distToTravel -= edgeLength;
|
||||
}
|
||||
}
|
||||
|
||||
edgeMus[i] = mix;
|
||||
particleIndices[i] = edgeIndex;
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public unsafe struct PinholeConstraintsBatchJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> particleIndices;
|
||||
[ReadOnly] public NativeArray<int> colliderIndices;
|
||||
|
||||
[ReadOnly] public NativeArray<float4> offsets;
|
||||
[ReadOnly] public NativeArray<float> parameters; // compliance, friction, motor speed, motor force, clamp behavior.
|
||||
[ReadOnly] public NativeArray<float> edgeMus;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float> lambdas;
|
||||
|
||||
[ReadOnly] public NativeArray<float4> positions;
|
||||
[ReadOnly] public NativeArray<float4> prevPositions;
|
||||
[ReadOnly] public NativeArray<float> invMasses;
|
||||
|
||||
[ReadOnly] public NativeArray<int> deformableEdges;
|
||||
|
||||
[ReadOnly] public NativeArray<BurstColliderShape> shapes;
|
||||
[ReadOnly] public NativeArray<BurstAffineTransform> transforms;
|
||||
[ReadOnly] public NativeArray<BurstRigidbody> rigidbodies;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> rigidbodyLinearDeltas;
|
||||
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> rigidbodyAngularDeltas;
|
||||
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
|
||||
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<int> counts;
|
||||
|
||||
[ReadOnly] public BurstInertialFrame inertialFrame;
|
||||
[ReadOnly] public float stepTime;
|
||||
[ReadOnly] public float substepTime;
|
||||
[ReadOnly] public float timeLeft;
|
||||
[ReadOnly] public int steps;
|
||||
[ReadOnly] public int activeConstraintCount;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
int edgeIndex = particleIndices[i];
|
||||
int colliderIndex = colliderIndices[i];
|
||||
|
||||
// if no collider or edge, ignore the constraint.
|
||||
if (edgeIndex < 0 || colliderIndex < 0)
|
||||
return;
|
||||
|
||||
float frameEnd = stepTime * steps;
|
||||
float substepsToEnd = timeLeft / substepTime;
|
||||
|
||||
// calculate time adjusted compliance
|
||||
float compliance = parameters[i * 5] / (substepTime * substepTime);
|
||||
|
||||
int p1 = deformableEdges[edgeIndex * 2];
|
||||
int p2 = deformableEdges[edgeIndex * 2 + 1];
|
||||
|
||||
// calculate projection on current edge:
|
||||
float mix = edgeMus[i];
|
||||
float4 particlePosition1 = math.lerp(prevPositions[p1], positions[p1], substepsToEnd);
|
||||
float4 particlePosition2 = math.lerp(prevPositions[p2], positions[p2], substepsToEnd);
|
||||
float4 projection = math.lerp(particlePosition1, particlePosition2, mix);
|
||||
|
||||
// express pin offset in world space:
|
||||
float4 worldPinOffset = transforms[colliderIndex].TransformPoint(offsets[i]);
|
||||
float4 predictedPinOffset = worldPinOffset;
|
||||
|
||||
float rigidbodyLinearW = 0;
|
||||
float rigidbodyAngularW = 0;
|
||||
|
||||
int rigidbodyIndex = shapes[colliderIndex].rigidbodyIndex;
|
||||
if (rigidbodyIndex >= 0)
|
||||
{
|
||||
var rigidbody = rigidbodies[rigidbodyIndex];
|
||||
|
||||
// predict offset point position using rb velocity at that point (can't integrate transform since position != center of mass)
|
||||
float4 pointVelocity = BurstMath.GetRigidbodyVelocityAtPoint(rigidbodyIndex, inertialFrame.frame.InverseTransformPoint(worldPinOffset), rigidbodies, rigidbodyLinearDeltas, rigidbodyAngularDeltas, inertialFrame);
|
||||
predictedPinOffset = BurstIntegration.IntegrateLinear(predictedPinOffset, inertialFrame.frame.TransformVector(pointVelocity), frameEnd);
|
||||
|
||||
// calculate linear and angular rigidbody effective masses (mass splitting: multiply by constraint count)
|
||||
rigidbodyLinearW = rigidbody.inverseMass * rigidbody.constraintCount;
|
||||
rigidbodyAngularW = BurstMath.RotationalInvMass(rigidbody.inverseInertiaTensor,
|
||||
worldPinOffset - rigidbody.com,
|
||||
math.normalizesafe(inertialFrame.frame.TransformPoint(projection) - predictedPinOffset)) * rigidbody.constraintCount;
|
||||
}
|
||||
|
||||
// Transform pinhole position to solver space for constraint solving:
|
||||
predictedPinOffset = inertialFrame.frame.InverseTransformPoint(predictedPinOffset);
|
||||
|
||||
float4 gradient = projection - predictedPinOffset;
|
||||
float constraint = math.length(gradient);
|
||||
float4 gradientDir = gradient / (constraint + BurstMath.epsilon);
|
||||
|
||||
float lambda = (-constraint - compliance * lambdas[i]) / (math.lerp(invMasses[p1], invMasses[p2], mix) + rigidbodyLinearW + rigidbodyAngularW + compliance + BurstMath.epsilon);
|
||||
lambdas[i] += lambda;
|
||||
float4 correction = lambda * gradientDir;
|
||||
|
||||
float baryScale = BurstMath.BaryScale(new float4(1 - mix, mix, 0, 0));
|
||||
|
||||
deltas[p1] += correction * baryScale * invMasses[p1] * (1 - mix) / substepsToEnd;
|
||||
counts[p1]++;
|
||||
|
||||
deltas[p2] += correction * baryScale * invMasses[p2] * mix / substepsToEnd;
|
||||
counts[p2]++;
|
||||
|
||||
if (rigidbodyIndex >= 0)
|
||||
{
|
||||
BurstMath.ApplyImpulse(rigidbodyIndex,
|
||||
-correction / frameEnd,
|
||||
inertialFrame.frame.InverseTransformPoint(worldPinOffset),
|
||||
rigidbodies, rigidbodyLinearDeltas, rigidbodyAngularDeltas, inertialFrame.frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct ApplyPinholeConstraintsBatchJob : IJob
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> particleIndices;
|
||||
[ReadOnly] public float sorFactor;
|
||||
|
||||
[ReadOnly] public NativeArray<int> deformableEdges;
|
||||
|
||||
[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 edgeIndex = particleIndices[i];
|
||||
if (edgeIndex < 0) continue;
|
||||
|
||||
int p1 = deformableEdges[edgeIndex * 2];
|
||||
int p2 = deformableEdges[edgeIndex * 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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c3a800919e2e435785c5beca1029b70
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf9959ac1dc214a0799c42583ae2cbdb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,26 +0,0 @@
|
||||
#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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf31f7a95aadc4c85a69a3400ba30608
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,472 +0,0 @@
|
||||
#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;
|
||||
|
||||
private bool m_RecalculateRestShape = false;
|
||||
|
||||
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 stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
return inputDeps;
|
||||
}
|
||||
|
||||
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int steps, float timeLeft)
|
||||
{
|
||||
if (m_RecalculateRestShape)
|
||||
{
|
||||
m_RecalculateRestShape = false;
|
||||
|
||||
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>(),
|
||||
principalRadii = solverAbstraction.principalRadii.AsNativeArray<float4>(),
|
||||
invMasses = solverAbstraction.invMasses.AsNativeArray<float>(),
|
||||
invRotationalMasses = solverAbstraction.invRotationalMasses.AsNativeArray<float>(),
|
||||
};
|
||||
|
||||
inputDeps = calculateRest.Schedule(numIndices.Length, 64, inputDeps);
|
||||
}
|
||||
|
||||
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,
|
||||
principalRadii = solverImplementation.principalRadii,
|
||||
|
||||
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()
|
||||
{
|
||||
m_RecalculateRestShape = true;
|
||||
}
|
||||
|
||||
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<float> invRotationalMasses,
|
||||
ref NativeArray<float4> restPositions,
|
||||
ref NativeArray<quaternion> restOrientations,
|
||||
ref NativeArray<float4> principalRadii)
|
||||
{
|
||||
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(BurstMath.GetParticleInertiaTensor(principalRadii[k], invRotationalMasses[k]).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<float> invRotationalMasses;
|
||||
[ReadOnly] public NativeArray<float4> principalRadii;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
RecalculateRestData(i,
|
||||
ref particleIndices,
|
||||
ref firstIndex,
|
||||
ref restComs,
|
||||
ref Aqq,
|
||||
ref deformation,
|
||||
ref numIndices,
|
||||
ref invMasses,
|
||||
ref invRotationalMasses,
|
||||
ref restPositions,
|
||||
ref restOrientations,
|
||||
ref principalRadii);
|
||||
}
|
||||
}
|
||||
|
||||
[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> principalRadii;
|
||||
|
||||
[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(BurstMath.GetParticleInertiaTensor(principalRadii[k], invRotationalMasses[k]).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], 5);
|
||||
|
||||
// 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 invRotationalMasses,
|
||||
ref restPositions,
|
||||
ref restOrientations,
|
||||
ref principalRadii);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 invRotationalMasses,
|
||||
ref restPositions,
|
||||
ref restOrientations,
|
||||
ref principalRadii);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a532b712a8e34bf8a610d420174d9b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da67648eb6cfe43fbb5574da14d23dc6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,26 +0,0 @@
|
||||
#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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f501f9a4acdd34395a31db88db413cb7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,151 +0,0 @@
|
||||
#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 steps, float timeLeft)
|
||||
{
|
||||
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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b78797a70a67646fe84c09d533a1bba9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5d27732f644a64569a0e8a1595d1f2a7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,26 +0,0 @@
|
||||
#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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0e33ed168e3c497b96274c765a12550
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,152 +0,0 @@
|
||||
#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 steps, float timeLeft)
|
||||
{
|
||||
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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cfc801159b76b4cc1a2a7593113d6935
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 67eda103405cc476bbd356a301fdc499
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,26 +0,0 @@
|
||||
#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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a79c4e863802e4ca19939ab6766329e8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,206 +0,0 @@
|
||||
#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 steps, float timeLeft)
|
||||
{
|
||||
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]);
|
||||
float3 dlambda = (gamma - compliances * lambdas[i]) / (W + compliances + BurstMath.epsilon);
|
||||
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];
|
||||
|
||||
quaternion orDelta = orientationDeltas[q];
|
||||
orDelta.value += rotDelta.value;
|
||||
orientationDeltas[q] = orDelta;
|
||||
|
||||
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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f505342239d5443fbd06fb4e610b240
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c77d80d2f6a7b4136bfdc684b23b91f3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,26 +0,0 @@
|
||||
#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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c12658b3bc614f3c921a54dc2489881
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,141 +0,0 @@
|
||||
#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 steps, float timeLeft)
|
||||
{
|
||||
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
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0333dee6dab0c40a9abc35796d0fd99a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0b17a4f4853654722be7ce3458a4ce7a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,26 +0,0 @@
|
||||
#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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user