Files
Fishing2/Assets/Obi/Scripts/Common/Backends/Compute/Solver/ComputeSolverImpl.cs
2026-01-22 22:08:21 +08:00

1439 lines
83 KiB
C#

using UnityEngine;
using UnityEngine.Rendering;
namespace Obi
{
public class ComputeSolverImpl : ISolverImpl
{
ObiSolver m_Solver;
public ObiSolver abstraction
{
get { return m_Solver; }
}
public int particleCount
{
get { return m_Solver.positions.count; }
}
public int activeParticleCount
{
get { return m_Solver.activeParticles.count; }
}
public int deformableTriangleCount
{
get { return m_Solver.deformableTriangles.count / 3; }
}
public int deformableEdgeCount
{
get { return m_Solver.deformableEdges.count / 2; }
}
public InertialFrame inertialFrame
{
get { return m_InertialFrame; }
}
public uint activeFoamParticleCount { private set; get; }
// Per-type constraints array:
IComputeConstraintsImpl[] constraints;
// Per-type iteration padding array:
private int[] padding = new int[Oni.ConstraintTypeCount];
// job handle:
private ComputeJobHandle jobHandle;
// particle contact generation:
public ComputeParticleGrid particleGrid;
// collider contact generation:
public ComputeColliderWorld colliderGrid;
// spatial queries:
public SpatialQueries spatialQueries;
// misc data:
private InertialFrame m_InertialFrame;
// cached particle data arrays (just wrappers over raw unmanaged data held by the abstract solver)
public GraphicsBuffer deadIndicesBuffer;
public GraphicsBuffer positionsBuffer;
public GraphicsBuffer orientationsBuffer;
public GraphicsBuffer startPositionsBuffer;
public GraphicsBuffer endPositionsBuffer;
public GraphicsBuffer startOrientationsBuffer;
public GraphicsBuffer endOrientationsBuffer;
public GraphicsBuffer restPositionsBuffer;
public GraphicsBuffer prevPositionsBuffer;
public GraphicsBuffer restOrientationsBuffer;
public GraphicsBuffer prevOrientationsBuffer;
public GraphicsBuffer renderablePositionsBuffer;
public GraphicsBuffer renderableOrientationsBuffer;
public GraphicsBuffer renderableRadiiBuffer;
public GraphicsBuffer colorsBuffer;
public GraphicsBuffer collisionMaterialIndexBuffer;
public GraphicsBuffer principalRadiiBuffer;
public GraphicsBuffer velocitiesBuffer;
public GraphicsBuffer invMassesBuffer;
public GraphicsBuffer phasesBuffer;
public GraphicsBuffer filtersBuffer;
public GraphicsBuffer angularVelocitiesBuffer;
public GraphicsBuffer invRotationalMassesBuffer;
public GraphicsBuffer externalForcesBuffer;
public GraphicsBuffer externalTorquesBuffer;
public GraphicsBuffer windBuffer;
public GraphicsBuffer lifeBuffer;
public GraphicsBuffer fluidDataBuffer;
public GraphicsBuffer userDataBuffer;
public GraphicsBuffer fluidMaterialsBuffer;
public GraphicsBuffer fluidMaterials2Buffer;
public GraphicsBuffer fluidInterfaceBuffer;
public GraphicsBuffer anisotropiesBuffer;
public GraphicsBuffer auxPositions;
public GraphicsBuffer auxVelocities;
public GraphicsBuffer auxColors;
public GraphicsBuffer auxAttributes;
public GraphicsBuffer auxOffsetInCell;
public GraphicsBuffer auxSortedToOriginal;
public GraphicsBuffer normalsBuffer;
public GraphicsBuffer cellCoordsBuffer;
public GraphicsBuffer positionDeltasIntBuffer;
public GraphicsBuffer orientationDeltasIntBuffer;
public GraphicsBuffer positionConstraintCountBuffer;
public GraphicsBuffer orientationConstraintCountBuffer;
public GraphicsBuffer activeParticlesBuffer;
public GraphicsBuffer fluidDispatchBuffer;
public GraphicsBuffer tangentsIntBuffer;
public GraphicsBuffer deformableEdgesBuffer;
public GraphicsBuffer deformableTrianglesBuffer;
public GraphicsBuffer solverToWorldBuffer;
public GraphicsBuffer worldToSolverBuffer;
public GraphicsBuffer inertialFrameBuffer;
private AffineTransform[] solverToWorldArray;
private AffineTransform[] worldToSolverArray;
private InertialFrame[] inertialFrameArray;
public GraphicsBuffer rigidbodyLinearDeltasBuffer;
public GraphicsBuffer rigidbodyAngularDeltasBuffer;
public GraphicsBuffer rigidbodyLinearDeltasIntBuffer;
public GraphicsBuffer rigidbodyAngularDeltasIntBuffer;
public GraphicsBuffer reducedBounds;
// simplices:
public SimplexCounts simplexCounts;
public GraphicsBuffer simplices;
public GraphicsBuffer simplexBounds;
public Aabb solverBounds;
private AsyncGPUReadbackRequest boundsRequest;
private ComputeShader solverShader;
private int applyInertialForcesKernel;
private int applyRigidbodyDeltasKernel;
private int predictPositionsKernel;
private int updateVelocitiesKernel;
private int updatePositionsKernel;
private int updateLifetimesKernel;
private int enforceLimitsKernel;
private int interpolateKernel;
private ComputeShader boundsShader;
private int simplexBoundsKernel;
private int editSimplexBoundsKernel;
private int boundsReductionKernel;
private ComputeShader deformableTrisShader;
private int resetNormalsKernel;
private int updateNormalsKernel;
private int updateEdgeNormalsKernel;
private int orientationFromNormalsKernel;
private ComputeShader foamShader;
private int sortDataKernel;
private int emitShapeFoamKernel;
private int emitFoamKernel;
private int copyAliveKernel;
private int updateFoamKernel;
private int integrateFoamKernel;
private int copyKernel;
private ComputeShader foamDensityShader;
private int clearGridKernel;
private int insertGridKernel;
private int sortByGridKernel;
private int computeDensityKernel;
private int applyDensityKernel;
private ComputeShader foamCollisionShader;
private int solveDiffuseContactsKernel;
public ComputeSolverImpl(ObiSolver solver)
{
this.m_Solver = solver;
jobHandle = new ComputeJobHandle();
solverBounds = new Aabb(solver.transform.position - Vector3.one, solver.transform.position + Vector3.one);
solver.queryResults.ResizeUninitialized((int)abstraction.maxQueryResults);
solver.queryResults.SafeAsComputeBuffer<QueryResult>(GraphicsBuffer.Target.Counter);
solver.foamCount.AsComputeBuffer<int>(GraphicsBuffer.Target.IndirectArguments);
solver.foamPositions.AsComputeBuffer<Vector4>();
solver.foamVelocities.AsComputeBuffer<Vector4>();
solver.foamColors.AsComputeBuffer<Vector4>();
solver.foamAttributes.AsComputeBuffer<Vector4>();
solverShader = GameObject.Instantiate(Resources.Load<ComputeShader>("Compute/Solver"));
applyInertialForcesKernel = solverShader.FindKernel("ApplyInertialForces");
applyRigidbodyDeltasKernel = solverShader.FindKernel("ApplyRigidbodyDeltas");
updateLifetimesKernel = solverShader.FindKernel("UpdateLifetimes");
predictPositionsKernel = solverShader.FindKernel("PredictPositions");
updateVelocitiesKernel = solverShader.FindKernel("UpdateVelocities");
updatePositionsKernel = solverShader.FindKernel("UpdatePositions");
enforceLimitsKernel = solverShader.FindKernel("EnforceLimits");
interpolateKernel = solverShader.FindKernel("Interpolate");
boundsShader = GameObject.Instantiate(Resources.Load<ComputeShader>("Compute/BoundsReduction"));
simplexBoundsKernel = boundsShader.FindKernel("RuntimeSimplexBounds");
editSimplexBoundsKernel = boundsShader.FindKernel("EditSimplexBounds");
boundsReductionKernel = boundsShader.FindKernel("Reduce");
deformableTrisShader = GameObject.Instantiate(Resources.Load<ComputeShader>("Compute/DeformableTriangles"));
resetNormalsKernel = deformableTrisShader.FindKernel("ResetNormals");
updateNormalsKernel = deformableTrisShader.FindKernel("UpdateNormals");
updateEdgeNormalsKernel = deformableTrisShader.FindKernel("UpdateEdgeNormals");
orientationFromNormalsKernel = deformableTrisShader.FindKernel("OrientationFromNormals");
foamShader = GameObject.Instantiate(Resources.Load<ComputeShader>("Compute/FluidFoam"));
sortDataKernel = foamShader.FindKernel("SortFluidData");
emitShapeFoamKernel = foamShader.FindKernel("EmitShape");
emitFoamKernel = foamShader.FindKernel("Emit");
copyAliveKernel = foamShader.FindKernel("CopyAliveCount");
updateFoamKernel = foamShader.FindKernel("Update");
copyKernel = foamShader.FindKernel("Copy");
integrateFoamKernel = foamShader.FindKernel("Integrate");
foamDensityShader = GameObject.Instantiate(Resources.Load<ComputeShader>("Compute/FluidFoamDensity"));
clearGridKernel = foamDensityShader.FindKernel("Clear");
insertGridKernel = foamDensityShader.FindKernel("InsertInGrid");
sortByGridKernel = foamDensityShader.FindKernel("SortByGrid");
computeDensityKernel = foamDensityShader.FindKernel("ComputeDensity");
applyDensityKernel = foamDensityShader.FindKernel("ApplyDensity");
foamCollisionShader = GameObject.Instantiate(Resources.Load<ComputeShader>("Compute/FluidFoamCollisions"));
solveDiffuseContactsKernel = foamCollisionShader.FindKernel("SolveDiffuseContacts");
solverToWorldBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, 1, 48);
solverToWorldArray = new AffineTransform[1];
worldToSolverBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, 1, 48);
worldToSolverArray = new AffineTransform[1];
inertialFrameBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, 1, 160);
inertialFrameArray = new InertialFrame[1];
fluidDispatchBuffer = new GraphicsBuffer(GraphicsBuffer.Target.IndirectArguments, 4, sizeof(uint));
// Initialize collision world:
GetOrCreateColliderWorld();
colliderGrid.IncreaseReferenceCount();
// Initialize contact generation acceleration structure:
particleGrid = new ComputeParticleGrid();
// Initialize spatial query system.
spatialQueries = new SpatialQueries(solver.maxQueryResults);
// Initialize constraint arrays:
constraints = new IComputeConstraintsImpl[Oni.ConstraintTypeCount];
constraints[(int)Oni.ConstraintType.Tether] = new ComputeTetherConstraints(this);
constraints[(int)Oni.ConstraintType.Volume] = new ComputeVolumeConstraints(this);
constraints[(int)Oni.ConstraintType.Chain] = new ComputeChainConstraints(this);
constraints[(int)Oni.ConstraintType.Bending] = new ComputeBendConstraints(this);
constraints[(int)Oni.ConstraintType.Distance] = new ComputeDistanceConstraints(this);
constraints[(int)Oni.ConstraintType.ShapeMatching] = new ComputeShapeMatchingConstraints(this);
constraints[(int)Oni.ConstraintType.BendTwist] = new ComputeBendTwistConstraints(this);
constraints[(int)Oni.ConstraintType.StretchShear] = new ComputeStretchShearConstraints(this);
constraints[(int)Oni.ConstraintType.Pin] = new ComputePinConstraints(this);
constraints[(int)Oni.ConstraintType.Pinhole] = new ComputePinholeConstraints(this);
constraints[(int)Oni.ConstraintType.Skin] = new ComputeSkinConstraints(this);
constraints[(int)Oni.ConstraintType.Aerodynamics] = new ComputeAerodynamicConstraints(this);
constraints[(int)Oni.ConstraintType.Stitch] = new ComputeStitchConstraints(this);
constraints[(int)Oni.ConstraintType.ParticleCollision] = new ComputeParticleCollisionConstraints(this);
constraints[(int)Oni.ConstraintType.ParticleCollision].CreateConstraintsBatch();
constraints[(int)Oni.ConstraintType.Collision] = new ComputeColliderCollisionConstraints(this);
constraints[(int)Oni.ConstraintType.Collision].CreateConstraintsBatch();
constraints[(int)Oni.ConstraintType.ParticleFriction] = new ComputeParticleFrictionConstraints(this);
constraints[(int)Oni.ConstraintType.ParticleFriction].CreateConstraintsBatch();
constraints[(int)Oni.ConstraintType.Friction] = new ComputeColliderFrictionConstraints(this);
constraints[(int)Oni.ConstraintType.Friction].CreateConstraintsBatch();
constraints[(int)Oni.ConstraintType.Density] = new ComputeDensityConstraints(this);
constraints[(int)Oni.ConstraintType.Density].CreateConstraintsBatch();
}
public void Destroy()
{
reducedBounds?.Dispose();
solverToWorldBuffer?.Dispose();
worldToSolverBuffer?.Dispose();
inertialFrameBuffer?.Dispose();
fluidDispatchBuffer?.Dispose();
for (int i = 0; i < constraints.Length; ++i)
if (constraints[i] != null)
constraints[i].Dispose();
// Get rid of particle and collider grids/queries:
particleGrid?.Dispose();
// cannot use null-coalescing because this is a GameObject, and Unity overrides !=
if (colliderGrid != null)
colliderGrid.DecreaseReferenceCount();
spatialQueries?.Dispose();
positionDeltasIntBuffer?.Dispose();
orientationDeltasIntBuffer?.Dispose();
rigidbodyLinearDeltasIntBuffer?.Dispose();
rigidbodyAngularDeltasIntBuffer?.Dispose();
tangentsIntBuffer?.Dispose();
simplexBounds?.Dispose();
auxPositions?.Dispose();
auxVelocities?.Dispose();
auxColors?.Dispose();
auxAttributes?.Dispose();
auxOffsetInCell?.Dispose();
auxSortedToOriginal?.Dispose();
}
private void GetOrCreateColliderWorld()
{
colliderGrid = GameObject.FindObjectOfType<ComputeColliderWorld>();
if (colliderGrid == null)
{
var world = new GameObject("ComputeCollisionWorld", typeof(ComputeColliderWorld));
colliderGrid = world.GetComponent<ComputeColliderWorld>();
}
}
public void PushData()
{
// Send data to the GPU:
abstraction.positions.Upload();
abstraction.orientations.Upload();
abstraction.velocities.Upload();
abstraction.angularVelocities.Upload();
abstraction.colors.Upload();
abstraction.startPositions.Upload();
abstraction.startOrientations.Upload();
abstraction.endPositions.Upload();
abstraction.endOrientations.Upload();
abstraction.restPositions.Upload();
abstraction.restOrientations.Upload();
abstraction.normals.Upload();
abstraction.principalRadii.Upload();
abstraction.invMasses.Upload();
abstraction.invRotationalMasses.Upload();
abstraction.phases.Upload();
abstraction.filters.Upload();
abstraction.externalForces.Upload();
abstraction.externalTorques.Upload();
abstraction.wind.Upload();
abstraction.life.Upload();
abstraction.fluidData.Upload();
abstraction.userData.Upload();
abstraction.fluidInterface.Upload();
abstraction.fluidMaterials.Upload();
abstraction.fluidMaterials2.Upload();
rigidbodyLinearDeltasIntBuffer.SetData(abstraction.rigidbodyLinearDeltas.AsNativeArray<VInt4>());
rigidbodyAngularDeltasIntBuffer.SetData(abstraction.rigidbodyAngularDeltas.AsNativeArray<VInt4>());
}
public void RequestReadback()
{
// Copy rigidbody deltas (int) to output buffers (float), then request readback:
solverShader.SetBuffer(applyRigidbodyDeltasKernel, "linearDeltasAsInt", rigidbodyLinearDeltasIntBuffer);
solverShader.SetBuffer(applyRigidbodyDeltasKernel, "angularDeltasAsInt", rigidbodyAngularDeltasIntBuffer);
solverShader.SetBuffer(applyRigidbodyDeltasKernel, "linearDeltas", rigidbodyLinearDeltasBuffer);
solverShader.SetBuffer(applyRigidbodyDeltasKernel, "angularDeltas", rigidbodyAngularDeltasBuffer);
solverShader.SetInt("particleCount", abstraction.rigidbodyLinearDeltas.count);
int threadGroups = ComputeMath.ThreadGroupCount(abstraction.rigidbodyLinearDeltas.count, 128);
solverShader.Dispatch(applyRigidbodyDeltasKernel, threadGroups, 1, 1);
abstraction.rigidbodyLinearDeltas.Readback();
abstraction.rigidbodyAngularDeltas.Readback();
// begin particle data async GPU -> CPU transfer.
// by default, only positions and velocities are read back.
// ObiActors can request whatever data they need in RequestReadback,
// then wait for it in SimulationEnd.
abstraction.positions.Readback();
abstraction.velocities.Readback();
// begin constraint data async GPU -> CPU transfer.
var sm = constraints[(int)Oni.ConstraintType.ShapeMatching] as ComputeShapeMatchingConstraints;
if (sm != null)
sm.RequestDataReadback();
// needed for tearing.
var dm = constraints[(int)Oni.ConstraintType.Distance] as ComputeDistanceConstraints;
if (dm != null)
dm.RequestDataReadback();
var pm = constraints[(int)Oni.ConstraintType.Pin] as ComputePinConstraints;
if (pm != null)
pm.RequestDataReadback();
var phm = constraints[(int)Oni.ConstraintType.Pinhole] as ComputePinholeConstraints;
if (phm != null)
phm.RequestDataReadback();
}
public void InitializeFrame(Vector4 translation, Vector4 scale, Quaternion rotation)
{
m_InertialFrame = new InertialFrame(translation, scale, rotation);
}
public void UpdateFrame(Vector4 translation, Vector4 scale, Quaternion rotation, float deltaTime)
{
m_InertialFrame.Update(translation, scale, rotation, deltaTime);
solverToWorldArray[0] = m_InertialFrame.frame;
solverToWorldBuffer.SetData(solverToWorldArray);
worldToSolverArray[0] = m_InertialFrame.frame.Inverse();
worldToSolverBuffer.SetData(worldToSolverArray);
inertialFrameArray[0] = m_InertialFrame;
inertialFrameBuffer.SetData(inertialFrameArray);
}
public IObiJobHandle ApplyFrame(float worldLinearInertiaScale, float worldAngularInertiaScale, float deltaTime)
{
if (activeParticleCount > 0)
{
// inverse linear part:
Matrix4x4 linear = Matrix4x4.TRS(Vector3.zero, inertialFrame.frame.rotation, new Vector3(1 / inertialFrame.frame.scale.x, 1 / inertialFrame.frame.scale.y, 1 / inertialFrame.frame.scale.z));
Matrix4x4 linearInv = Matrix4x4.Transpose(linear);
// non-inertial frame accelerations:
Vector4 angularVel = (linearInv * Matrix4x4.Scale(inertialFrame.angularVelocity) * linear).Diagonal();
Vector4 eulerAccel = (linearInv * Matrix4x4.Scale(inertialFrame.angularAcceleration) * linear).Diagonal();
Vector4 inertialAccel = linearInv * inertialFrame.acceleration;
int threadGroups = ComputeMath.ThreadGroupCount(activeParticleCount, 128);
solverShader.SetInt("particleCount", activeParticleCount);
solverShader.SetFloat("deltaTime", deltaTime);
solverShader.SetFloat("worldLinearInertiaScale", abstraction.worldLinearInertiaScale);
solverShader.SetFloat("worldAngularInertiaScale", abstraction.worldAngularInertiaScale);
solverShader.SetVector("angularVel", angularVel);
solverShader.SetVector("eulerAccel", eulerAccel);
solverShader.SetVector("inertialAccel", inertialAccel);
solverShader.SetVector("ambientWind", abstraction.parameters.ambientWind);
solverShader.SetBool("inertialWind", abstraction.windSpace == Space.World);
solverShader.SetBuffer(applyInertialForcesKernel, "activeParticles", activeParticlesBuffer);
solverShader.SetBuffer(applyInertialForcesKernel, "positions", positionsBuffer);
solverShader.SetBuffer(applyInertialForcesKernel, "velocities", velocitiesBuffer);
solverShader.SetBuffer(applyInertialForcesKernel, "invMasses", invMassesBuffer);
solverShader.SetBuffer(applyInertialForcesKernel, "wind", windBuffer);
solverShader.SetBuffer(applyInertialForcesKernel, "inertialSolverFrame", inertialFrameBuffer);
solverShader.Dispatch(applyInertialForcesKernel, threadGroups, 1, 1);
}
return jobHandle;
}
public void SetDeformableTriangles(ObiNativeIntList indices, ObiNativeVector2List uvs)
{
if (indices.count > 0)
{
deformableTrianglesBuffer = indices.AsComputeBuffer<int>();
var deformableUVsBuffer = uvs.AsComputeBuffer<Vector2>();
deformableTrisShader.SetBuffer(updateNormalsKernel, "deformableTriangles", deformableTrianglesBuffer);
deformableTrisShader.SetBuffer(updateNormalsKernel, "deformableTriangleUVs", deformableUVsBuffer);
deformableTrisShader.SetInt("triangleCount", deformableTriangleCount);
}
}
public void SetDeformableEdges(ObiNativeIntList indices)
{
if (indices.count > 0)
{
deformableEdgesBuffer = indices.AsComputeBuffer<int>();
deformableTrisShader.SetBuffer(updateEdgeNormalsKernel, "deformableEdges", deformableEdgesBuffer);
deformableTrisShader.SetInt("edgeCount", deformableEdgeCount);
}
}
public void SetSimplices(ObiNativeIntList simplices, SimplexCounts counts)
{
this.simplexCounts = counts;
if (simplices.count > 0)
{
boundsShader.SetInt("pointCount", simplexCounts.pointCount);
boundsShader.SetInt("edgeCount", simplexCounts.edgeCount);
boundsShader.SetInt("triangleCount", simplexCounts.triangleCount);
this.simplices = simplices.AsComputeBuffer<int>();
cellCoordsBuffer = abstraction.cellCoords.AsComputeBuffer<VInt4>();
if (simplexBounds == null || counts.simplexCount > simplexBounds.count)
{
simplexBounds?.Dispose();
simplexBounds = new GraphicsBuffer(GraphicsBuffer.Target.Structured, counts.simplexCount * 2, 32);
reducedBounds?.Dispose();
reducedBounds = new GraphicsBuffer(GraphicsBuffer.Target.Structured, ComputeMath.NextMultiple(counts.simplexCount * 2, 256), 32);
}
// Even though we usually store simplices for collision detection, the grid is reused for fluid meshing
// so the capacity we set should be at least the total amount of particles in the solver.
if (particleGrid != null)
{
if (particleGrid.SetCapacity(Mathf.Max(counts.simplexCount, particleCount),
(uint)Mathf.Max(1, abstraction.maxParticleContacts),
(uint)Mathf.Max(1, abstraction.maxParticleNeighbors)))
{
// resize to maximum number of contacts:
abstraction.colliderContacts.ResizeUninitialized(particleGrid.contactPairs.count);
abstraction.colliderContacts.SafeAsComputeBuffer<Oni.Contact>(GraphicsBuffer.Target.Counter);
abstraction.particleContacts.ResizeUninitialized(particleGrid.contactPairs.count);
abstraction.particleContacts.SafeAsComputeBuffer<Oni.Contact>(GraphicsBuffer.Target.Counter);
abstraction.contactEffectiveMasses.ResizeUninitialized(particleGrid.contactPairs.count);
abstraction.contactEffectiveMasses.SafeAsComputeBuffer<ContactEffectiveMasses>();
abstraction.particleContactEffectiveMasses.ResizeUninitialized(particleGrid.contactPairs.count);
abstraction.particleContactEffectiveMasses.SafeAsComputeBuffer<ContactEffectiveMasses>();
}
}
}
else
this.simplices = null;
}
public void SetActiveParticles(ObiNativeIntList indices)
{
// TODO: indices.computebuffer has been deleted when adding an item. We now need to
// update the compute buffer if needed.
if (indices.computeBuffer == null || indices.computeBuffer.count != indices.capacity)
{
//Debug.Log("create");
activeParticlesBuffer = indices.AsComputeBuffer<int>(indices.capacity);
}
else
{
//Debug.Log("update");
indices.UploadFullCapacity(); //unmaps the entire memory buffer up to capacity.
}
if (activeParticlesBuffer != null)
{
solverShader.SetBuffer(predictPositionsKernel, "activeParticles", activeParticlesBuffer);
solverShader.SetBuffer(updateVelocitiesKernel, "activeParticles", activeParticlesBuffer);
solverShader.SetBuffer(updatePositionsKernel, "activeParticles", activeParticlesBuffer);
solverShader.SetBuffer(enforceLimitsKernel, "activeParticles", activeParticlesBuffer);
}
}
public IObiJobHandle UpdateBounds(IObiJobHandle inputDeps, float stepTime)
{
if (activeParticleCount > 0 && reducedBounds != null)
{
boundsShader.SetFloat("deltaTime", stepTime);
boundsShader.SetFloat("collisionMargin", abstraction.parameters.collisionMargin);
boundsShader.SetFloat("particleCCD", abstraction.parameters.particleCCD);
int boundsCount = simplexCounts.simplexCount;
int threadGroups = ComputeMath.ThreadGroupCount(boundsCount, 256);
// at edit time, the collision materials buffer will be null since
// the collider world is not updated.
if (colliderGrid.materialsBuffer != null)
{
boundsShader.SetBuffer(simplexBoundsKernel, "simplexBounds", simplexBounds);
boundsShader.SetBuffer(simplexBoundsKernel, "simplices", simplices);
boundsShader.SetBuffer(simplexBoundsKernel, "reducedBounds", reducedBounds);
boundsShader.SetBuffer(simplexBoundsKernel, "activeParticles", activeParticlesBuffer);
boundsShader.SetBuffer(simplexBoundsKernel, "positions", positionsBuffer);
boundsShader.SetBuffer(simplexBoundsKernel, "velocities", velocitiesBuffer);
boundsShader.SetBuffer(simplexBoundsKernel, "principalRadii", principalRadiiBuffer);
boundsShader.SetBuffer(simplexBoundsKernel, "fluidMaterials", fluidMaterialsBuffer);
boundsShader.SetBuffer(simplexBoundsKernel, "collisionMaterials", colliderGrid.materialsBuffer);
boundsShader.SetBuffer(simplexBoundsKernel, "collisionMaterialIndices", collisionMaterialIndexBuffer);
boundsShader.Dispatch(simplexBoundsKernel, threadGroups, 1, 1);
}
else
{
boundsShader.SetBuffer(editSimplexBoundsKernel, "simplexBounds", simplexBounds);
boundsShader.SetBuffer(editSimplexBoundsKernel, "simplices", simplices);
boundsShader.SetBuffer(editSimplexBoundsKernel, "reducedBounds", reducedBounds);
boundsShader.SetBuffer(editSimplexBoundsKernel, "activeParticles", activeParticlesBuffer);
boundsShader.SetBuffer(editSimplexBoundsKernel, "positions", positionsBuffer);
boundsShader.SetBuffer(editSimplexBoundsKernel, "velocities", velocitiesBuffer);
boundsShader.SetBuffer(editSimplexBoundsKernel, "principalRadii", principalRadiiBuffer);
boundsShader.SetBuffer(editSimplexBoundsKernel, "fluidMaterials", fluidMaterialsBuffer);
boundsShader.Dispatch(editSimplexBoundsKernel, threadGroups, 1, 1);
}
boundsShader.SetBuffer(boundsReductionKernel, "reducedBounds", reducedBounds);
do
{
boundsShader.Dispatch(boundsReductionKernel, threadGroups, 1, 1);
threadGroups = ComputeMath.ThreadGroupCount(boundsCount, 256);
boundsCount /= 256;
}
while (threadGroups > 1);
boundsRequest = AsyncGPUReadback.Request(reducedBounds, 32, 0);
// update lifetimes:
solverShader.SetFloat("deltaTime",stepTime);
solverShader.SetBuffer(updateLifetimesKernel, "activeParticles", activeParticlesBuffer);
solverShader.SetBuffer(updateLifetimesKernel, "life", lifeBuffer);
solverShader.SetBuffer(updateLifetimesKernel, "deadParticles", deadIndicesBuffer);
solverShader.Dispatch(updateLifetimesKernel, ComputeMath.ThreadGroupCount(activeParticleCount, 128), 1, 1);
}
return inputDeps;
}
public void GetBounds(ref Vector3 min, ref Vector3 max)
{
// wait for last pending bounds async request:
boundsRequest.WaitForCompletion();
if (boundsRequest.done && !boundsRequest.hasError)
solverBounds = boundsRequest.GetData<Aabb>(0)[0];
min = solverBounds.min;
max = solverBounds.max;
}
public int GetConstraintCount(Oni.ConstraintType type)
{
/*if ((int)type > 0 && (int)type < constraints.Length)
{
int count = 0;
for (int i = 0; i < constraints[(int)type].Count; ++i)
{
count += constraints[(int)type][i].GetConstraintCount();
}
return count;
}
return 0;*/
return 0;
}
public void SetParameters(Oni.SolverParameters parameters)
{
// These should be better passed using a constant buffer, but constant buffers do not work in 2021 :(
//https://issuetracker.unity3d.com/issues/compute-shader-is-not-using-defined-constants-when-setting-data-with-setconstantbuffer
solverShader.SetInt("mode", (int)parameters.mode);
solverShader.SetInt("interpolation", (int)parameters.interpolation);
solverShader.SetVector("gravity", parameters.gravity);
solverShader.SetFloat("damping", parameters.damping);
solverShader.SetFloat("sleepThreshold", parameters.sleepThreshold);
solverShader.SetFloat("collisionMargin", parameters.collisionMargin);
solverShader.SetFloat("maxVelocity", parameters.maxVelocity);
solverShader.SetFloat("maxAngularVelocity", parameters.maxAngularVelocity);
}
public void SetConstraintGroupParameters(Oni.ConstraintType type, ref Oni.ConstraintParameters parameters)
{
// No need to implement. This backend grabs parameters from the abstraction when it needs them.
}
public void ParticleCountChanged(ObiSolver solver)
{
deadIndicesBuffer = abstraction.deadParticles.AsComputeBuffer<int>(abstraction.deadParticles.capacity, GraphicsBuffer.Target.Counter);
colorsBuffer = abstraction.colors.AsComputeBuffer<Vector4>();
positionsBuffer = abstraction.positions.AsComputeBuffer<Vector4>();
orientationsBuffer = abstraction.orientations.AsComputeBuffer<Quaternion>();
startPositionsBuffer = abstraction.startPositions.AsComputeBuffer<Vector4>();
endPositionsBuffer = abstraction.endPositions.AsComputeBuffer<Vector4>();
startOrientationsBuffer = abstraction.startOrientations.AsComputeBuffer<Quaternion>();
endOrientationsBuffer = abstraction.endOrientations.AsComputeBuffer<Quaternion>();
restPositionsBuffer = abstraction.restPositions.AsComputeBuffer<Vector4>();
restOrientationsBuffer = abstraction.restOrientations.AsComputeBuffer<Vector4>();
prevPositionsBuffer = abstraction.prevPositions.AsComputeBuffer<Vector4>();
prevOrientationsBuffer = abstraction.prevOrientations.AsComputeBuffer<Quaternion>();
renderablePositionsBuffer = abstraction.renderablePositions.AsComputeBuffer<Vector4>();
renderableOrientationsBuffer = abstraction.renderableOrientations.AsComputeBuffer<Quaternion>();
renderableRadiiBuffer = abstraction.renderableRadii.AsComputeBuffer<Vector4>();
collisionMaterialIndexBuffer = abstraction.collisionMaterials.AsComputeBuffer<int>();
angularVelocitiesBuffer = abstraction.angularVelocities.AsComputeBuffer<Vector4>();
invRotationalMassesBuffer = abstraction.invRotationalMasses.AsComputeBuffer<float>();
externalForcesBuffer = abstraction.externalForces.AsComputeBuffer<Vector4>();
externalTorquesBuffer = abstraction.externalTorques.AsComputeBuffer<Vector4>();
windBuffer = abstraction.wind.AsComputeBuffer<Vector4>();
velocitiesBuffer = abstraction.velocities.AsComputeBuffer<Vector4>();
principalRadiiBuffer = abstraction.principalRadii.AsComputeBuffer<Vector4>();
invMassesBuffer = abstraction.invMasses.AsComputeBuffer<float>();
phasesBuffer = abstraction.phases.AsComputeBuffer<int>();
filtersBuffer = abstraction.filters.AsComputeBuffer<int>();
lifeBuffer = abstraction.life.AsComputeBuffer<float>();
fluidDataBuffer = abstraction.fluidData.AsComputeBuffer<Vector4>();
userDataBuffer = abstraction.userData.AsComputeBuffer<Vector4>();
fluidInterfaceBuffer = abstraction.fluidInterface.AsComputeBuffer<Vector4>();
fluidMaterialsBuffer = abstraction.fluidMaterials.AsComputeBuffer<Vector4>();
fluidMaterials2Buffer = abstraction.fluidMaterials2.AsComputeBuffer<Vector4>();
anisotropiesBuffer = abstraction.anisotropies.AsComputeBuffer<Matrix4x4>();
normalsBuffer = abstraction.normals.AsComputeBuffer<Vector4>();
positionConstraintCountBuffer = abstraction.positionConstraintCounts.AsComputeBuffer<int>();
orientationConstraintCountBuffer = abstraction.orientationConstraintCounts.AsComputeBuffer<int>();
if (positionDeltasIntBuffer != null)
{
positionDeltasIntBuffer.Dispose();
positionDeltasIntBuffer = null;
}
if (abstraction.positionDeltas.count > 0)
{
positionDeltasIntBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, abstraction.positionDeltas.count, abstraction.positionDeltas.stride);
positionDeltasIntBuffer.SetData(new Vector4[abstraction.positionDeltas.count]);
}
if (orientationDeltasIntBuffer != null)
{
orientationDeltasIntBuffer.Dispose();
orientationDeltasIntBuffer = null;
}
if (abstraction.orientationDeltas.count > 0)
{
orientationDeltasIntBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, abstraction.orientationDeltas.count, abstraction.orientationDeltas.stride);
orientationDeltasIntBuffer.SetData(new Vector4[abstraction.orientationDeltas.count]);
}
if (tangentsIntBuffer != null)
{
tangentsIntBuffer.Dispose();
tangentsIntBuffer = null;
}
if (abstraction.normals.count > 0)
{
tangentsIntBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, abstraction.normals.count, abstraction.normals.stride);
tangentsIntBuffer.SetData(new VInt4[abstraction.normals.count]);
}
if (positionsBuffer != null) solverShader.SetBuffer(predictPositionsKernel, "positions", positionsBuffer);
if (prevPositionsBuffer != null) solverShader.SetBuffer(predictPositionsKernel, "prevPositions", prevPositionsBuffer);
if (orientationsBuffer != null) solverShader.SetBuffer(predictPositionsKernel, "orientations", orientationsBuffer);
if (prevOrientationsBuffer != null) solverShader.SetBuffer(predictPositionsKernel, "prevOrientations", prevOrientationsBuffer);
if (velocitiesBuffer != null) solverShader.SetBuffer(predictPositionsKernel, "velocities", velocitiesBuffer);
if (invMassesBuffer != null) solverShader.SetBuffer(predictPositionsKernel, "invMasses", invMassesBuffer);
if (angularVelocitiesBuffer != null) solverShader.SetBuffer(predictPositionsKernel, "angularVelocities", angularVelocitiesBuffer);
if (invRotationalMassesBuffer != null) solverShader.SetBuffer(predictPositionsKernel, "invRotationalMasses", invRotationalMassesBuffer);
if (externalForcesBuffer != null) solverShader.SetBuffer(predictPositionsKernel, "externalForces", externalForcesBuffer);
if (externalTorquesBuffer != null) solverShader.SetBuffer(predictPositionsKernel, "externalTorques", externalTorquesBuffer);
if (phasesBuffer != null) solverShader.SetBuffer(predictPositionsKernel, "phases", phasesBuffer);
if (fluidInterfaceBuffer != null) solverShader.SetBuffer(predictPositionsKernel, "buoyancies", fluidInterfaceBuffer);
if (positionsBuffer != null) solverShader.SetBuffer(updateVelocitiesKernel, "positions", positionsBuffer);
if (prevPositionsBuffer != null) solverShader.SetBuffer(updateVelocitiesKernel, "prevPositions", prevPositionsBuffer);
if (orientationsBuffer != null) solverShader.SetBuffer(updateVelocitiesKernel, "orientations", orientationsBuffer);
if (prevOrientationsBuffer != null) solverShader.SetBuffer(updateVelocitiesKernel, "prevOrientations", prevOrientationsBuffer);
if (velocitiesBuffer != null) solverShader.SetBuffer(updateVelocitiesKernel, "velocities", velocitiesBuffer);
if (angularVelocitiesBuffer != null) solverShader.SetBuffer(updateVelocitiesKernel, "angularVelocities", angularVelocitiesBuffer);
if (invMassesBuffer != null) solverShader.SetBuffer(updateVelocitiesKernel, "invMasses", invMassesBuffer);
if (invRotationalMassesBuffer != null) solverShader.SetBuffer(updateVelocitiesKernel, "invRotationalMasses", invRotationalMassesBuffer);
if (positionsBuffer != null) solverShader.SetBuffer(updatePositionsKernel, "positions", positionsBuffer);
if (prevPositionsBuffer != null) solverShader.SetBuffer(updatePositionsKernel, "prevPositions", prevPositionsBuffer);
if (orientationsBuffer != null) solverShader.SetBuffer(updatePositionsKernel, "orientations", orientationsBuffer);
if (prevOrientationsBuffer != null) solverShader.SetBuffer(updatePositionsKernel, "prevOrientations", prevOrientationsBuffer);
if (velocitiesBuffer != null) solverShader.SetBuffer(updatePositionsKernel, "velocities", velocitiesBuffer);
if (angularVelocitiesBuffer != null) solverShader.SetBuffer(updatePositionsKernel, "angularVelocities", angularVelocitiesBuffer);
if (positionsBuffer != null) solverShader.SetBuffer(enforceLimitsKernel, "positions", positionsBuffer);
if (prevPositionsBuffer != null) solverShader.SetBuffer(enforceLimitsKernel, "prevPositions", prevPositionsBuffer);
if (lifeBuffer != null) solverShader.SetBuffer(enforceLimitsKernel, "life", lifeBuffer);
if (phasesBuffer != null) solverShader.SetBuffer(enforceLimitsKernel, "phases", phasesBuffer);
if (positionsBuffer != null) solverShader.SetBuffer(interpolateKernel, "positions", positionsBuffer);
if (startPositionsBuffer != null) solverShader.SetBuffer(interpolateKernel, "startPositions", startPositionsBuffer);
if (endPositionsBuffer != null) solverShader.SetBuffer(interpolateKernel, "endPositions", endPositionsBuffer);
if (renderablePositionsBuffer != null) solverShader.SetBuffer(interpolateKernel, "renderablePositions", renderablePositionsBuffer);
if (orientationsBuffer != null) solverShader.SetBuffer(interpolateKernel, "orientations", orientationsBuffer);
if (startOrientationsBuffer != null) solverShader.SetBuffer(interpolateKernel, "startOrientations", startOrientationsBuffer);
if (endOrientationsBuffer != null) solverShader.SetBuffer(interpolateKernel, "endOrientations", endOrientationsBuffer);
if (renderableOrientationsBuffer != null) solverShader.SetBuffer(interpolateKernel, "renderableOrientations", renderableOrientationsBuffer);
if (principalRadiiBuffer != null) solverShader.SetBuffer(interpolateKernel, "principalRadii", principalRadiiBuffer);
if (renderableRadiiBuffer != null) solverShader.SetBuffer(interpolateKernel, "renderableRadii", renderableRadiiBuffer);
}
public void MaxFoamParticleCountChanged(ObiSolver solver)
{
auxPositions?.Dispose();
auxVelocities?.Dispose();
auxColors?.Dispose();
auxAttributes?.Dispose();
auxOffsetInCell?.Dispose();
auxSortedToOriginal?.Dispose();
if (m_Solver.maxFoamParticles > 0)
{
solver.foamPositions.AsComputeBuffer<Vector4>();
solver.foamVelocities.AsComputeBuffer<Vector4>();
solver.foamColors.AsComputeBuffer<Vector4>();
solver.foamAttributes.AsComputeBuffer<Vector4>();
auxPositions = new GraphicsBuffer(GraphicsBuffer.Target.Structured, (int)m_Solver.maxFoamParticles, 16);
auxVelocities = new GraphicsBuffer(GraphicsBuffer.Target.Structured, (int)m_Solver.maxFoamParticles, 16);
auxColors = new GraphicsBuffer(GraphicsBuffer.Target.Structured, (int)m_Solver.maxFoamParticles, 16);
auxAttributes = new GraphicsBuffer(GraphicsBuffer.Target.Structured, (int)m_Solver.maxFoamParticles, 16);
auxOffsetInCell = new GraphicsBuffer(GraphicsBuffer.Target.Structured, (int)m_Solver.maxFoamParticles, 4);
auxSortedToOriginal = new GraphicsBuffer(GraphicsBuffer.Target.Structured, (int)m_Solver.maxFoamParticles, 4);
}
}
public void SetRigidbodyArrays(ObiSolver solver)
{
rigidbodyLinearDeltasBuffer = solver.rigidbodyLinearDeltas.SafeAsComputeBuffer<Vector4>();
rigidbodyAngularDeltasBuffer = solver.rigidbodyAngularDeltas.SafeAsComputeBuffer<Vector4>();
if (rigidbodyLinearDeltasIntBuffer != null)
{
rigidbodyLinearDeltasIntBuffer.Dispose();
rigidbodyLinearDeltasIntBuffer = null;
}
if (rigidbodyAngularDeltasIntBuffer != null)
{
rigidbodyAngularDeltasIntBuffer.Dispose();
rigidbodyAngularDeltasIntBuffer = null;
}
rigidbodyLinearDeltasIntBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, rigidbodyLinearDeltasBuffer.count, solver.rigidbodyLinearDeltas.stride);
rigidbodyLinearDeltasIntBuffer.SetData(new Vector4[rigidbodyLinearDeltasBuffer.count]);
rigidbodyAngularDeltasIntBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, rigidbodyAngularDeltasBuffer.count, solver.rigidbodyAngularDeltas.stride);
rigidbodyAngularDeltasIntBuffer.SetData(new Vector4[rigidbodyAngularDeltasBuffer.count]);
}
public IConstraintsBatchImpl CreateConstraintsBatch(Oni.ConstraintType type)
{
if (constraints[(int)type] != null)
return constraints[(int)type].CreateConstraintsBatch();
return null;
}
public void DestroyConstraintsBatch(IConstraintsBatchImpl batch)
{
if (batch != null && constraints[(int)batch.constraintType] != null)
constraints[(int)batch.constraintType].RemoveBatch(batch);
}
public void FinishSimulation()
{
// Make sure GPU->CPU readbacks have finished.
// by default, only positions and velocities are read back.
// ObiActors can request whatever data they need in RequestData,
// then wait for it in SimulationEnd.
abstraction.positions.WaitForReadback();
abstraction.velocities.WaitForReadback();
abstraction.rigidbodyLinearDeltas.WaitForReadback();
abstraction.rigidbodyAngularDeltas.WaitForReadback();
var sm = constraints[(int)Oni.ConstraintType.ShapeMatching] as ComputeShapeMatchingConstraints;
if (sm != null)
sm.WaitForReadback();
var dm = constraints[(int)Oni.ConstraintType.Distance] as ComputeDistanceConstraints;
if (dm != null)
dm.WaitForReadback();
var pm = constraints[(int)Oni.ConstraintType.Pin] as ComputePinConstraints;
if (pm != null)
pm.WaitForReadback();
var phm = constraints[(int)Oni.ConstraintType.Pinhole] as ComputePinholeConstraints;
if (phm != null)
phm.WaitForReadback();
abstraction.externalForces.WipeToZero();
abstraction.externalTorques.WipeToZero();
abstraction.externalForces.Upload();
abstraction.externalTorques.Upload();
// copy end to start positions.
abstraction.startPositions.CopyFrom(abstraction.endPositions);
abstraction.startOrientations.CopyFrom(abstraction.endOrientations);
// now that we got position / orientation data in the CPU set them as this step's end positions / orientations.
abstraction.endPositions.CopyFrom(abstraction.positions);
abstraction.endOrientations.CopyFrom(abstraction.orientations);
abstraction.startPositions.Upload(true);
abstraction.startOrientations.Upload(true);
abstraction.endPositions.Upload(true);
abstraction.endOrientations.Upload(true);
}
public IObiJobHandle CollisionDetection(IObiJobHandle inputDeps, float stepTime)
{
var collisionParameters = abstraction.GetConstraintParameters(Oni.ConstraintType.Collision);
var particleCollisionParameters = abstraction.GetConstraintParameters(Oni.ConstraintType.ParticleCollision);
var densityParameters = abstraction.GetConstraintParameters(Oni.ConstraintType.Density);
if (particleCollisionParameters.enabled ||
densityParameters.enabled)
{
UpdateDiffuseDensity(stepTime);
UnityEngine.Profiling.Profiler.BeginSample("Build Simplex Grid");
particleGrid.BuildGrid(this, stepTime);
UnityEngine.Profiling.Profiler.EndSample();
if (densityParameters.enabled)
{
UnityEngine.Profiling.Profiler.BeginSample("Generate Fluid Neighborhoods");
particleGrid.GenerateFluidNeighborhoods(this);
UnityEngine.Profiling.Profiler.EndSample();
}
if (particleCollisionParameters.enabled)
{
UnityEngine.Profiling.Profiler.BeginSample("Generate Particle Contacts");
particleGrid.GenerateContacts(this);
UnityEngine.Profiling.Profiler.EndSample();
}
}
if (collisionParameters.enabled)
{
UnityEngine.Profiling.Profiler.BeginSample("Generate Collider Contacts");
colliderGrid.GenerateContacts(this, stepTime);
UnityEngine.Profiling.Profiler.EndSample();
UnityEngine.Profiling.Profiler.BeginSample("Apply Force Zones");
colliderGrid.ApplyForceZones(this, stepTime);
UnityEngine.Profiling.Profiler.EndSample();
}
return inputDeps;
}
public IObiJobHandle Substep(IObiJobHandle handle, float stepTime, float substepTime, int steps, float timeLeft)
{
int threadGroups = ComputeMath.ThreadGroupCount(activeParticleCount, 128);
solverShader.SetInt("particleCount", activeParticleCount);
// if there's no active particles yet, don't do anything:
if (activeParticleCount > 0)
{
solverShader.SetFloat("deltaTime", substepTime);
solverShader.SetFloat("velocityScale", Mathf.Pow(1 - Mathf.Clamp(m_Solver.parameters.damping, 0, 1), substepTime));
// Predict positions:
solverShader.Dispatch(predictPositionsKernel, threadGroups, 1, 1);
ApplyConstraints(stepTime, substepTime, steps, timeLeft);
EnforceLimits(threadGroups);
// Update velocities:
solverShader.Dispatch(updateVelocitiesKernel, threadGroups, 1, 1);
// Calculate velocity adjustments (forces, etc):
CalculateVelocityCorrections(stepTime, substepTime, steps, timeLeft);
}
// Update diffuse particles: (need to have calculated velocity corrections first, to measure vorticity/velocity)
int substepsLeft = Mathf.RoundToInt(timeLeft / substepTime);
int foamPadding = Mathf.CeilToInt(abstraction.substeps / (float)abstraction.foamSubsteps);
if (substepsLeft % foamPadding == 0)
{
UpdateDiffuseParticles(substepTime * foamPadding);
UpdateDiffuseCollisions(substepTime * foamPadding);
IntegrateDiffuseParticles(substepTime * foamPadding);
}
// Update particle positions:
if (activeParticleCount > 0)
{
UpdatePositions(substepTime, threadGroups);
}
return handle;
}
private void CalculateVelocityCorrections(float stepTime, float substepTime, int steps, float timeLeft)
{
// Apply aerodynamic constraints:
constraints[(int)Oni.ConstraintType.Aerodynamics].Project(stepTime, substepTime, steps, timeLeft);
var densityParameters = m_Solver.GetConstraintParameters(Oni.ConstraintType.Density);
if (densityParameters.enabled)
{
var d = constraints[(int)Oni.ConstraintType.Density] as ComputeDensityConstraints;
if (d != null)
d.CalculateVelocityCorrections(substepTime);
}
}
private void UpdatePositions(float deltaTime, int threadGroups)
{
var densityParameters = m_Solver.GetConstraintParameters(Oni.ConstraintType.Density);
if (densityParameters.enabled)
{
var d = constraints[(int)Oni.ConstraintType.Density] as ComputeDensityConstraints;
if (d != null)
d.ApplyVelocityCorrections(deltaTime);
}
// Update positions:
solverShader.Dispatch(updatePositionsKernel, threadGroups, 1, 1);
}
private void ApplyConstraints(float stepTime, float substepTime, int steps, float timeLeft)
{
// calculate max amount of iterations required, and initialize constraints..
int maxIterations = 0;
for (int i = 0; i < Oni.ConstraintTypeCount; ++i)
{
var parameters = m_Solver.GetConstraintParameters((Oni.ConstraintType)i);
if (parameters.enabled)
{
maxIterations = Mathf.Max(maxIterations, parameters.iterations);
constraints[i].Initialize(stepTime, substepTime, steps, timeLeft);
}
}
// calculate iteration paddings:
for (int i = 0; i < Oni.ConstraintTypeCount; ++i)
{
var parameters = m_Solver.GetConstraintParameters((Oni.ConstraintType)i);
if (parameters.enabled && parameters.iterations > 0)
padding[i] = Mathf.CeilToInt(maxIterations / (float)parameters.iterations);
else
padding[i] = maxIterations;
}
// perform projection iterations:
for (int i = 1; i < maxIterations; ++i)
{
for (int j = 0; j < Oni.ConstraintTypeCount; ++j)
{
if (j != (int)Oni.ConstraintType.Aerodynamics)
{
var parameters = m_Solver.GetConstraintParameters((Oni.ConstraintType)j);
if (parameters.enabled && i % padding[j] == 0)
constraints[j].Project(stepTime, substepTime, steps, timeLeft);
}
}
}
// final iteration, all groups together:
for (int i = 0; i < Oni.ConstraintTypeCount; ++i)
{
if (i != (int)Oni.ConstraintType.Aerodynamics)
{
var parameters = m_Solver.GetConstraintParameters((Oni.ConstraintType)i);
if (parameters.enabled && parameters.iterations > 0)
constraints[i].Project(stepTime, substepTime, steps, timeLeft);
}
}
// Despite friction constraints being applied after collision (since coulomb friction depends on normal impulse)
// we perform a collision iteration right at the end to ensure the final state meets the Signorini-Fichera conditions.
var param = m_Solver.GetConstraintParameters(Oni.ConstraintType.ParticleCollision);
if (param.enabled && param.iterations > 0)
constraints[(int)Oni.ConstraintType.ParticleCollision].Project(stepTime, substepTime, steps, timeLeft);
param = m_Solver.GetConstraintParameters(Oni.ConstraintType.Collision);
if (param.enabled && param.iterations > 0)
constraints[(int)Oni.ConstraintType.Collision].Project(stepTime, substepTime, steps, timeLeft);
}
private void EnforceLimits(int threadGroups)
{
if (abstraction.useLimits)
{
// keep particles within bounds:
solverShader.SetBool("killOffLimits", abstraction.killOffLimitsParticles);
solverShader.SetVector("boundaryLimitsMin", abstraction.boundaryLimits.min);
solverShader.SetVector("boundaryLimitsMax", abstraction.boundaryLimits.max);
solverShader.Dispatch(enforceLimitsKernel, threadGroups, 1, 1);
}
}
public IObiJobHandle ApplyInterpolation(IObiJobHandle inputDeps, ObiNativeVector4List startPositions, ObiNativeQuaternionList startOrientations, float stepTime, float unsimulatedTime)
{
if (particleCount <= 0)
return inputDeps;
int threadGroups = ComputeMath.ThreadGroupCount(particleCount, 128);
solverShader.SetInt("particleCount", particleCount);
solverShader.SetFloat("deltaTime", stepTime);
solverShader.SetFloat("blendFactor", stepTime > 0 ? unsimulatedTime / stepTime : 0);
solverShader.SetInt("interpolate", (int)m_Solver.parameters.interpolation);
// Interpolate particle state:
solverShader.Dispatch(interpolateKernel, threadGroups, 1, 1);
// Reset normals:
if ((deformableTriangleCount > 0 || deformableEdgeCount > 0) && normalsBuffer != null)
{
threadGroups = ComputeMath.ThreadGroupCount(normalsBuffer.count, 128);
deformableTrisShader.SetInt("normalsCount", normalsBuffer.count);
deformableTrisShader.SetBuffer(resetNormalsKernel, "phases", phasesBuffer);
deformableTrisShader.SetBuffer(resetNormalsKernel, "normals", normalsBuffer);
deformableTrisShader.SetBuffer(resetNormalsKernel, "tangentsInt", tangentsIntBuffer);
deformableTrisShader.Dispatch(resetNormalsKernel, threadGroups, 1, 1);
// Update deformable triangle normals
if (deformableTriangleCount > 0)
{
threadGroups = ComputeMath.ThreadGroupCount(deformableTriangleCount, 128);
deformableTrisShader.SetBuffer(updateNormalsKernel, "renderablePositions", renderablePositionsBuffer);
deformableTrisShader.SetBuffer(updateNormalsKernel, "normalsInt", normalsBuffer);
deformableTrisShader.SetBuffer(updateNormalsKernel, "tangentsInt", tangentsIntBuffer);
deformableTrisShader.Dispatch(updateNormalsKernel, threadGroups, 1, 1);
}
// Update deformable edge normals
if (deformableEdgeCount > 0)
{
threadGroups = ComputeMath.ThreadGroupCount(deformableEdgeCount, 128);
deformableTrisShader.SetBuffer(updateEdgeNormalsKernel, "renderablePositions", renderablePositionsBuffer);
deformableTrisShader.SetBuffer(updateEdgeNormalsKernel, "velocities", velocitiesBuffer);
deformableTrisShader.SetBuffer(updateEdgeNormalsKernel, "wind", windBuffer);
deformableTrisShader.SetBuffer(updateEdgeNormalsKernel, "normalsInt", normalsBuffer);
deformableTrisShader.Dispatch(updateEdgeNormalsKernel, threadGroups, 1, 1);
}
// Update particle orientations
threadGroups = ComputeMath.ThreadGroupCount(normalsBuffer.count, 128);
deformableTrisShader.SetBuffer(orientationFromNormalsKernel, "phases", phasesBuffer);
deformableTrisShader.SetBuffer(orientationFromNormalsKernel, "renderableOrientations", renderableOrientationsBuffer);
deformableTrisShader.SetBuffer(orientationFromNormalsKernel, "normals", normalsBuffer);
deformableTrisShader.SetBuffer(orientationFromNormalsKernel, "tangentsInt", tangentsIntBuffer);
deformableTrisShader.Dispatch(orientationFromNormalsKernel, threadGroups, 1, 1);
}
// project renderable position/orientation of pinned particles:
var pinparam = abstraction.GetConstraintParameters(Oni.ConstraintType.Pin);
if (pinparam.enabled && pinparam.iterations > 0)
{
var d = constraints[(int)Oni.ConstraintType.Pin] as ComputePinConstraints;
if (Application.isPlaying && d != null)
d.ProjectRenderablePositions();
}
//make sure density constraints are enabled, otherwise particles have no neighbors and neighbor lists will be uninitialized.
var param = m_Solver.GetConstraintParameters(Oni.ConstraintType.Density);
if (param.enabled && param.iterations > 0)
{
// Fluid laplacian/anisotropy (only if we're in play mode, in-editor we have no particlegrid/sorted data).
var d = constraints[(int)Oni.ConstraintType.Density] as ComputeDensityConstraints;
if (Application.isPlaying && d != null)
d.CalculateAnisotropyLaplacianSmoothing();
}
return inputDeps;
}
private void UpdateDiffuseDensity(float deltaTime)
{
var system = abstraction.GetRenderSystem<ObiFoamGenerator>() as ComputeFoamRenderSystem;
if (system != null && m_Solver.maxFoamParticles > 0 && particleGrid.cellCounts != null)
{
for (int i = 0; i < system.renderers.Count; ++i)
{
// solver indices compute buffer may be null
if (system.renderers[i].pressure > 0 &&
system.renderers[i].actor.solverIndices?.computeBuffer != null)
{
float scale = 0.01f + Mathf.Clamp01(1 - system.renderers[i].density);
float radius = system.renderers[i].size * scale;
int cellThreadGroups = ComputeMath.ThreadGroupCount(particleGrid.cellCounts.count, 128);
foamDensityShader.SetFloat("deltaTime", deltaTime);
foamDensityShader.SetInt("maxCells", particleGrid.cellCounts.count);
foamDensityShader.SetInt("maxFoamParticles", abstraction.foamPositions.computeBuffer.count);
foamDensityShader.SetInt("mode", (int)abstraction.parameters.mode);
foamDensityShader.SetFloat("pressure", system.renderers[i].pressure);
foamDensityShader.SetFloat("particleRadius", radius);
foamDensityShader.SetFloat("smoothingRadius", radius * 2 * system.renderers[i].smoothingRadius);
foamDensityShader.SetFloat("surfaceTension", system.renderers[i].surfaceTension);
foamDensityShader.SetFloat("viscosity", system.renderers[i].viscosity);
foamDensityShader.SetVector("volumeLightDirection", system.renderers[i].volumeLight != null ? abstraction.transform.InverseTransformDirection(system.renderers[i].volumeLight.transform.forward) : Vector3.down);
foamDensityShader.SetBuffer(clearGridKernel, "cellStart", particleGrid.cellOffsets);
foamDensityShader.SetBuffer(clearGridKernel, "cellCounts", particleGrid.cellCounts);
foamDensityShader.Dispatch(clearGridKernel, cellThreadGroups, 1, 1);
foamDensityShader.SetBuffer(insertGridKernel, "inputPositions", abstraction.foamPositions.computeBuffer);
foamDensityShader.SetBuffer(insertGridKernel, "offsetInCell", auxOffsetInCell);
foamDensityShader.SetBuffer(insertGridKernel, "cellCounts", particleGrid.cellCounts);
foamDensityShader.SetBuffer(insertGridKernel, "dispatch", abstraction.foamCount.computeBuffer);
foamDensityShader.DispatchIndirect(insertGridKernel, abstraction.foamCount.computeBuffer);
// prefix sum
particleGrid.cellsPrefixSum.Sum(particleGrid.cellCounts, particleGrid.cellOffsets);
foamDensityShader.SetBuffer(sortByGridKernel, "inputPositions", abstraction.foamPositions.computeBuffer);
foamDensityShader.SetBuffer(sortByGridKernel, "inputVelocities", abstraction.foamVelocities.computeBuffer);
foamDensityShader.SetBuffer(sortByGridKernel, "sortedPositions", auxPositions);
foamDensityShader.SetBuffer(sortByGridKernel, "sortedVelocities", auxVelocities);
foamDensityShader.SetBuffer(sortByGridKernel, "sortedToOriginal", auxSortedToOriginal);
foamDensityShader.SetBuffer(sortByGridKernel, "offsetInCell", auxOffsetInCell);
foamDensityShader.SetBuffer(sortByGridKernel, "cellStart", particleGrid.cellOffsets);
foamDensityShader.SetBuffer(sortByGridKernel, "cellCounts", particleGrid.cellCounts);
foamDensityShader.SetBuffer(sortByGridKernel, "dispatch", abstraction.foamCount.computeBuffer);
foamDensityShader.DispatchIndirect(sortByGridKernel, abstraction.foamCount.computeBuffer);
foamDensityShader.SetBuffer(computeDensityKernel, "inputPositions", abstraction.foamPositions.computeBuffer);
foamDensityShader.SetBuffer(computeDensityKernel, "sortedPositions", auxPositions);
foamDensityShader.SetBuffer(computeDensityKernel, "fluidData", auxColors);
foamDensityShader.SetBuffer(computeDensityKernel, "cellStart", particleGrid.cellOffsets);
foamDensityShader.SetBuffer(computeDensityKernel, "cellCounts", particleGrid.cellCounts);
foamDensityShader.SetBuffer(computeDensityKernel, "dispatch", abstraction.foamCount.computeBuffer);
foamDensityShader.DispatchIndirect(computeDensityKernel, abstraction.foamCount.computeBuffer);
foamDensityShader.SetBuffer(applyDensityKernel, "inputPositions", abstraction.foamPositions.computeBuffer);
foamDensityShader.SetBuffer(applyDensityKernel, "inputVelocities", abstraction.foamVelocities.computeBuffer);
foamDensityShader.SetBuffer(applyDensityKernel, "sortedPositions", auxPositions);
foamDensityShader.SetBuffer(applyDensityKernel, "sortedVelocities", auxVelocities);
foamDensityShader.SetBuffer(applyDensityKernel, "sortedToOriginal", auxSortedToOriginal);
foamDensityShader.SetBuffer(applyDensityKernel, "fluidData", auxColors);
foamDensityShader.SetBuffer(applyDensityKernel, "cellStart", particleGrid.cellOffsets);
foamDensityShader.SetBuffer(applyDensityKernel, "cellCounts", particleGrid.cellCounts);
foamDensityShader.SetBuffer(applyDensityKernel, "dispatch", abstraction.foamCount.computeBuffer);
foamDensityShader.DispatchIndirect(applyDensityKernel, abstraction.foamCount.computeBuffer);
}
}
}
else
activeFoamParticleCount = 0;
}
private void UpdateDiffuseCollisions(float deltaTime)
{
if (!abstraction.foamCollisions) return;
foamCollisionShader.SetFloat("radiusScale", 0.3f);
foamCollisionShader.SetFloat("colliderCount", colliderGrid.colliderCount);
foamCollisionShader.SetInt("maxCells", ComputeColliderWorld.maxCells);
foamCollisionShader.SetInt("cellsPerCollider", ComputeColliderWorld.cellsPerCollider);
foamCollisionShader.SetInt("shapeTypeCount", Oni.ColliderShapeTypeCount);
foamCollisionShader.SetFloat("deltaTime", deltaTime);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "inputPositions", abstraction.foamPositions.computeBuffer);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "inputVelocities", abstraction.foamVelocities.computeBuffer);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "inputAttributes", abstraction.foamAttributes.computeBuffer);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "aabbs", colliderGrid.aabbsBuffer);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "transforms", colliderGrid.transformsBuffer);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "shapes", colliderGrid.shapesBuffer);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "rigidbodies", colliderGrid.rigidbodiesBuffer);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "sortedColliderIndices", colliderGrid.sortedColliderIndicesBuffer);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "levelPopulation", colliderGrid.levelPopulation);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "cellOffsets", colliderGrid.cellOffsetsBuffer);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "cellCounts", colliderGrid.cellCountsBuffer);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "triangleMeshHeaders", colliderGrid.triangleMeshHeaders);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "bihNodes", colliderGrid.bihNodes);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "triangles", colliderGrid.triangles);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "vertices", colliderGrid.vertices);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "edgeMeshHeaders", colliderGrid.edgeMeshHeaders);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "edgeBihNodes", colliderGrid.edgeBihNodes);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "edges", colliderGrid.edges);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "edgeVertices", colliderGrid.edgeVertices);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "distanceFieldHeaders", colliderGrid.distanceFieldHeaders);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "dfNodes", colliderGrid.dfNodes);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "heightFieldHeaders", colliderGrid.heightFieldHeaders);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "heightFieldSamples", colliderGrid.heightFieldSamples);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "worldToSolver", worldToSolverBuffer);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "solverToWorld", solverToWorldBuffer);
foamCollisionShader.SetBuffer(solveDiffuseContactsKernel, "dispatch", abstraction.foamCount.computeBuffer);
foamCollisionShader.DispatchIndirect(solveDiffuseContactsKernel, abstraction.foamCount.computeBuffer);
}
private void UpdateDiffuseParticles(float deltaTime)
{
var system = abstraction.GetRenderSystem<ObiFoamGenerator>() as ComputeFoamRenderSystem;
if (system != null && m_Solver.maxFoamParticles > 0 && particleGrid.sortedLinearVel != null)
{
foamShader.SetFloat("deltaTime", deltaTime);
foamShader.SetFloat("randomSeed", Time.frameCount % 16535 + Random.value);
foamShader.SetVector("gravity", m_Solver.parameters.gravity * m_Solver.parameters.foamGravityScale);
foamShader.SetVector("agingOverPopulation", new Vector3(m_Solver.foamAccelAgingRange.x, m_Solver.foamAccelAgingRange.y, m_Solver.foamAccelAging));
foamShader.SetInt("maxFoamParticles", abstraction.foamPositions.computeBuffer.count);
foamShader.SetInt("minFluidNeighbors", abstraction.foamMinNeighbors);
foamShader.SetInt("maxCells", particleGrid.maxCells);
foamShader.SetInt("pointCount", simplexCounts.pointCount);
foamShader.SetInt("edgeCount", simplexCounts.edgeCount);
foamShader.SetInt("triangleCount", simplexCounts.triangleCount);
foamShader.SetBuffer(sortDataKernel, "positions", positionsBuffer);
foamShader.SetBuffer(sortDataKernel, "velocities", velocitiesBuffer);
foamShader.SetBuffer(sortDataKernel, "angularVelocities", angularVelocitiesBuffer);
foamShader.SetBuffer(sortDataKernel, "orientations", renderableOrientationsBuffer);
foamShader.SetBuffer(sortDataKernel, "principalRadii", renderableRadiiBuffer);
foamShader.SetBuffer(sortDataKernel, "sortedPositions", particleGrid.sortedPositions);
foamShader.SetBuffer(sortDataKernel, "sortedVelocities", particleGrid.sortedLinearVel);
foamShader.SetBuffer(sortDataKernel, "sortedAngularVelocities", particleGrid.sortedAngularVel);
foamShader.SetBuffer(sortDataKernel, "sortedOrientations", particleGrid.sortedPrevPosOrientations);
foamShader.SetBuffer(sortDataKernel, "sortedRadii", particleGrid.sortedPrincipalRadii);
foamShader.SetBuffer(sortDataKernel, "sortedToOriginal", particleGrid.sortedFluidIndices);
foamShader.SetBuffer(sortDataKernel, "dispatch", fluidDispatchBuffer);
foamShader.DispatchIndirect(sortDataKernel, fluidDispatchBuffer);
int threadGroups;
foamShader.SetBuffer(emitFoamKernel, "positions", positionsBuffer);
foamShader.SetBuffer(emitFoamKernel, "velocities", velocitiesBuffer);
foamShader.SetBuffer(emitFoamKernel, "angularVelocities", angularVelocitiesBuffer);
foamShader.SetBuffer(emitFoamKernel, "fluidData", fluidDataBuffer);
foamShader.SetBuffer(emitFoamKernel, "principalRadii", principalRadiiBuffer);
foamShader.SetBuffer(emitFoamKernel, "outputPositions", abstraction.foamPositions.computeBuffer);
foamShader.SetBuffer(emitFoamKernel, "outputVelocities", abstraction.foamVelocities.computeBuffer);
foamShader.SetBuffer(emitFoamKernel, "outputColors", abstraction.foamColors.computeBuffer);
foamShader.SetBuffer(emitFoamKernel, "outputAttributes", abstraction.foamAttributes.computeBuffer);
foamShader.SetBuffer(emitFoamKernel, "dispatch", abstraction.foamCount.computeBuffer);
foamShader.SetBuffer(emitShapeFoamKernel, "outputPositions", abstraction.foamPositions.computeBuffer);
foamShader.SetBuffer(emitShapeFoamKernel, "outputVelocities", abstraction.foamVelocities.computeBuffer);
foamShader.SetBuffer(emitShapeFoamKernel, "outputColors", abstraction.foamColors.computeBuffer);
foamShader.SetBuffer(emitShapeFoamKernel, "outputAttributes", abstraction.foamAttributes.computeBuffer);
foamShader.SetBuffer(emitShapeFoamKernel, "dispatch", abstraction.foamCount.computeBuffer);
for (int i = 0; i < system.renderers.Count; ++i)
{
// solver indices compute buffer may be null
if (system.renderers[i].actor.solverIndices?.computeBuffer != null)
{
threadGroups = ComputeMath.ThreadGroupCount(system.renderers[i].actor.activeParticleCount, 128);
foamShader.SetInt("activeParticleCount", system.renderers[i].actor.activeParticleCount);
foamShader.SetVector("vorticityRange", system.renderers[i].vorticityRange);
foamShader.SetVector("velocityRange", system.renderers[i].velocityRange);
foamShader.SetFloat("foamGenerationRate", system.renderers[i].foamGenerationRate);
foamShader.SetFloat("potentialIncrease", system.renderers[i].foamPotential);
foamShader.SetFloat("potentialDiffusion", Mathf.Pow(1 - Mathf.Clamp01(system.renderers[i].foamPotentialDiffusion), deltaTime));
foamShader.SetFloat("buoyancy", system.renderers[i].buoyancy);
foamShader.SetFloat("drag", system.renderers[i].drag);
foamShader.SetFloat("airDrag", Mathf.Pow(1 - Mathf.Clamp01(system.renderers[i].atmosphericDrag), deltaTime));
foamShader.SetFloat("airAging", system.renderers[i].airAging);
foamShader.SetFloat("isosurface", system.renderers[i].isosurface);
foamShader.SetFloat("particleSize", system.renderers[i].size);
foamShader.SetFloat("sizeRandom", system.renderers[i].sizeRandom);
foamShader.SetFloat("lifetime", system.renderers[i].lifetime);
foamShader.SetFloat("lifetimeRandom", system.renderers[i].lifetimeRandom);
foamShader.SetVector("foamColor", system.renderers[i].color);
if (system.renderers[i] is ObiFoamEmitter)
{
var emitter = system.renderers[i] as ObiFoamEmitter;
int particlesToEmit = emitter.GetParticleNumberToEmit(deltaTime);
threadGroups = ComputeMath.ThreadGroupCount(particlesToEmit, 128);
foamShader.SetInt("particlesToEmit", particlesToEmit);
foamShader.SetInt("emitterShape", (int)emitter.shape);
foamShader.SetVector("emitterPosition", emitter.shapeTransform != null? abstraction.transform.InverseTransformPoint(emitter.shapeTransform.position) : Vector3.zero);
foamShader.SetVector("emitterRotation", (emitter.shapeTransform != null ? emitter.shapeTransform.rotation * Quaternion.Inverse(abstraction.transform.rotation): Quaternion.identity).AsVector4());
foamShader.SetVector("emitterSize", emitter.shapeSize);
foamShader.Dispatch(emitShapeFoamKernel, threadGroups, 1, 1);
}
else // generator
{
foamShader.SetBuffer(emitFoamKernel, "activeParticles", system.renderers[i].actor.solverIndices.computeBuffer);
foamShader.Dispatch(emitFoamKernel, threadGroups, 1, 1);
}
}
}
foamShader.SetBuffer(copyAliveKernel, "dispatch", abstraction.foamCount.computeBuffer);
foamShader.Dispatch(copyAliveKernel, 1, 1, 1);
foamShader.SetBuffer(updateFoamKernel, "cellOffsets", particleGrid.cellOffsets);
foamShader.SetBuffer(updateFoamKernel, "cellCounts", particleGrid.cellCounts);
foamShader.SetBuffer(updateFoamKernel, "gridHashToSortedIndex", particleGrid.cellHashToMortonIndex);
foamShader.SetBuffer(updateFoamKernel, "levelPopulation", particleGrid.levelPopulation);
foamShader.SetBuffer(updateFoamKernel, "solverBounds", reducedBounds);
foamShader.SetBuffer(updateFoamKernel, "positions", particleGrid.sortedPositions);
foamShader.SetBuffer(updateFoamKernel, "orientations", particleGrid.sortedPrevPosOrientations);
foamShader.SetBuffer(updateFoamKernel, "principalRadii", particleGrid.sortedPrincipalRadii);
foamShader.SetBuffer(updateFoamKernel, "velocities", particleGrid.sortedLinearVel);
foamShader.SetBuffer(updateFoamKernel, "angularVelocities", particleGrid.sortedAngularVel);
foamShader.SetBuffer(updateFoamKernel, "fluidMaterial", particleGrid.sortedFluidMaterials);
foamShader.SetBuffer(updateFoamKernel, "fluidData", particleGrid.sortedFluidData);
foamShader.SetBuffer(updateFoamKernel, "fluidSimplices", particleGrid.sortedSimplexToFluid);
foamShader.SetBuffer(updateFoamKernel, "sortedToOriginal", particleGrid.sortedFluidIndices);
foamShader.SetBuffer(updateFoamKernel, "inputPositions", abstraction.foamPositions.computeBuffer);
foamShader.SetBuffer(updateFoamKernel, "inputVelocities", abstraction.foamVelocities.computeBuffer);
foamShader.SetBuffer(updateFoamKernel, "inputColors", abstraction.foamColors.computeBuffer);
foamShader.SetBuffer(updateFoamKernel, "inputAttributes", abstraction.foamAttributes.computeBuffer);
foamShader.SetBuffer(updateFoamKernel, "outputPositions", auxPositions);
foamShader.SetBuffer(updateFoamKernel, "outputVelocities", auxVelocities);
foamShader.SetBuffer(updateFoamKernel, "outputColors", auxColors);
foamShader.SetBuffer(updateFoamKernel, "outputAttributes", auxAttributes);
foamShader.SetBuffer(updateFoamKernel, "dispatch", abstraction.foamCount.computeBuffer);
foamShader.DispatchIndirect(updateFoamKernel, abstraction.foamCount.computeBuffer);
// copy aux buffers to solver buffers:
foamShader.SetBuffer(copyKernel, "inputPositions", auxPositions);
foamShader.SetBuffer(copyKernel, "inputVelocities", auxVelocities);
foamShader.SetBuffer(copyKernel, "inputColors", auxColors);
foamShader.SetBuffer(copyKernel, "inputAttributes", auxAttributes);
foamShader.SetBuffer(copyKernel, "outputPositions", abstraction.foamPositions.computeBuffer);
foamShader.SetBuffer(copyKernel, "outputVelocities", abstraction.foamVelocities.computeBuffer);
foamShader.SetBuffer(copyKernel, "outputColors", abstraction.foamColors.computeBuffer);
foamShader.SetBuffer(copyKernel, "outputAttributes", abstraction.foamAttributes.computeBuffer);
foamShader.SetBuffer(copyKernel, "dispatch", abstraction.foamCount.computeBuffer);
foamShader.DispatchIndirect(copyKernel, abstraction.foamCount.computeBuffer, 16);
AsyncGPUReadback.Request(abstraction.foamCount.computeBuffer, 4, 12, (AsyncGPUReadbackRequest obj) =>
{
if (obj.done && !obj.hasError)
this.activeFoamParticleCount = obj.GetData<uint>()[0];
});
}
else
activeFoamParticleCount = 0;
}
private void IntegrateDiffuseParticles(float deltaTime)
{
foamShader.SetFloat("deltaTime", deltaTime);
foamShader.SetBuffer(integrateFoamKernel, "outputPositions", abstraction.foamPositions.computeBuffer);
foamShader.SetBuffer(integrateFoamKernel, "outputVelocities", abstraction.foamVelocities.computeBuffer);
foamShader.SetBuffer(integrateFoamKernel, "dispatch", abstraction.foamCount.computeBuffer);
foamShader.DispatchIndirect(integrateFoamKernel, abstraction.foamCount.computeBuffer);
}
public void SpatialQuery(ObiNativeQueryShapeList shapes, ObiNativeAffineTransformList transforms, ObiNativeQueryResultList results)
{
if (abstraction.queryResults.count != abstraction.maxQueryResults)
{
abstraction.queryResults.ResizeUninitialized((int)abstraction.maxQueryResults);
abstraction.queryResults.SafeAsComputeBuffer<QueryResult>(GraphicsBuffer.Target.Counter);
}
spatialQueries.SpatialQuery(this, shapes.SafeAsComputeBuffer<QueryShape>(),
transforms.SafeAsComputeBuffer<AffineTransform>(),
results.computeBuffer);
}
public int GetParticleGridSize()
{
//return particleGrid.grid.usedCells.Length;
return 0;
}
public void GetParticleGrid(ObiNativeAabbList cells)
{
//particleGrid.GetCells(cells);
}
}
}