Files
UnrealEngine/Engine/Plugins/Runtime/HairStrands/Shaders/Private/NiagaraDataInterfacePressureGridTemplate.ush
2025-05-18 13:04:45 +08:00

549 lines
22 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
NiagaraDataInterfacePressureGrid.ush
=============================================================================*/
/* -----------------------------------------------------------------
* Scale the velocity, mass and distance buffer from the current to the destination buffer
* -----------------------------------------------------------------
*/
void ScaleCellDistance_{ParameterName}(in int3 GridIndex, in float GridLength )
{
float FluidDistance = ConvertGridScalar_{ParameterName}(GridIndex,FLUID_DISTANCE_OFFSET);
[branch]
if(FluidDistance < 0.5 * GridLength)
{
const float SolidDistance = (GetGridScalar_{ParameterName}(int3(GridIndex.x+0,GridIndex.y+0,GridIndex.z+0),SOLID_DISTANCE_OFFSET) +
GetGridScalar_{ParameterName}(int3(GridIndex.x+0,GridIndex.y+0,GridIndex.z+1),SOLID_DISTANCE_OFFSET) +
GetGridScalar_{ParameterName}(int3(GridIndex.x+0,GridIndex.y+1,GridIndex.z+0),SOLID_DISTANCE_OFFSET) +
GetGridScalar_{ParameterName}(int3(GridIndex.x+0,GridIndex.y+1,GridIndex.z+1),SOLID_DISTANCE_OFFSET) +
GetGridScalar_{ParameterName}(int3(GridIndex.x+1,GridIndex.y+0,GridIndex.z+0),SOLID_DISTANCE_OFFSET) +
GetGridScalar_{ParameterName}(int3(GridIndex.x+1,GridIndex.y+0,GridIndex.z+1),SOLID_DISTANCE_OFFSET) +
GetGridScalar_{ParameterName}(int3(GridIndex.x+1,GridIndex.y+1,GridIndex.z+0),SOLID_DISTANCE_OFFSET) +
GetGridScalar_{ParameterName}(int3(GridIndex.x+1,GridIndex.y+1,GridIndex.z+1),SOLID_DISTANCE_OFFSET) ) / 8.0;
if(SolidDistance < 0.0) FluidDistance = -0.5 * GridLength;
}
SetGridScalar_{ParameterName}(GridIndex,FLUID_DISTANCE_OFFSET,FluidDistance);
}
void ScaleFaceVelocity_{ParameterName}(in int3 GridIndex, in int ComponentIndex)
{
const float GridMomentum = ConvertGridScalar_{ParameterName}(GridIndex,FLUID_VELOCITY_OFFSET+ComponentIndex);
const float GridMass = ConvertGridScalar_{ParameterName}(GridIndex,FLUID_MASS_OFFSET+ComponentIndex);
float GridVelocity = (GridMass != 0.0) ? GridMomentum / GridMass : 0.0;
SetGridScalar_{ParameterName}(GridIndex,FLUID_VELOCITY_OFFSET+ComponentIndex,GridVelocity);
SetGridScalar_{ParameterName}(GridIndex,FLUID_MASS_OFFSET+ComponentIndex,GridMass);
}
void ScaleCellFields_{ParameterName}(in int GridHash, in float GridLength, in float DeltaTime, out bool OutTransferStatus)
{
const int3 GridIndex = GetGridIndex_{ParameterName}(GridHash);
OutTransferStatus = false;
if(IsFaceValid_{ParameterName}(GridIndex,0))
{
ScaleFaceVelocity_{ParameterName}(GridIndex,0);
}
if(IsFaceValid_{ParameterName}(GridIndex,1))
{
ScaleFaceVelocity_{ParameterName}(GridIndex,1);
}
if(IsFaceValid_{ParameterName}(GridIndex,2))
{
ScaleFaceVelocity_{ParameterName}(GridIndex,2);
}
if(IsCellValid_{ParameterName}(GridIndex))
{
ScaleCellDistance_{ParameterName}(GridIndex,GridLength);
}
if(IsCellValid_{ParameterName}(GridIndex))
{
const float SourceDensity = ConvertGridScalar_{ParameterName}(GridIndex,FLUID_DENSITY_OFFSET);
const float CurrentDensity = max(1.0,SourceDensity);
//const float DensityRatio = GridLength * (1.0-CurrentDensity) / DeltaTime;
const float DensityRatio = (CurrentDensity != 0.0) ? GridLength * log(1.0/CurrentDensity) / DeltaTime : 0.0;
SetGridScalar_{ParameterName}(GridIndex,FLUID_DENSITY_OFFSET,DensityRatio);
}
}
/* -----------------------------------------------------------------
* Build Distance/Density Field from particles
* -----------------------------------------------------------------
*/
// Compute the distance from the particle to the grid
void BuildDistanceField_{ParameterName}(in float3 GridOrigin, in float GridLength, in float3 ParticlePosition, out bool OutFunctionStatus )
{
OutFunctionStatus = true;
const float3 GridPosition = GetGridPosition_{ParameterName}(ParticlePosition,GridOrigin);
float3 GridFraction = float3(0,0,0);
const int3 GridIndex = ComputeGridIndex_{ParameterName}(GridPosition,float3(0.5,0.5,0.5),GridLength,GridFraction);
const float NodeRadius = GridLength * 0.5 * 1.414213;
for(int i = -2; i <= 2; ++i)
for(int j = -2; j <= 2; ++j)
for(int k = -2; k <= 2; ++k)
{
const int3 GridLocation = int3(GridIndex.x+i,GridIndex.y+j,GridIndex.z+k);
if( IsCellValid_{ParameterName}(GridLocation) )
{
const float3 CellPosition = (GridLocation+float3(0.5,0.5,0.5))*GridLength+GridOrigin;
const float CellDistance = length(CellPosition-ParticlePosition) - NodeRadius;
InterlockedMinScalar_{ParameterName}(GridLocation,FLUID_DISTANCE_OFFSET,CellDistance);
}
}
}
// Transfer the density from the particle to the grid
void BuildDensityField_{ParameterName}(in float3 GridOrigin, in float GridLength,
in float3 ParticlePosition, in float ParticleMass, in float ParticleDensity, out bool OutFunctionStatus )
{
OutFunctionStatus = true;
const float3 GridPosition = GetGridPosition_{ParameterName}(ParticlePosition,GridOrigin);
float3 GridFraction = float3(0,0,0);
const int3 GridIndex = ComputeGridIndex_{ParameterName}(GridPosition,float3(0.5,0.5,0.5),GridLength,GridFraction);
const float GridScale = 1.0 / (GridLength*GridLength*GridLength);
for(int i = 0; i < 2; ++i)
{
const float GridWeightX = (i == 0) ? 1.0 - GridFraction.x : GridFraction.x;
for(int j = 0; j < 2; ++j)
{
const float GridWeightY = (j == 0) ? 1.0 - GridFraction.y : GridFraction.y;
for(int k = 0; k < 2; ++k)
{
const float GridWeightZ = (k == 0) ? 1.0 - GridFraction.z : GridFraction.z;
const float GridWeightXYZ = GridWeightX*GridWeightY*GridWeightZ;
const int3 GridLocation = int3(GridIndex.x+i,GridIndex.y+j,GridIndex.z+k);
if( IsCellValid_{ParameterName}(GridLocation) )
{
InterlockedAddScalar_{ParameterName}(GridLocation,FLUID_DENSITY_OFFSET,GridWeightXYZ*ParticleMass*GridScale);
}
}
}
}
}
/* -----------------------------------------------------------------
* Get Density field from grid
* -----------------------------------------------------------------
*/
// Sample the grid velocity field and gradient at the particle world position
void GetDensityField_{ParameterName}(in float3 GridOrigin, in float GridLength,
in float3 ParticlePosition, out float OutParticleDensity)
{
OutParticleDensity = 0.0;
if(isfinite(GridLength))
{
const float3 GridPosition = GetGridPosition_{ParameterName}(ParticlePosition,GridOrigin);
float3 GridFraction = float3(0,0,0);
const int3 GridIndex = ComputeGridIndex_{ParameterName}(GridPosition,float3(0.5,0.5,0.5),GridLength,GridFraction);
for(int i = 0; i < 2; ++i)
{
const float GridWeightX = (i == 0) ? 1.0 - GridFraction.x : GridFraction.x;
for(int j = 0; j < 2; ++j)
{
const float GridWeightY = (j == 0) ? 1.0 - GridFraction.y : GridFraction.y;
for(int k = 0; k < 2; ++k)
{
const float GridWeightZ = (k == 0) ? 1.0 - GridFraction.z : GridFraction.z;
const float GridWeightXYZ = GridWeightX*GridWeightY*GridWeightZ;
const int3 GridLocation = int3(GridIndex.x+i,GridIndex.y+j,GridIndex.z+k);
if( IsCellValid_{ParameterName}(GridLocation) )
{
OutParticleDensity += GetGridScalar_{ParameterName}(GridLocation,FLUID_DENSITY_OFFSET) * GridWeightXYZ;
}
}
}
}
}
}
// Sample the grid velocity field and gradient at the particle world position
void UpdateDeformationGradient_{ParameterName}(in float DeltaTime, in float4x4 VelocityGradient,
in float4x4 DeformationGradient, out float4x4 OutDeformationGradient, out float OutGradientDeterminant)
{
float3x3 PositionGradient;
PositionGradient[0] = VelocityGradient[0].xyz * DeltaTime;
PositionGradient[1] = VelocityGradient[1].xyz * DeltaTime;
PositionGradient[2] = VelocityGradient[2].xyz * DeltaTime;
float3x3 ElasticGradient;
ElasticGradient[0] = DeformationGradient[0].xyz;
ElasticGradient[1] = DeformationGradient[1].xyz;
ElasticGradient[2] = DeformationGradient[2].xyz;
if(isfinite(PositionGradient[0][0]) && isfinite(PositionGradient[1][1]) && isfinite(PositionGradient[2][2]) )
{
ElasticGradient += mul(PositionGradient,ElasticGradient);
}
OutGradientDeterminant = determinant(ElasticGradient);
OutDeformationGradient[0] = float4(ElasticGradient[0].xyz,0.0);
OutDeformationGradient[1] = float4(ElasticGradient[1].xyz,0.0);
OutDeformationGradient[2] = float4(ElasticGradient[2].xyz,0.0);
OutDeformationGradient[3] = float4(0.0,0.0,0.0,0.0);
}
/* -----------------------------------------------------------------
* Update boundary weights
* -----------------------------------------------------------------
*/
float GetFractionInsideEdge_{ParameterName}(in float SignedDistanceA, in float SignedDistanceB)
{
const bool IsInsideA = SignedDistanceA<0.0;
const bool IsInsideB = SignedDistanceB<0.0;
return (IsInsideA && IsInsideB) ? 1.0 : (IsInsideA && !IsInsideB) ? SignedDistanceA / (SignedDistanceA - SignedDistanceB) :
(!IsInsideA && IsInsideB) ? SignedDistanceB / (SignedDistanceB - SignedDistanceA) : 0.0;
}
float GetFractionInsideImplA_{ParameterName}(in float SignedDistanceA, in float SignedDistanceB, in float SignedDistanceD)
{
const float Side0 = 1.0 - GetFractionInsideEdge_{ParameterName}(SignedDistanceA,SignedDistanceD);
const float Side1 = 1.0 - GetFractionInsideEdge_{ParameterName}(SignedDistanceA,SignedDistanceB);
return 1.0 - 0.5 * Side0 * Side1;
}
float GetFractionInsideImplB_{ParameterName}(in float SignedDistanceA, in float SignedDistanceB, in float SignedDistanceC, in float SignedDistanceD)
{
const float Side0 = GetFractionInsideEdge_{ParameterName}(SignedDistanceA,SignedDistanceD);
const float Side1 = GetFractionInsideEdge_{ParameterName}(SignedDistanceB,SignedDistanceC);
return 0.5 * ( Side0 + Side1);
}
float GetFractionInsideImplC_{ParameterName}(in float SignedDistanceA, in float SignedDistanceB, in float SignedDistanceC, in float SignedDistanceD)
{
const float MiddlePoint = 0.25 * (SignedDistanceA+SignedDistanceB+SignedDistanceC+SignedDistanceD);
if(MiddlePoint < 0.0)
{
float FaceArea = 0.0;
const float Side1 = 1.0 - GetFractionInsideEdge_{ParameterName}(SignedDistanceA,SignedDistanceD);
const float Side3 = 1.0 - GetFractionInsideEdge_{ParameterName}(SignedDistanceC,SignedDistanceD);
FaceArea += 0.5 * Side3 * Side1;
const float Side2 = 1.0 - GetFractionInsideEdge_{ParameterName}(SignedDistanceC,SignedDistanceB);
const float Side0 = 1.0 - GetFractionInsideEdge_{ParameterName}(SignedDistanceA,SignedDistanceB);
FaceArea += 0.5 * Side0 * Side2;
return 1.0 - FaceArea;
}
else
{
float FaceArea = 0.0;
const float Side0 = 1.0 - GetFractionInsideEdge_{ParameterName}(SignedDistanceA,SignedDistanceB);
const float Side1 = 1.0 - GetFractionInsideEdge_{ParameterName}(SignedDistanceA,SignedDistanceD);
FaceArea += 0.5 * Side0 * Side1;
const float Side2 = 1.0 - GetFractionInsideEdge_{ParameterName}(SignedDistanceC,SignedDistanceB);
const float Side3 = 1.0 - GetFractionInsideEdge_{ParameterName}(SignedDistanceC,SignedDistanceD);
FaceArea += 0.5 * Side3 * Side2;
return FaceArea;
}
}
float GetFractionInsideImplD_{ParameterName}(in float SignedDistanceA, in float SignedDistanceB, in float SignedDistanceD)
{
const float Side0 = GetFractionInsideEdge_{ParameterName}(SignedDistanceA,SignedDistanceD);
const float Side1 = GetFractionInsideEdge_{ParameterName}(SignedDistanceA,SignedDistanceB);
return 0.5 * Side0 * Side1;
}
float GetFractionInsideFace_{ParameterName}(in float SignedDistanceA, in float SignedDistanceB, in float SignedDistanceC, in float SignedDistanceD )
{
const bool IsInsideA = SignedDistanceA<0.0;
const bool IsInsideB = SignedDistanceB<0.0;
const bool IsInsideC = SignedDistanceC<0.0;
const bool IsInsideD = SignedDistanceD<0.0;
const int InsideCount = IsInsideA + IsInsideB + IsInsideC + IsInsideD;
[branch]
if(InsideCount == 4)
{
return 1.0;
}
else if(InsideCount == 3)
{
[branch]
if(!IsInsideA)
{
return GetFractionInsideImplA_{ParameterName}(SignedDistanceA,SignedDistanceB,SignedDistanceD);
}
else if(!IsInsideB)
{
return GetFractionInsideImplA_{ParameterName}(SignedDistanceB,SignedDistanceC,SignedDistanceA);
}
else if(!IsInsideC)
{
return GetFractionInsideImplA_{ParameterName}(SignedDistanceC,SignedDistanceD,SignedDistanceB);
}
else if(!IsInsideD)
{
return GetFractionInsideImplA_{ParameterName}(SignedDistanceD,SignedDistanceA,SignedDistanceC);
}
}
else if(InsideCount == 2)
{
[branch]
if(IsInsideA && IsInsideB)
{
return GetFractionInsideImplB_{ParameterName}(SignedDistanceA,SignedDistanceB,SignedDistanceC, SignedDistanceD);
}
else if(IsInsideB && IsInsideC)
{
return GetFractionInsideImplB_{ParameterName}(SignedDistanceB,SignedDistanceC,SignedDistanceD, SignedDistanceA);
}
else if(IsInsideC && IsInsideD)
{
return GetFractionInsideImplB_{ParameterName}(SignedDistanceC,SignedDistanceD,SignedDistanceA, SignedDistanceB);
}
else if(IsInsideD && IsInsideA)
{
return GetFractionInsideImplB_{ParameterName}(SignedDistanceD,SignedDistanceA,SignedDistanceB, SignedDistanceC);
}
else if(IsInsideA && IsInsideC)
{
return GetFractionInsideImplC_{ParameterName}(SignedDistanceA,SignedDistanceB,SignedDistanceC, SignedDistanceD);
}
else if(IsInsideB && IsInsideD)
{
return GetFractionInsideImplC_{ParameterName}(SignedDistanceB,SignedDistanceC,SignedDistanceD, SignedDistanceA);
}
}
else if(InsideCount == 1)
{
[branch]
if(IsInsideA)
{
return GetFractionInsideImplA_{ParameterName}(SignedDistanceA,SignedDistanceB,SignedDistanceD);
}
else if(IsInsideB)
{
return GetFractionInsideImplA_{ParameterName}(SignedDistanceB,SignedDistanceC,SignedDistanceA);
}
else if(IsInsideC)
{
return GetFractionInsideImplA_{ParameterName}(SignedDistanceC,SignedDistanceD,SignedDistanceB);
}
else if(IsInsideD)
{
return GetFractionInsideImplA_{ParameterName}(SignedDistanceD,SignedDistanceA,SignedDistanceC);
}
}
return 0;
}
// Update the solid weights and velocities
void SetSolidBoundary_{ParameterName}(in int GridHash, in float SolidDistance, in float3 SolidVelocity, out bool OutBoundaryStatus)
{
const int3 GridIndex = GetGridIndex_{ParameterName}(GridHash);
OutBoundaryStatus = false;
[branch]
if( IsNodeValid_{ParameterName}(GridIndex))
{
OutBoundaryStatus = true;
SetGridScalar_{ParameterName}(GridIndex,SOLID_DISTANCE_OFFSET,SolidDistance);
SetGridVector_{ParameterName}(GridIndex,SOLID_VELOCITY_OFFSET,SolidVelocity);
}
}
void ComputeFaceWeights_{ParameterName}(in int3 GridLocation, in int ComponentIndex, out float SignedDistance, inout float ParticleVelocity )
{
SignedDistance = GetGridScalar_{ParameterName}(GridLocation,SOLID_DISTANCE_OFFSET);
ParticleVelocity += GetGridScalar_{ParameterName}(GridLocation,SOLID_VELOCITY_OFFSET+ComponentIndex);
}
void ComputeComponentWeights_{ParameterName}(in int3 GridIndex, in int ComponentIndex)
{
[branch]
if( IsFaceInside_{ParameterName}(GridIndex,ComponentIndex))
{
float SignedDistance[4];
float ParticleVelocity = 0.0;
[branch]
if(ComponentIndex == 0)
{
ComputeFaceWeights_{ParameterName}(int3(GridIndex.x,GridIndex.y+0,GridIndex.z+0),ComponentIndex,SignedDistance[0],ParticleVelocity);
ComputeFaceWeights_{ParameterName}(int3(GridIndex.x,GridIndex.y+0,GridIndex.z+1),ComponentIndex,SignedDistance[1],ParticleVelocity);
ComputeFaceWeights_{ParameterName}(int3(GridIndex.x,GridIndex.y+1,GridIndex.z+0),ComponentIndex,SignedDistance[2],ParticleVelocity);
ComputeFaceWeights_{ParameterName}(int3(GridIndex.x,GridIndex.y+1,GridIndex.z+1),ComponentIndex,SignedDistance[3],ParticleVelocity);
}
else if(ComponentIndex == 1)
{
ComputeFaceWeights_{ParameterName}(int3(GridIndex.x+0,GridIndex.y,GridIndex.z+0),ComponentIndex,SignedDistance[0],ParticleVelocity);
ComputeFaceWeights_{ParameterName}(int3(GridIndex.x+0,GridIndex.y,GridIndex.z+1),ComponentIndex,SignedDistance[1],ParticleVelocity);
ComputeFaceWeights_{ParameterName}(int3(GridIndex.x+1,GridIndex.y,GridIndex.z+0),ComponentIndex,SignedDistance[2],ParticleVelocity);
ComputeFaceWeights_{ParameterName}(int3(GridIndex.x+1,GridIndex.y,GridIndex.z+1),ComponentIndex,SignedDistance[3],ParticleVelocity);
}
else
{
ComputeFaceWeights_{ParameterName}(int3(GridIndex.x+0,GridIndex.y+0,GridIndex.z),ComponentIndex,SignedDistance[0],ParticleVelocity);
ComputeFaceWeights_{ParameterName}(int3(GridIndex.x+0,GridIndex.y+1,GridIndex.z),ComponentIndex,SignedDistance[1],ParticleVelocity);
ComputeFaceWeights_{ParameterName}(int3(GridIndex.x+1,GridIndex.y+0,GridIndex.z),ComponentIndex,SignedDistance[2],ParticleVelocity);
ComputeFaceWeights_{ParameterName}(int3(GridIndex.x+1,GridIndex.y+1,GridIndex.z),ComponentIndex,SignedDistance[3],ParticleVelocity);
}
const float SolidWeight = max(0.0,min(1.0 - GetFractionInsideFace_{ParameterName}(SignedDistance[0],SignedDistance[1],SignedDistance[3],SignedDistance[2]),1.0));
const float SolidVelocity = 0.25 * ParticleVelocity;
SetGridScalar_{ParameterName}(GridIndex,SOLID_WEIGHT_OFFSET+ComponentIndex,SolidWeight);
SetGridScalar_{ParameterName}(GridIndex,SOLID_VELOCITY_OFFSET+ComponentIndex,SolidVelocity);
}
}
// Update the solid weights and velocities
void ComputeBoundaryWeights_{ParameterName}(in int GridHash, out bool OutWeightsStatus)
{
const int3 GridIndex = GetGridIndex_{ParameterName}(GridHash);
OutWeightsStatus = false;
ComputeComponentWeights_{ParameterName}(GridIndex,0);
ComputeComponentWeights_{ParameterName}(GridIndex,1);
ComputeComponentWeights_{ParameterName}(GridIndex,2);
}
/* -----------------------------------------------------------------
* Sample Velocity field from grid
* -----------------------------------------------------------------
*/
// Compute the grid pressure
// Mdv/dt = Jt * P with C = Volume * div(V) = 0.0 = ( vnx * wnx * dx * dx - vpx * wpx * dx * dx ) + ... (divergence theorem)
// -> dv = inv(M) * Jt * P * dt;
// Jnx = dC/dvnx = wnx * dx * dx, Jpx = dC/dvpx = -wpx * dx * dx
// since C = C0 + dC/dv * dv = C0 + J * dv = 0 = C0 + J * inv(M) * Jt * P * dt; and M = wnx * mnx
// the schur complement is J * inv(M) * Jt * P * dt = -C0 -> P * dt = -C0 / (wnx * dx * dx * wnx * dx * dx / ( wnx * mnx) + wpx * ....)
// P * dt = - sum( vnx * wnx * dx * dx - vpx * wpx * dx * dx ) / sum (wnx * dx * dx * wnx * dx * dx / ( wnx * mnx);
// = - sum( vnx * wnx ) / sum( wnx * dx * dx / mnx ) = -sum( vnx * wnx ) / ( dx * dx * sum( wnx / mnx ) )
// P * dt * dx * dx = Pt = -sum( vnx * wnx ) / ( sum( wnx / mnx ) )
// dv = wnx * dx * dx * P * dt / (wnx * mnx) = Pt / mnx
float ComputeGridPressure_{ParameterName}(in int3 PrevIndex, in float CentreDistance, out float3 PrevFraction, out float3 NextFraction)
{
float GridPressure = 0.0;
float GridDivergence = 0.0;
float GridFraction = 0.0;
for(int ComponentIndex = 0; ComponentIndex < 3; ++ComponentIndex)
{
int3 NextIndex = PrevIndex; NextIndex[ComponentIndex] += 1;
const float PrevDistance = GetGridScalar_{ParameterName}(PrevIndex,FLUID_DISTANCE_OFFSET);
PrevFraction[ComponentIndex] = (PrevDistance < 0.0) ? 1.0 : max(GetFractionInsideEdge_{ParameterName}(CentreDistance,PrevDistance),0.01);
const float PrevWeight = GetGridScalar_{ParameterName}(PrevIndex,SOLID_WEIGHT_OFFSET+ComponentIndex);
GridDivergence -= GetGridScalar_{ParameterName}(PrevIndex,SOLID_VELOCITY_OFFSET+ComponentIndex) * (1.0-PrevWeight);
GridDivergence -= GetGridScalar_{ParameterName}(PrevIndex,FLUID_VELOCITY_OFFSET+ComponentIndex) * PrevWeight;
GridFraction += PrevWeight / PrevFraction[ComponentIndex];
const float NextDistance = GetGridScalar_{ParameterName}(NextIndex,FLUID_DISTANCE_OFFSET);
NextFraction[ComponentIndex] = (NextDistance < 0.0) ? 1.0 : max(GetFractionInsideEdge_{ParameterName}(CentreDistance,NextDistance),0.01);
const float NextWeight = GetGridScalar_{ParameterName}(NextIndex,SOLID_WEIGHT_OFFSET+ComponentIndex);
GridDivergence += GetGridScalar_{ParameterName}(NextIndex,SOLID_VELOCITY_OFFSET+ComponentIndex) * (1.0-NextWeight);
GridDivergence += GetGridScalar_{ParameterName}(NextIndex,FLUID_VELOCITY_OFFSET+ComponentIndex) * NextWeight;
GridFraction += NextWeight / NextFraction[ComponentIndex];
}
if( GridFraction > 0.0)
{
//GridDivergence += GetGridScalar_{ParameterName}(PrevIndex,FLUID_DENSITY_OFFSET);
GridPressure = -GridDivergence / (GridFraction);
}
return GridPressure;
}
// Project the pressure grid to be divergence free
void SolveGridPressure_{ParameterName}(in int GridHash, in int InitStage, out bool OutProjectStatus)
{
OutProjectStatus = false;
const int3 PrevIndex = GetGridIndex_{ParameterName}(GridHash);
const bool IsInitStage = (SimulationStageIndex == InitStage) || (SimulationStageIndex == (InitStage+1));
if(IsCellValid_{ParameterName}(PrevIndex))
{
if( (PrevIndex.x+PrevIndex.y+PrevIndex.z+SimulationStageIndex) % 2 == 0)
{
OutProjectStatus = true;
const float CentreDistance = GetGridScalar_{ParameterName}(PrevIndex,FLUID_DISTANCE_OFFSET);
if( CentreDistance < 0.0)
{
float3 PrevFraction = float3(0,0,0);
float3 NextFraction = float3(0,0,0);
float GridPressure = ComputeGridPressure_{ParameterName}(PrevIndex,CentreDistance,PrevFraction,NextFraction);
if(!IsInitStage)
{
AddGridScalar_{ParameterName}(PrevIndex,FLUID_PRESSURE_OFFSET,GridPressure);
}
else
{
GridPressure = GetGridScalar_{ParameterName}(PrevIndex,FLUID_PRESSURE_OFFSET);
}
for( int ComponentIndex = 0; ComponentIndex < 3; ++ComponentIndex)
{
int3 NextIndex = PrevIndex; NextIndex[ComponentIndex] += 1;
const float PrevWeight = GetGridScalar_{ParameterName}(PrevIndex,SOLID_WEIGHT_OFFSET+ComponentIndex);
if( PrevWeight > 0.0 && PrevFraction[ComponentIndex] > 0.0)
{
AddGridScalar_{ParameterName}(PrevIndex,FLUID_VELOCITY_OFFSET+ComponentIndex,-GridPressure/PrevFraction[ComponentIndex]);
}
else
{
const float SolidVelocity = GetGridScalar_{ParameterName}(PrevIndex,SOLID_VELOCITY_OFFSET+ComponentIndex);
SetGridScalar_{ParameterName}(PrevIndex,FLUID_VELOCITY_OFFSET+ComponentIndex,SolidVelocity);
}
const float NextWeight = GetGridScalar_{ParameterName}(NextIndex,SOLID_WEIGHT_OFFSET+ComponentIndex);
if( NextWeight > 0.0 && NextFraction[ComponentIndex] > 0.0)
{
AddGridScalar_{ParameterName}(NextIndex,FLUID_VELOCITY_OFFSET+ComponentIndex,GridPressure/NextFraction[ComponentIndex]);
}
else
{
const float SolidVelocity = GetGridScalar_{ParameterName}(NextIndex,SOLID_VELOCITY_OFFSET+ComponentIndex);
SetGridScalar_{ParameterName}(NextIndex,FLUID_VELOCITY_OFFSET+ComponentIndex,SolidVelocity);
}
}
}
else
{
SetGridScalar_{ParameterName}(PrevIndex,FLUID_PRESSURE_OFFSET,0.0);
}
}
}
}