Files
2024-11-20 15:21:28 +01:00

566 lines
20 KiB
Plaintext

Shader "Fluxy/Simulation/FluidSimulation"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Normals ("Normals", 2D) = "bump" {}
}
SubShader
{
Cull Off ZWrite Off ZTest Always
HLSLINCLUDE
#pragma prefer_hlslcc gles
#pragma exclude_renderers d3d11_9x
#pragma target 2.0
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "../FluidUtils.hlsl"
ENDHLSL
Pass
{
Name "AdvectState"
HLSLPROGRAM
v2f_lean vert (appdata_lean v)
{
v2f_lean o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
float4 _MainTex_TexelSize;
float _DeltaTime;
float4 frag (v2f_lean i) : SV_Target
{
int tileID = GetTileID(i.uv);
float4 wrapmode = _WrapMode[tileID];
// read velocity field at current texel
// (use bilinear interpolation as velocity tex can have different resolution)
float2 vel = tex2D_bilinear(_Velocity, i.uv, _Velocity_TexelSize, _TileData[tileID], wrapmode).rg;
// trace back in time and read state values:
float2 sourceUV = i.uv + _Offsets[tileID] - vel * _DeltaTime;
float4 advected = tex2D_bilinear(_MainTex, sourceUV, _MainTex_TexelSize, _TileData[tileID], wrapmode);
// scale velocity with density at source to simulate adhesion:
vel *= saturate((1 - _Adhesion[tileID])*2 - 1 + advected.a);
return tex2D_bilinear(_MainTex, i.uv + _Offsets[tileID] - vel * _DeltaTime , _MainTex_TexelSize, _TileData[tileID], wrapmode);
}
ENDHLSL
}
Pass
{
Name "AdvectVelocity"
HLSLPROGRAM
v2f_lean vert (appdata_lean v)
{
v2f_lean o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
float4 _MainTex_TexelSize;
float _DeltaTime;
float4 frag (v2f_lean i) : SV_Target
{
int tileID = GetTileID(i.uv);
float4 wrapmode = float4(_WrapMode[tileID].xy,1,1);
// read velocity field at current texel:
float2 vel = tex2D(_MainTex, i.uv).rg;
// trace back in time and read interpolated values:
return tex2D_bilinear(_MainTex, i.uv - vel * _DeltaTime + _Offsets[tileID], _MainTex_TexelSize, _TileData[tileID], wrapmode);
}
ENDHLSL
}
Pass
{
Name "Dissipation"
HLSLPROGRAM
v2f_lean vert (appdata_lean v)
{
v2f_lean o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
float _DeltaTime;
float4 frag (v2f_lean i) : SV_Target
{
int tileID = GetTileID(i.uv);
float2 tileUV = UVToTile(i.uv,tileID);
float falloff = (1 - SquareFalloff(tileUV,_EdgeFalloff[tileID].x)) * _EdgeFalloff[tileID].y;
return saturate(tex2D(_MainTex, i.uv) - (_Dissipation[tileID] + falloff) * _DeltaTime);
}
ENDHLSL
}
Pass
{
Name "Curl"
HLSLPROGRAM
v2f_lean vert (appdata_lean v)
{
v2f_lean o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
float4 _MainTex_TexelSize;
float _DeltaTime;
float4 frag (v2f_lean i) : SV_Target
{
int tileID = GetTileID(i.uv);
float2 offset = _MainTex_TexelSize.xy;
float4 rect = _TileData[tileID];
int4 wrapmask = _WrapMode[tileID] * float4(1,1,0,0);
float4 vC = tex2D(_MainTex, i.uv);
// calculate curl:
float vL = tex2D_nearest(_MainTex, i.uv + float2(-offset.x,0), _MainTex_TexelSize, rect, wrapmask).g;
float vR = tex2D_nearest(_MainTex, i.uv + float2(offset.x,0) , _MainTex_TexelSize, rect, wrapmask).g;
float vB = tex2D_nearest(_MainTex, i.uv + float2(0,-offset.y), _MainTex_TexelSize, rect, wrapmask).r;
float vT = tex2D_nearest(_MainTex, i.uv + float2(0,offset.y) , _MainTex_TexelSize, rect, wrapmask).r;
vC.b = (vL - vR + vT - vB) * 0.5;
return vC;
}
ENDHLSL
}
Pass
{
Name "DensityGradient"
ColorMask RG
HLSLPROGRAM
v2f_lean vert (appdata_lean v)
{
v2f_lean o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
float4 _MainTex_TexelSize;
float4 frag (v2f_lean i) : SV_Target
{
int tileID = GetTileID(i.uv);
float3 offset = float3(_MainTex_TexelSize.xy,0);
float4 rect = _TileData[tileID];
int4 wrapmask = _WrapMode[tileID];
float hb0 = tex2D_nearest(_MainTex, i.uv - offset.xz, _MainTex_TexelSize, rect, wrapmask).a;
float hb1 = tex2D_nearest(_MainTex, i.uv - offset.zy, _MainTex_TexelSize, rect, wrapmask).a;
float h0 = tex2D_nearest(_MainTex, i.uv + offset.xz, _MainTex_TexelSize, rect, wrapmask).a;
float h1 = tex2D_nearest(_MainTex, i.uv + offset.zy, _MainTex_TexelSize, rect, wrapmask).a;
float3 p0 = float3 ( offset.xz, (h0 - hb0));
float3 p1 = float3 ( offset.zy, (h1 - hb1));
float3 nrm = normalize (cross (p0, p1));
return float4(nrm.xy,0,0);
}
ENDHLSL
}
Pass
{
Name "Divergence"
HLSLPROGRAM
v2f_lean vert (appdata_lean v)
{
v2f_lean o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
float4 _MainTex_TexelSize;
float4 frag (v2f_lean i) : SV_Target
{
int tileID = GetTileID(i.uv);
float2 offset = _MainTex_TexelSize.xy;
float4 rect = _TileData[tileID];
int4 wrapmask = _WrapMode[tileID];
float4 vC = tex2D(_MainTex, i.uv);
// calculate divergence:
float vL = tex2D_nearest(_MainTex, i.uv + float2(-offset.x,0), _MainTex_TexelSize, rect, wrapmask).r;
float vR = tex2D_nearest(_MainTex, i.uv + float2(offset.x, 0), _MainTex_TexelSize, rect, wrapmask).r;
float vB = tex2D_nearest(_MainTex, i.uv + float2(0,-offset.y), _MainTex_TexelSize, rect, wrapmask).g;
float vT = tex2D_nearest(_MainTex, i.uv + float2(0, offset.y), _MainTex_TexelSize, rect, wrapmask).g;
vC.b = -(vR - vL + vT - vB) * 0.5;
return vC;
}
ENDHLSL
}
Pass
{
Name "Pressure"
HLSLPROGRAM
v2f_lean vert (appdata_lean v)
{
v2f_lean o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
float4 _MainTex_TexelSize;
static const float weights[7] = {
-0.57843719174,
-0.36519596949,
-0.23187988879,
-0.14529589353,
-0.08816487385,
-0.05184872885,
-0.02906462467
};
float2 axis;
float4 frag (v2f_lean i) : SV_Target
{
int tileID = GetTileID(i.uv);
float2 offset = _MainTex_TexelSize.xy * axis;
float4 c = tex2D(_MainTex, i.uv);
c.a *= weights[0];
float4 rect = _TileData[tileID];
int4 wrapmask = _WrapMode[tileID] * float4(1,1,0,0);
c.a += tex2D_nearest(_MainTex, i.uv - offset * 6, _MainTex_TexelSize, rect, wrapmask).a * weights[6];
c.a += tex2D_nearest(_MainTex, i.uv - offset * 5, _MainTex_TexelSize, rect, wrapmask).a * weights[5];
c.a += tex2D_nearest(_MainTex, i.uv - offset * 4, _MainTex_TexelSize, rect, wrapmask).a * weights[4];
c.a += tex2D_nearest(_MainTex, i.uv - offset * 3, _MainTex_TexelSize, rect, wrapmask).a * weights[3];
c.a += tex2D_nearest(_MainTex, i.uv - offset * 2, _MainTex_TexelSize, rect, wrapmask).a * weights[2];
c.a += tex2D_nearest(_MainTex, i.uv - offset, _MainTex_TexelSize, rect, wrapmask).a * weights[1];
c.a += tex2D_nearest(_MainTex, i.uv + offset, _MainTex_TexelSize, rect, wrapmask).a * weights[1];
c.a += tex2D_nearest(_MainTex, i.uv + offset * 2, _MainTex_TexelSize, rect, wrapmask).a * weights[2];
c.a += tex2D_nearest(_MainTex, i.uv + offset * 3, _MainTex_TexelSize, rect, wrapmask).a * weights[3];
c.a += tex2D_nearest(_MainTex, i.uv + offset * 4, _MainTex_TexelSize, rect, wrapmask).a * weights[4];
c.a += tex2D_nearest(_MainTex, i.uv + offset * 5, _MainTex_TexelSize, rect, wrapmask).a * weights[5];
c.a += tex2D_nearest(_MainTex, i.uv + offset * 6, _MainTex_TexelSize, rect, wrapmask).a * weights[6];
return c;
}
ENDHLSL
}
Pass
{
Name "SubtractPressureGradient"
Blend One One
HLSLPROGRAM
v2f_lean vert (appdata_lean v)
{
v2f_lean o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
float4 _MainTex_TexelSize;
float4 frag (v2f_lean i) : SV_Target
{
int tileID = GetTileID(i.uv);
float2 offset = _MainTex_TexelSize.xy;
float4 rect = _TileData[tileID];
int4 wrapmask = _WrapMode[tileID] * float4(1,1,0,0);
float pL = tex2D_nearest(_MainTex, i.uv + float2(-offset.x,0), _MainTex_TexelSize, rect, wrapmask).a;
float pR = tex2D_nearest(_MainTex, i.uv + float2(offset.x, 0), _MainTex_TexelSize, rect, wrapmask).a;
float pB = tex2D_nearest(_MainTex, i.uv + float2(0,-offset.y), _MainTex_TexelSize, rect, wrapmask).a;
float pT = tex2D_nearest(_MainTex, i.uv + float2(0, offset.y), _MainTex_TexelSize, rect, wrapmask).a;
return float4(-float2(pR - pL, pT - pB) * 0.5 * _Pressure[tileID], 0, 0);
}
ENDHLSL
}
Pass
{
Name "Splat ID"
HLSLPROGRAM
sampler2D _MainTex;
v2f_lean vert (appdata_lean v)
{
v2f_lean o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.vertex.xy = VertexToTile(o.vertex.xy,_TileIndex);
o.uv = v.uv;
return o;
}
float4 frag (v2f_lean i) : SV_Target
{
return EncodeTileID();
}
ENDHLSL
}
Pass
{
Name "Clear State"
HLSLPROGRAM
sampler2D _MainTex;
float4 _ClearColor;
v2f_lean vert (appdata_lean v)
{
v2f_lean o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.vertex.xy = VertexToTile(o.vertex.xy,_TileIndex);
o.uv = v.uv;
return o;
}
float4 frag (v2f_lean i) : SV_Target
{
return tex2D(_MainTex,i.uv) * _ClearColor;
}
ENDHLSL
}
Pass
{
Name "JacobiIteration"
HLSLPROGRAM
v2f_lean vert (appdata_lean v)
{
v2f_lean o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
float4 _MainTex_TexelSize;
float4 frag (v2f_lean i) : SV_Target
{
int tileID = GetTileID(i.uv);
float2 offset = _MainTex_TexelSize.xy;
float4 rect = _TileData[tileID];
int4 wrapmask = _WrapMode[tileID];
float4 xC = tex2D(_MainTex, i.uv);
// calculate pressure from divergence:
float xL = tex2D_nearest(_MainTex, i.uv + float2(-offset.x,0),_MainTex_TexelSize, rect, wrapmask).a;
float xR = tex2D_nearest(_MainTex, i.uv + float2(offset.x,0),_MainTex_TexelSize, rect, wrapmask).a;
float xB = tex2D_nearest(_MainTex, i.uv + float2(0,-offset.y),_MainTex_TexelSize, rect, wrapmask).a;
float xT = tex2D_nearest(_MainTex, i.uv + float2(0,offset.y),_MainTex_TexelSize, rect, wrapmask).a;
xC.a = (xL + xR + xB + xT + xC.b) * 0.25;
return xC;
}
ENDHLSL
}
Pass
{
Name "CopyDivergenceToPressure"
HLSLPROGRAM
v2f_lean vert (appdata_lean v)
{
v2f_lean o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
float4 frag (v2f_lean i) : SV_Target
{
float4 vC = tex2D(_MainTex, i.uv);
vC.a = vC.b;
return vC;
}
ENDHLSL
}
Pass
{
Name "ExternalForces"
HLSLPROGRAM
struct appdata
{
float4 vertex : POSITION;
float4 normal : NORMAL;
float4 tangent : TANGENT;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
half3x3 worldToTangent : TEXCOORD1;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.uv = v.uv;
o.vertex = mul(UNITY_MATRIX_P, float4(v.uv.xy,0,1));
o.vertex.xy = VertexToTile(o.vertex.xy,_TileIndex);
// UnityObjectToWorldNormal without normalization:
half3 wNormal = mul(v.normal, (float3x3)unity_WorldToObject);
// UnityObjectToWorldDir without normalization:
half3 wTangent = mul((float3x3)unity_ObjectToWorld, v.tangent.xyz);
// normalize avoiding div by zero:
wNormal /= max(length(wNormal),0.00001);
wTangent /= max(length(wTangent),0.00001);
// compute bitangent from cross product of normal and tangent
half tangentSign = v.tangent.w * unity_WorldTransformParams.w;
half3 wBitangent = cross(wNormal, wTangent) * tangentSign;
// output the tangent space matrix
o.worldToTangent = half3x3(wTangent, wBitangent, wNormal);
return o;
}
sampler2D _MainTex;
sampler2D _State;
sampler2D _Normals;
float4 _MainTex_TexelSize;
float _NormalScale;
float2 _NormalTiling;
float _DeltaTime;
float4 frag (v2f i) : SV_Target
{
float2 uv = TileToUV(i.uv,_TileIndex);
float2 offset = _MainTex_TexelSize.xy;
float4 rect = _TileData[_TileIndex];
// calculate curvature (divergence of density gradient):
int4 wrapmask = _WrapMode[_TileIndex];
float2 grad = tex2D(_State, uv).rg;
float l = tex2D_nearest(_State, uv + float2(-offset.x,0),_MainTex_TexelSize, rect, wrapmask).r;
float r = tex2D_nearest(_State, uv + float2(offset.x,0),_MainTex_TexelSize, rect, wrapmask).r;
float b = tex2D_nearest(_State, uv + float2(0,-offset.y),_MainTex_TexelSize, rect, wrapmask).g;
float t = tex2D_nearest(_State, uv + float2(0,offset.y),_MainTex_TexelSize, rect, wrapmask).g;
float curv = -(r - l + t - b) * 0.5;
// calculate curl gradient:
int4 curlWrapmask = _WrapMode[_TileIndex] * float4(1,1,0,0);
float vL = tex2D_nearest(_MainTex, uv + float2(-offset.x,0), _MainTex_TexelSize, rect, curlWrapmask).b;
float vR = tex2D_nearest(_MainTex, uv + float2(offset.x, 0), _MainTex_TexelSize, rect, curlWrapmask).b;
float vB = tex2D_nearest(_MainTex, uv + float2(0,-offset.y), _MainTex_TexelSize, rect, curlWrapmask).b;
float vT = tex2D_nearest(_MainTex, uv + float2(0, offset.y), _MainTex_TexelSize, rect, curlWrapmask).b;
// cross(N, W) = N.yx * W;
float2 curlGrad = float2(abs(vB) - abs(vT), abs(vR) - abs(vL)) * 0.5;
float curlMag = length(curlGrad);
// sample velocity at current texel:
float4 vel = tex2D(_MainTex, uv);
// viscosity (velocity dissipation)
vel.rg *= _Viscosity[_TileIndex];
// vorticity confinement:
float2 vortConf = curlMag > 0.001 ? _VortConf[_TileIndex] * vel.b * curlGrad / curlMag : float2(0,0);
// surface tension: first term controls drop shape (higher = rounder), second term controls drop size (higher = smaller)
float2 surfTension = grad.rg * curv * 2 * _SurfaceTension[_TileIndex];
// transform external forces from world to tangent space:
float3 externalForce = mul(i.worldToTangent, _ExternalForce[_TileIndex]);
// add all forces together:
vel.rg += (externalForce.xy + surfTension + vortConf + _Buoyancy[_TileIndex] * tex2D(_State,uv).a) * _DeltaTime;
// unpack container surface normal, project velocity vector to surface:
UnpackNormalAndProjectVelocity(_Normals, i.uv * _NormalTiling, _NormalScale, vel.rg);
// damping (falloff):
float falloff = (1 - SquareFalloff(i.uv,_EdgeFalloff[_TileIndex].z)) * _EdgeFalloff[_TileIndex].w;
vel.rg -= vel.rg * _DeltaTime * falloff;
return vel;
}
ENDHLSL
}
}
}