371 lines
17 KiB
C#
371 lines
17 KiB
C#
#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
|
|
using UnityEngine;
|
|
using Unity.Jobs;
|
|
using Unity.Collections;
|
|
using Unity.Collections.LowLevel.Unsafe;
|
|
using Unity.Mathematics;
|
|
using Unity.Burst;
|
|
using System.Collections;
|
|
|
|
namespace Obi
|
|
{
|
|
public class BurstDensityConstraintsBatch : BurstConstraintsBatchImpl, IDensityConstraintsBatchImpl
|
|
{
|
|
public BatchData batchData;
|
|
|
|
public BurstDensityConstraintsBatch(BurstDensityConstraints constraints)
|
|
{
|
|
m_Constraints = constraints;
|
|
m_ConstraintType = Oni.ConstraintType.Density;
|
|
}
|
|
|
|
public override JobHandle Initialize(JobHandle inputDeps, float substepTime)
|
|
{
|
|
return inputDeps;
|
|
}
|
|
|
|
public override JobHandle Evaluate(JobHandle inputDeps, float stepTime, float substepTime, int substeps)
|
|
{
|
|
|
|
// update densities and gradients:
|
|
var updateDensities = new UpdateDensitiesJob()
|
|
{
|
|
pairs = ((BurstSolverImpl)constraints.solver).fluidInteractions,
|
|
positions = solverImplementation.positions,
|
|
invMasses = solverImplementation.invMasses,
|
|
restDensities = solverImplementation.restDensities,
|
|
diffusion = solverImplementation.diffusion,
|
|
userData = solverImplementation.userData,
|
|
fluidData = solverImplementation.fluidData,
|
|
batchData = batchData,
|
|
dt = substepTime
|
|
};
|
|
|
|
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
|
|
return updateDensities.Schedule(batchData.workItemCount, batchCount, inputDeps);
|
|
}
|
|
|
|
public override JobHandle Apply(JobHandle inputDeps, float substepTime)
|
|
{
|
|
var parameters = solverAbstraction.GetConstraintParameters(m_ConstraintType);
|
|
|
|
// update densities and gradients:
|
|
var apply = new ApplyDensityConstraintsJob()
|
|
{
|
|
invMasses = solverImplementation.invMasses,
|
|
radii = solverImplementation.smoothingRadii,
|
|
restDensities = solverImplementation.restDensities,
|
|
surfaceTension = solverImplementation.surfaceTension,
|
|
pairs = ((BurstSolverImpl)constraints.solver).fluidInteractions,
|
|
densityKernel = new Poly6Kernel(solverAbstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
|
|
positions = solverImplementation.positions,
|
|
fluidData = solverImplementation.fluidData,
|
|
batchData = batchData,
|
|
sorFactor = parameters.SORFactor
|
|
};
|
|
|
|
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
|
|
return apply.Schedule(batchData.workItemCount, batchCount, inputDeps);
|
|
}
|
|
|
|
public JobHandle CalculateViscosityAndNormals(JobHandle inputDeps, float deltaTime)
|
|
{
|
|
var viscosity = new NormalsViscosityAndVorticityJob()
|
|
{
|
|
positions = solverImplementation.positions,
|
|
invMasses = solverImplementation.invMasses,
|
|
radii = solverImplementation.smoothingRadii,
|
|
restDensities = solverImplementation.restDensities,
|
|
viscosities = solverImplementation.viscosities,
|
|
fluidData = solverImplementation.fluidData,
|
|
pairs = ((BurstSolverImpl)constraints.solver).fluidInteractions,
|
|
velocities = solverImplementation.velocities,
|
|
vorticities = solverImplementation.vorticities,
|
|
normals = solverImplementation.normals,
|
|
batchData = batchData
|
|
};
|
|
|
|
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
|
|
return viscosity.Schedule(batchData.workItemCount, batchCount, inputDeps);
|
|
}
|
|
|
|
public JobHandle CalculateVorticity(JobHandle inputDeps)
|
|
{
|
|
var eta = new CalculateVorticityEta()
|
|
{
|
|
invMasses = solverImplementation.invMasses,
|
|
restDensities = solverImplementation.restDensities,
|
|
pairs = ((BurstSolverImpl)constraints.solver).fluidInteractions,
|
|
vorticities = solverImplementation.vorticities,
|
|
eta = ((BurstDensityConstraints)this.constraints).eta,
|
|
batchData = batchData
|
|
};
|
|
|
|
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
|
|
return eta.Schedule(batchData.workItemCount, batchCount, inputDeps);
|
|
}
|
|
|
|
public JobHandle AccumulateSmoothPositions(JobHandle inputDeps)
|
|
{
|
|
var accumulateSmooth = new AccumulateSmoothPositionsJob()
|
|
{
|
|
renderablePositions = solverImplementation.renderablePositions,
|
|
smoothPositions = ((BurstDensityConstraints)this.constraints).smoothPositions,
|
|
radii = solverImplementation.smoothingRadii,
|
|
densityKernel = new Poly6Kernel(solverAbstraction.parameters.mode == Oni.SolverParameters.Mode.Mode2D),
|
|
pairs = ((BurstSolverImpl)constraints.solver).fluidInteractions,
|
|
batchData = batchData
|
|
};
|
|
|
|
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
|
|
return accumulateSmooth.Schedule(batchData.workItemCount, batchCount, inputDeps);
|
|
}
|
|
|
|
public JobHandle AccumulateAnisotropy(JobHandle inputDeps)
|
|
{
|
|
var accumulateAnisotropy = new AccumulateAnisotropyJob()
|
|
{
|
|
renderablePositions = solverImplementation.renderablePositions,
|
|
smoothPositions = ((BurstDensityConstraints)this.constraints).smoothPositions,
|
|
anisotropies = ((BurstDensityConstraints)this.constraints).anisotropies,
|
|
pairs = ((BurstSolverImpl)constraints.solver).fluidInteractions,
|
|
batchData = batchData
|
|
};
|
|
|
|
int batchCount = batchData.isLast ? batchData.workItemCount : 1;
|
|
return accumulateAnisotropy.Schedule(batchData.workItemCount, batchCount, inputDeps);
|
|
}
|
|
|
|
[BurstCompile]
|
|
public struct UpdateDensitiesJob : IJobParallelFor
|
|
{
|
|
[ReadOnly] public NativeArray<float4> positions;
|
|
[ReadOnly] public NativeArray<float> invMasses;
|
|
[ReadOnly] public NativeArray<float> restDensities;
|
|
[ReadOnly] public NativeArray<float> diffusion;
|
|
[ReadOnly] public NativeArray<FluidInteraction> pairs;
|
|
|
|
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> userData;
|
|
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> fluidData;
|
|
|
|
[ReadOnly] public BatchData batchData;
|
|
|
|
[ReadOnly] public float dt;
|
|
|
|
public void Execute(int workItemIndex)
|
|
{
|
|
int start, end;
|
|
batchData.GetConstraintRange(workItemIndex, out start, out end);
|
|
|
|
for (int i = start; i < end; ++i)
|
|
{
|
|
var pair = pairs[i];
|
|
|
|
float restVolumeA = 1.0f / invMasses[pair.particleA] / restDensities[pair.particleA];
|
|
float restVolumeB = 1.0f / invMasses[pair.particleB] / restDensities[pair.particleB];
|
|
|
|
float gradA = restVolumeB * pair.avgGradient;
|
|
float gradB = restVolumeA * pair.avgGradient;
|
|
|
|
float vA = restVolumeB / restVolumeA;
|
|
float vB = restVolumeA / restVolumeB;
|
|
|
|
// accumulate pbf data (density, gradients):
|
|
fluidData[pair.particleA] += new float4(vA * pair.avgKernel, 0, gradA, gradA * gradA);
|
|
fluidData[pair.particleB] += new float4(vB * pair.avgKernel, 0, gradB, gradB * gradB);
|
|
|
|
// property diffusion:
|
|
float diffusionSpeed = (diffusion[pair.particleA] + diffusion[pair.particleB]) * pair.avgKernel * dt;
|
|
float4 userDelta = (userData[pair.particleB] - userData[pair.particleA]) * diffusionSpeed;
|
|
userData[pair.particleA] += vA * userDelta;
|
|
userData[pair.particleB] -= vB * userDelta;
|
|
}
|
|
}
|
|
}
|
|
|
|
[BurstCompile]
|
|
public struct ApplyDensityConstraintsJob : IJobParallelFor
|
|
{
|
|
[ReadOnly] public NativeArray<float> invMasses;
|
|
[ReadOnly] public NativeArray<float> radii;
|
|
[ReadOnly] public NativeArray<float> restDensities;
|
|
[ReadOnly] public NativeArray<float> surfaceTension;
|
|
[ReadOnly] public NativeArray<FluidInteraction> pairs;
|
|
[ReadOnly] public Poly6Kernel densityKernel;
|
|
|
|
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> positions;
|
|
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> fluidData;
|
|
|
|
[ReadOnly] public BatchData batchData;
|
|
[ReadOnly] public float sorFactor;
|
|
|
|
public void Execute(int workItemIndex)
|
|
{
|
|
int start, end;
|
|
batchData.GetConstraintRange(workItemIndex, out start, out end);
|
|
|
|
for (int i = start; i < end; ++i)
|
|
{
|
|
var pair = pairs[i];
|
|
|
|
float restVolumeA = 1.0f / invMasses[pair.particleA] / restDensities[pair.particleA];
|
|
float restVolumeB = 1.0f / invMasses[pair.particleB] / restDensities[pair.particleB];
|
|
|
|
// calculate tensile instability correction factor:
|
|
float wAvg = pair.avgKernel / ((densityKernel.W(0, radii[pair.particleA]) + densityKernel.W(0, radii[pair.particleB])) * 0.5f);
|
|
float scorrA = -(0.001f + 0.2f * surfaceTension[pair.particleA]) * wAvg / (invMasses[pair.particleA] * fluidData[pair.particleA][3]);
|
|
float scorrB = -(0.001f + 0.2f * surfaceTension[pair.particleB]) * wAvg / (invMasses[pair.particleB] * fluidData[pair.particleB][3]);
|
|
|
|
// calculate position delta:
|
|
float4 delta = pair.gradient * pair.avgGradient * ((fluidData[pair.particleA][1] + scorrA) * restVolumeB + (fluidData[pair.particleB][1] + scorrB) * restVolumeA) * sorFactor;
|
|
positions[pair.particleA] += delta * invMasses[pair.particleA];
|
|
positions[pair.particleB] -= delta * invMasses[pair.particleB];
|
|
}
|
|
}
|
|
}
|
|
|
|
[BurstCompile]
|
|
public struct NormalsViscosityAndVorticityJob : IJobParallelFor
|
|
{
|
|
[ReadOnly] public NativeArray<float4> positions;
|
|
[ReadOnly] public NativeArray<float> invMasses;
|
|
[ReadOnly] public NativeArray<float> radii;
|
|
[ReadOnly] public NativeArray<float> restDensities;
|
|
[ReadOnly] public NativeArray<float> viscosities;
|
|
[ReadOnly] public NativeArray<float4> fluidData;
|
|
[ReadOnly] public NativeArray<FluidInteraction> pairs;
|
|
|
|
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> velocities;
|
|
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> vorticities;
|
|
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> normals;
|
|
|
|
[ReadOnly] public BatchData batchData;
|
|
|
|
public void Execute(int workItemIndex)
|
|
{
|
|
int start, end;
|
|
batchData.GetConstraintRange(workItemIndex, out start, out end);
|
|
|
|
for (int i = start; i < end; ++i)
|
|
{
|
|
var pair = pairs[i];
|
|
|
|
float restVolumeA = 1.0f / invMasses[pair.particleA] / restDensities[pair.particleA];
|
|
float restVolumeB = 1.0f / invMasses[pair.particleB] / restDensities[pair.particleB];
|
|
|
|
// XSPH viscosity:
|
|
float viscosityCoeff = math.min(viscosities[pair.particleA], viscosities[pair.particleB]);
|
|
float4 relVelocity = velocities[pair.particleB] - velocities[pair.particleA];
|
|
float4 viscosity = viscosityCoeff * relVelocity * pair.avgKernel;
|
|
velocities[pair.particleA] += viscosity * restVolumeB;
|
|
velocities[pair.particleB] -= viscosity * restVolumeA;
|
|
|
|
// calculate vorticity:
|
|
float4 vgrad = pair.gradient * pair.avgGradient;
|
|
float4 vorticity = new float4(math.cross(relVelocity.xyz,vgrad.xyz),0);
|
|
vorticities[pair.particleA] += vorticity * restVolumeB;
|
|
vorticities[pair.particleB] += vorticity * restVolumeA;
|
|
|
|
// calculate color field normal:
|
|
float radius = (radii[pair.particleA] + radii[pair.particleB]) * 0.5f;
|
|
normals[pair.particleA] += vgrad * radius / invMasses[pair.particleB] / fluidData[pair.particleB][0];
|
|
normals[pair.particleB] -= vgrad * radius / invMasses[pair.particleA] / fluidData[pair.particleA][0];
|
|
}
|
|
}
|
|
}
|
|
|
|
[BurstCompile]
|
|
public struct CalculateVorticityEta : IJobParallelFor
|
|
{
|
|
[ReadOnly] public NativeArray<float4> vorticities;
|
|
[ReadOnly] public NativeArray<float> invMasses;
|
|
[ReadOnly] public NativeArray<float> restDensities;
|
|
|
|
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<FluidInteraction> pairs;
|
|
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> eta;
|
|
|
|
[ReadOnly] public BatchData batchData;
|
|
|
|
public void Execute(int workItemIndex)
|
|
{
|
|
int start, end;
|
|
batchData.GetConstraintRange(workItemIndex, out start, out end);
|
|
|
|
for (int i = start; i < end; ++i)
|
|
{
|
|
var pair = pairs[i];
|
|
|
|
float4 vgrad = pair.gradient * pair.avgGradient;
|
|
eta[pair.particleA] += math.length(vorticities[pair.particleA]) * vgrad / invMasses[pair.particleB] / restDensities[pair.particleB];
|
|
eta[pair.particleB] -= math.length(vorticities[pair.particleB]) * vgrad / invMasses[pair.particleA] / restDensities[pair.particleA];
|
|
}
|
|
}
|
|
}
|
|
|
|
[BurstCompile]
|
|
public struct AccumulateSmoothPositionsJob : IJobParallelFor
|
|
{
|
|
[ReadOnly] public NativeArray<float4> renderablePositions;
|
|
[ReadOnly] public NativeArray<float> radii;
|
|
[ReadOnly] public Poly6Kernel densityKernel;
|
|
|
|
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float4> smoothPositions;
|
|
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<FluidInteraction> pairs;
|
|
|
|
[ReadOnly] public BatchData batchData;
|
|
|
|
public void Execute(int workItemIndex)
|
|
{
|
|
int start, end;
|
|
batchData.GetConstraintRange(workItemIndex, out start, out end);
|
|
|
|
for (int i = start; i < end; ++i)
|
|
{
|
|
var pair = pairs[i];
|
|
|
|
float4 gradient = (renderablePositions[pair.particleA] - renderablePositions[pair.particleB]);
|
|
float distance = math.length(gradient);
|
|
|
|
pair.avgKernel = (densityKernel.W(distance, radii[pair.particleA]) +
|
|
densityKernel.W(distance, radii[pair.particleB])) * 0.5f;
|
|
|
|
smoothPositions[pair.particleA] += new float4(renderablePositions[pair.particleB].xyz,1) * pair.avgKernel;
|
|
smoothPositions[pair.particleB] += new float4(renderablePositions[pair.particleA].xyz,1) * pair.avgKernel;
|
|
|
|
pairs[i] = pair;
|
|
}
|
|
}
|
|
}
|
|
|
|
[BurstCompile]
|
|
public struct AccumulateAnisotropyJob : IJobParallelFor
|
|
{
|
|
[ReadOnly] public NativeArray<float4> renderablePositions;
|
|
[ReadOnly] public NativeArray<float4> smoothPositions;
|
|
[ReadOnly] public NativeArray<FluidInteraction> pairs;
|
|
|
|
[NativeDisableContainerSafetyRestriction][NativeDisableParallelForRestriction] public NativeArray<float3x3> anisotropies;
|
|
|
|
[ReadOnly] public BatchData batchData;
|
|
|
|
public void Execute(int workItemIndex)
|
|
{
|
|
int start, end;
|
|
batchData.GetConstraintRange(workItemIndex, out start, out end);
|
|
|
|
for (int i = start; i < end; ++i)
|
|
{
|
|
var pair = pairs[i];
|
|
|
|
float4 distanceA = renderablePositions[pair.particleB] - smoothPositions[pair.particleA];
|
|
float4 distanceB = renderablePositions[pair.particleA] - smoothPositions[pair.particleB];
|
|
|
|
anisotropies[pair.particleA] += BurstMath.multrnsp(distanceA,distanceA) * pair.avgKernel;
|
|
anisotropies[pair.particleB] += BurstMath.multrnsp(distanceB,distanceB) * pair.avgKernel;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
#endif |