修改水

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

@@ -1,8 +1,9 @@
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
using Unity.Jobs;
using Unity.Burst;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using Unity.Mathematics;
namespace Obi
@@ -11,6 +12,10 @@ namespace Obi
{
public NativeList<int> fluidParticles;
public NativeArray<float4> eta;
public NativeArray<float4> smoothPositions;
public NativeArray<float3x3> anisotropies;
public BurstDensityConstraints(BurstSolverImpl solver) : base(solver, Oni.ConstraintType.Density)
{
fluidParticles = new NativeList<int>(Allocator.Persistent);
@@ -34,12 +39,12 @@ namespace Obi
batch.Destroy();
}
protected override JobHandle EvaluateSequential(JobHandle inputDeps, float stepTime, float substepTime, int steps, float timeLeft)
protected override JobHandle EvaluateSequential(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
return EvaluateParallel(inputDeps, stepTime, substepTime, steps, timeLeft);
return EvaluateParallel(inputDeps, stepTime, substepTime, substeps);
}
protected override JobHandle EvaluateParallel(JobHandle inputDeps, float stepTime, float substepTime, int steps, float timeLeft)
protected override JobHandle EvaluateParallel(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
{
inputDeps = UpdateInteractions(inputDeps);
@@ -48,41 +53,15 @@ namespace Obi
{
if (batches[i].enabled)
{
inputDeps = batches[i].Evaluate(inputDeps, stepTime, substepTime, steps, timeLeft);
inputDeps = batches[i].Evaluate(inputDeps, stepTime, substepTime, substeps);
m_Solver.ScheduleBatchedJobsIfNeeded();
}
}
// calculate per-particle density lambdas:
// calculate per-particle lambdas:
inputDeps = CalculateLambdas(inputDeps, substepTime);
// calculate viscosity/vorticity:
for (int i = 0; i < batches.Count; ++i)
{
if (batches[i].enabled)
{
inputDeps = batches[i].ViscosityAndVorticity(inputDeps);
m_Solver.ScheduleBatchedJobsIfNeeded();
}
}
// apply viscosity/vorticity positional deltas:
var app = new ApplyPositionDeltasJob()
{
fluidParticles = fluidParticles,
positions = m_Solver.positions,
deltas = m_Solver.positionDeltas,
counts = m_Solver.positionConstraintCounts,
anisotropies = m_Solver.anisotropies,
normals = m_Solver.normals,
fluidData = m_Solver.fluidData,
matchingRotations = m_Solver.orientationDeltas,
linearFromAngular = m_Solver.restPositions,
};
inputDeps = app.Schedule(fluidParticles.Length, 64, inputDeps);
// apply density positional deltas:
// then apply them:
for (int i = 0; i < batches.Count; ++i)
{
if (batches[i].enabled)
@@ -95,23 +74,29 @@ namespace Obi
return inputDeps;
}
public JobHandle CalculateVelocityCorrections(JobHandle inputDeps, float deltaTime)
public JobHandle ApplyVelocityCorrections(JobHandle inputDeps, float deltaTime)
{
eta = new NativeArray<float4>(((BurstSolverImpl)solver).particleCount, Allocator.TempJob);
for (int i = 0; i < batches.Count; ++i)
{
if (batches[i].enabled)
{
inputDeps = batches[i].CalculateNormals(inputDeps, deltaTime);
inputDeps = batches[i].CalculateViscosityAndNormals(inputDeps, deltaTime);
m_Solver.ScheduleBatchedJobsIfNeeded();
}
}
return inputDeps;
}
for (int i = 0; i < batches.Count; ++i)
{
if (batches[i].enabled)
{
inputDeps = batches[i].CalculateVorticity(inputDeps);
m_Solver.ScheduleBatchedJobsIfNeeded();
}
}
public JobHandle ApplyVelocityCorrections(JobHandle inputDeps, float deltaTime)
{
inputDeps = ApplyAtmosphere(inputDeps, deltaTime);
inputDeps = ApplyVorticityAndAtmosphere(inputDeps, deltaTime);
m_Solver.ScheduleBatchedJobsIfNeeded();
return inputDeps;
@@ -121,7 +106,10 @@ namespace Obi
{
// if the constraints are deactivated or we need no anisotropy:
if (((BurstSolverImpl)solver).abstraction.parameters.maxAnisotropy <= 1)
return inputDeps;
return IdentityAnisotropy(inputDeps);
smoothPositions = new NativeArray<float4>(((BurstSolverImpl)solver).particleCount, Allocator.TempJob);
anisotropies = new NativeArray<float3x3>(((BurstSolverImpl)solver).particleCount, Allocator.TempJob);
for (int i = 0; i < batches.Count; ++i)
{
@@ -151,11 +139,8 @@ namespace Obi
// clear existing fluid data:
var clearData = new ClearFluidDataJob()
{
fluidParticles = fluidParticles,
fluidData = m_Solver.fluidData,
massCenters = m_Solver.normals,
prevMassCenters = m_Solver.renderablePositions,
moments = m_Solver.anisotropies
fluidParticles = fluidParticles.AsDeferredJobArray(),
fluidData = ((BurstSolverImpl)solver).abstraction.fluidData.AsNativeArray<float4>(),
};
inputDeps = clearData.Schedule(fluidParticles.Length, 64, inputDeps);
@@ -165,7 +150,7 @@ namespace Obi
{
pairs = m_Solver.fluidInteractions,
positions = m_Solver.positions,
fluidMaterials = m_Solver.fluidMaterials,
radii = m_Solver.smoothingRadii,
densityKernel = new Poly6Kernel(((BurstSolverImpl)solver).abstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
gradientKernel = new SpikyKernel(((BurstSolverImpl)solver).abstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
};
@@ -176,65 +161,64 @@ namespace Obi
private JobHandle CalculateLambdas(JobHandle inputDeps, float deltaTime)
{
// calculate lagrange multipliers:
var calculateLambdas = new CalculateLambdasJob
var calculateLambdas = new CalculateLambdasJob()
{
fluidParticles = fluidParticles,
positions = m_Solver.positions,
prevPositions = m_Solver.prevPositions,
matchingRotations = m_Solver.restPositions.Reinterpret<quaternion>(),
principalRadii = m_Solver.principalRadii,
fluidMaterials = m_Solver.fluidMaterials,
fluidParticles = fluidParticles.AsDeferredJobArray(),
invMasses = m_Solver.invMasses,
radii = m_Solver.smoothingRadii,
restDensities = m_Solver.restDensities,
surfaceTension = m_Solver.surfaceTension,
densityKernel = new Poly6Kernel(m_Solver.abstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
gradientKernel = new SpikyKernel(m_Solver.abstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
fluidData = m_Solver.fluidData,
massCenters = m_Solver.normals,
prevMassCenters = m_Solver.renderablePositions,
moments = m_Solver.anisotropies,
deltas = m_Solver.positionDeltas,
counts = m_Solver.positionConstraintCounts,
solverParams = m_Solver.abstraction.parameters
normals = m_Solver.normals,
vorticity = m_Solver.vorticities,
fluidData = m_Solver.fluidData
};
return calculateLambdas.Schedule(fluidParticles.Length,64,inputDeps);
}
private JobHandle ApplyAtmosphere(JobHandle inputDeps, float deltaTime)
private JobHandle ApplyVorticityAndAtmosphere(JobHandle inputDeps, float deltaTime)
{
var conf = new ApplyAtmosphereJob
// calculate lagrange multipliers:
var conf = new ApplyVorticityConfinementAndAtmosphere()
{
fluidParticles = fluidParticles,
fluidParticles = fluidParticles.AsDeferredJobArray(),
wind = m_Solver.wind,
fluidInterface = m_Solver.fluidInterface,
fluidMaterials2 = m_Solver.fluidMaterials2,
principalRadii = m_Solver.principalRadii,
vorticities = m_Solver.vorticities,
eta = eta,
atmosphericDrag = m_Solver.athmosphericDrag,
atmosphericPressure = m_Solver.athmosphericPressure,
vorticityConfinement = m_Solver.vortConfinement,
restDensities = m_Solver.restDensities,
normals = m_Solver.normals,
fluidData = m_Solver.fluidData,
velocities = m_Solver.velocities,
angularVelocities = m_Solver.angularVelocities,
vorticity = m_Solver.restOrientations.Reinterpret<float4>(),
vorticityAccelerations = m_Solver.orientationDeltas.Reinterpret<float4>(),
linearAccelerations = m_Solver.positionDeltas,
linearFromAngular = m_Solver.restPositions,
angularDiffusion = m_Solver.anisotropies,
positions = m_Solver.positions,
prevPositions = m_Solver.prevPositions,
dt = deltaTime,
solverParams = m_Solver.abstraction.parameters
dt = deltaTime
};
return conf.Schedule(fluidParticles.Length, 64, inputDeps);
}
private JobHandle IdentityAnisotropy(JobHandle inputDeps)
{
var idAnisotropy = new IdentityAnisotropyJob()
{
fluidParticles = fluidParticles.AsDeferredJobArray(),
principalAxes = m_Solver.anisotropies,
radii = m_Solver.principalRadii
};
return idAnisotropy.Schedule(fluidParticles.Length, 64, inputDeps);
}
private JobHandle AverageSmoothPositions(JobHandle inputDeps)
{
var average = new AverageSmoothPositionsJob()
{
fluidParticles = fluidParticles,
fluidParticles = fluidParticles.AsDeferredJobArray(),
renderablePositions = m_Solver.renderablePositions,
anisotropies = m_Solver.anisotropies
smoothPositions = smoothPositions
};
return average.Schedule(fluidParticles.Length, 64, inputDeps);
@@ -244,16 +228,13 @@ namespace Obi
{
var average = new AverageAnisotropyJob()
{
fluidParticles = fluidParticles,
fluidParticles = fluidParticles.AsDeferredJobArray(),
renderablePositions = m_Solver.renderablePositions,
renderableOrientations = m_Solver.renderableOrientations,
smoothPositions = smoothPositions,
principalRadii = m_Solver.principalRadii,
anisotropies = m_Solver.anisotropies,
anisotropies = anisotropies,
maxAnisotropy = m_Solver.abstraction.parameters.maxAnisotropy,
renderableRadii = m_Solver.renderableRadii,
fluidData = m_Solver.fluidData,
life = m_Solver.life,
solverParams = m_Solver.abstraction.parameters
principalAxes = m_Solver.anisotropies
};
return average.Schedule(fluidParticles.Length, 64, inputDeps);
@@ -262,19 +243,12 @@ namespace Obi
[BurstCompile]
public struct ClearFluidDataJob : IJobParallelFor
{
[ReadOnly] public NativeList<int> fluidParticles;
[ReadOnly] public NativeArray<int> fluidParticles;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> fluidData;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> massCenters;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> prevMassCenters;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4x4> moments;
public void Execute(int i)
{
int p = fluidParticles[i];
fluidData[p] = float4.zero;
massCenters[p] = float4.zero;
prevMassCenters[p] = float4.zero;
moments[p] = float4x4.zero;
fluidData[fluidParticles[i]] = float4.zero;
}
}
@@ -282,7 +256,7 @@ namespace Obi
public struct UpdateInteractionsJob : IJobParallelFor
{
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float4> fluidMaterials;
[ReadOnly] public NativeArray<float> radii;
[ReadOnly] public Poly6Kernel densityKernel;
[ReadOnly] public SpikyKernel gradientKernel;
@@ -295,16 +269,16 @@ namespace Obi
var pair = pairs[i];
// calculate normalized gradient vector:
pair.gradient = new float4((positions[pair.particleA] - positions[pair.particleB]).xyz,0);
pair.gradient = (positions[pair.particleA] - positions[pair.particleB]);
float distance = math.length(pair.gradient);
pair.gradient /= distance + math.FLT_MIN_NORMAL;
// calculate and store average density and gradient kernels:
pair.avgKernel = (densityKernel.W(distance, fluidMaterials[pair.particleA].x) +
densityKernel.W(distance, fluidMaterials[pair.particleB].x)) * 0.5f;
pair.avgKernel = (densityKernel.W(distance, radii[pair.particleA]) +
densityKernel.W(distance, radii[pair.particleB])) * 0.5f;
pair.avgGradient = (gradientKernel.W(distance, fluidMaterials[pair.particleA].x) +
gradientKernel.W(distance, fluidMaterials[pair.particleB].x)) * 0.5f;
pair.avgGradient = (gradientKernel.W(distance, radii[pair.particleA]) +
gradientKernel.W(distance, radii[pair.particleB])) * 0.5f;
pairs[i] = pair;
}
@@ -313,239 +287,164 @@ namespace Obi
[BurstCompile]
public struct CalculateLambdasJob : IJobParallelFor
{
[ReadOnly] public NativeList<int> fluidParticles;
[ReadOnly] public NativeArray<float4> positions;
[ReadOnly] public NativeArray<float4> prevPositions;
[ReadOnly] public NativeArray<float4> principalRadii;
[ReadOnly] public NativeArray<float4> fluidMaterials;
[ReadOnly] public NativeArray<int> fluidParticles;
[ReadOnly] public NativeArray<float> invMasses;
[ReadOnly] public NativeArray<float> radii;
[ReadOnly] public NativeArray<float> restDensities;
[ReadOnly] public NativeArray<float> surfaceTension;
[ReadOnly] public Poly6Kernel densityKernel;
[ReadOnly] public SpikyKernel gradientKernel;
[ReadOnly] public Oni.SolverParameters solverParams;
[ReadOnly] public SpikyKernel gradientKernel;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> normals;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> vorticity;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> fluidData;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> massCenters;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> prevMassCenters;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4x4> moments;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<quaternion> matchingRotations;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
public void Execute(int p)
{
int i = fluidParticles[p];
float restVolume = math.pow(principalRadii[i].x * 2, 3 - (int)solverParams.mode);
float4 data = fluidData[i];
float grad = restVolume * gradientKernel.W(0, fluidMaterials[i].x);
// self particle contribution to density, gradient and mass centers:
data += new float4(densityKernel.W(0, fluidMaterials[i].x), 0, grad, grad * grad + data[2] * data[2]);
massCenters[i] += new float4(positions[i].xyz, 1) / positions[i].w;
prevMassCenters[i] += new float4(prevPositions[i].xyz, 1) / positions[i].w;
// usually, we'd weight density by mass (density contrast formulation) by dividing by invMass. Then, multiply by invMass when
// calculating the state equation (density / restDensity - 1, restDensity = mass / volume, so density * invMass * restVolume - 1
// We end up with density / invMass * invMass * restVolume - 1, invMass cancels out.
float constraint = math.max(0, data[0] * restVolume - 1) * fluidMaterials[i].w;
// calculate lambda:
data[1] = -constraint / (positions[i].w * data[3] + math.FLT_MIN_NORMAL);
fluidData[i] = data;
// get total neighborhood mass:
float M = massCenters[i][3];
massCenters[i] /= massCenters[i][3];
prevMassCenters[i] /= prevMassCenters[i][3];
// update moments:
moments[i] += (BurstMath.multrnsp4(positions[i], prevPositions[i]) + float4x4.identity * math.pow(principalRadii[i].x, 2) * 0.001f) / positions[i].w;
moments[i] -= M * BurstMath.multrnsp4(massCenters[i], prevMassCenters[i]);
// extract neighborhood orientation delta:
matchingRotations[i] = BurstMath.ExtractRotation(moments[i], quaternion.identity, 5);
// viscosity and vorticity:
float4 viscGoal = new float4(massCenters[i].xyz + math.rotate(matchingRotations[i], (prevPositions[i] - prevMassCenters[i]).xyz), 0);
deltas[i] += (viscGoal - positions[i]) * fluidMaterials[i].z;
counts[i]++;
}
}
[BurstCompile]
public struct ApplyPositionDeltasJob : IJobParallelFor
{
[ReadOnly] public NativeList<int> fluidParticles;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> deltas;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<int> counts;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> normals;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4x4> anisotropies;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<quaternion> matchingRotations;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> linearFromAngular;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> fluidData;
public void Execute(int p)
{
int i = fluidParticles[p];
if (counts[i] > 0)
{
positions[i] += new float4(deltas[i].xyz,0) / counts[i];
deltas[i] = float4.zero;
counts[i] = 0;
}
normals[i] = float4.zero;
anisotropies[i] = float4x4.zero;
linearFromAngular[i] = float4.zero;
matchingRotations[i] = new quaternion(0, 0, 0, 0);
vorticity[i] = float4.zero;
// zero out fluidData.z in preparation to accumulate relative velocity.
float4 data = fluidData[i];
data.z = 0;
float grad = gradientKernel.W(0, radii[i]) / invMasses[i] / restDensities[i];
// self particle contribution to density and gradient:
data += new float4(densityKernel.W(0, radii[i]), 0, grad, grad * grad + data[2] * data[2]);
// weight by mass:
data[0] /= invMasses[i];
// evaluate density constraint (clamp pressure):
float constraint = math.max(-0.5f * surfaceTension[i], data[0] / restDensities[i] - 1);
// calculate lambda:
data[1] = -constraint / (invMasses[i] * data[3] + math.FLT_MIN_NORMAL);
fluidData[i] = data;
}
}
[BurstCompile]
public struct ApplyAtmosphereJob : IJobParallelFor
public struct ApplyVorticityConfinementAndAtmosphere : IJobParallelFor
{
[ReadOnly] public NativeList<int> fluidParticles;
[ReadOnly] public NativeArray<int> fluidParticles;
[ReadOnly] public NativeArray<float4> wind;
[ReadOnly] public NativeArray<float4> fluidInterface;
[ReadOnly] public NativeArray<float4> fluidMaterials2;
[ReadOnly] public NativeArray<float4> principalRadii;
[ReadOnly] public NativeArray<float4> vorticities;
[ReadOnly] public NativeArray<float> atmosphericDrag;
[ReadOnly] public NativeArray<float> atmosphericPressure;
[ReadOnly] public NativeArray<float> vorticityConfinement;
[ReadOnly] public NativeArray<float> restDensities;
[ReadOnly] public NativeArray<float4> normals;
[ReadOnly] public NativeArray<float4> fluidData;
[ReadOnly] public NativeArray<float4> linearFromAngular;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> positions;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> prevPositions;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> linearAccelerations;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> vorticityAccelerations;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4> vorticity;
[NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] public NativeArray<float4x4> angularDiffusion;
[DeallocateOnJobCompletion] [ReadOnly] public NativeArray<float4> eta;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> angularVelocities;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> velocities;
[ReadOnly] public float dt;
[ReadOnly] public Oni.SolverParameters solverParams;
public void Execute(int p)
{
int i = fluidParticles[p];
float restVolume = math.pow(principalRadii[i].x * 2, 3 - (int)solverParams.mode);
//atmospheric drag:
float4 velocityDiff = velocities[i] - wind[i];
// particles near the surface should experience drag:
velocities[i] -= fluidInterface[i].x * velocityDiff * math.max(0, 1 - fluidData[i][0] * restVolume) * dt;
velocities[i] -= atmosphericDrag[i] * velocityDiff * math.max(0, 1 - fluidData[i][0] / restDensities[i]) * dt;
// ambient pressure:
velocities[i] += fluidInterface[i].y * normals[i] * dt;
velocities[i] += atmosphericPressure[i] * normals[i] * dt;
// angular accel due to baroclinity:
angularVelocities[i] += new float4(fluidMaterials2[i].z * math.cross(-normals[i].xyz, -velocityDiff.xyz), 0) * dt;
angularVelocities[i] -= fluidMaterials2[i].w * angularDiffusion[i].c0;
// apply vorticity confinement:
velocities[i] += new float4(math.cross(math.normalizesafe(eta[i]).xyz,vorticities[i].xyz), 0) * vorticityConfinement[i] * dt;
}
}
// micropolar vorticity:
velocities[i] += fluidMaterials2[i].x * linearAccelerations[i] * dt;
vorticity[i] += fluidMaterials2[i].x * (vorticityAccelerations[i] * 0.5f - vorticity[i]) * dt;
vorticity[i] -= fluidMaterials2[i].y * angularDiffusion[i].c1;
[BurstCompile]
public struct IdentityAnisotropyJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> fluidParticles;
[ReadOnly] public NativeArray<float4> radii;
linearAccelerations[i] = float4.zero;
vorticityAccelerations[i] = float4.zero;
angularDiffusion[i] = float4x4.zero;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> principalAxes;
// we want to add together linear and angular velocity fields and use result to advect particles without modifying either field:
positions[i] += new float4(linearFromAngular[i].xyz * dt,0);
prevPositions[i] += new float4(linearFromAngular[i].xyz * dt, 0);
public void Execute(int p)
{
int i = fluidParticles[p];
// align the principal axes of the particle with the solver axes:
principalAxes[i * 3] = new float4(1,0,0,radii[i].x);
principalAxes[i * 3 + 1] = new float4(0,1,0,radii[i].x);
principalAxes[i * 3 + 2] = new float4(0,0,1,radii[i].x);
}
}
[BurstCompile]
public struct AverageSmoothPositionsJob : IJobParallelFor
{
[ReadOnly] public NativeList<int> fluidParticles;
[ReadOnly] public NativeArray<int> fluidParticles;
[ReadOnly] public NativeArray<float4> renderablePositions;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4x4> anisotropies;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> smoothPositions;
public void Execute(int p)
{
int i = fluidParticles[p];
var smoothPos = anisotropies[i];
if (smoothPos.c3.w > 0)
smoothPos.c3 /= smoothPos.c3.w;
if (smoothPositions[i].w > 0)
smoothPositions[i] /= smoothPositions[i].w;
else
smoothPos.c3.xyz = renderablePositions[i].xyz;
anisotropies[i] = smoothPos;
smoothPositions[i] = renderablePositions[i];
}
}
[BurstCompile]
public struct AverageAnisotropyJob : IJobParallelFor
{
[ReadOnly] public NativeList<int> fluidParticles;
[ReadOnly] public NativeArray<int> fluidParticles;
[ReadOnly] public NativeArray<float4> principalRadii;
[ReadOnly] public float maxAnisotropy;
[ReadOnly] public NativeArray<float4x4> anisotropies;
[ReadOnly] public NativeArray<float> life;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> fluidData;
[ReadOnly]
[DeallocateOnJobCompletion]
public NativeArray<float4> smoothPositions;
[ReadOnly]
[DeallocateOnJobCompletion]
public NativeArray<float3x3> anisotropies;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> renderablePositions;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<quaternion> renderableOrientations;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> renderableRadii;
[ReadOnly] public Oni.SolverParameters solverParams;
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> principalAxes;
public void Execute(int p)
{
int i = fluidParticles[p];
if (anisotropies[i].c3.w > 0 && (anisotropies[i].c0[0] + anisotropies[i].c1[1] + anisotropies[i].c2[2]) > 0.01f)
if (smoothPositions[i].w > 0 && (anisotropies[i].c0[0] + anisotropies[i].c1[1] + anisotropies[i].c2[2]) > 0.01f)
{
float3 singularValues;
float3x3 u;
BurstMath.EigenSolve(math.float3x3(anisotropies[i] / anisotropies[i].c3.w), out singularValues, out u);
BurstMath.EigenSolve(anisotropies[i] / smoothPositions[i].w, out singularValues, out u);
float max = singularValues[0];
float3 s = math.max(singularValues,new float3(max / maxAnisotropy)) / max * principalRadii[i].x;
renderableOrientations[i] = quaternion.LookRotationSafe(u.c2,u.c1);
renderableRadii[i] = new float4(s.xyz,1);
principalAxes[i * 3] = new float4(u.c0, s.x);
principalAxes[i * 3 + 1] = new float4(u.c1, s.y);
principalAxes[i * 3 + 2] = new float4(u.c2, s.z);
}
else
{
float radius = principalRadii[i].x / maxAnisotropy;
renderableOrientations[i] = quaternion.identity;
renderableRadii[i] = new float4(radius,radius,radius,1);
float4 data = fluidData[i];
data.x = 1 / math.pow(math.abs(radius * 2), 3 - (int)solverParams.mode); // normal volume of an isolated particle.
fluidData[i] = data;
principalAxes[i * 3] = new float4(1, 0, 0, radius);
principalAxes[i * 3 + 1] = new float4(0, 1, 0, radius);
principalAxes[i * 3 + 2] = new float4(0, 0, 1, radius);
}
renderablePositions[i] = math.lerp(renderablePositions[i], anisotropies[i].c3, math.min((maxAnisotropy - 1)/3.0f,1));
// inactive particles have radii.w == 0, set it right away for particles killed during this frame
// to keep them from being rendered during this frame instead of waiting to do it at the start of next sim step:
float4 radii = renderableRadii[i];
radii.w = life[i] <= 0 ? 0 : radii.w;
renderableRadii[i] = radii;
renderablePositions[i] = smoothPositions[i];
}
}
}