Files
Fishing2/Assets/Obi/Scripts/Common/Backends/Compute/DataStructures/ComputeParticleGrid.cs
2025-11-10 00:08:26 +08:00

425 lines
26 KiB
C#

using UnityEngine;
using System;
namespace Obi
{
public class ComputeParticleGrid : IDisposable
{
public ComputeShader gridShader;
public int clearKernel;
public int insertSimplicesKernel;
public int gridPopulationKernel;
public int sortSimplicesKernel;
public int buildFluidDispatchKernel;
public int buildMortonKernel;
public int mortonSortKernel;
public int sortFluidSimplicesKernel;
public int sameLevelNeighborsKernel;
public int upperLevelsNeighborsKernel;
public int buildFluidIndexBufferKernel;
public int contactsKernel;
public ComputePrefixSum cellsPrefixSum;
private ComputePrefixSum fluidPrefixSum;
public GraphicsBuffer cellCounts; // for each cell, how many simplices in it.
public GraphicsBuffer cellOffsets; // index of the first simplex in the cell (on gridToMorton buffer).
public GraphicsBuffer offsetInCell; // for each simplex, offset within its cell.
public GraphicsBuffer levelPopulation; // buffer storing amount of entries in each grid level
public GraphicsBuffer neighbors; // neighbor indices for all particles. (maxNeighbors * simplexCount in size)
public GraphicsBuffer neighborCounts; // amount of neighbors for each particle. (simplexCount in size)
public GraphicsBuffer contactPairs; // list of particle pairs.
public GraphicsBuffer dispatchBuffer; // dispatch info for iterating trough contacts.
public GraphicsBuffer cellHashToMortonIndex;
public GraphicsBuffer mortonSortedCellHashes; // contains all cell hashes sorted according to their morton index.
public GraphicsBuffer sortedSimplexIndices; // maps from grid index to simplex index.
public GraphicsBuffer sortedFluidIndices; // contains compacted sorted indices of fluid simplices *only*. Eg, entry 0 contains the index of the first fluid simplex along the morton curve.
public GraphicsBuffer sortedSimplexToFluid; // maps from sorted simplex index to sorted fluid index, or -1 if the simplex is not fluid.
public GraphicsBuffer sortedPrincipalRadii; // Used by Density constraints: needs to be sorted once per step (not changed by constraints)
public GraphicsBuffer sortedFluidMaterials; // Used by Density constraints: needs to be sorted once per step (not changed by constraints)
public GraphicsBuffer sortedFluidInterface; // Used by Density constraints: needs to be sorted once per step (not changed by constraints)
public GraphicsBuffer sortedFluidData; // Used by Density constraints: no need to be sorted (constraints output).
public GraphicsBuffer sortedLinearVel; // Not used by density constraints: used for foam advection and mesher.
public GraphicsBuffer sortedAngularVel; // Not used by density constraints: used for foam advection.
public GraphicsBuffer sortedPositions; // Used by Density constraints: needs to be sorted once per iteration.
public GraphicsBuffer sortedPrevPosOrientations; // Used by Density constraints: needs to be sorted once per iteration. Reuse for orientations (foam advection and mesher).
public GraphicsBuffer sortedUserDataColor; // Used by Density constraints: needs to be sorted once per iteration. Reuse for colors (mesher).
private const int maxGridLevels = 24;
private uint[] clearDispatch = { 0, 1, 1, 0 };
public int maxParticleNeighbors { get; private set; } = 128;
public int maxParticleContacts { get; private set; } = 4;
public int maxCells{
get { return cellCounts != null ? cellCounts.count : 0; }
}
public ComputeParticleGrid()
{
gridShader = GameObject.Instantiate(Resources.Load<ComputeShader>("Compute/ParticleGrid"));
clearKernel = gridShader.FindKernel("Clear");
insertSimplicesKernel = gridShader.FindKernel("InsertSimplices");
gridPopulationKernel = gridShader.FindKernel("FindPopulatedLevels");
sortSimplicesKernel = gridShader.FindKernel("SortSimplices");
buildFluidDispatchKernel = gridShader.FindKernel("BuildFluidDispatch");
buildMortonKernel = gridShader.FindKernel("BuildMortonIndices");
mortonSortKernel = gridShader.FindKernel("MortonSort");
sortFluidSimplicesKernel = gridShader.FindKernel("SortFluidSimplices");
sameLevelNeighborsKernel = gridShader.FindKernel("FindFluidNeighborsInSameLevel");
upperLevelsNeighborsKernel = gridShader.FindKernel("FindFluidNeighborsInUpperLevels");
buildFluidIndexBufferKernel = gridShader.FindKernel("BuildFluidParticleIndexBuffer");
contactsKernel = gridShader.FindKernel("BuildContactList");
levelPopulation = new GraphicsBuffer(GraphicsBuffer.Target.Structured, maxGridLevels + 1, 4);
dispatchBuffer = new GraphicsBuffer(GraphicsBuffer.Target.IndirectArguments, 4, sizeof(uint));
}
private void Clear()
{
cellsPrefixSum?.Dispose();
fluidPrefixSum?.Dispose();
if (cellCounts != null)
cellCounts.Dispose();
if (cellOffsets != null)
cellOffsets.Dispose();
if (offsetInCell != null)
offsetInCell.Dispose();
if (contactPairs != null)
contactPairs.Dispose();
if (neighbors != null)
neighbors.Dispose();
if (neighborCounts != null)
neighborCounts.Dispose();
if (cellHashToMortonIndex != null)
cellHashToMortonIndex.Dispose();
if (mortonSortedCellHashes != null)
mortonSortedCellHashes.Dispose();
if (sortedSimplexIndices != null)
sortedSimplexIndices.Dispose();
if (sortedFluidIndices != null)
sortedFluidIndices.Dispose();
if (sortedSimplexToFluid != null)
sortedSimplexToFluid.Dispose();
if (sortedPositions != null)
sortedPositions.Dispose();
if (sortedPrevPosOrientations != null)
sortedPrevPosOrientations.Dispose();
if (sortedPrincipalRadii != null)
sortedPrincipalRadii.Dispose();
if (sortedFluidMaterials != null)
sortedFluidMaterials.Dispose();
if (sortedFluidInterface != null)
sortedFluidInterface.Dispose();
if (sortedUserDataColor != null)
sortedUserDataColor.Dispose();
if (sortedFluidData != null)
sortedFluidData.Dispose();
if (sortedLinearVel != null)
sortedLinearVel.Dispose();
if (sortedAngularVel != null)
sortedAngularVel.Dispose();
cellsPrefixSum = null;
fluidPrefixSum = null;
cellCounts = null;
cellOffsets = null;
offsetInCell = null;
contactPairs = null;
neighbors = null;
neighborCounts = null;
sortedSimplexIndices = null;
cellHashToMortonIndex = null;
sortedFluidIndices = null;
sortedSimplexToFluid = null;
sortedPositions = null;
sortedPrevPosOrientations = null;
sortedPrincipalRadii = null;
sortedFluidMaterials = null;
sortedFluidInterface = null;
sortedUserDataColor = null;
sortedFluidData = null;
sortedLinearVel = null;
sortedAngularVel = null;
}
public void Dispose()
{
if (levelPopulation != null)
levelPopulation.Dispose();
if (dispatchBuffer != null)
dispatchBuffer.Dispose();
levelPopulation = null;
dispatchBuffer = null;
Clear();
}
// Sets the maximum amount of items that can be stored in the grid.
public bool SetCapacity(int capacity, uint maxParticleContacts, uint maxParticleNeighbors)
{
if (offsetInCell == null || capacity > offsetInCell.count ||
maxParticleNeighbors != this.maxParticleNeighbors ||
maxParticleContacts != this.maxParticleContacts)
{
Clear();
this.maxParticleNeighbors = (int)maxParticleNeighbors;
this.maxParticleContacts = (int)maxParticleContacts;
capacity *= 2;
int hashtableSize = (int)(capacity * 1.5f);
// hashtable data:
cellCounts = new GraphicsBuffer(GraphicsBuffer.Target.Structured, hashtableSize, 4);
cellOffsets = new GraphicsBuffer(GraphicsBuffer.Target.Structured, hashtableSize, 4);
mortonSortedCellHashes = new GraphicsBuffer(GraphicsBuffer.Target.Structured, hashtableSize, 4);
cellHashToMortonIndex = new GraphicsBuffer(GraphicsBuffer.Target.Structured, hashtableSize, 4);
cellsPrefixSum = new ComputePrefixSum(hashtableSize);
// per simplex data:
offsetInCell = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capacity, 4);
sortedSimplexIndices = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capacity, 4);
sortedFluidIndices = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capacity, 4);
sortedSimplexToFluid = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capacity, 4);
// contact pairs and neighbor lists:
contactPairs = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capacity * (int)maxParticleContacts, 8);
neighbors = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capacity * (int)maxParticleNeighbors, 4);
neighborCounts = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capacity, 4);
// sorted fluid simplex data:
fluidPrefixSum = new ComputePrefixSum(capacity);
sortedPrincipalRadii = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capacity, 16);
sortedFluidMaterials = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capacity, 16);
sortedFluidInterface = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capacity, 16);
sortedPositions = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capacity, 16);
sortedPrevPosOrientations = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capacity, 16);
sortedUserDataColor = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capacity, 16);
sortedFluidData = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capacity, 16);
sortedLinearVel = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capacity, 16);
sortedAngularVel = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capacity, 16);
return true;
}
return false;
}
public void BuildGrid(ComputeSolverImpl solver, float deltaTime)
{
dispatchBuffer.SetData(clearDispatch);
solver.fluidDispatchBuffer.SetData(clearDispatch);
if (solver.simplexCounts.simplexCount > 0)
{
gridShader.SetInt("pointCount", solver.simplexCounts.pointCount);
gridShader.SetInt("edgeCount", solver.simplexCounts.edgeCount);
gridShader.SetInt("triangleCount", solver.simplexCounts.triangleCount);
gridShader.SetInt("maxContacts", contactPairs.count);
gridShader.SetInt("maxCells", cellCounts.count);
gridShader.SetInt("maxNeighbors", maxParticleNeighbors);
gridShader.SetFloat("deltaTime", deltaTime);
gridShader.SetFloat("collisionMargin", solver.abstraction.parameters.collisionMargin);
gridShader.SetFloat("particleCCD", solver.abstraction.parameters.particleCCD);
int cellThreadGroups = ComputeMath.ThreadGroupCount(cellCounts.count, 128);
solver.abstraction.particleContacts.computeBuffer.SetCounterValue(0);
int simplexThreadGroups = ComputeMath.ThreadGroupCount(solver.simplexCounts.simplexCount, 128);
// clear grid:
gridShader.SetBuffer(clearKernel, "cellCounts", cellCounts);
gridShader.SetBuffer(clearKernel, "cellOffsets", cellOffsets);
gridShader.SetBuffer(clearKernel, "levelPopulation", levelPopulation);
gridShader.SetBuffer(clearKernel, "mortonSortedCellHashes", mortonSortedCellHashes);
gridShader.Dispatch(clearKernel, cellThreadGroups, 1, 1);
// insert simplices in grid and flag fluid simplices:
gridShader.SetBuffer(insertSimplicesKernel, "solverBounds", solver.reducedBounds);
gridShader.SetBuffer(insertSimplicesKernel, "simplexBounds", solver.simplexBounds);
gridShader.SetBuffer(insertSimplicesKernel, "simplices", solver.simplices);
gridShader.SetBuffer(insertSimplicesKernel, "phases", solver.phasesBuffer);
gridShader.SetBuffer(insertSimplicesKernel, "neighborCounts", neighborCounts);
gridShader.SetBuffer(insertSimplicesKernel, "levelPopulation", levelPopulation);
gridShader.SetBuffer(insertSimplicesKernel, "cellCoords", solver.cellCoordsBuffer);
gridShader.SetBuffer(insertSimplicesKernel, "cellCounts", cellCounts);
gridShader.SetBuffer(insertSimplicesKernel, "offsetInCell", offsetInCell);
gridShader.SetBuffer(insertSimplicesKernel, "cellOffsets", cellOffsets);
gridShader.Dispatch(insertSimplicesKernel, simplexThreadGroups, 1, 1);
// find populated grid levels:
gridShader.SetBuffer(gridPopulationKernel, "levelPopulation", levelPopulation);
gridShader.Dispatch(gridPopulationKernel, 1, 1, 1);
// sort cells along morton curve:
gridShader.SetBuffer(mortonSortKernel, "mortonSortedCellHashes", mortonSortedCellHashes);
gridShader.SetBuffer(mortonSortKernel, "cellOffsets", cellOffsets);
gridShader.SetBuffer(mortonSortKernel, "cellCounts", cellCounts);
int numPairs = ObiUtils.CeilToPowerOfTwo(maxCells) / 2;
int numStages = (int)Mathf.Log(numPairs * 2, 2);
int groups = ComputeMath.ThreadGroupCount(numPairs, 128);
for (int stageIndex = 0; stageIndex < numStages; stageIndex++)
{
for (int stepIndex = 0; stepIndex < stageIndex + 1; stepIndex++)
{
int groupWidth = 1 << (stageIndex - stepIndex);
int groupHeight = 2 * groupWidth - 1;
gridShader.SetInt("groupWidth", groupWidth);
gridShader.SetInt("groupHeight", groupHeight);
gridShader.SetInt("stepIndex", stepIndex);
gridShader.Dispatch(mortonSortKernel, groups, 1, 1);
}
}
// build morton indices:
gridShader.SetBuffer(buildMortonKernel, "mortonSortedCellHashes", mortonSortedCellHashes);
gridShader.SetBuffer(buildMortonKernel, "cellHashToMortonIndex", cellHashToMortonIndex);
gridShader.Dispatch(buildMortonKernel, cellThreadGroups, 1, 1);
// prefix sum to build cell start array:
cellsPrefixSum.Sum(cellCounts, cellOffsets);
// sort simplex indices and compact fluid simplex indices:
gridShader.SetBuffer(sortSimplicesKernel, "phases", solver.phasesBuffer);
gridShader.SetBuffer(sortSimplicesKernel, "cellHashToMortonIndex", cellHashToMortonIndex);
gridShader.SetBuffer(sortSimplicesKernel, "sortedSimplexIndices", sortedSimplexIndices);
gridShader.SetBuffer(sortSimplicesKernel, "sortedFluidIndices", sortedFluidIndices);
gridShader.SetBuffer(sortSimplicesKernel, "R_offsetInCell", offsetInCell);
gridShader.SetBuffer(sortSimplicesKernel, "R_cellOffsets", cellOffsets);
gridShader.SetBuffer(sortSimplicesKernel, "R_cellCoords", solver.cellCoordsBuffer);
gridShader.SetBuffer(sortSimplicesKernel, "simplices", solver.simplices);
gridShader.Dispatch(sortSimplicesKernel, simplexThreadGroups, 1, 1);
// prefix sum of fluid flags:
fluidPrefixSum.Sum(sortedFluidIndices, sortedSimplexToFluid);
// build fluid dispatch buffer:
gridShader.SetBuffer(buildFluidDispatchKernel, "fluidDispatchBuffer", solver.fluidDispatchBuffer);
gridShader.SetBuffer(buildFluidDispatchKernel, "sortedFluidIndices", sortedFluidIndices);
gridShader.SetBuffer(buildFluidDispatchKernel, "sortedSimplexToFluid", sortedSimplexToFluid);
gridShader.Dispatch(buildFluidDispatchKernel, 1, 1, 1);
// sort fluid data:
gridShader.SetBuffer(sortFluidSimplicesKernel, "sortedFluidIndices", sortedFluidIndices);
gridShader.SetBuffer(sortFluidSimplicesKernel, "cellHashToMortonIndex", cellHashToMortonIndex);
gridShader.SetBuffer(sortFluidSimplicesKernel, "positions", solver.positionsBuffer);
gridShader.SetBuffer(sortFluidSimplicesKernel, "fluidInterface", solver.fluidInterfaceBuffer);
gridShader.SetBuffer(sortFluidSimplicesKernel, "principalRadii", solver.principalRadiiBuffer);
gridShader.SetBuffer(sortFluidSimplicesKernel, "phases", solver.phasesBuffer);
gridShader.SetBuffer(sortFluidSimplicesKernel, "sortedPositions", sortedPositions);
gridShader.SetBuffer(sortFluidSimplicesKernel, "sortedFluidMaterials", sortedFluidMaterials);
gridShader.SetBuffer(sortFluidSimplicesKernel, "sortedFluidInterface", sortedFluidInterface);
gridShader.SetBuffer(sortFluidSimplicesKernel, "sortedPrincipalRadii", sortedPrincipalRadii);
gridShader.SetBuffer(sortFluidSimplicesKernel, "fluidMaterials", solver.fluidMaterialsBuffer);
gridShader.SetBuffer(sortFluidSimplicesKernel, "R_offsetInCell", offsetInCell);
gridShader.SetBuffer(sortFluidSimplicesKernel, "R_cellOffsets", cellOffsets);
gridShader.SetBuffer(sortFluidSimplicesKernel, "R_cellCoords", solver.cellCoordsBuffer);
gridShader.SetBuffer(sortFluidSimplicesKernel, "sortedSimplexToFluid", sortedSimplexToFluid);
gridShader.SetBuffer(sortFluidSimplicesKernel, "simplices", solver.simplices);
gridShader.SetBuffer(sortFluidSimplicesKernel, "fluidDispatchBuffer", solver.fluidDispatchBuffer);
gridShader.Dispatch(sortFluidSimplicesKernel, simplexThreadGroups, 1, 1);
}
}
public void GenerateContacts(ComputeSolverImpl solver)
{
if (solver.simplexCounts.simplexCount > 0)
{
int simplexThreadGroups = ComputeMath.ThreadGroupCount(solver.simplexCounts.simplexCount, 128);
// generate contacts list:
gridShader.SetBuffer(contactsKernel, "simplices", solver.simplices);
gridShader.SetBuffer(contactsKernel, "sortedSimplexIndices", sortedSimplexIndices);
gridShader.SetBuffer(contactsKernel, "sortedPositions", sortedPositions);
gridShader.SetBuffer(contactsKernel, "sortedFluidMaterials", sortedFluidMaterials);
gridShader.SetBuffer(contactsKernel, "positions", solver.positionsBuffer);
gridShader.SetBuffer(contactsKernel, "cellHashToMortonIndex", cellHashToMortonIndex);
gridShader.SetBuffer(contactsKernel, "restPositions", solver.restPositionsBuffer);
gridShader.SetBuffer(contactsKernel, "orientations", solver.orientationsBuffer);
gridShader.SetBuffer(contactsKernel, "restOrientations", solver.restOrientationsBuffer);
gridShader.SetBuffer(contactsKernel, "velocities", solver.velocitiesBuffer);
gridShader.SetBuffer(contactsKernel, "invMasses", solver.invMassesBuffer);
gridShader.SetBuffer(contactsKernel, "phases", solver.phasesBuffer);
gridShader.SetBuffer(contactsKernel, "filters", solver.filtersBuffer);
gridShader.SetBuffer(contactsKernel, "principalRadii", solver.principalRadiiBuffer);
gridShader.SetBuffer(contactsKernel, "normals", solver.normalsBuffer);
gridShader.SetBuffer(contactsKernel, "R_cellCoords", solver.cellCoordsBuffer);
gridShader.SetBuffer(contactsKernel, "R_cellOffsets", cellOffsets);
gridShader.SetBuffer(contactsKernel, "R_cellCounts", cellCounts);
gridShader.SetBuffer(contactsKernel, "R_offsetInCell", offsetInCell);
gridShader.SetBuffer(contactsKernel, "R_levelPopulation", levelPopulation);
gridShader.SetBuffer(contactsKernel, "particleContacts", solver.abstraction.particleContacts.computeBuffer);
gridShader.SetBuffer(contactsKernel, "contactPairs", contactPairs);
gridShader.SetBuffer(contactsKernel, "dispatchBuffer", dispatchBuffer);
gridShader.Dispatch(contactsKernel, simplexThreadGroups, 1, 1);
}
}
public void GenerateFluidNeighborhoods(ComputeSolverImpl solver)
{
if (solver.simplexCounts.simplexCount > 0)
{
// generate fluid neighbors list:
gridShader.SetBuffer(sameLevelNeighborsKernel, "solverBounds", solver.reducedBounds);
gridShader.SetBuffer(sameLevelNeighborsKernel, "cellHashToMortonIndex", cellHashToMortonIndex);
gridShader.SetBuffer(sameLevelNeighborsKernel, "sortedFluidIndices", sortedFluidIndices);
gridShader.SetBuffer(sameLevelNeighborsKernel, "sortedPositions", sortedPositions);
gridShader.SetBuffer(sameLevelNeighborsKernel, "sortedFluidMaterials", sortedFluidMaterials);
gridShader.SetBuffer(sameLevelNeighborsKernel, "R_cellCoords", solver.cellCoordsBuffer);
gridShader.SetBuffer(sameLevelNeighborsKernel, "R_cellOffsets", cellOffsets);
gridShader.SetBuffer(sameLevelNeighborsKernel, "R_cellCounts", cellCounts);
gridShader.SetBuffer(sameLevelNeighborsKernel, "R_offsetInCell", offsetInCell);
gridShader.SetBuffer(sameLevelNeighborsKernel, "R_levelPopulation", levelPopulation);
gridShader.SetBuffer(sameLevelNeighborsKernel, "sortedSimplexToFluid", sortedSimplexToFluid);
gridShader.SetBuffer(sameLevelNeighborsKernel, "simplices", solver.simplices);
gridShader.SetBuffer(sameLevelNeighborsKernel, "neighbors", neighbors);
gridShader.SetBuffer(sameLevelNeighborsKernel, "neighborCounts", neighborCounts);
gridShader.SetBuffer(sameLevelNeighborsKernel, "dispatchBuffer", solver.fluidDispatchBuffer);
gridShader.DispatchIndirect(sameLevelNeighborsKernel, solver.fluidDispatchBuffer);
gridShader.SetBuffer(upperLevelsNeighborsKernel, "solverBounds", solver.reducedBounds);
gridShader.SetBuffer(upperLevelsNeighborsKernel, "cellHashToMortonIndex", cellHashToMortonIndex);
gridShader.SetBuffer(upperLevelsNeighborsKernel, "sortedPositions", sortedPositions);
gridShader.SetBuffer(upperLevelsNeighborsKernel, "sortedFluidIndices", sortedFluidIndices);
gridShader.SetBuffer(upperLevelsNeighborsKernel, "mortonSortedSimplexIndices", mortonSortedCellHashes);
gridShader.SetBuffer(upperLevelsNeighborsKernel, "sortedFluidMaterials", sortedFluidMaterials);
gridShader.SetBuffer(upperLevelsNeighborsKernel, "R_cellCoords", solver.cellCoordsBuffer);
gridShader.SetBuffer(upperLevelsNeighborsKernel, "R_cellOffsets", cellOffsets);
gridShader.SetBuffer(upperLevelsNeighborsKernel, "R_cellCounts", cellCounts);
gridShader.SetBuffer(upperLevelsNeighborsKernel, "R_offsetInCell", offsetInCell);
gridShader.SetBuffer(upperLevelsNeighborsKernel, "R_levelPopulation", levelPopulation);
gridShader.SetBuffer(upperLevelsNeighborsKernel, "sortedSimplexToFluid", sortedSimplexToFluid);
gridShader.SetBuffer(upperLevelsNeighborsKernel, "simplices", solver.simplices);
gridShader.SetBuffer(upperLevelsNeighborsKernel, "neighbors", neighbors);
gridShader.SetBuffer(upperLevelsNeighborsKernel, "neighborCounts", neighborCounts);
gridShader.SetBuffer(upperLevelsNeighborsKernel, "dispatchBuffer", solver.fluidDispatchBuffer);
gridShader.DispatchIndirect(upperLevelsNeighborsKernel, solver.fluidDispatchBuffer);
gridShader.SetBuffer(buildFluidIndexBufferKernel, "sortedFluidIndices", sortedFluidIndices);
gridShader.SetBuffer(buildFluidIndexBufferKernel, "simplices", solver.simplices);
gridShader.SetBuffer(buildFluidIndexBufferKernel, "dispatchBuffer", solver.fluidDispatchBuffer);
gridShader.DispatchIndirect(buildFluidIndexBufferKernel, solver.fluidDispatchBuffer);
}
}
}
}