重新导入obi
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
#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]
|
||||
struct ApplyInertialForcesJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> activeParticles;
|
||||
[ReadOnly] public NativeArray<float4> positions;
|
||||
[ReadOnly] public NativeArray<float> invMasses;
|
||||
|
||||
[ReadOnly] public float4 angularVel;
|
||||
[ReadOnly] public float4 inertialAccel;
|
||||
[ReadOnly] public float4 eulerAccel;
|
||||
|
||||
[ReadOnly] public float worldLinearInertiaScale;
|
||||
[ReadOnly] public float worldAngularInertiaScale;
|
||||
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float4> velocities;
|
||||
|
||||
[ReadOnly] public float deltaTime;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
int i = activeParticles[index];
|
||||
|
||||
if (invMasses[i] > 0)
|
||||
{
|
||||
float4 euler = new float4(math.cross(eulerAccel.xyz, positions[i].xyz), 0);
|
||||
float4 centrifugal = new float4(math.cross(angularVel.xyz, math.cross(angularVel.xyz, positions[i].xyz)), 0);
|
||||
float4 coriolis = 2 * new float4(math.cross(angularVel.xyz, velocities[i].xyz), 0);
|
||||
float4 angularAccel = euler + coriolis + centrifugal;
|
||||
|
||||
velocities[i] -= (inertialAccel * worldLinearInertiaScale + angularAccel * worldAngularInertiaScale) * deltaTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9583eea8cf2234362a59c97e3f908a85
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,53 @@
|
||||
#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]
|
||||
struct ParticleToBoundsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> activeParticles;
|
||||
[ReadOnly] public NativeArray<float4> positions;
|
||||
[ReadOnly] public NativeArray<float4> radii;
|
||||
|
||||
public NativeArray<BurstAabb> bounds;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
int p = activeParticles[i];
|
||||
bounds[i] = new BurstAabb(positions[p] - radii[p].x, positions[p] + radii[p].x);
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
struct BoundsReductionJob : IJobParallelFor
|
||||
{
|
||||
[NativeDisableParallelForRestriction] public NativeArray<BurstAabb> bounds; // the length of bounds must be a multiple of size.
|
||||
[ReadOnly] public int stride;
|
||||
[ReadOnly] public int size;
|
||||
|
||||
public void Execute(int first)
|
||||
{
|
||||
int baseIndex = first * size;
|
||||
for (int i = 1; i < size; ++i)
|
||||
{
|
||||
int dest = baseIndex * stride;
|
||||
int source = (baseIndex + i) * stride;
|
||||
|
||||
if (source < bounds.Length)
|
||||
{
|
||||
var v = bounds[dest];
|
||||
v.EncapsulateBounds(bounds[source]);
|
||||
bounds[dest] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31e84cee4b2444511a44d1c8ff0c8cd1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,55 @@
|
||||
#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]
|
||||
struct BuildSimplexAabbs : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<float4> radii;
|
||||
[ReadOnly] public NativeArray<float> fluidRadii;
|
||||
[ReadOnly] public NativeArray<float4> positions;
|
||||
[ReadOnly] public NativeArray<float4> velocities;
|
||||
|
||||
// simplex arrays:
|
||||
[ReadOnly] public NativeArray<int> simplices;
|
||||
[ReadOnly] public SimplexCounts simplexCounts;
|
||||
|
||||
[ReadOnly] public NativeArray<int> particleMaterialIndices;
|
||||
[ReadOnly] public NativeArray<BurstCollisionMaterial> collisionMaterials;
|
||||
[ReadOnly] public float collisionMargin;
|
||||
[ReadOnly] public float continuousCollisionDetection;
|
||||
[ReadOnly] public float dt;
|
||||
|
||||
public NativeArray<BurstAabb> simplexBounds;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
int simplexStart = simplexCounts.GetSimplexStartAndSize(i, out int simplexSize);
|
||||
|
||||
var bounds = new BurstAabb(float.MaxValue, float.MinValue);
|
||||
for (int j = 0; j < simplexSize; ++j)
|
||||
{
|
||||
int p = simplices[simplexStart + j];
|
||||
|
||||
// Find this particle's stick distance:
|
||||
int m = particleMaterialIndices[p];
|
||||
float stickDistance = m >= 0 ? collisionMaterials[m].stickDistance : 0;
|
||||
|
||||
// Expand simplex bounds, using both the particle's original position and its velocity:
|
||||
bounds.EncapsulateParticle(positions[p], positions[p] + velocities[p] * continuousCollisionDetection * dt,
|
||||
math.max(radii[p].x + stickDistance, fluidRadii[p] * 0.5f) + collisionMargin);
|
||||
}
|
||||
|
||||
simplexBounds[i] = bounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7834dd4a6de2346b5b36154d6aaa531a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,970 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using UnityEngine;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public class BurstSolverImpl : ISolverImpl
|
||||
{
|
||||
ObiSolver m_Solver;
|
||||
|
||||
public ObiSolver abstraction
|
||||
{
|
||||
get { return m_Solver; }
|
||||
}
|
||||
|
||||
public int particleCount
|
||||
{
|
||||
get { return m_Solver.positions.count; }
|
||||
}
|
||||
|
||||
public int activeParticleCount
|
||||
{
|
||||
get { return abstraction.activeParticles.count; }
|
||||
}
|
||||
|
||||
public BurstInertialFrame inertialFrame
|
||||
{
|
||||
get { return m_InertialFrame; }
|
||||
}
|
||||
|
||||
public BurstAffineTransform solverToWorld
|
||||
{
|
||||
get { return m_InertialFrame.frame; }
|
||||
}
|
||||
|
||||
public BurstAffineTransform worldToSolver
|
||||
{
|
||||
get { return m_InertialFrame.frame.Inverse(); }
|
||||
}
|
||||
|
||||
private const int maxBatches = 17;
|
||||
|
||||
private ConstraintBatcher<ContactProvider> collisionConstraintBatcher;
|
||||
private ConstraintBatcher<FluidInteractionProvider> fluidConstraintBatcher;
|
||||
|
||||
// Per-type constraints array:
|
||||
private IBurstConstraintsImpl[] constraints;
|
||||
|
||||
// Per-type iteration padding array:
|
||||
private int[] padding = new int[Oni.ConstraintTypeCount];
|
||||
|
||||
// Pool job handles to avoid runtime alloc:
|
||||
private JobHandlePool<BurstJobHandle> jobHandlePool;
|
||||
|
||||
// particle contact generation:
|
||||
public ParticleGrid particleGrid;
|
||||
public NativeArray<BurstContact> particleContacts;
|
||||
public NativeArray<BatchData> particleBatchData;
|
||||
|
||||
// fluid interaction generation:
|
||||
public NativeArray<FluidInteraction> fluidInteractions;
|
||||
public NativeArray<BatchData> fluidBatchData;
|
||||
|
||||
// collider contact generation:
|
||||
private BurstColliderWorld colliderGrid;
|
||||
public NativeArray<BurstContact> colliderContacts;
|
||||
|
||||
// misc data:
|
||||
public NativeArray<int> activeParticles;
|
||||
private NativeList<int> deformableTriangles;
|
||||
|
||||
public NativeArray<int> simplices;
|
||||
public SimplexCounts simplexCounts;
|
||||
|
||||
private BurstInertialFrame m_InertialFrame; // local to world inertial frame.
|
||||
private int scheduledJobCounter = 0;
|
||||
|
||||
// cached particle data arrays (just wrappers over raw unmanaged data held by the abstract solver)
|
||||
public NativeArray<float4> positions;
|
||||
public NativeArray<float4> restPositions;
|
||||
public NativeArray<float4> prevPositions;
|
||||
public NativeArray<float4> renderablePositions;
|
||||
|
||||
public NativeArray<quaternion> orientations;
|
||||
public NativeArray<quaternion> restOrientations;
|
||||
public NativeArray<quaternion> prevOrientations;
|
||||
public NativeArray<quaternion> renderableOrientations;
|
||||
|
||||
public NativeArray<float4> velocities;
|
||||
public NativeArray<float4> angularVelocities;
|
||||
|
||||
public NativeArray<float> invMasses;
|
||||
public NativeArray<float> invRotationalMasses;
|
||||
public NativeArray<float4> invInertiaTensors;
|
||||
|
||||
public NativeArray<float4> externalForces;
|
||||
public NativeArray<float4> externalTorques;
|
||||
public NativeArray<float4> wind;
|
||||
|
||||
public NativeArray<float4> positionDeltas;
|
||||
public NativeArray<quaternion> orientationDeltas;
|
||||
public NativeArray<int> positionConstraintCounts;
|
||||
public NativeArray<int> orientationConstraintCounts;
|
||||
|
||||
public NativeArray<int> collisionMaterials;
|
||||
public NativeArray<int> phases;
|
||||
public NativeArray<int> filters;
|
||||
public NativeArray<float4> anisotropies;
|
||||
public NativeArray<float4> principalRadii;
|
||||
public NativeArray<float4> normals;
|
||||
|
||||
public NativeArray<float4> vorticities;
|
||||
public NativeArray<float4> fluidData;
|
||||
public NativeArray<float4> userData;
|
||||
public NativeArray<float> smoothingRadii;
|
||||
public NativeArray<float> buoyancies;
|
||||
public NativeArray<float> restDensities;
|
||||
public NativeArray<float> viscosities;
|
||||
public NativeArray<float> surfaceTension;
|
||||
public NativeArray<float> vortConfinement;
|
||||
public NativeArray<float> athmosphericDrag;
|
||||
public NativeArray<float> athmosphericPressure;
|
||||
public NativeArray<float> diffusion;
|
||||
|
||||
public NativeArray<int4> cellCoords;
|
||||
public NativeArray<BurstAabb> simplexBounds;
|
||||
|
||||
private ConstraintSorter<BurstContact> contactSorter;
|
||||
|
||||
public BurstSolverImpl(ObiSolver solver)
|
||||
{
|
||||
this.m_Solver = solver;
|
||||
|
||||
jobHandlePool = new JobHandlePool<BurstJobHandle>(4);
|
||||
contactSorter = new ConstraintSorter<BurstContact>();
|
||||
|
||||
// Initialize collision world:
|
||||
GetOrCreateColliderWorld();
|
||||
colliderGrid.IncreaseReferenceCount();
|
||||
|
||||
deformableTriangles = new NativeList<int>(64, Allocator.Persistent);
|
||||
|
||||
// Initialize contact generation acceleration structure:
|
||||
particleGrid = new ParticleGrid();
|
||||
|
||||
// Initialize constraint batcher:
|
||||
collisionConstraintBatcher = new ConstraintBatcher<ContactProvider>(maxBatches);
|
||||
fluidConstraintBatcher = new ConstraintBatcher<FluidInteractionProvider>(maxBatches);
|
||||
|
||||
// Initialize constraint arrays:
|
||||
constraints = new IBurstConstraintsImpl[Oni.ConstraintTypeCount];
|
||||
constraints[(int)Oni.ConstraintType.Tether] = new BurstTetherConstraints(this);
|
||||
constraints[(int)Oni.ConstraintType.Volume] = new BurstVolumeConstraints(this);
|
||||
constraints[(int)Oni.ConstraintType.Chain] = new BurstChainConstraints(this);
|
||||
constraints[(int)Oni.ConstraintType.Bending] = new BurstBendConstraints(this);
|
||||
constraints[(int)Oni.ConstraintType.Distance] = new BurstDistanceConstraints(this);
|
||||
constraints[(int)Oni.ConstraintType.ShapeMatching] = new BurstShapeMatchingConstraints(this);
|
||||
constraints[(int)Oni.ConstraintType.BendTwist] = new BurstBendTwistConstraints(this);
|
||||
constraints[(int)Oni.ConstraintType.StretchShear] = new BurstStretchShearConstraints(this);
|
||||
constraints[(int)Oni.ConstraintType.Pin] = new BurstPinConstraints(this);
|
||||
constraints[(int)Oni.ConstraintType.ParticleCollision] = new BurstParticleCollisionConstraints(this);
|
||||
constraints[(int)Oni.ConstraintType.Density] = new BurstDensityConstraints(this);
|
||||
constraints[(int)Oni.ConstraintType.Collision] = new BurstColliderCollisionConstraints(this);
|
||||
constraints[(int)Oni.ConstraintType.Skin] = new BurstSkinConstraints(this);
|
||||
constraints[(int)Oni.ConstraintType.Aerodynamics] = new BurstAerodynamicConstraints(this);
|
||||
constraints[(int)Oni.ConstraintType.Stitch] = new BurstStitchConstraints(this);
|
||||
constraints[(int)Oni.ConstraintType.ParticleFriction] = new BurstParticleFrictionConstraints(this);
|
||||
constraints[(int)Oni.ConstraintType.Friction] = new BurstColliderFrictionConstraints(this);
|
||||
|
||||
var c = constraints[(int)Oni.ConstraintType.Collision] as BurstColliderCollisionConstraints;
|
||||
c.CreateConstraintsBatch();
|
||||
|
||||
var f = constraints[(int)Oni.ConstraintType.Friction] as BurstColliderFrictionConstraints;
|
||||
f.CreateConstraintsBatch();
|
||||
}
|
||||
|
||||
public void Destroy()
|
||||
{
|
||||
for (int i = 0; i < constraints.Length; ++i)
|
||||
if (constraints[i] != null)
|
||||
constraints[i].Dispose();
|
||||
|
||||
// Get rid of particle and collider grids:
|
||||
particleGrid.Dispose();
|
||||
|
||||
if (colliderGrid != null)
|
||||
colliderGrid.DecreaseReferenceCount();
|
||||
|
||||
collisionConstraintBatcher.Dispose();
|
||||
fluidConstraintBatcher.Dispose();
|
||||
|
||||
if (deformableTriangles.IsCreated)
|
||||
deformableTriangles.Dispose();
|
||||
if (simplexBounds.IsCreated)
|
||||
simplexBounds.Dispose();
|
||||
|
||||
if (particleContacts.IsCreated)
|
||||
particleContacts.Dispose();
|
||||
if (particleBatchData.IsCreated)
|
||||
particleBatchData.Dispose();
|
||||
if (fluidInteractions.IsCreated)
|
||||
fluidInteractions.Dispose();
|
||||
if (fluidBatchData.IsCreated)
|
||||
fluidBatchData.Dispose();
|
||||
if (colliderContacts.IsCreated)
|
||||
colliderContacts.Dispose();
|
||||
|
||||
}
|
||||
|
||||
public void ReleaseJobHandles()
|
||||
{
|
||||
jobHandlePool.ReleaseAll();
|
||||
}
|
||||
|
||||
// Utility function to count scheduled jobs. Call it once per job.
|
||||
// Will JobHandle.ScheduleBatchedJobs once there's a good bunch of scheduled jobs.
|
||||
public void ScheduleBatchedJobsIfNeeded()
|
||||
{
|
||||
if (scheduledJobCounter++ > 16)
|
||||
{
|
||||
scheduledJobCounter = 0;
|
||||
JobHandle.ScheduleBatchedJobs();
|
||||
}
|
||||
}
|
||||
|
||||
private void GetOrCreateColliderWorld()
|
||||
{
|
||||
colliderGrid = GameObject.FindObjectOfType<BurstColliderWorld>();
|
||||
if (colliderGrid == null)
|
||||
{
|
||||
var world = new GameObject("BurstCollisionWorld", typeof(BurstColliderWorld));
|
||||
colliderGrid = world.GetComponent<BurstColliderWorld>();
|
||||
}
|
||||
}
|
||||
|
||||
public void InitializeFrame(Vector4 translation, Vector4 scale, Quaternion rotation)
|
||||
{
|
||||
m_InertialFrame = new BurstInertialFrame(translation, scale, rotation);
|
||||
}
|
||||
|
||||
public void UpdateFrame(Vector4 translation, Vector4 scale, Quaternion rotation, float deltaTime)
|
||||
{
|
||||
m_InertialFrame.Update(translation, scale, rotation, deltaTime);
|
||||
}
|
||||
|
||||
public void ApplyFrame(float worldLinearInertiaScale, float worldAngularInertiaScale, float deltaTime)
|
||||
{
|
||||
// inverse linear part:
|
||||
float4x4 linear = float4x4.TRS(float3.zero, inertialFrame.frame.rotation, math.rcp(inertialFrame.frame.scale.xyz));
|
||||
float4x4 linearInv = math.transpose(linear);
|
||||
|
||||
// non-inertial frame accelerations:
|
||||
float4 angularVel = math.mul(linearInv, math.mul(float4x4.Scale(inertialFrame.angularVelocity.xyz), linear)).diagonal();
|
||||
float4 eulerAccel = math.mul(linearInv, math.mul(float4x4.Scale(inertialFrame.angularAcceleration.xyz), linear)).diagonal();
|
||||
float4 inertialAccel = math.mul(linearInv, inertialFrame.acceleration);
|
||||
|
||||
var applyInertialForces = new ApplyInertialForcesJob()
|
||||
{
|
||||
activeParticles = activeParticles,
|
||||
positions = positions,
|
||||
velocities = velocities,
|
||||
invMasses = invMasses,
|
||||
angularVel = angularVel,
|
||||
inertialAccel = inertialAccel,
|
||||
eulerAccel = eulerAccel,
|
||||
worldLinearInertiaScale = worldLinearInertiaScale,
|
||||
worldAngularInertiaScale = worldAngularInertiaScale,
|
||||
deltaTime = deltaTime,
|
||||
};
|
||||
|
||||
applyInertialForces.Schedule(activeParticleCount, 64).Complete();
|
||||
}
|
||||
|
||||
public int GetDeformableTriangleCount()
|
||||
{
|
||||
return deformableTriangles.Length / 3;
|
||||
}
|
||||
|
||||
public void SetDeformableTriangles(int[] indices, int num, int destOffset)
|
||||
{
|
||||
if (destOffset + num >= deformableTriangles.Length / 3)
|
||||
deformableTriangles.ResizeUninitialized((destOffset + num) * 3);
|
||||
for (int i = 0; i < num * 3; ++i)
|
||||
deformableTriangles[i + destOffset * 3] = indices[i];
|
||||
}
|
||||
|
||||
public int RemoveDeformableTriangles(int num, int sourceOffset)
|
||||
{
|
||||
if (deformableTriangles.IsCreated)
|
||||
{
|
||||
int amount = deformableTriangles.Length / 3;
|
||||
|
||||
if (num < 0)
|
||||
{
|
||||
deformableTriangles.Clear();
|
||||
return amount;
|
||||
}
|
||||
|
||||
int set = ClampArrayAccess(amount, num, sourceOffset);
|
||||
int end = sourceOffset + set;
|
||||
|
||||
// TODO: replace by built in method in 0.9.0
|
||||
deformableTriangles.RemoveRangeBurst(sourceOffset * 3, (end - sourceOffset) * 3 );
|
||||
|
||||
return set;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void SetSimplices(ObiNativeIntList simplices, SimplexCounts counts)
|
||||
{
|
||||
this.simplices = simplices.AsNativeArray<int>();
|
||||
this.simplexCounts = counts;
|
||||
|
||||
if (simplexBounds.IsCreated)
|
||||
simplexBounds.Dispose();
|
||||
|
||||
simplexBounds = new NativeArray<BurstAabb>(counts.simplexCount, Allocator.Persistent);
|
||||
cellCoords = abstraction.cellCoords.AsNativeArray<int4>();
|
||||
}
|
||||
|
||||
public void SetActiveParticles(ObiNativeIntList indices)
|
||||
{
|
||||
activeParticles = indices.AsNativeArray<int>();
|
||||
}
|
||||
|
||||
int ClampArrayAccess(int size, int num, int offset)
|
||||
{
|
||||
return math.min(num, math.max(0, size - offset));
|
||||
}
|
||||
|
||||
public JobHandle RecalculateInertiaTensors(JobHandle inputDeps)
|
||||
{
|
||||
var updateInertiaTensors = new UpdateInertiaTensorsJob()
|
||||
{
|
||||
activeParticles = activeParticles,
|
||||
inverseMasses = abstraction.invMasses.AsNativeArray<float>(),
|
||||
inverseRotationalMasses = abstraction.invRotationalMasses.AsNativeArray<float>(),
|
||||
principalRadii = abstraction.principalRadii.AsNativeArray<float4>(),
|
||||
inverseInertiaTensors = abstraction.invInertiaTensors.AsNativeArray<float4>(),
|
||||
};
|
||||
|
||||
return updateInertiaTensors.Schedule(activeParticleCount, 128, inputDeps);
|
||||
}
|
||||
|
||||
public void GetBounds(ref Vector3 min, ref Vector3 max)
|
||||
{
|
||||
int chunkSize = 4;
|
||||
NativeArray<BurstAabb> bounds = new NativeArray<BurstAabb>(activeParticleCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
|
||||
|
||||
var particleBoundsJob = new ParticleToBoundsJob()
|
||||
{
|
||||
activeParticles = activeParticles,
|
||||
positions = positions,
|
||||
radii = principalRadii,
|
||||
bounds = bounds
|
||||
};
|
||||
|
||||
JobHandle reduction = particleBoundsJob.Schedule(activeParticles.Length, 64);
|
||||
|
||||
// parallel reduction:
|
||||
int chunks = bounds.Length;
|
||||
int stride = 1;
|
||||
|
||||
while (chunks > 1)
|
||||
{
|
||||
var reductionJob = new BoundsReductionJob()
|
||||
{
|
||||
bounds = bounds,
|
||||
stride = stride,
|
||||
size = chunkSize,
|
||||
};
|
||||
reduction = reductionJob.Schedule(chunks, 1, reduction);
|
||||
|
||||
chunks = (int)math.ceil(chunks / (float)chunkSize);
|
||||
stride *= chunkSize;
|
||||
}
|
||||
|
||||
reduction.Complete();
|
||||
|
||||
// the parallel reduction leaves the final bounds in the first entry:
|
||||
if (bounds.Length > 0)
|
||||
{
|
||||
min = bounds[0].min.xyz;
|
||||
max = bounds[0].max.xyz;
|
||||
}
|
||||
|
||||
bounds.Dispose();
|
||||
}
|
||||
|
||||
public void ResetForces()
|
||||
{
|
||||
abstraction.externalForces.WipeToZero();
|
||||
abstraction.externalTorques.WipeToZero();
|
||||
abstraction.wind.WipeToZero();
|
||||
|
||||
// We're at the end of a whole step (not a substep), so dispose of contact buffers:
|
||||
if (particleContacts.IsCreated)
|
||||
particleContacts.Dispose();
|
||||
if (particleBatchData.IsCreated)
|
||||
particleBatchData.Dispose();
|
||||
if (colliderContacts.IsCreated)
|
||||
colliderContacts.Dispose();
|
||||
}
|
||||
|
||||
public int GetConstraintCount(Oni.ConstraintType type)
|
||||
{
|
||||
if ((int)type > 0 && (int)type < constraints.Length)
|
||||
return constraints[(int)type].GetConstraintCount();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void GetCollisionContacts(Oni.Contact[] contacts, int count)
|
||||
{
|
||||
NativeArray<Oni.Contact>.Copy(colliderContacts.Reinterpret<Oni.Contact>(),0, contacts,0,count);
|
||||
}
|
||||
|
||||
public void GetParticleCollisionContacts(Oni.Contact[] contacts, int count)
|
||||
{
|
||||
NativeArray<Oni.Contact>.Copy(particleContacts.Reinterpret<Oni.Contact>(),0, contacts,0,count);
|
||||
}
|
||||
|
||||
public void SetParameters(Oni.SolverParameters parameters)
|
||||
{
|
||||
// No need to implement. This backend grabs parameters from the abstraction when it needs them.
|
||||
}
|
||||
|
||||
public void SetConstraintGroupParameters(Oni.ConstraintType type, ref Oni.ConstraintParameters parameters)
|
||||
{
|
||||
// No need to implement. This backend grabs parameters from the abstraction when it needs them.
|
||||
}
|
||||
|
||||
public void ParticleCountChanged(ObiSolver solver)
|
||||
{
|
||||
positions = abstraction.positions.AsNativeArray<float4>();
|
||||
restPositions = abstraction.restPositions.AsNativeArray<float4>();
|
||||
prevPositions = abstraction.prevPositions.AsNativeArray<float4>();
|
||||
renderablePositions = abstraction.renderablePositions.AsNativeArray<float4>();
|
||||
|
||||
orientations = abstraction.orientations.AsNativeArray<quaternion>();
|
||||
restOrientations = abstraction.restOrientations.AsNativeArray<quaternion>();
|
||||
prevOrientations = abstraction.prevOrientations.AsNativeArray<quaternion>();
|
||||
renderableOrientations = abstraction.renderableOrientations.AsNativeArray<quaternion>();
|
||||
|
||||
velocities = abstraction.velocities.AsNativeArray<float4>();
|
||||
angularVelocities = abstraction.angularVelocities.AsNativeArray<float4>();
|
||||
|
||||
invMasses = abstraction.invMasses.AsNativeArray<float>();
|
||||
invRotationalMasses = abstraction.invRotationalMasses.AsNativeArray<float>();
|
||||
invInertiaTensors = abstraction.invInertiaTensors.AsNativeArray<float4>();
|
||||
|
||||
externalForces = abstraction.externalForces.AsNativeArray<float4>();
|
||||
externalTorques = abstraction.externalTorques.AsNativeArray<float4>();
|
||||
wind = abstraction.wind.AsNativeArray<float4>();
|
||||
|
||||
positionDeltas = abstraction.positionDeltas.AsNativeArray<float4>();
|
||||
orientationDeltas = abstraction.orientationDeltas.AsNativeArray<quaternion>();
|
||||
positionConstraintCounts = abstraction.positionConstraintCounts.AsNativeArray<int>();
|
||||
orientationConstraintCounts = abstraction.orientationConstraintCounts.AsNativeArray<int>();
|
||||
|
||||
collisionMaterials = abstraction.collisionMaterials.AsNativeArray<int>();
|
||||
phases = abstraction.phases.AsNativeArray<int>();
|
||||
filters = abstraction.filters.AsNativeArray<int>();
|
||||
anisotropies = abstraction.anisotropies.AsNativeArray<float4>();
|
||||
principalRadii = abstraction.principalRadii.AsNativeArray<float4>();
|
||||
normals = abstraction.normals.AsNativeArray<float4>();
|
||||
|
||||
vorticities = abstraction.vorticities.AsNativeArray<float4>();
|
||||
fluidData = abstraction.fluidData.AsNativeArray<float4>();
|
||||
userData = abstraction.userData.AsNativeArray<float4>();
|
||||
smoothingRadii = abstraction.smoothingRadii.AsNativeArray<float>();
|
||||
buoyancies = abstraction.buoyancies.AsNativeArray<float>();
|
||||
restDensities = abstraction.restDensities.AsNativeArray<float>();
|
||||
viscosities = abstraction.viscosities.AsNativeArray<float>();
|
||||
surfaceTension = abstraction.surfaceTension.AsNativeArray<float>();
|
||||
vortConfinement = abstraction.vortConfinement.AsNativeArray<float>();
|
||||
athmosphericDrag = abstraction.atmosphericDrag.AsNativeArray<float>();
|
||||
athmosphericPressure = abstraction.atmosphericPressure.AsNativeArray<float>();
|
||||
diffusion = abstraction.diffusion.AsNativeArray<float>();
|
||||
}
|
||||
|
||||
public void SetRigidbodyArrays(ObiSolver solver)
|
||||
{
|
||||
// No need to implement. This backend grabs arrays from the abstraction when it needs them.
|
||||
}
|
||||
|
||||
public IConstraintsBatchImpl CreateConstraintsBatch(Oni.ConstraintType type)
|
||||
{
|
||||
return constraints[(int)type].CreateConstraintsBatch();
|
||||
}
|
||||
|
||||
public void DestroyConstraintsBatch(IConstraintsBatchImpl batch)
|
||||
{
|
||||
if (batch != null)
|
||||
constraints[(int)batch.constraintType].RemoveBatch(batch);
|
||||
}
|
||||
|
||||
public IObiJobHandle CollisionDetection(float stepTime)
|
||||
{
|
||||
var fluidHandle = FindFluidParticles();
|
||||
|
||||
var inertiaUpdate = RecalculateInertiaTensors(fluidHandle);
|
||||
|
||||
return jobHandlePool.Borrow().SetHandle(GenerateContacts(inertiaUpdate, stepTime));
|
||||
}
|
||||
|
||||
protected JobHandle FindFluidParticles()
|
||||
{
|
||||
var d = constraints[(int)Oni.ConstraintType.Density] as BurstDensityConstraints;
|
||||
|
||||
// Update positions:
|
||||
var findFluidJob = new FindFluidParticlesJob()
|
||||
{
|
||||
activeParticles = activeParticles,
|
||||
phases = m_Solver.phases.AsNativeArray<int>(),
|
||||
fluidParticles = d.fluidParticles,
|
||||
};
|
||||
|
||||
return findFluidJob.Schedule();
|
||||
}
|
||||
|
||||
protected JobHandle UpdateSimplexBounds(JobHandle inputDeps, float deltaTime)
|
||||
{
|
||||
var buildAabbs = new BuildSimplexAabbs
|
||||
{
|
||||
radii = principalRadii,
|
||||
fluidRadii = smoothingRadii,
|
||||
positions = positions,
|
||||
velocities = velocities,
|
||||
|
||||
simplices = simplices,
|
||||
simplexCounts = simplexCounts,
|
||||
simplexBounds = simplexBounds,
|
||||
|
||||
particleMaterialIndices = abstraction.collisionMaterials.AsNativeArray<int>(),
|
||||
collisionMaterials = ObiColliderWorld.GetInstance().collisionMaterials.AsNativeArray<BurstCollisionMaterial>(),
|
||||
collisionMargin = abstraction.parameters.collisionMargin,
|
||||
continuousCollisionDetection = abstraction.parameters.continuousCollisionDetection,
|
||||
dt = deltaTime,
|
||||
};
|
||||
return buildAabbs.Schedule(simplexCounts.simplexCount, 32, inputDeps);
|
||||
}
|
||||
|
||||
protected JobHandle GenerateContacts(JobHandle inputDeps, float deltaTime)
|
||||
{
|
||||
// Dispose of previous fluid interactions.
|
||||
// We need fluid data during interpolation, for anisotropic fluid particles. For this reason,
|
||||
// we can't dispose of these arrays in ResetForces() at the end of each full step. They must use persistent allocation.
|
||||
|
||||
if (fluidInteractions.IsCreated)
|
||||
fluidInteractions.Dispose();
|
||||
if (fluidBatchData.IsCreated)
|
||||
fluidBatchData.Dispose();
|
||||
|
||||
// get constraint parameters for constraint types that depend on broadphases:
|
||||
var collisionParameters = m_Solver.GetConstraintParameters(Oni.ConstraintType.Collision);
|
||||
var particleCollisionParameters = m_Solver.GetConstraintParameters(Oni.ConstraintType.ParticleCollision);
|
||||
var densityParameters = m_Solver.GetConstraintParameters(Oni.ConstraintType.Density);
|
||||
|
||||
// if no enabled constraints that require broadphase info, skip it entirely.
|
||||
if (collisionParameters.enabled ||
|
||||
particleCollisionParameters.enabled ||
|
||||
densityParameters.enabled)
|
||||
{
|
||||
// update the bounding box of each simplex:
|
||||
inputDeps = UpdateSimplexBounds(inputDeps, deltaTime);
|
||||
|
||||
|
||||
// generate particle-particle and particle-collider interactions in parallel:
|
||||
JobHandle generateParticleInteractionsHandle = inputDeps, generateContactsHandle = inputDeps;
|
||||
|
||||
// particle-particle interactions (contacts, fluids)
|
||||
if (particleCollisionParameters.enabled || densityParameters.enabled)
|
||||
{
|
||||
particleGrid.Update(this, deltaTime, inputDeps);
|
||||
generateParticleInteractionsHandle = particleGrid.GenerateContacts(this, deltaTime);
|
||||
}
|
||||
|
||||
// particle-collider interactions (contacts)
|
||||
if (collisionParameters.enabled)
|
||||
{
|
||||
generateContactsHandle = colliderGrid.GenerateContacts(this, deltaTime, inputDeps);
|
||||
}
|
||||
|
||||
JobHandle.CombineDependencies(generateParticleInteractionsHandle, generateContactsHandle).Complete();
|
||||
|
||||
// allocate arrays for interactions and batch data:
|
||||
particleContacts = new NativeArray<BurstContact>(particleGrid.particleContactQueue.Count, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
|
||||
particleBatchData = new NativeArray<BatchData>(maxBatches, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
|
||||
|
||||
fluidInteractions = new NativeArray<FluidInteraction>(particleGrid.fluidInteractionQueue.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
|
||||
fluidBatchData = new NativeArray<BatchData>(maxBatches, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
|
||||
|
||||
colliderContacts = new NativeArray<BurstContact>(colliderGrid.colliderContactQueue.Count, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
|
||||
|
||||
// dequeue contacts/interactions into temporary arrays:
|
||||
var rawParticleContacts = new NativeArray<BurstContact>(particleGrid.particleContactQueue.Count, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
|
||||
var sortedParticleContacts = new NativeArray<BurstContact>(particleGrid.particleContactQueue.Count, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
|
||||
var rawFluidInteractions = new NativeArray<FluidInteraction>(particleGrid.fluidInteractionQueue.Count, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
|
||||
|
||||
DequeueIntoArrayJob<BurstContact> dequeueParticleContacts = new DequeueIntoArrayJob<BurstContact>()
|
||||
{
|
||||
InputQueue = particleGrid.particleContactQueue,
|
||||
OutputArray = rawParticleContacts
|
||||
};
|
||||
|
||||
DequeueIntoArrayJob<FluidInteraction> dequeueFluidInteractions = new DequeueIntoArrayJob<FluidInteraction>()
|
||||
{
|
||||
InputQueue = particleGrid.fluidInteractionQueue,
|
||||
OutputArray = rawFluidInteractions
|
||||
};
|
||||
|
||||
DequeueIntoArrayJob<BurstContact> dequeueColliderContacts = new DequeueIntoArrayJob<BurstContact>()
|
||||
{
|
||||
InputQueue = colliderGrid.colliderContactQueue,
|
||||
OutputArray = colliderContacts
|
||||
};
|
||||
|
||||
var dequeueHandle = JobHandle.CombineDependencies(dequeueParticleContacts.Schedule(), dequeueFluidInteractions.Schedule(), dequeueColliderContacts.Schedule());
|
||||
|
||||
// Sort contacts for jitter-free gauss-seidel (sequential) solving:
|
||||
dequeueHandle = contactSorter.SortConstraints(simplexCounts.simplexCount, rawParticleContacts, ref sortedParticleContacts, dequeueHandle);
|
||||
|
||||
ContactProvider contactProvider = new ContactProvider()
|
||||
{
|
||||
contacts = sortedParticleContacts,
|
||||
sortedContacts = particleContacts,
|
||||
simplices = simplices,
|
||||
simplexCounts = simplexCounts
|
||||
};
|
||||
|
||||
FluidInteractionProvider fluidProvider = new FluidInteractionProvider()
|
||||
{
|
||||
interactions = rawFluidInteractions,
|
||||
sortedInteractions = fluidInteractions,
|
||||
};
|
||||
|
||||
// batch particle contacts:
|
||||
var activeParticleBatchCount = new NativeArray<int>(1, Allocator.TempJob);
|
||||
var particleBatchHandle = collisionConstraintBatcher.BatchConstraints(ref contactProvider, particleCount, ref particleBatchData, ref activeParticleBatchCount, dequeueHandle);
|
||||
|
||||
// batch fluid interactions:
|
||||
var activeFluidBatchCount = new NativeArray<int>(1, Allocator.TempJob);
|
||||
var fluidBatchHandle = fluidConstraintBatcher.BatchConstraints(ref fluidProvider, particleCount, ref fluidBatchData, ref activeFluidBatchCount, dequeueHandle);
|
||||
|
||||
JobHandle.CombineDependencies(particleBatchHandle, fluidBatchHandle).Complete();
|
||||
|
||||
// Generate particle contact/friction batches:
|
||||
var pc = constraints[(int)Oni.ConstraintType.ParticleCollision] as BurstParticleCollisionConstraints;
|
||||
var pf = constraints[(int)Oni.ConstraintType.ParticleFriction] as BurstParticleFrictionConstraints;
|
||||
|
||||
for (int i = 0; i < pc.batches.Count; ++i)
|
||||
pc.batches[i].enabled = false;
|
||||
|
||||
for (int i = 0; i < pf.batches.Count; ++i)
|
||||
pf.batches[i].enabled = false;
|
||||
|
||||
for (int i = 0; i < activeParticleBatchCount[0]; ++i)
|
||||
{
|
||||
// create extra batches if not enough:
|
||||
if (i == pc.batches.Count)
|
||||
{
|
||||
pc.CreateConstraintsBatch();
|
||||
pf.CreateConstraintsBatch();
|
||||
}
|
||||
|
||||
pc.batches[i].enabled = true;
|
||||
pf.batches[i].enabled = true;
|
||||
|
||||
(pc.batches[i] as BurstParticleCollisionConstraintsBatch).batchData = particleBatchData[i];
|
||||
(pf.batches[i] as BurstParticleFrictionConstraintsBatch ).batchData = particleBatchData[i];
|
||||
}
|
||||
|
||||
// Generate fluid interaction batches:
|
||||
var dc = constraints[(int)Oni.ConstraintType.Density] as BurstDensityConstraints;
|
||||
|
||||
for (int i = 0; i < dc.batches.Count; ++i)
|
||||
dc.batches[i].enabled = false;
|
||||
|
||||
for (int i = 0; i < activeFluidBatchCount[0]; ++i)
|
||||
{
|
||||
// create extra batches if not enough:
|
||||
if (i == dc.batches.Count)
|
||||
dc.CreateConstraintsBatch();
|
||||
|
||||
dc.batches[i].enabled = true;
|
||||
|
||||
(dc.batches[i] as BurstDensityConstraintsBatch).batchData = fluidBatchData[i];
|
||||
}
|
||||
|
||||
// dispose of temporary buffers:
|
||||
rawParticleContacts.Dispose();
|
||||
rawFluidInteractions.Dispose();
|
||||
sortedParticleContacts.Dispose();
|
||||
activeParticleBatchCount.Dispose();
|
||||
activeFluidBatchCount.Dispose();
|
||||
|
||||
}
|
||||
|
||||
return inputDeps;
|
||||
}
|
||||
|
||||
public IObiJobHandle Substep(float stepTime, float substepTime, int substeps)
|
||||
{
|
||||
// Apply aerodynamics
|
||||
JobHandle aerodynamicsHandle = constraints[(int)Oni.ConstraintType.Aerodynamics].Project(new JobHandle(), stepTime, substepTime, substeps);
|
||||
|
||||
// Predict positions:
|
||||
var predictPositions = new PredictPositionsJob()
|
||||
{
|
||||
activeParticles = activeParticles,
|
||||
phases = phases,
|
||||
buoyancies = buoyancies,
|
||||
|
||||
externalForces = externalForces,
|
||||
inverseMasses = invMasses,
|
||||
positions = positions,
|
||||
previousPositions = prevPositions,
|
||||
velocities = velocities,
|
||||
|
||||
externalTorques = externalTorques,
|
||||
inverseRotationalMasses = invRotationalMasses,
|
||||
orientations = orientations,
|
||||
previousOrientations = prevOrientations,
|
||||
angularVelocities = angularVelocities,
|
||||
|
||||
gravity = new float4(m_Solver.parameters.gravity, 0),
|
||||
deltaTime = substepTime,
|
||||
is2D = abstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D
|
||||
};
|
||||
|
||||
JobHandle predictPositionsHandle = predictPositions.Schedule(activeParticles.Length, 128, aerodynamicsHandle);
|
||||
|
||||
// Project position constraints:
|
||||
JobHandle projectionHandle = ApplyConstraints(predictPositionsHandle, stepTime, substepTime, substeps);
|
||||
|
||||
// Update velocities:
|
||||
var updateVelocitiesJob = new UpdateVelocitiesJob()
|
||||
{
|
||||
activeParticles = activeParticles,
|
||||
|
||||
inverseMasses = invMasses,
|
||||
previousPositions = prevPositions,
|
||||
positions = positions,
|
||||
velocities = velocities,
|
||||
|
||||
inverseRotationalMasses = invRotationalMasses,
|
||||
previousOrientations = prevOrientations,
|
||||
orientations = orientations,
|
||||
angularVelocities = angularVelocities,
|
||||
|
||||
deltaTime = substepTime,
|
||||
is2D = abstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D
|
||||
};
|
||||
|
||||
JobHandle updateVelocitiesHandle = updateVelocitiesJob.Schedule(activeParticles.Length, 128, projectionHandle);
|
||||
|
||||
// velocity constraints:
|
||||
JobHandle velocityCorrectionsHandle = ApplyVelocityCorrections(updateVelocitiesHandle, substepTime);
|
||||
|
||||
// Update positions:
|
||||
var updatePositionsJob = new UpdatePositionsJob()
|
||||
{
|
||||
activeParticles = activeParticles,
|
||||
positions = positions,
|
||||
previousPositions = prevPositions,
|
||||
velocities = velocities,
|
||||
orientations = orientations,
|
||||
previousOrientations = prevOrientations,
|
||||
angularVelocities = angularVelocities,
|
||||
velocityScale = math.pow(1 - math.clamp(m_Solver.parameters.damping, 0, 1), substepTime),
|
||||
sleepThreshold = m_Solver.parameters.sleepThreshold
|
||||
};
|
||||
|
||||
JobHandle updatePositionsHandle = updatePositionsJob.Schedule(activeParticles.Length, 128, velocityCorrectionsHandle);
|
||||
|
||||
return jobHandlePool.Borrow().SetHandle(updatePositionsHandle);
|
||||
}
|
||||
|
||||
private JobHandle ApplyVelocityCorrections(JobHandle inputDeps, float deltaTime)
|
||||
{
|
||||
var densityParameters = m_Solver.GetConstraintParameters(Oni.ConstraintType.Density);
|
||||
|
||||
if (densityParameters.enabled)
|
||||
{
|
||||
var d = constraints[(int)Oni.ConstraintType.Density] as BurstDensityConstraints;
|
||||
if (d != null)
|
||||
{
|
||||
return d.ApplyVelocityCorrections(inputDeps, deltaTime);
|
||||
}
|
||||
}
|
||||
return inputDeps;
|
||||
}
|
||||
|
||||
private JobHandle ApplyConstraints(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
|
||||
{
|
||||
|
||||
// calculate max amount of iterations required, and initialize constraints..
|
||||
int maxIterations = 0;
|
||||
for (int i = 0; i < Oni.ConstraintTypeCount; ++i)
|
||||
{
|
||||
var parameters = m_Solver.GetConstraintParameters((Oni.ConstraintType)i);
|
||||
if (parameters.enabled)
|
||||
{
|
||||
maxIterations = math.max(maxIterations, parameters.iterations);
|
||||
inputDeps = constraints[i].Initialize(inputDeps, substepTime);
|
||||
}
|
||||
}
|
||||
|
||||
// calculate iteration paddings:
|
||||
for (int i = 0; i < Oni.ConstraintTypeCount; ++i)
|
||||
{
|
||||
var parameters = m_Solver.GetConstraintParameters((Oni.ConstraintType)i);
|
||||
if (parameters.enabled && parameters.iterations > 0)
|
||||
padding[i] = (int)math.ceil(maxIterations / (float)parameters.iterations);
|
||||
else
|
||||
padding[i] = maxIterations;
|
||||
}
|
||||
|
||||
// perform projection iterations:
|
||||
for (int i = 1; i < maxIterations; ++i)
|
||||
{
|
||||
for (int j = 0; j < Oni.ConstraintTypeCount; ++j)
|
||||
{
|
||||
if (j != (int)Oni.ConstraintType.Aerodynamics)
|
||||
{
|
||||
var parameters = m_Solver.GetConstraintParameters((Oni.ConstraintType)j);
|
||||
if (parameters.enabled && i % padding[j] == 0)
|
||||
inputDeps = constraints[j].Project(inputDeps, stepTime, substepTime, substeps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// final iteration, all groups together:
|
||||
for (int i = 0; i < Oni.ConstraintTypeCount; ++i)
|
||||
{
|
||||
if (i != (int)Oni.ConstraintType.Aerodynamics)
|
||||
{
|
||||
var parameters = m_Solver.GetConstraintParameters((Oni.ConstraintType)i);
|
||||
if (parameters.enabled && parameters.iterations > 0)
|
||||
inputDeps = constraints[i].Project(inputDeps, stepTime, substepTime, substeps);
|
||||
}
|
||||
}
|
||||
|
||||
// Despite friction constraints being applied after collision (since coulomb friction depends on normal impulse)
|
||||
// we perform a collision iteration right at the end to ensure the final state meets the Signorini-Fichera conditions.
|
||||
var param = m_Solver.GetConstraintParameters(Oni.ConstraintType.ParticleCollision);
|
||||
if (param.enabled && param.iterations > 0)
|
||||
inputDeps = constraints[(int)Oni.ConstraintType.ParticleCollision].Project(inputDeps, stepTime, substepTime, substeps);
|
||||
param = m_Solver.GetConstraintParameters(Oni.ConstraintType.Collision);
|
||||
if (param.enabled && param.iterations > 0)
|
||||
inputDeps = constraints[(int)Oni.ConstraintType.Collision].Project(inputDeps, stepTime, substepTime, substeps);
|
||||
|
||||
return inputDeps;
|
||||
}
|
||||
|
||||
public void ApplyInterpolation(ObiNativeVector4List startPositions, ObiNativeQuaternionList startOrientations, float stepTime, float unsimulatedTime)
|
||||
{
|
||||
|
||||
// Interpolate particle positions and orientations.
|
||||
var interpolate = new InterpolationJob()
|
||||
{
|
||||
positions = positions,
|
||||
startPositions = startPositions.AsNativeArray<float4>(),
|
||||
renderablePositions = renderablePositions,
|
||||
|
||||
orientations = orientations,
|
||||
startOrientations = startOrientations.AsNativeArray<quaternion>(),
|
||||
renderableOrientations = renderableOrientations,
|
||||
|
||||
deltaTime = stepTime,
|
||||
unsimulatedTime = unsimulatedTime,
|
||||
interpolationMode = m_Solver.parameters.interpolation
|
||||
};
|
||||
|
||||
JobHandle jobHandle = interpolate.Schedule(m_Solver.positions.count, 128);
|
||||
|
||||
// Update deformable triangle normals
|
||||
var updateNormals = new UpdateNormalsJob()
|
||||
{
|
||||
renderPositions = renderablePositions,
|
||||
deformableTriangles = deformableTriangles,
|
||||
normals = normals
|
||||
};
|
||||
|
||||
jobHandle = updateNormals.Schedule(jobHandle);
|
||||
|
||||
// fluid laplacian/anisotropy:
|
||||
var d = constraints[(int)Oni.ConstraintType.Density] as BurstDensityConstraints;
|
||||
if (d != null)
|
||||
jobHandle = d.CalculateAnisotropyLaplacianSmoothing(jobHandle);
|
||||
|
||||
// update axis:
|
||||
var updatePrincipalAxis = new UpdatePrincipalAxisJob()
|
||||
{
|
||||
activeParticles = activeParticles,
|
||||
renderableOrientations = renderableOrientations,
|
||||
phases = phases,
|
||||
principalRadii = principalRadii,
|
||||
principalAxis = anisotropies,
|
||||
};
|
||||
|
||||
jobHandle = updatePrincipalAxis.Schedule(activeParticles.Length, 128, jobHandle);
|
||||
|
||||
jobHandle.Complete();
|
||||
|
||||
}
|
||||
|
||||
public void InterpolateDiffuseProperties(ObiNativeVector4List properties,
|
||||
ObiNativeVector4List diffusePositions,
|
||||
ObiNativeVector4List diffuseProperties,
|
||||
ObiNativeIntList neighbourCount,
|
||||
int diffuseCount)
|
||||
{
|
||||
particleGrid.InterpolateDiffuseProperties(this,
|
||||
properties.AsNativeArray<float4>(),
|
||||
diffusePositions.AsNativeArray<float4>(),
|
||||
diffuseProperties.AsNativeArray<float4>(),
|
||||
neighbourCount.AsNativeArray<int>(),
|
||||
diffuseCount).Complete();
|
||||
}
|
||||
|
||||
public void SpatialQuery(ObiNativeQueryShapeList shapes, ObiNativeAffineTransformList transforms, ObiNativeQueryResultList results)
|
||||
{
|
||||
var resultsQueue = new NativeQueue<BurstQueryResult>(Allocator.Persistent);
|
||||
|
||||
particleGrid.SpatialQuery(this,
|
||||
shapes.AsNativeArray<BurstQueryShape>(),
|
||||
transforms.AsNativeArray<BurstAffineTransform>(),
|
||||
resultsQueue).Complete();
|
||||
|
||||
int count = resultsQueue.Count;
|
||||
results.ResizeUninitialized(count);
|
||||
|
||||
var dequeueQueryResults = new DequeueIntoArrayJob<BurstQueryResult>()
|
||||
{
|
||||
InputQueue = resultsQueue,
|
||||
OutputArray = results.AsNativeArray<BurstQueryResult>()
|
||||
};
|
||||
|
||||
var dequeueHandle = dequeueQueryResults.Schedule();
|
||||
|
||||
var distanceJob = new CalculateQueryDistances()
|
||||
{
|
||||
prevPositions = prevPositions,
|
||||
prevOrientations = prevOrientations,
|
||||
radii = principalRadii,
|
||||
simplices = simplices,
|
||||
simplexCounts = simplexCounts,
|
||||
queryResults = results.AsNativeArray<BurstQueryResult>()
|
||||
};
|
||||
|
||||
distanceJob.Schedule(count, 16, dequeueHandle).Complete();
|
||||
|
||||
resultsQueue.Dispose();
|
||||
}
|
||||
|
||||
public int GetParticleGridSize()
|
||||
{
|
||||
return particleGrid.grid.usedCells.Length;
|
||||
}
|
||||
public void GetParticleGrid(ObiNativeAabbList cells)
|
||||
{
|
||||
particleGrid.GetCells(cells);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d37e8b7fe851346debbbd28e17c1e593
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,26 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using Unity.Burst;
|
||||
using Unity.Jobs;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
[BurstCompile]
|
||||
public struct DequeueIntoArrayJob<T> : IJob where T : unmanaged
|
||||
{
|
||||
public int StartIndex;
|
||||
public NativeQueue<T> InputQueue;
|
||||
[WriteOnly] public NativeArray<T> OutputArray;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
int queueCount = InputQueue.Count;
|
||||
|
||||
for (int i = StartIndex; i < StartIndex + queueCount; i++)
|
||||
{
|
||||
OutputArray[i] = InputQueue.Dequeue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e9889084567047d389e79cf39fc3391
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
#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]
|
||||
struct FindFluidParticlesJob : IJob
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> activeParticles;
|
||||
[ReadOnly] public NativeArray<int> phases;
|
||||
|
||||
public NativeList<int> fluidParticles;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
fluidParticles.Clear();
|
||||
|
||||
for (int i = 0; i < activeParticles.Length; ++i)
|
||||
{
|
||||
int p = activeParticles[i];
|
||||
if ((phases[p] & (int)ObiUtils.ParticleFlags.Fluid) != 0)
|
||||
fluidParticles.Add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 58485b95b70f24a809a8f9509faabdad
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,42 @@
|
||||
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
||||
using Unity.Jobs;
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Burst;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
[BurstCompile]
|
||||
struct InterpolationJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<float4> startPositions;
|
||||
[ReadOnly] public NativeArray<float4> positions;
|
||||
[WriteOnly] public NativeArray<float4> renderablePositions;
|
||||
|
||||
[ReadOnly] public NativeArray<quaternion> startOrientations;
|
||||
[ReadOnly] public NativeArray<quaternion> orientations;
|
||||
[WriteOnly] public NativeArray<quaternion> renderableOrientations;
|
||||
|
||||
[ReadOnly] public float deltaTime;
|
||||
[ReadOnly] public float unsimulatedTime;
|
||||
[ReadOnly] public Oni.SolverParameters.Interpolation interpolationMode;
|
||||
|
||||
// The code actually running on the job
|
||||
public void Execute(int i)
|
||||
{
|
||||
if (interpolationMode == Oni.SolverParameters.Interpolation.Interpolate && deltaTime > 0)
|
||||
{
|
||||
float alpha = unsimulatedTime / deltaTime;
|
||||
|
||||
renderablePositions[i] = math.lerp(startPositions[i], positions[i], alpha);
|
||||
renderableOrientations[i] = math.normalize(math.slerp(startOrientations[i], orientations[i], alpha));
|
||||
}
|
||||
else
|
||||
{
|
||||
renderablePositions[i] = positions[i];
|
||||
renderableOrientations[i] = math.normalize(orientations[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8928e13e186424d31a319347de871c16
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,82 @@
|
||||
#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]
|
||||
struct PredictPositionsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> activeParticles;
|
||||
[ReadOnly] public NativeArray<int> phases;
|
||||
[ReadOnly] public NativeArray<float> buoyancies;
|
||||
|
||||
// linear/position properties:
|
||||
[ReadOnly] public NativeArray<float4> externalForces;
|
||||
[ReadOnly] public NativeArray<float> inverseMasses;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float4> previousPositions;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float4> positions;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float4> velocities;
|
||||
|
||||
// angular/orientation properties:
|
||||
[ReadOnly] public NativeArray<float4> externalTorques;
|
||||
[ReadOnly] public NativeArray<float> inverseRotationalMasses;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<quaternion> previousOrientations;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<quaternion> orientations;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float4> angularVelocities;
|
||||
|
||||
[ReadOnly] public float4 gravity;
|
||||
[ReadOnly] public float deltaTime;
|
||||
[ReadOnly] public bool is2D;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
int i = activeParticles[index];
|
||||
|
||||
// the previous position/orientation is the current position/orientation at the start of the step.
|
||||
previousPositions[i] = positions[i];
|
||||
previousOrientations[i] = orientations[i];
|
||||
|
||||
if (inverseMasses[i] > 0)
|
||||
{
|
||||
float4 effectiveGravity = gravity;
|
||||
|
||||
// Adjust gravity for buoyant fluid particles:
|
||||
if ((phases[i] & (int)ObiUtils.ParticleFlags.Fluid) != 0)
|
||||
effectiveGravity *= -buoyancies[i];
|
||||
|
||||
// apply external forces and gravity:
|
||||
float4 vel = velocities[i] + (inverseMasses[i] * externalForces[i] + effectiveGravity) * deltaTime;
|
||||
|
||||
// project velocity to 2D plane if needed:
|
||||
if (is2D)
|
||||
vel[3] = 0;
|
||||
|
||||
velocities[i] = vel;
|
||||
}
|
||||
|
||||
if (inverseRotationalMasses[i] > 0)
|
||||
{
|
||||
// apply external torques (simplification: we don't use full inertia tensor here)
|
||||
float4 angularVel = angularVelocities[i] + inverseRotationalMasses[i] * externalTorques[i] * deltaTime;
|
||||
|
||||
// project angular velocity to 2D plane normal if needed:
|
||||
if (is2D)
|
||||
angularVel = angularVel.project(new float4(0, 0, 1, 0));
|
||||
|
||||
angularVelocities[i] = angularVel;
|
||||
}
|
||||
|
||||
// integrate velocities:
|
||||
positions[i] = BurstIntegration.IntegrateLinear(positions[i], velocities[i], deltaTime);
|
||||
orientations[i] = BurstIntegration.IntegrateAngular(orientations[i], angularVelocities[i], deltaTime);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fcd4a6f15c3844229a95fa41f283d408
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,38 @@
|
||||
#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]
|
||||
struct UpdateInertiaTensorsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> activeParticles;
|
||||
|
||||
[ReadOnly] public NativeArray<float> inverseMasses;
|
||||
[ReadOnly] public NativeArray<float> inverseRotationalMasses;
|
||||
[ReadOnly] public NativeArray<float4> principalRadii;
|
||||
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float4> inverseInertiaTensors;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
int i = activeParticles[index];
|
||||
|
||||
float4 sqrRadii = principalRadii[i] * principalRadii[i];
|
||||
|
||||
inverseInertiaTensors[i] = 5 * inverseRotationalMasses[i] * new float4(
|
||||
1 / math.max(sqrRadii[1] + sqrRadii[2], BurstMath.epsilon),
|
||||
1 / math.max(sqrRadii[0] + sqrRadii[2], BurstMath.epsilon),
|
||||
1 / math.max(sqrRadii[0] + sqrRadii[1], BurstMath.epsilon),
|
||||
0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fac27eeae85e84131bebdf89ad1d6802
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,43 @@
|
||||
#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]
|
||||
struct UpdateNormalsJob : IJob
|
||||
{
|
||||
[ReadOnly] public NativeList<int> deformableTriangles;
|
||||
[ReadOnly] public NativeArray<float4> renderPositions;
|
||||
public NativeArray<float4> normals;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
for (int i = 0; i < normals.Length; ++i)
|
||||
normals[i] = float4.zero;
|
||||
|
||||
// Accumulate normals:
|
||||
for (int i = 0; i < deformableTriangles.Length; i += 3)
|
||||
{
|
||||
float4 v1 = renderPositions[deformableTriangles[i]];
|
||||
float4 v2 = renderPositions[deformableTriangles[i + 1]];
|
||||
float4 v3 = renderPositions[deformableTriangles[i + 2]];
|
||||
|
||||
float4 n = new float4(math.cross((v2 - v1).xyz, (v3 - v1).xyz), 0);
|
||||
|
||||
normals[deformableTriangles[i]] += n;
|
||||
normals[deformableTriangles[i + 1]] += n;
|
||||
normals[deformableTriangles[i + 2]] += n;
|
||||
}
|
||||
|
||||
for (int i = 0; i < normals.Length; ++i)
|
||||
normals[i] = math.normalizesafe(normals[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c46e86e164afb414fbc171972a53eb91
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,51 @@
|
||||
#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]
|
||||
struct UpdatePositionsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> activeParticles;
|
||||
|
||||
// linear/position properties:
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float4> positions;
|
||||
[ReadOnly] public NativeArray<float4> previousPositions;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float4> velocities;
|
||||
|
||||
// angular/orientation properties:
|
||||
[NativeDisableParallelForRestriction] public NativeArray<quaternion> orientations;
|
||||
[ReadOnly] public NativeArray<quaternion> previousOrientations;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float4> angularVelocities;
|
||||
|
||||
[ReadOnly] public float velocityScale;
|
||||
[ReadOnly] public float sleepThreshold;
|
||||
|
||||
// The code actually running on the job
|
||||
public void Execute(int index)
|
||||
{
|
||||
int i = activeParticles[index];
|
||||
|
||||
// damp velocities:
|
||||
velocities[i] *= velocityScale;
|
||||
angularVelocities[i] *= velocityScale;
|
||||
|
||||
// if the kinetic energy is below the sleep threshold, keep the particle at its previous position.
|
||||
if (math.lengthsq(velocities[i]) * 0.5f + math.lengthsq(angularVelocities[i]) * 0.5f <= sleepThreshold)
|
||||
{
|
||||
positions[i] = previousPositions[i];
|
||||
orientations[i] = previousOrientations[i];
|
||||
velocities[i] = float4.zero;
|
||||
angularVelocities[i] = float4.zero;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a41d3897adb37457da8385a46e6f0bb6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,50 @@
|
||||
#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]
|
||||
struct UpdatePrincipalAxisJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> activeParticles;
|
||||
[ReadOnly] public NativeArray<quaternion> renderableOrientations;
|
||||
[ReadOnly] public NativeArray<int> phases;
|
||||
[ReadOnly] public NativeArray<float4> principalRadii;
|
||||
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float4> principalAxis;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
int i = activeParticles[index];
|
||||
|
||||
// fluid particles get their principal axes from the neighborhood matrix, so skip them.
|
||||
if ((phases[i] & (int)ObiUtils.ParticleFlags.Fluid) == 0)
|
||||
{
|
||||
int i3 = i * 3;
|
||||
float4x4 rot = renderableOrientations[i].toMatrix();
|
||||
|
||||
// set axis direction:
|
||||
float4 pAxis1 = rot.c0;
|
||||
float4 pAxis2 = rot.c1;
|
||||
float4 pAxis3 = rot.c2;
|
||||
|
||||
// set axis length:
|
||||
pAxis1[3] = principalRadii[i][0];
|
||||
pAxis2[3] = principalRadii[i][1];
|
||||
pAxis3[3] = principalRadii[i][2];
|
||||
|
||||
principalAxis[i3] = pAxis1;
|
||||
principalAxis[i3+1] = pAxis2;
|
||||
principalAxis[i3+2] = pAxis3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22028834877974573b3b29b8a2b8f6cc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,58 @@
|
||||
#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]
|
||||
struct UpdateVelocitiesJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> activeParticles;
|
||||
|
||||
// linear/position properties:
|
||||
[ReadOnly] public NativeArray<float> inverseMasses;
|
||||
[ReadOnly] public NativeArray<float4> previousPositions;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<float4> positions;
|
||||
[NativeDisableParallelForRestriction] [WriteOnly] public NativeArray<float4> velocities;
|
||||
|
||||
// angular/orientation properties:
|
||||
[ReadOnly] public NativeArray<float> inverseRotationalMasses;
|
||||
[ReadOnly] public NativeArray<quaternion> previousOrientations;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<quaternion> orientations;
|
||||
[NativeDisableParallelForRestriction] [WriteOnly] public NativeArray<float4> angularVelocities;
|
||||
|
||||
[ReadOnly] public float deltaTime;
|
||||
[ReadOnly] public bool is2D;
|
||||
|
||||
// The code actually running on the job
|
||||
public void Execute(int index)
|
||||
{
|
||||
int i = activeParticles[index];
|
||||
|
||||
// Project particles on the XY plane if we are in 2D mode:
|
||||
if (is2D)
|
||||
{
|
||||
// restrict position to the 2D plane
|
||||
float4 pos = positions[i];
|
||||
pos[2] = previousPositions[i][2];
|
||||
positions[i] = pos;
|
||||
}
|
||||
|
||||
if (inverseMasses[i] > 0)
|
||||
velocities[i] = BurstIntegration.DifferentiateLinear(positions[i], previousPositions[i], deltaTime);
|
||||
else
|
||||
velocities[i] = float4.zero;
|
||||
|
||||
if (inverseRotationalMasses[i] > 0)
|
||||
angularVelocities[i] = BurstIntegration.DifferentiateAngular(orientations[i], previousOrientations[i], deltaTime);
|
||||
else
|
||||
angularVelocities[i] = float4.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d10fd506f9f2645ecbf2d61a4634a5ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user