修改水

This commit is contained in:
2026-01-01 22:00:33 +08:00
parent 040a222bd6
commit 9ceffccd39
1800 changed files with 103929 additions and 139495 deletions

View File

@@ -24,12 +24,8 @@ namespace Obi
[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)
{
@@ -44,14 +40,6 @@ namespace Obi
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));
}
}
}
}

View File

@@ -10,52 +10,18 @@ using System.Collections;
namespace Obi
{
[BurstCompile]
struct CalculateSimplexBoundsJob : IJobParallelFor
struct ParticleToBoundsJob : IJobParallelFor
{
[ReadOnly] public NativeArray<float4> radii;
[ReadOnly] public NativeArray<float4> fluidMaterials;
[ReadOnly] public NativeArray<int> activeParticles;
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float4> velocities;
[ReadOnly] public NativeArray<float4> radii;
// 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 NativeArray<BurstAabb> bounds;
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;
int p = activeParticles[i];
bounds[i] = new BurstAabb(positions[p] - radii[p].x, positions[p] + radii[p].x);
}
}

View File

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

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: e2ac6f480787440e7bd2610e4545bd9e
guid: 7834dd4a6de2346b5b36154d6aaa531a
MonoImporter:
externalObjects: {}
serializedVersion: 2

File diff suppressed because one or more lines are too long

View File

@@ -1,42 +0,0 @@
#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

@@ -1,361 +0,0 @@
#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

@@ -3,49 +3,38 @@ 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;
[ReadOnly] public NativeArray<float4> positions;
[WriteOnly] public NativeArray<float4> renderablePositions;
[ReadOnly] public NativeArray<quaternion> orientations;
[ReadOnly] public NativeArray<quaternion> startOrientations;
[ReadOnly] public NativeArray<quaternion> endOrientations;
[ReadOnly] public NativeArray<quaternion> orientations;
[WriteOnly] public NativeArray<quaternion> renderableOrientations;
[ReadOnly] public NativeArray<float4> principalRadii;
[WriteOnly] public NativeArray<float4> renderableRadii;
[ReadOnly] public float blendFactor;
[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)
if (interpolationMode == Oni.SolverParameters.Interpolation.Interpolate && deltaTime > 0)
{
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];
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] = endPositions[i];
renderableOrientations[i] = math.normalize(endOrientations[i]);
renderableRadii[i] = principalRadii[i];
renderablePositions[i] = positions[i];
renderableOrientations[i] = math.normalize(orientations[i]);
}
}
}

View File

@@ -14,7 +14,7 @@ namespace Obi
{
[ReadOnly] public NativeArray<int> activeParticles;
[ReadOnly] public NativeArray<int> phases;
[ReadOnly] public NativeArray<float4> buoyancies;
[ReadOnly] public NativeArray<float> buoyancies;
// linear/position properties:
[ReadOnly] public NativeArray<float4> externalForces;
@@ -48,7 +48,7 @@ namespace Obi
// Adjust gravity for buoyant fluid particles:
if ((phases[i] & (int)ObiUtils.ParticleFlags.Fluid) != 0)
effectiveGravity *= -buoyancies[i].z;
effectiveGravity *= -buoyancies[i];
// apply external forces and gravity:
float4 vel = velocities[i] + (inverseMasses[i] * externalForces[i] + effectiveGravity) * deltaTime;
@@ -63,13 +63,13 @@ namespace Obi
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;
float4 angularVel = angularVelocities[i] + inverseRotationalMasses[i] * externalTorques[i] * deltaTime;
// project angular velocity to 2D plane normal if needed:
if (is2D)
angularVel = angularVel.project(new float3(0, 0, 1));
angularVel = angularVel.project(new float4(0, 0, 1, 0));
angularVelocities[i] = new float4(angularVel, angularVelocities[i].w);
angularVelocities[i] = angularVel;
}
// integrate velocities:

View File

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

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 354e2117ba6e94ad8afbfe95160a553b
guid: fac27eeae85e84131bebdf89ad1d6802
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,122 +1,43 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Mathematics;
using Unity.Burst;
using UnityEngine;
using System;
using System.Collections;
namespace Obi
{
[BurstCompile]
struct ResetNormals : IJobParallelFor
struct UpdateNormalsJob : IJob
{
[ReadOnly] public NativeArray<int> phases;
[ReadOnly] public NativeList<int> deformableTriangles;
[ReadOnly] public NativeArray<float4> renderPositions;
public NativeArray<float4> normals;
[WriteOnly] public NativeArray<float4> tangents;
public void Execute(int i)
public void Execute()
{
// leave fluid and softbody normals intact.
if ((phases[i] & (int)ObiUtils.ParticleFlags.Fluid) == 0 && normals[i].w >= 0)
{
for (int i = 0; i < normals.Length; ++i)
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)
// Accumulate normals:
for (int i = 0; i < deformableTriangles.Length; i += 3)
{
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;
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;
}
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)
{
for (int i = 0; i < normals.Length; ++i)
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
#endif

View File

@@ -1,41 +0,0 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Burst;
using System;
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

@@ -26,42 +26,25 @@ namespace Obi
[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;
velocities[i] *= velocityScale;
angularVelocities[i] *= velocityScale;
// 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)
if (math.lengthsq(velocities[i]) * 0.5f + math.lengthsq(angularVelocities[i]) * 0.5f <= sleepThreshold)
{
positions[i] = previousPositions[i];
orientations[i] = previousOrientations[i];
velocity = float4.zero;
angVelocity.xyz = float3.zero;
velocities[i] = float4.zero;
angularVelocities[i] = float4.zero;
}
velocities[i] = velocity;
angularVelocities[i] = angVelocity;
}
}
}

View File

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

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 54f132d8cdea34935be3c33b0d1ca4d1
guid: 22028834877974573b3b29b8a2b8f6cc
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -24,7 +24,7 @@ namespace Obi
[ReadOnly] public NativeArray<float> inverseRotationalMasses;
[ReadOnly] public NativeArray<quaternion> previousOrientations;
[NativeDisableParallelForRestriction] public NativeArray<quaternion> orientations;
[NativeDisableParallelForRestriction] public NativeArray<float4> angularVelocities;
[NativeDisableParallelForRestriction] [WriteOnly] public NativeArray<float4> angularVelocities;
[ReadOnly] public float deltaTime;
[ReadOnly] public bool is2D;
@@ -49,7 +49,7 @@ namespace Obi
velocities[i] = float4.zero;
if (inverseRotationalMasses[i] > 0)
angularVelocities[i] = new float4(BurstIntegration.DifferentiateAngular(orientations[i], previousOrientations[i], deltaTime).xyz, angularVelocities[i].w);
angularVelocities[i] = BurstIntegration.DifferentiateAngular(orientations[i], previousOrientations[i], deltaTime);
else
angularVelocities[i] = float4.zero;
}