549 lines
22 KiB
HLSL
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);
|
|
}
|
|
}
|
|
}
|
|
}
|