添加插件

This commit is contained in:
2025-11-10 00:08:26 +08:00
parent 4059c207c0
commit 76f80db694
2814 changed files with 436400 additions and 178 deletions

View File

@@ -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 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;
[NativeDisableParallelForRestriction] public NativeArray<float4> wind;
[ReadOnly] public float deltaTime;
[ReadOnly] public float4 ambientWind;
[ReadOnly] public BurstInertialFrame inertialFrame;
[ReadOnly] public bool inertialWind;
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;
}
wind[i] = ambientWind;
if (inertialWind)
{
float4 wsPos = inertialFrame.frame.TransformPoint(positions[i]);
wind[i] -= inertialFrame.frame.InverseTransformVector(inertialFrame.VelocityAtPoint(wsPos));
}
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,87 @@
#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 CalculateSimplexBoundsJob : IJobParallelFor
{
[ReadOnly] public NativeArray<float4> radii;
[ReadOnly] public NativeArray<float4> fluidMaterials;
[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;
public NativeArray<BurstAabb> simplexBounds;
public NativeArray<BurstAabb> reducedBounds;
[ReadOnly] public Oni.SolverParameters parameters;
[ReadOnly] public float dt;
public void Execute(int i)
{
int simplexStart = simplexCounts.GetSimplexStartAndSize(i, out int simplexSize);
var sxBounds = new BurstAabb(float.MaxValue, float.MinValue);
var soBounds = new BurstAabb(float.MaxValue, float.MinValue);
for (int j = 0; j < simplexSize; ++j)
{
int p = simplices[simplexStart + j];
int m = particleMaterialIndices[p];
float solidRadius = radii[p].x + (m >= 0 ? collisionMaterials[m].stickDistance : 0);
// Expand simplex bounds, using both the particle's original position and its velocity.
// Add collision margin for both fluid neighborhood too (prevents explosions at high pressures due to neighborhood deficiency)
sxBounds.EncapsulateParticle(positions[p],
BurstIntegration.IntegrateLinear(positions[p], velocities[p], dt * parameters.particleCCD),
math.max(solidRadius, fluidMaterials[p].x * 0.5f) + parameters.collisionMargin);
soBounds.EncapsulateParticle(positions[p],
BurstIntegration.IntegrateLinear(positions[p], velocities[p], dt),
solidRadius);
}
simplexBounds[i] = sxBounds;
reducedBounds[i] = soBounds;
}
}
[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

View File

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

File diff suppressed because one or more lines are too long

View File

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

View File

@@ -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

View File

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

View File

@@ -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 EnforceLimitsJob : IJobParallelFor
{
[NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableParallelForRestriction] public NativeArray<float4> prevPositions;
[NativeDisableParallelForRestriction] public NativeArray<float> life;
[ReadOnly] public NativeArray<int> phases;
[ReadOnly] public NativeArray<int> activeParticles;
[ReadOnly] public bool killOffLimits;
[ReadOnly] public BurstAabb boundaryLimits;
public void Execute(int index)
{
int i = activeParticles[index];
float4 pos = positions[i];
float4 prevPos = prevPositions[i];
bool outside = math.any(math.step(pos, boundaryLimits.min).xyz + math.step(boundaryLimits.max, pos).xyz);
if ((phases[i] & (int)ObiUtils.ParticleFlags.Isolated) != 0)
life[i] = outside && killOffLimits ? 0 : life[i];
pos.xyz = math.clamp(pos, boundaryLimits.min, boundaryLimits.max).xyz;
prevPos.xyz = math.clamp(prevPos, boundaryLimits.min, boundaryLimits.max).xyz;
positions[i] = pos;
prevPositions[i] = prevPos;
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,33 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using 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

View File

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

View File

@@ -0,0 +1,361 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using Unity.Jobs;
using Unity.Collections;
using Unity.Mathematics;
using Unity.Burst;
using Unity.Collections.LowLevel.Unsafe;
using System.Threading;
namespace Obi
{
[BurstCompile]
unsafe struct EmitParticlesJob : IJobParallelFor
{
[NativeDisableParallelForRestriction] public NativeArray<float4> outputPositions;
[NativeDisableParallelForRestriction] public NativeArray<float4> outputVelocities;
[NativeDisableParallelForRestriction] public NativeArray<float4> outputColors;
[NativeDisableParallelForRestriction] public NativeArray<float4> outputAttributes;
[NativeDisableParallelForRestriction] public NativeArray<int> dispatchBuffer;
public uint emitterShape;
public float4 emitterPosition;
public quaternion emitterRotation;
public float4 emitterSize;
public float lifetime;
public float lifetimeRandom;
public float particleSize;
public float sizeRandom;
public float buoyancy;
public float drag;
public float airdrag;
public float airAging;
public float isosurface;
public float4 foamColor;
public float randomSeed;
public float deltaTime;
public void Execute(int i)
{
int* dispatch = (int*)dispatchBuffer.GetUnsafePtr();
// atomically increment alive particle counter:
int count = Interlocked.Add(ref dispatch[3], 1) - 1;
if (count < outputPositions.Length)
{
// initialize foam particle in a random position inside the cylinder spawned by fluid particle:
float3 radialVelocity;
float4 pos;
if (emitterShape == 0)
BurstMath.RandomInCylinder(randomSeed + i, -new float4(0, 1, 0, 0) * emitterSize.y * 0.5f, new float4(0, 1, 0, 0), emitterSize.y, math.max(emitterSize.x, emitterSize.z) * 0.5f, out pos, out radialVelocity);
else
BurstMath.RandomInBox(randomSeed + i, float4.zero, emitterSize, out pos, out radialVelocity);
float2 random = BurstMath.Hash21(randomSeed - i);
// calculate initial life/size/color:
float initialLife = math.max (0, lifetime - lifetime * random.x * lifetimeRandom);
float initialSize = particleSize - particleSize * random.y * sizeRandom;
outputPositions[count] = new float4(emitterPosition.xyz + math.rotate(emitterRotation, pos.xyz), 0);
outputVelocities[count] = new float4(0,0,0, buoyancy);
outputColors[count] = foamColor;
outputAttributes[count] = new float4(1, 1 / initialLife, initialSize, BurstMath.PackFloatRGBA(new float4(airAging / 50.0f, airdrag, drag, isosurface)));
}
}
}
[BurstCompile]
unsafe struct GenerateParticlesJob : IJobParallelFor
{
[ReadOnly] [DeallocateOnJobCompletion] public NativeArray<int> activeParticles;
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float4> velocities;
[ReadOnly] public NativeArray<float4> principalRadii;
[ReadOnly] public NativeArray<float4> fluidData;
[NativeDisableParallelForRestriction] public NativeArray<float4> angularVelocities;
[NativeDisableParallelForRestriction] public NativeArray<float4> outputPositions;
[NativeDisableParallelForRestriction] public NativeArray<float4> outputVelocities;
[NativeDisableParallelForRestriction] public NativeArray<float4> outputColors;
[NativeDisableParallelForRestriction] public NativeArray<float4> outputAttributes;
[NativeDisableParallelForRestriction] public NativeArray<int> dispatchBuffer;
public float2 vorticityRange;
public float2 velocityRange;
public float potentialIncrease;
public float potentialDiffusion;
public float foamGenerationRate;
public float lifetime;
public float lifetimeRandom;
public float particleSize;
public float sizeRandom;
public float buoyancy;
public float drag;
public float airdrag;
public float airAging;
public float isosurface;
public float4 foamColor;
public float randomSeed;
public float deltaTime;
public void Execute(int i)
{
int* dispatch = (int*)dispatchBuffer.GetUnsafePtr();
int p = activeParticles[i];
float4 angVel = angularVelocities[p];
float2 potential = BurstMath.UnpackFloatRG(angVel.w);
// calculate foam potential increase:
float vorticityPotential = BurstMath.Remap01(fluidData[p].z, vorticityRange.x, vorticityRange.y);
float velocityPotential = BurstMath.Remap01(math.length(velocities[p].xyz), velocityRange.x, velocityRange.y);
float potentialDelta = velocityPotential * vorticityPotential * deltaTime * potentialIncrease;
// update foam potential:
potential.y = math.saturate(potential.y * potentialDiffusion + potentialDelta);
// calculate amount of emitted particles
potential.x += foamGenerationRate * potential.y * deltaTime;
int emitCount = (int)potential.x;
potential.x -= emitCount;
for (int j = 0; j < emitCount; ++j)
{
// atomically increment alive particle counter:
int count = Interlocked.Add(ref dispatch[3], 1) - 1;
if (count < outputPositions.Length)
{
// initialize foam particle in a random position inside the cylinder spawned by fluid particle:
float3 radialVelocity;
float4 pos;
BurstMath.RandomInCylinder(randomSeed + p + j, positions[p], math.normalizesafe(velocities[p]), math.length(velocities[p]) * deltaTime, principalRadii[p].x, out pos, out radialVelocity);
float2 random = BurstMath.Hash21(randomSeed - p - j);
// calculate initial life/size/color:
float initialLife = velocityPotential * (lifetime - lifetime * random.x * lifetimeRandom);
float initialSize = particleSize - particleSize * random.y * sizeRandom;
outputPositions[count] = pos;
outputVelocities[count] = velocities[p] + new float4(radialVelocity, buoyancy);
outputColors[count] = foamColor;
outputAttributes[count] = new float4(1, 1/initialLife, initialSize, BurstMath.PackFloatRGBA(new float4(airAging/50.0f, airdrag, drag, isosurface)));
}
}
angVel.w = BurstMath.PackFloatRG(potential);
angularVelocities[p] = angVel;
}
}
[BurstCompile]
unsafe struct UpdateParticlesJob : IJobParallelForDefer
{
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<quaternion> orientations;
[ReadOnly] public NativeArray<float4> velocities;
[ReadOnly] public NativeArray<float4> angularVelocities;
[ReadOnly] public NativeArray<float4> principalRadii;
[ReadOnly] public NativeArray<float4> fluidData;
[ReadOnly] public NativeArray<float4> fluidMaterial;
[ReadOnly] public NativeArray<int> simplices;
[ReadOnly] public SimplexCounts simplexCounts;
[ReadOnly] public NativeMultilevelGrid<int> grid;
[DeallocateOnJobCompletion]
[ReadOnly] public NativeArray<int> gridLevels;
[ReadOnly] public Poly6Kernel densityKernel;
[ReadOnly] public NativeArray<float4> inputPositions;
[ReadOnly] public NativeArray<float4> inputVelocities;
[ReadOnly] public NativeArray<float4> inputColors;
[ReadOnly] public NativeArray<float4> inputAttributes;
[NativeDisableParallelForRestriction] public NativeArray<float4> outputPositions;
[NativeDisableParallelForRestriction] public NativeArray<float4> outputVelocities;
[NativeDisableParallelForRestriction] public NativeArray<float4> outputColors;
[NativeDisableParallelForRestriction] public NativeArray<float4> outputAttributes;
[NativeDisableParallelForRestriction] public NativeArray<int> dispatchBuffer;
[ReadOnly] public Oni.SolverParameters parameters;
public float3 agingOverPopulation;
public int minFluidNeighbors;
public float deltaTime;
public int currentAliveParticles;
static readonly int4[] offsets =
{
new int4(0, 0, 0, 1),
new int4(1, 0, 0, 1),
new int4(0, 1, 0, 1),
new int4(1, 1, 0, 1),
new int4(0, 0, 1, 1),
new int4(1, 0, 1, 1),
new int4(0, 1, 1, 1),
new int4(1, 1, 1, 1)
};
public void Execute(int i)
{
int* dispatch = (int*)dispatchBuffer.GetUnsafePtr();
int count = Interlocked.Add(ref dispatch[3], -1);
if (count < inputPositions.Length && inputAttributes[count].x > 0)
{
int aliveCount = Interlocked.Add(ref dispatch[7], 1) - 1;
float4 attributes = inputAttributes[count];
float4 packedData = BurstMath.UnpackFloatRGBA(attributes.w);
int offsetCount = ((int)parameters.mode == 1) ? 4 : 8;
float4 advectedVelocity = float4.zero;
float4 advectedAngVelocity = float4.zero;
float kernelSum = -packedData.w;
uint neighbourCount = 0;
float4 diffusePos = inputPositions[count];
for (int k = 0; k < gridLevels.Length; ++k)
{
int l = gridLevels[k];
float radius = NativeMultilevelGrid<int>.CellSizeOfLevel(l);
float interactionDist = radius * 0.5f;
float4 cellCoords = math.floor(diffusePos / radius);
cellCoords[3] = 0;
if ((int)parameters.mode == 1)
cellCoords[2] = 0;
float4 posInCell = diffusePos - (cellCoords * radius + new float4(interactionDist));
int4 quadrant = (int4)math.sign(posInCell);
quadrant[3] = l;
for (int o = 0; o < offsetCount; ++o)
{
int cellIndex;
if (grid.TryGetCellIndex((int4)cellCoords + offsets[o] * quadrant, out cellIndex))
{
var cell = grid.usedCells[cellIndex];
for (int n = 0; n < cell.Length; ++n)
{
int simplexStart = simplexCounts.GetSimplexStartAndSize(cell[n], out int simplexSize);
for (int a = 0; a < simplexSize; ++a)
{
int p = simplices[simplexStart + a];
float4 normal = diffusePos - positions[p];
normal[3] = 0;
if ((int)parameters.mode == 1)
normal[2] = 0;
float d = math.length(normal);
if (d <= interactionDist)
{
float3 radii = fluidMaterial[p].x * (principalRadii[p].xyz / principalRadii[p].x);
float4 angVel = new float4(math.cross(angularVelocities[p].xyz, normal.xyz), 0);
advectedAngVelocity += angVel * densityKernel.W(d, radii.x) / densityKernel.W(0, radii.x);
normal.xyz = math.mul(math.conjugate(orientations[p]), normal.xyz) / radii;
d = math.length(normal) * radii.x;
// scale by volume (* 1 / normalized density)
float w = densityKernel.W(d, radii.x) / fluidData[p].x;
kernelSum += w;
advectedVelocity += velocities[p] * w;
neighbourCount++;
}
}
}
}
}
}
float4 forces = float4.zero;
float velocityScale = 1;
float agingScale = 1 + BurstMath.Remap01(currentAliveParticles / (float)inputPositions.Length, agingOverPopulation.x, agingOverPopulation.y) * (agingOverPopulation.z - 1);
// foam/bubble particle:
if (kernelSum > BurstMath.epsilon && neighbourCount >= minFluidNeighbors)
{
// advection:
forces = packedData.z / deltaTime * (advectedVelocity / (kernelSum + packedData.w) + advectedAngVelocity - inputVelocities[count]);
// buoyancy:
forces -= new float4(parameters.gravity * parameters.foamGravityScale * inputVelocities[count].w * math.saturate(kernelSum), 0);
}
else // ballistic:
{
// gravity:
forces += new float4(parameters.gravity * parameters.foamGravityScale, 0);
// atmospheric drag/aging:
velocityScale = packedData.y;
agingScale *= packedData.x * 50;
}
// don't change 4th component, as its used to store buoyancy control parameter.
forces[3] = 0;
// update particle data:
attributes.x -= attributes.y * deltaTime * agingScale;
outputAttributes[aliveCount] = attributes;
outputColors[aliveCount] = inputColors[count];
// integrate:
outputVelocities[aliveCount] = (inputVelocities[count] + forces * deltaTime) * velocityScale;
outputPositions[aliveCount] = new float4((inputPositions[count] + outputVelocities[aliveCount] * deltaTime).xyz,neighbourCount);
}
}
}
[BurstCompile]
unsafe struct CopyJob : IJobParallelForDefer
{
[ReadOnly] public NativeArray<float4> inputPositions;
[ReadOnly] public NativeArray<float4> inputVelocities;
[ReadOnly] public NativeArray<float4> inputColors;
[ReadOnly] public NativeArray<float4> inputAttributes;
[NativeDisableParallelForRestriction] public NativeArray<float4> outputPositions;
[NativeDisableParallelForRestriction] public NativeArray<float4> outputVelocities;
[NativeDisableParallelForRestriction] public NativeArray<float4> outputColors;
[NativeDisableParallelForRestriction] public NativeArray<float4> outputAttributes;
[NativeDisableParallelForRestriction] public NativeArray<int> dispatchBuffer;
public void Execute(int i)
{
if (i == 0)
{
dispatchBuffer[3] = dispatchBuffer[7];
dispatchBuffer[7] = 0;
}
outputPositions[i] = inputPositions[i];
outputVelocities[i] = inputVelocities[i];
outputColors[i] = inputColors[i];
outputAttributes[i] = inputAttributes[i];
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,53 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using Unity.Jobs;
using Unity.Collections;
using Unity.Mathematics;
using Unity.Burst;
using UnityEngine;
namespace Obi
{
[BurstCompile]
struct InterpolationJob : IJobParallelFor
{
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float4> startPositions;
[ReadOnly] public NativeArray<float4> endPositions;
[WriteOnly] public NativeArray<float4> renderablePositions;
[ReadOnly] public NativeArray<quaternion> orientations;
[ReadOnly] public NativeArray<quaternion> startOrientations;
[ReadOnly] public NativeArray<quaternion> endOrientations;
[WriteOnly] public NativeArray<quaternion> renderableOrientations;
[ReadOnly] public NativeArray<float4> principalRadii;
[WriteOnly] public NativeArray<float4> renderableRadii;
[ReadOnly] public float blendFactor;
[ReadOnly] public Oni.SolverParameters.Interpolation interpolationMode;
// The code actually running on the job
public void Execute(int i)
{
if (interpolationMode == Oni.SolverParameters.Interpolation.Interpolate)
{
renderablePositions[i] = math.lerp(startPositions[i], endPositions[i], blendFactor);
renderableOrientations[i] = math.normalize(math.slerp(startOrientations[i], endOrientations[i], blendFactor));
renderableRadii[i] = principalRadii[i];
}
else if (interpolationMode == Oni.SolverParameters.Interpolation.Extrapolate)
{
renderablePositions[i] = math.lerp(endPositions[i], positions[i], blendFactor);
renderableOrientations[i] = math.normalize(math.slerp(endOrientations[i], orientations[i], blendFactor));
renderableRadii[i] = principalRadii[i];
}
else
{
renderablePositions[i] = endPositions[i];
renderableOrientations[i] = math.normalize(endOrientations[i]);
renderableRadii[i] = principalRadii[i];
}
}
}
}
#endif

View File

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

View File

@@ -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<float4> 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].z;
// 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)
float3 angularVel = angularVelocities[i].xyz + inverseRotationalMasses[i] * externalTorques[i].xyz * deltaTime;
// project angular velocity to 2D plane normal if needed:
if (is2D)
angularVel = angularVel.project(new float3(0, 0, 1));
angularVelocities[i] = new float4(angularVel, angularVelocities[i].w);
}
// integrate velocities:
positions[i] = BurstIntegration.IntegrateLinear(positions[i], velocities[i], deltaTime);
orientations[i] = BurstIntegration.IntegrateAngular(orientations[i], angularVelocities[i], deltaTime);
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,122 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using Unity.Jobs;
using Unity.Collections;
using Unity.Mathematics;
using Unity.Burst;
using UnityEngine;
namespace Obi
{
[BurstCompile]
struct ResetNormals : IJobParallelFor
{
[ReadOnly] public NativeArray<int> phases;
public NativeArray<float4> normals;
[WriteOnly] public NativeArray<float4> tangents;
public void Execute(int i)
{
// leave fluid and softbody normals intact.
if ((phases[i] & (int)ObiUtils.ParticleFlags.Fluid) == 0 && normals[i].w >= 0)
{
normals[i] = float4.zero;
tangents[i] = float4.zero;
}
}
}
[BurstCompile]
unsafe struct UpdateTriangleNormalsJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> deformableTriangles;
[ReadOnly] public NativeArray<float2> deformableTriangleUVs;
[ReadOnly] public NativeArray<float4> renderPositions;
[NativeDisableParallelForRestriction] public NativeArray<float4> normals;
[NativeDisableParallelForRestriction] public NativeArray<float4> tangents;
public void Execute(int i)
{
int p1 = deformableTriangles[i*3];
int p2 = deformableTriangles[i*3 + 1];
int p3 = deformableTriangles[i*3 + 2];
float3 m1 = (renderPositions[p2] - renderPositions[p1]).xyz;
float3 m2 = (renderPositions[p3] - renderPositions[p1]).xyz;
float2 s = deformableTriangleUVs[i * 3 + 1] - deformableTriangleUVs[i * 3];
float2 t = deformableTriangleUVs[i * 3 + 2] - deformableTriangleUVs[i * 3];
float4 normal = new float4(math.cross(m1, m2), 0);
float4 tangent = float4.zero;
float area = s.x * t.y - t.x * s.y;
if (math.abs(area) > BurstMath.epsilon)
{
tangent = new float4(t.y * m1.x - s.y * m2.x,
t.y * m1.y - s.y * m2.y,
t.y * m1.z - s.y * m2.z, 0) / area;
}
BurstMath.AtomicAdd(normals, p1, normal);
BurstMath.AtomicAdd(normals, p2, normal);
BurstMath.AtomicAdd(normals, p3, normal);
BurstMath.AtomicAdd(tangents, p1, tangent);
BurstMath.AtomicAdd(tangents, p2, tangent);
BurstMath.AtomicAdd(tangents, p3, tangent);
}
}
[BurstCompile]
unsafe struct UpdateEdgeNormalsJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> deformableEdges;
[ReadOnly] public NativeArray<float4> velocities;
[ReadOnly] public NativeArray<float4> wind;
[ReadOnly] public NativeArray<float4> renderPositions;
[NativeDisableParallelForRestriction] public NativeArray<float4> normals;
public void Execute(int i)
{
int p1 = deformableEdges[i * 2];
int p2 = deformableEdges[i * 2 + 1];
float4 edge = renderPositions[p2] - renderPositions[p1];
float4 avgWind = (velocities[p1] + velocities[p2]) * 0.5f - (wind[p1] + wind[p2]) * 0.5f;
float4 normal = avgWind - math.projectsafe(avgWind, edge);
BurstMath.AtomicAdd(normals, p1, normal);
BurstMath.AtomicAdd(normals, p2, normal);
}
}
[BurstCompile]
struct RenderableOrientationFromNormals : IJobParallelFor
{
[ReadOnly] public NativeArray<int> phases;
public NativeArray<float4> normals;
public NativeArray<float4> tangents;
[WriteOnly] public NativeArray<quaternion> renderableOrientations;
public void Execute(int i)
{
if (((phases[i] & (int)ObiUtils.ParticleFlags.Fluid) == 0 && normals[i].w >= 0) && // not fluid or softbody (no SDF stored)
math.lengthsq(normals[i]) > BurstMath.epsilon &&
math.lengthsq(tangents[i]) > BurstMath.epsilon)
{
normals[i] = math.normalizesafe(normals[i]);
tangents[i] = math.normalizesafe(tangents[i]);
// particle orientation from normal/tangent:
renderableOrientations[i] = quaternion.LookRotation(normals[i].xyz, tangents[i].xyz);
}
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,41 @@
#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;
using System.Collections;
using System.Threading;
namespace Obi
{
[BurstCompile]
unsafe struct UpdateParticleLifetimesJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> activeParticles;
[NativeDisableParallelForRestriction] public NativeArray<float> life;
[NativeDisableParallelForRestriction] public NativeArray<int> deadParticles;
[NativeDisableContainerSafetyRestriction] public NativeReference<int> deadParticleCount;
[ReadOnly] public float dt;
public void Execute(int i)
{
int p = activeParticles[i];
life[p] -= dt;
if (life[p] <= 0)
{
int* countRef = (int*)deadParticleCount.GetUnsafePtr();
int count = Interlocked.Increment(ref countRef[0]) - 1;
deadParticles[count] = p;
life[p] = 0;
}
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,68 @@
#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;
[ReadOnly] public float maxVelocity;
[ReadOnly] public float maxAngularVelocity;
// The code actually running on the job
public void Execute(int index)
{
int i = activeParticles[index];
float4 velocity = velocities[i];
float4 angVelocity = angularVelocities[i];
// damp velocities:
velocity *= velocityScale;
angVelocity.xyz *= velocityScale;
// clamp velocities:
float velMagnitude = math.length(velocity);
float angularVelMagnitude = math.length(angVelocity.xyz);
if (velMagnitude > BurstMath.epsilon)
velocity *= math.min(maxVelocity, velMagnitude) / velMagnitude;
if (angularVelMagnitude > BurstMath.epsilon)
angVelocity.xyz *= math.min(maxAngularVelocity, angularVelMagnitude) / angularVelMagnitude;
// if the kinetic energy is below the sleep threshold, keep the particle at its previous position.
if (velMagnitude * velMagnitude * 0.5f + angularVelMagnitude * angularVelMagnitude * 0.5f <= sleepThreshold)
{
positions[i] = previousPositions[i];
orientations[i] = previousOrientations[i];
velocity = float4.zero;
angVelocity.xyz = float3.zero;
}
velocities[i] = velocity;
angularVelocities[i] = angVelocity;
}
}
}
#endif

View File

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

View File

@@ -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] 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] = new float4(BurstIntegration.DifferentiateAngular(orientations[i], previousOrientations[i], deltaTime).xyz, angularVelocities[i].w);
else
angularVelocities[i] = float4.zero;
}
}
}
#endif

View File

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