├── .gitignore ├── Assets ├── StableFluid.meta └── StableFluid │ ├── ComputeShaders.meta │ ├── ComputeShaders │ ├── Solver2D.compute │ ├── Solver2D.compute.meta │ ├── Solver3D.compute │ └── Solver3D.compute.meta │ ├── Material.meta │ ├── Material │ ├── AddSource.mat │ ├── AddSource.mat.meta │ ├── Debug.mat │ ├── Debug.mat.meta │ ├── Sample.mat │ └── Sample.mat.meta │ ├── Scene.meta │ ├── Scene │ ├── sample.unity │ └── sample.unity.meta │ ├── Scripts.meta │ ├── Scripts │ ├── MouseSourceProvider.cs │ ├── MouseSourceProvider.cs.meta │ ├── Render.meta │ ├── Render │ │ ├── RenderEffect.cs │ │ ├── RenderEffect.cs.meta │ │ ├── RenderUtility.cs │ │ └── RenderUtility.cs.meta │ ├── Solver2D.cs │ ├── Solver2D.cs.meta │ ├── Solver3D.cs │ ├── Solver3D.cs.meta │ ├── SolverBase.cs │ └── SolverBase.cs.meta │ ├── Shaders.meta │ └── Shaders │ ├── AddSource.shader │ ├── AddSource.shader.meta │ ├── Sample.shader │ └── Sample.shader.meta ├── ProjectSettings ├── AudioManager.asset ├── ClusterInputManager.asset ├── DynamicsManager.asset ├── EditorBuildSettings.asset ├── EditorSettings.asset ├── GraphicsSettings.asset ├── InputManager.asset ├── NavMeshAreas.asset ├── NetworkManager.asset ├── Physics2DSettings.asset ├── ProjectSettings.asset ├── ProjectVersion.txt ├── QualitySettings.asset ├── TagManager.asset ├── TimeManager.asset └── UnityConnectSettings.asset └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /[Ll]ibrary/ 2 | /[Tt]emp/ 3 | /[Oo]bj/ 4 | /[Bb]uild/ 5 | /[Bb]uilds/ 6 | /Assets/AssetStoreTools* 7 | 8 | # Visual Studio 2015 cache directory 9 | /.vs/ 10 | 11 | # Autogenerated VS/MD/Consulo solution and project files 12 | ExportedObj/ 13 | .consulo/ 14 | *.csproj 15 | *.unityproj 16 | *.sln 17 | *.suo 18 | *.tmp 19 | *.user 20 | *.userprefs 21 | *.pidb 22 | *.booproj 23 | *.svd 24 | *.pdb 25 | 26 | # Unity3D generated meta files 27 | *.pidb.meta 28 | 29 | # Unity3D Generated File On Crash Reports 30 | sysinfo.txt 31 | 32 | # Builds 33 | *.apk 34 | *.unitypackage 35 | -------------------------------------------------------------------------------- /Assets/StableFluid.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 816fe6518ea9a2945b2da1e11ae9de98 3 | folderAsset: yes 4 | timeCreated: 1492760910 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/StableFluid/ComputeShaders.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 338a95aa7bfec30449efec661c1e1b6c 3 | folderAsset: yes 4 | timeCreated: 1499733814 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/StableFluid/ComputeShaders/Solver2D.compute: -------------------------------------------------------------------------------- 1 | // Each #kernel tells which function to compile; you can have many kernels 2 | #pragma kernel AddSourceDensity 3 | #pragma kernel DiffuseDensity 4 | #pragma kernel AdvectDensity 5 | #pragma kernel AdvectDensityFromExt 6 | #pragma kernel SwapDensity 7 | 8 | #pragma kernel AddSourceVelocity 9 | #pragma kernel DiffuseVelocity 10 | #pragma kernel AdvectVelocity 11 | #pragma kernel SwapVelocity 12 | #pragma kernel ProjectStep1 13 | #pragma kernel ProjectStep2 14 | #pragma kernel ProjectStep3 15 | 16 | #pragma kernel Draw 17 | 18 | #define THREAD_X 32 19 | #define THREAD_Y 32 20 | #define THREAD_Z 1 21 | #define GS_ITERATE 2 //Gauss-Seidel法の反復回数. パフォーマンスに直結します.素早い拡散が必要なければ低い値で. 22 | 23 | float diff; 24 | float visc; 25 | float dt; 26 | float velocityCoef; 27 | float densityCoef; 28 | 29 | RWTexture2D solver; //xy = velocity, z = density 30 | RWTexture2D density; //density field 31 | RWTexture2D velocity; //velocity field 32 | RWTexture2D prev; //xy = prev velocity field, z = prev density field. when project step x = p, y = div 33 | Texture2D source; //xy = velocity source, z = density source 34 | 35 | void SetBoundaryDensity(uint2 id, uint w, uint h) 36 | { 37 | density[id] = (id.x == 0) ? density[id + uint2(1,0)] : density[id]; 38 | density[id] = (id.x == w-1) ? density[uint2(w-2, id.y)] : density[id]; 39 | density[id] = (id.y == 0) ? density[id + uint2(0,1)] : density[id]; 40 | density[id] = (id.y == h-1) ? density[uint2(id.x, h-2)] : density[id]; 41 | 42 | density[id] = (id.x == 0 && id.y == 0) ? 0.5 * (density[uint2(1,0)] + density[uint2(0,1)]) : density[id]; 43 | density[id] = (id.x == 0 && id.y == h-1) ? 0.5 * (density[uint2(1,h-1)] + density[uint2(0,h-2)]) : density[id]; 44 | density[id] = (id.x == w-1 && id.y == 0) ? 0.5 * (density[uint2(w-2,0)] + density[uint2(w-1,1)]) : density[id]; 45 | density[id] = (id.x == w-1 && id.y == h-1) ? 0.5 * (density[uint2(w-2,h-1)] + density[uint2(w-1,h-2)]) : density[id]; 46 | } 47 | 48 | void SetBoundaryVelocity(uint2 id, uint w, uint h) 49 | { 50 | velocity[id] = (id.x == 0) ? float2(-velocity[id + uint2(1,0)].x, velocity[id].y) : velocity[id]; 51 | velocity[id] = (id.x == w-1) ? float2(-velocity[uint2(w-2, id.y)].x, velocity[id].y) : velocity[id]; 52 | velocity[id] = (id.y == 0) ? float2(velocity[id].x, -velocity[id + uint2(0,1)].y) : velocity[id]; 53 | velocity[id] = (id.y == h-1) ? float2(velocity[id].x, -velocity[uint2(id.x, h-2)].y) : velocity[id]; 54 | 55 | velocity[id] = (id.x == 0 && id.y == 0) ? 0.5 * (velocity[uint2(1,0)] + velocity[uint2(0,1)]) : velocity[id]; 56 | velocity[id] = (id.x == 0 && id.y == h-1) ? 0.5 * (velocity[uint2(1,h-1)] + velocity[uint2(0,h-2)]) : velocity[id]; 57 | velocity[id] = (id.x == w-1 && id.y == 0) ? 0.5 * (velocity[uint2(w-2,0)] + velocity[uint2(w-1,1)]) : velocity[id]; 58 | velocity[id] = (id.x == w-1 && id.y == h-1) ? 0.5 * (velocity[uint2(w-2,h-1)] + velocity[uint2(w-1,h-2)]) : velocity[id]; 59 | } 60 | 61 | void SetBoundaryDivergence(uint2 id, uint w, uint h) 62 | { 63 | prev[id] = (id.x == 0) ? float3(prev[id].x, prev[id + uint2(1,0)].y, prev[id].z) : prev[id]; 64 | prev[id] = (id.x == w-1) ? float3(prev[id].x, prev[uint2(w-2, id.y)].y, prev[id].z) : prev[id]; 65 | prev[id] = (id.y == 0) ? float3(prev[id].x, prev[id + uint2(0,1)].y, prev[id].z) : prev[id]; 66 | prev[id] = (id.y == h-1) ? float3(prev[id].x, prev[uint2(id.x, h-2)].y, prev[id].z) : prev[id]; 67 | 68 | prev[id] = (id.x == 0 && id.y == 0) ? float3(prev[id].x, 0.5 * (prev[uint2(1,0)].y + prev[uint2(0,1)].y), prev[id].z) : prev[id]; 69 | prev[id] = (id.x == 0 && id.y == h-1) ? float3(prev[id].x, 0.5 * (prev[uint2(1,h-2)].y + prev[uint2(0,h-2)].y), prev[id].z) : prev[id]; 70 | prev[id] = (id.x == w-1 && id.y == 0) ? float3(prev[id].x, 0.5 * (prev[uint2(w-2,0)].y + prev[uint2(w-1,1)].y), prev[id].z) : prev[id]; 71 | prev[id] = (id.x == w-1 && id.y == h-1) ? float3(prev[id].x, 0.5 * (prev[uint2(w-2,h-1)].y + prev[uint2(w-1,h-2)].y), prev[id].z) : prev[id]; 72 | } 73 | 74 | void SetBoundaryDivPositive(uint2 id, uint w, uint h) 75 | { 76 | prev[id] = (id.x == 0) ? float3(prev[id + uint2(1,0)].x, prev[id].yz) : prev[id]; 77 | prev[id] = (id.x == w-1) ? float3(prev[uint2(w-2, id.y)].x, prev[id].yz) : prev[id]; 78 | prev[id] = (id.y == 0) ? float3(prev[id + uint2(0,1)].x, prev[id].yz) : prev[id]; 79 | prev[id] = (id.y == h-1) ? float3(prev[uint2(id.x, h-2)].x, prev[id].yz) : prev[id]; 80 | 81 | prev[id] = (id.x == 0 && id.y == 0) ? float3(0.5 * (prev[uint2(1,0)].x + prev[uint2(0,1)].x), prev[id].yz) : prev[id]; 82 | prev[id] = (id.x == 0 && id.y == h-1) ? float3(0.5 * (prev[uint2(1,h-1)].x + prev[uint2(0,h-2)].x), prev[id].yz) : prev[id]; 83 | prev[id] = (id.x == w-1 && id.y == 0) ? float3(0.5 * (prev[uint2(w-2,0)].x + prev[uint2(w-1,1)].x), prev[id].yz) : prev[id]; 84 | prev[id] = (id.x == w-1 && id.y == h-1) ? float3(0.5 * (prev[uint2(w-2,h-1)].x + prev[uint2(w-1,h-2)].x), prev[id].yz) : prev[id]; 85 | } 86 | 87 | //密度場外力項. 88 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 89 | void AddSourceDensity(uint2 id : SV_DispatchThreadID) 90 | { 91 | uint w, h; 92 | density.GetDimensions(w, h); 93 | 94 | if (id.x < w && id.y < h) 95 | { 96 | density[id] += source[id].z * densityCoef * dt; 97 | prev[id] = float3(prev[id].xy, source[id].z * densityCoef * dt); 98 | } 99 | } 100 | 101 | //速度場外力項. 102 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 103 | void AddSourceVelocity(uint2 id : SV_DispatchThreadID) 104 | { 105 | uint w, h; 106 | velocity.GetDimensions(w, h); 107 | 108 | if (id.x < w && id.y < h) 109 | { 110 | velocity[id] += source[id].xy * velocityCoef * dt; 111 | prev[id] = float3(source[id].xy * velocityCoef * dt, prev[id].z); 112 | } 113 | } 114 | 115 | //密度場拡散項.diff∇・∇densによる勾配・発散をGauss-Seidel法にて計算。diffは拡散係数. 116 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 117 | void DiffuseDensity(uint2 id : SV_DispatchThreadID) 118 | { 119 | uint w, h; 120 | density.GetDimensions(w, h); 121 | 122 | if (id.x < w && id.y < h) 123 | { 124 | float a = dt * diff * w * h; 125 | 126 | //TODO:Congugate gradient法でも試してみる 127 | [unroll] 128 | for (int k = 0; k < GS_ITERATE; k++) { 129 | density[id] = (prev[id].z + a * (density[int2(id.x - 1, id.y)] + density[int2(id.x + 1, id.y)] + density[int2(id.x, id.y - 1)] + density[int2(id.x, id.y + 1)])) / (1 + 4 * a); 130 | SetBoundaryDensity(id, w, h); 131 | } 132 | } 133 | } 134 | 135 | //速度場拡散(粘性)項.visc∇・∇velocityによる勾配・発散をGauss-Seidel法にて計算。viscはkinematic visocity(動粘性摩擦係数). 136 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 137 | void DiffuseVelocity(uint2 id : SV_DispatchThreadID) 138 | { 139 | uint w, h; 140 | velocity.GetDimensions(w, h); 141 | 142 | if (id.x < w && id.y < h) 143 | { 144 | float a = dt * visc * w * h; 145 | 146 | //TODO:Congugate gradient法でも試してみる 147 | [unroll] 148 | for (int k = 0; k < GS_ITERATE; k++) { 149 | velocity[id] = (prev[id].xy + a * (velocity[int2(id.x - 1, id.y)] + velocity[int2(id.x + 1, id.y)] + velocity[int2(id.x, id.y - 1)] + velocity[int2(id.x, id.y + 1)])) / (1 + 4 * a); 150 | SetBoundaryVelocity(id, w, h); 151 | } 152 | } 153 | } 154 | 155 | //密度場移流項. 156 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 157 | void AdvectDensity(uint2 id : SV_DispatchThreadID) 158 | { 159 | uint w, h; 160 | density.GetDimensions(w, h); 161 | 162 | if (id.x < w && id.y < h) 163 | { 164 | int ddx0, ddx1, ddy0, ddy1; 165 | float x, y, s0, t0, s1, t1, dfdt; 166 | 167 | dfdt = dt * (w + h) * 0.5; 168 | 169 | //各偏微分方向-(w*dt*速度場の各偏微分座標、つまり移流するポテンシャル座標を出す. 170 | x = (float)id.x - dfdt * velocity[id].x; 171 | y = (float)id.y - dfdt * velocity[id].y; 172 | //移流ポテンシャル座標xyは0.5~横幅-0.5以内にクランプ. 173 | clamp(x, 0.5, w + 0.5); 174 | clamp(y, 0.5, h + 0.5); 175 | //xyのそれぞれ近似の偏微分セルを求める. 176 | ddx0 = floor(x); 177 | ddx1 = ddx0 + 1; 178 | ddy0 = floor(y); 179 | ddy1 = ddy0 + 1; 180 | //intセルと目標座標の間に端数がある為、各偏微分方向の差分をx1,x0系という形で出す. 181 | s1 = x - ddx0; 182 | s0 = 1.0 - s1; 183 | t1 = y - ddy0; 184 | t0 = 1.0 - t1; 185 | 186 | //ポテンシャル座標の密度を1step前の密度場から持ってくる. 187 | //ただし、xyがセルのど真ん中の値を指してる訳ではないので、セルとfloatとの差分と1-との値を近傍4セル分線形補完して算出する. 188 | density[id] = s0 * (t0 * prev[int2(ddx0, ddy0)].z + t1 * prev[int2(ddx0, ddy1)].z) + 189 | s1 * (t0 * prev[int2(ddx1, ddy0)].z + t1 * prev[int2(ddx1, ddy1)].z); 190 | SetBoundaryDensity(id, w, h); 191 | } 192 | } 193 | 194 | //密度場移流項(このカーネルはvelocity stepを用いず、速度場を外部からsource texにフェッチした物を参照する事によって軽量化を狙う為用意). 195 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 196 | void AdvectDensityFromExt(uint2 id : SV_DispatchThreadID) 197 | { 198 | uint w, h; 199 | density.GetDimensions(w, h); 200 | 201 | if (id.x < w && id.y < h) 202 | { 203 | int ddx0, ddx1, ddy0, ddy1; 204 | float x, y, s0, t0, s1, t1, dfdt; 205 | 206 | dfdt = dt * (w + h) * 0.5; 207 | 208 | //各偏微分方向-(w*dt*速度場の各偏微分座標、つまり移流するポテンシャル座標を出す. 209 | //NOTE:外部参照パターン. 210 | x = (float)id.x - dfdt * source[id].x; 211 | y = (float)id.y - dfdt * source[id].y; 212 | //移流ポテンシャル座標xyは0.5~横幅-0.5以内にクランプ. 213 | clamp(x, 0.5, w + 0.5); 214 | clamp(y, 0.5, h + 0.5); 215 | //xyのそれぞれ近似の偏微分セルを求める. 216 | ddx0 = floor(x); 217 | ddx1 = ddx0 + 1; 218 | ddy0 = floor(y); 219 | ddy1 = ddy0 + 1; 220 | //intセルと目標座標の間に端数がある為、各偏微分方向の差分をx1,x0系という形で出す. 221 | s1 = x - ddx0; 222 | s0 = 1.0 - s1; 223 | t1 = y - ddy0; 224 | t0 = 1.0 - t1; 225 | 226 | //ポテンシャル座標の密度を1step前の密度場から持ってくる. 227 | //ただし、xyがセルのど真ん中の値を指してる訳ではないので、セルとfloatとの差分と1-との値を近傍4セル分線形補完して算出する. 228 | density[id] = s0 * (t0 * prev[int2(ddx0, ddy0)].z + t1 * prev[int2(ddx0, ddy1)].z) + 229 | s1 * (t0 * prev[int2(ddx1, ddy0)].z + t1 * prev[int2(ddx1, ddy1)].z); 230 | SetBoundaryDensity(id, w, h); 231 | } 232 | } 233 | 234 | //速度場移流項. 235 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 236 | void AdvectVelocity(uint2 id : SV_DispatchThreadID) 237 | { 238 | uint w, h; 239 | density.GetDimensions(w, h); 240 | 241 | if (id.x < w && id.y < h) 242 | { 243 | int ddx0, ddx1, ddy0, ddy1; 244 | float x, y, s0, t0, s1, t1, dfdt; 245 | 246 | dfdt = dt * (w + h) * 0.5; 247 | 248 | //各偏微分方向-(w*dt*速度場の各偏微分座標、つまり移流するポテンシャル座標を出す. 249 | x = (float)id.x - dfdt * prev[id].x; 250 | y = (float)id.y - dfdt * prev[id].y; 251 | //移流ポテンシャル座標xyzは0.5~横幅-0.5以内にクランプ. 252 | clamp(x, 0.5, w + 0.5); 253 | clamp(y, 0.5, h + 0.5); 254 | //xyのそれぞれ近似の偏微分セルを求める. 255 | ddx0 = floor(x); 256 | ddx1 = ddx0 + 1; 257 | ddy0 = floor(y); 258 | ddy1 = ddy0 + 1; 259 | //intセルと目標座標の間に端数がある為、各偏微分方向の差分をx1,x0系という形で出す. 260 | s1 = x - ddx0; 261 | s0 = 1.0 - s1; 262 | t1 = y - ddy0; 263 | t0 = 1.0 - t1; 264 | 265 | //ポテンシャル座標の速度ベクトルを1step前の密度場から持ってくる. 266 | //ただし、xyがセルのど真ん中の値を指してる訳ではないので、セルとfloatとの差分と1-との値を近傍4セル分線形補完して算出する. 267 | velocity[id] = s0 * (t0 * prev[int2(ddx0, ddy0)].xy + t1 * prev[int2(ddx0, ddy1)].xy) + 268 | s1 * (t0 * prev[int2(ddx1, ddy0)].xy + t1 * prev[int2(ddx1, ddy1)].xy); 269 | SetBoundaryVelocity(id, w, h); 270 | } 271 | } 272 | 273 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 274 | void SwapDensity(uint2 id : SV_DispatchThreadID) 275 | { 276 | uint w, h; 277 | density.GetDimensions(w, h); 278 | 279 | if (id.x < w && id.y < h) 280 | { 281 | float temp = density[id]; 282 | //density[id] = prev[id].z; 283 | prev[id] = float3(prev[id].xy, temp); 284 | } 285 | } 286 | 287 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 288 | void SwapVelocity(uint2 id : SV_DispatchThreadID) 289 | { 290 | uint w, h; 291 | velocity.GetDimensions(w, h); 292 | 293 | if (id.x < w && id.y < h) 294 | { 295 | float2 temp = float2(velocity[id].x, velocity[id].y); 296 | //velocity[id] = prev[id].xy; 297 | prev[id] = float3(temp, prev[id].z); 298 | } 299 | } 300 | 301 | //非圧縮性流体の為、速度divergenceの流出入を∇・u = 0にする外圧pを求め、速度場に投影. 302 | //速度場圧力項Step1. 303 | //step1では、発散の算出まで. 304 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 305 | void ProjectStep1(uint2 id : SV_DispatchThreadID) 306 | { 307 | uint w, h; 308 | velocity.GetDimensions(w, h); 309 | 310 | if (id.x < w && id.y < h) 311 | { 312 | float2 uvd; 313 | uvd = float2(1.0 / w, 1.0 / h); 314 | 315 | prev[id] = float3(0.0, 316 | -0.5 * (uvd.x * (velocity[int2(id.x + 1, id.y)].x - velocity[int2(id.x - 1, id.y)].x)) + 317 | (uvd.y * (velocity[int2(id.x, id.y + 1)].y - velocity[int2(id.x, id.y - 1)].y)), 318 | prev[id].z); 319 | 320 | SetBoundaryDivergence(id, w, h); 321 | SetBoundaryDivPositive(id, w, h); 322 | } 323 | } 324 | 325 | //速度場圧力項Step2. 326 | //step2では、step1で求めた発散から外圧∇pを求める. 327 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 328 | void ProjectStep2(uint2 id : SV_DispatchThreadID) 329 | { 330 | uint w, h; 331 | 332 | velocity.GetDimensions(w, h); 333 | 334 | if (id.x < w && id.y < h) 335 | { 336 | for (int k = 0; k < GS_ITERATE; k++) 337 | { 338 | prev[id] = float3( 339 | (prev[id].y + prev[uint2(id.x - 1, id.y)].x + prev[uint2(id.x + 1, id.y)].x + 340 | prev[uint2(id.x, id.y - 1)].x + prev[uint2(id.x, id.y + 1)].x) / 4, 341 | prev[id].yz); 342 | SetBoundaryDivPositive(id, w, h); 343 | } 344 | } 345 | } 346 | 347 | //速度場圧力項Step3. 348 | //step3では、step2で求めた外圧∇pを現在の速度場に減算し、∇・u = 0にしている. 349 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 350 | void ProjectStep3(uint2 id : SV_DispatchThreadID) 351 | { 352 | uint w, h; 353 | 354 | velocity.GetDimensions(w, h); 355 | 356 | if (id.x < w && id.y < h) 357 | { 358 | float velX, velY; 359 | float2 uvd; 360 | uvd = float2(1.0 / w, 1.0 / h); 361 | 362 | velX = velocity[id].x; 363 | velY = velocity[id].y; 364 | 365 | velX -= 0.5 * (prev[uint2(id.x + 1, id.y)].x - prev[uint2(id.x - 1, id.y)].x) / uvd.x; 366 | velY -= 0.5 * (prev[uint2(id.x, id.y + 1)].x - prev[uint2(id.x, id.y - 1)].x) / uvd.y; 367 | 368 | velocity[id] = float2(velX, velY); 369 | SetBoundaryVelocity(id, w, h); 370 | } 371 | } 372 | 373 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 374 | void Draw(uint2 id : SV_DispatchThreadID) 375 | { 376 | uint w, h; 377 | solver.GetDimensions(w, h); 378 | 379 | if (id.x < w && id.y < h) 380 | { 381 | solver[id] = float4(velocity[id].xy, density[id], 1); 382 | } 383 | } -------------------------------------------------------------------------------- /Assets/StableFluid/ComputeShaders/Solver2D.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8f93e96f4f3aed44592d1d829b633854 3 | timeCreated: 1493362868 4 | licenseType: Pro 5 | ComputeShaderImporter: 6 | currentAPIMask: 4 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/StableFluid/ComputeShaders/Solver3D.compute: -------------------------------------------------------------------------------- 1 | // Each #kernel tells which function to compile; you can have many kernels 2 | #pragma kernel AddSourceDensity 3 | #pragma kernel DiffuseDensity 4 | #pragma kernel AdvectDensity 5 | #pragma kernel AdvectDensityFromExt 6 | #pragma kernel SwapDensity 7 | 8 | #pragma kernel AddSourceVelocity 9 | #pragma kernel DiffuseVelocity 10 | #pragma kernel AdvectVelocity 11 | #pragma kernel SwapVelocity 12 | #pragma kernel ProjectStep1 13 | #pragma kernel ProjectStep2 14 | #pragma kernel ProjectStep3 15 | 16 | #pragma kernel Draw 17 | 18 | #define THREAD_X 16 19 | #define THREAD_Y 16 20 | #define THREAD_Z 4 21 | #define GS_ITERATE 2 //Gauss-Seidel法の反復回数. パフォーマンスに直結します.素早い拡散が必要なければ低い値で. 22 | 23 | float diff; 24 | float visc; 25 | float dt; 26 | float velocityCoef; 27 | float densityCoef; 28 | 29 | RWTexture3D solver; //xy = velocity, z = density 30 | RWTexture3D density; //density field 31 | RWTexture3D velocity; //velocity field 32 | RWTexture3D prev; //xyz = prev velocity, w = prev density. when project step x = p, y = div 33 | Texture3D source; //xyz = velocity source, w = density source 34 | 35 | SamplerState _PointClamp; 36 | 37 | void SetBoundaryDensity(uint3 id, uint w, uint h, uint d) 38 | { 39 | density[id] = (id.x == 0) ? density[id + uint3(1,0,0)] : density[id]; 40 | density[id] = (id.x == w-1) ? density[uint3(w-2, id.yz)] : density[id]; 41 | density[id] = (id.y == 0) ? density[id + uint3(0,1,0)] : density[id]; 42 | density[id] = (id.y == h-1) ? density[uint3(id.x, h-2, id.z)] : density[id]; 43 | density[id] = (id.z == 0) ? density[id + uint3(0,0,1)] : density[id]; 44 | density[id] = (id.z == d-1) ? density[uint3(id.xy, d-2)] : density[id]; 45 | 46 | density[id] = (id.x == 0 && id.y == 0 && id.z != 0 && id.z != d-1) ? 0.5 * (density[uint3(1,0,id.z)] + density[uint3(0,1,id.z)]) : density[id]; 47 | density[id] = (id.x == 0 && id.y == 0 && id.z == 0) ? (density[uint3(1,0,0)] + density[uint3(0,1,0)] + density[uint3(0,0,1)]) / 3 : density[id]; 48 | density[id] = (id.x == 0 && id.y == 0 && id.z == d-1) ? (density[uint3(1,0,d-1)] + density[uint3(0,1,d-1)] + density[uint3(0,0,d-2)]) / 3 : density[id]; 49 | density[id] = (id.x == 0 && id.y == h-1 && id.z != 0 && id.z != d-1) ? 0.5 * (density[uint3(1,h-1,id.z)] + density[uint3(0,h-2,id.z)]) : density[id]; 50 | density[id] = (id.x == 0 && id.y == h-1 && id.z == 0) ? (density[uint3(1,h-1,0)] + density[uint3(0,h-2,0)] + density[uint3(0,h-1,1)]) / 3 : density[id]; 51 | density[id] = (id.x == 0 && id.y == h-1 && id.z == d-1) ? (density[uint3(1,h-1,d-1)] + density[uint3(0,h-2,d-1)] + density[uint3(0,h-1,d-2)]) / 3 : density[id]; 52 | density[id] = (id.x == w-1 && id.y == 0 && id.z != 0 && id.z != d-1) ? 0.5 * (density[uint3(w-2,0,id.z)] + density[uint3(w-1,1,id.z)]) : density[id]; 53 | density[id] = (id.x == w-1 && id.y == 0 && id.z == 0) ? (density[uint3(w-2,0,0)] + density[uint3(w-1,1,0)] + density[uint3(w-1,0,1)]) / 3 : density[id]; 54 | density[id] = (id.x == w-1 && id.y == 0 && id.z == d-1) ? (density[uint3(w-2,0,d-1)] + density[uint3(w-1,1,d-1)] + density[uint3(w-1,0,d-2)]) / 3 : density[id]; 55 | density[id] = (id.x == w-1 && id.y == h-1 && id.z != 0 && id.z != d-1) ? 0.5 * (density[uint3(w-2,h-1,id.z)] + density[uint3(w-1,h-2,id.z)]) : density[id]; 56 | density[id] = (id.x == w-1 && id.y == h-1 && id.z == 0) ? (density[uint3(w-2,h-1,0)] + density[uint3(w-1,h-2,0)] + density[uint3(w-1,h-1,1)]) / 3 : density[id]; 57 | density[id] = (id.x == w-1 && id.y == h-1 && id.z != d-1) ? (density[uint3(w-2,h-1,d-1)] + density[uint3(w-1,h-2,d-1)] + density[uint3(w-1,h-1,d-2)]) / 3 : density[id]; 58 | } 59 | 60 | void SetBoundaryVelocity(uint3 id, uint w, uint h, uint d) 61 | { 62 | velocity[id] = (id.x == 0) ? float3(-velocity[id + uint3(1,0,0)].x, velocity[id].yz) : velocity[id]; 63 | velocity[id] = (id.x == w-1) ? float3(-velocity[uint3(w-2,id.yz)].x, velocity[id].yz) : velocity[id]; 64 | velocity[id] = (id.y == 0) ? float3(velocity[id].x, -velocity[id + uint3(0,1,0)].y, velocity[id].z) : velocity[id]; 65 | velocity[id] = (id.y == h-1) ? float3(velocity[id].x, -velocity[uint3(id.x,h-2,id.z)].y, velocity[id].z) : velocity[id]; 66 | velocity[id] = (id.z == 0) ? float3(velocity[id].xy, -velocity[id + uint3(0,0,1)].z) : velocity[id]; 67 | velocity[id] = (id.z == d-1) ? float3(velocity[id].xy, -velocity[uint3(id.xy,d-2)].z) : velocity[id]; 68 | 69 | velocity[id] = (id.x == 0 && id.y == 0 && id.z != 0 && id.z != d-1) ? 0.5 * (velocity[uint3(1,0,id.z)] + velocity[uint3(0,1,id.z)]) : velocity[id]; 70 | velocity[id] = (id.x == 0 && id.y == 0 && id.z == 0) ? (velocity[uint3(1,0,0)] + velocity[uint3(0,1,0)] + velocity[uint3(0,0,1)]) / 3 : velocity[id]; 71 | velocity[id] = (id.x == 0 && id.y == 0 && id.z == d-1) ? (velocity[uint3(1,0,d-1)] + velocity[uint3(0,1,d-1)] + velocity[uint3(0,0,d-2)]) / 3 : velocity[id]; 72 | velocity[id] = (id.x == 0 && id.y == h-1 && id.z != 0 && id.z != d-1) ? 0.5 * (velocity[uint3(1,h-1,id.z)] + velocity[uint3(0,h-2,id.z)]) : velocity[id]; 73 | velocity[id] = (id.x == 0 && id.y == h-1 && id.z == 0) ? (velocity[uint3(1,h-1,0)] + velocity[uint3(0,h-2,0)] + velocity[uint3(0,h-1,1)]) / 3 : velocity[id]; 74 | velocity[id] = (id.x == 0 && id.y == h-1 && id.z == d-1) ? (velocity[uint3(1,h-1,d-1)] + velocity[uint3(0,h-2,d-1)] + velocity[uint3(0,h-1,d-2)]) / 3 : velocity[id]; 75 | velocity[id] = (id.x == w-1 && id.y == 0 && id.z != 0 && id.z != d-1) ? 0.5 * (velocity[uint3(w-2,0,id.z)] + velocity[uint3(w-1,1,id.z)]) : velocity[id]; 76 | velocity[id] = (id.x == w-1 && id.y == 0 && id.z == 0) ? (velocity[uint3(w-2,0,0)] + velocity[uint3(w-1,1,0)] + velocity[uint3(w-1,0,1)]) / 3 : velocity[id]; 77 | velocity[id] = (id.x == w-1 && id.y == 0 && id.z == d-1) ? (velocity[uint3(w-2,0,d-1)] + velocity[uint3(w-1,1,d-1)] + velocity[uint3(w-1,0,d-2)]) / 3 : velocity[id]; 78 | velocity[id] = (id.x == w-1 && id.y == h-1 && id.z != 0 && id.z != d-1) ? 0.5 * (velocity[uint3(w-2,h-1,id.z)] + velocity[uint3(w-1,h-2,id.z)]) : velocity[id]; 79 | velocity[id] = (id.x == w-1 && id.y == h-1 && id.z == 0) ? (velocity[uint3(w-2,h-1,0)] + velocity[uint3(w-1,h-2,0)] + velocity[uint3(w-1,h-1,1)]) / 3 : velocity[id]; 80 | velocity[id] = (id.x == w-1 && id.y == h-1 && id.z != d-1) ? (velocity[uint3(w-2,h-1,d-1)] + velocity[uint3(w-1,h-2,d-1)] + velocity[uint3(w-1,h-1,d-2)]) / 3 : velocity[id]; 81 | } 82 | 83 | void SetBoundaryDiv(uint3 id, uint w, uint h, uint d) 84 | { 85 | prev[id] = (id.x == 0) ? float4(prev[id].x, prev[id + uint3(1,0,0)].y, prev[id].zw) : prev[id]; 86 | prev[id] = (id.x == w-1) ? float4(prev[id].x, prev[uint3(w-2, id.yz)].y, prev[id].zw) : prev[id]; 87 | prev[id] = (id.y == 0) ? float4(prev[id].x, prev[id + uint3(0,1,0)].y, prev[id].zw) : prev[id]; 88 | prev[id] = (id.y == h-1) ? float4(prev[id].x, prev[uint3(id.x, h-2, id.z)].y, prev[id].zw) : prev[id]; 89 | prev[id] = (id.z == 0) ? float4(prev[id].x, prev[id + uint3(0,0,1)].y, prev[id].zw) : prev[id]; 90 | prev[id] = (id.z == d-1) ? float4(prev[id].x, prev[uint3(id.xy, d-2)].y, prev[id].zw) : prev[id]; 91 | 92 | prev[id] = (id.x == 0 && id.y == 0 && id.z != 0 && id.z != d-1) ? float4(prev[id].x, 0.5 * (prev[uint3(1,0,id.z)].y + prev[uint3(0,1,id.z)].y), prev[id].zw) : prev[id]; 93 | prev[id] = (id.x == 0 && id.y == 0 && id.z == 0) ? float4(prev[id].x, (prev[uint3(1,0,0)].y + prev[uint3(0,1,0)].y + prev[uint3(0,0,1)].y) / 3, prev[id].zw) : prev[id]; 94 | prev[id] = (id.x == 0 && id.y == 0 && id.z == d-1) ? float4(prev[id].x, (prev[uint3(1,0,d-1)].y + prev[uint3(0,1,d-1)].y + prev[uint3(0,0,d-2)].y) / 3, prev[id].zw) : prev[id]; 95 | prev[id] = (id.x == 0 && id.y == h-1 && id.z != 0 && id.z != d-1) ? float4(prev[id].x, 0.5 * (prev[uint3(1,h-1,id.z)].y + prev[uint3(0,h-2,id.z)].y), prev[id].zw) : prev[id]; 96 | prev[id] = (id.x == 0 && id.y == h-1 && id.z == 0) ? float4(prev[id].x, (prev[uint3(1,h-1,0)].y + prev[uint3(0,h-2,0)].y + prev[uint3(0,h-1,1)].y) / 3, prev[id].zw) : prev[id]; 97 | prev[id] = (id.x == 0 && id.y == h-1 && id.z == d-1) ? float4(prev[id].x, (prev[uint3(1,h-1,d-1)].y + prev[uint3(0,h-2,d-1)].y + prev[uint3(0,h-1,d-2)].y) / 3, prev[id].zw) : prev[id]; 98 | prev[id] = (id.x == w-1 && id.y == 0 && id.z != 0 && id.z != d-1) ? float4(prev[id].x, 0.5 * (prev[uint3(w-2,0,id.z)].y + prev[uint3(w-1,1,id.z)].y), prev[id].zw) : prev[id]; 99 | prev[id] = (id.x == w-1 && id.y == 0 && id.z == 0) ? float4(prev[id].x, (prev[uint3(w-2,0,0)].y + prev[uint3(w-1,1,0)].y + prev[uint3(w-1,0,1)].y) / 3, prev[id].zw) : prev[id]; 100 | prev[id] = (id.x == w-1 && id.y == 0 && id.z == d-1) ? float4(prev[id].x, (prev[uint3(w-2,0,d-1)].y + prev[uint3(w-1,1,d-1)].y + prev[uint3(w-1,0,d-2)].y) / 3, prev[id].zw) : prev[id]; 101 | prev[id] = (id.x == w-1 && id.y == h-1 && id.z != 0 && id.z != d-1) ? float4(prev[id].x, 0.5 * (prev[uint3(w-2,h-1,id.z)].y + prev[uint3(w-1,h-2,id.z)].y), prev[id].zw) : prev[id]; 102 | prev[id] = (id.x == w-1 && id.y == h-1 && id.z == 0) ? float4(prev[id].x, (prev[uint3(w-2,h-1,0)].y + prev[uint3(w-1,h-2,0)].y + prev[uint3(w-1,h-1,1)].y) / 3, prev[id].zw) : prev[id]; 103 | prev[id] = (id.x == w-1 && id.y == h-1 && id.z != d-1) ? float4(prev[id].x, (prev[uint3(w-2,h-1,d-1)].y + prev[uint3(w-1,h-2,d-1)].y + prev[uint3(w-1,h-1,d-2)].y) / 3, prev[id].zw) : prev[id]; 104 | } 105 | 106 | void SetBoundaryP(uint3 id, uint w, uint h, uint d) 107 | { 108 | prev[id] = (id.x == 0) ? float4(prev[id + uint3(1,0,0)].x, prev[id].yzw) : prev[id]; 109 | prev[id] = (id.x == w-1) ? float4(prev[uint3(w-2, id.yz)].x, prev[id].yzw) : prev[id]; 110 | prev[id] = (id.y == 0) ? float4(prev[id + uint3(0,1,0)].x, prev[id].yzw) : prev[id]; 111 | prev[id] = (id.y == h-1) ? float4(prev[uint3(id.x, h-2, id.z)].x, prev[id].yzw) : prev[id]; 112 | prev[id] = (id.z == 0) ? float4(prev[id + uint3(0,0,1)].x, prev[id].yzw) : prev[id]; 113 | prev[id] = (id.z == d-1) ? float4(prev[uint3(id.xy, d-2)].x, prev[id].yzw) : prev[id]; 114 | 115 | prev[id] = (id.x == 0 && id.y == 0 && id.z != 0 && id.z != d-1) ? float4(0.5 * (prev[uint3(1,0,id.z)].x + prev[uint3(0,1,id.z)].x), prev[id].yzw) : prev[id]; 116 | prev[id] = (id.x == 0 && id.y == 0 && id.z == 0) ? float4((prev[uint3(1,0,0)].x + prev[uint3(0,1,0)].x + prev[uint3(0,0,1)].x) / 3, prev[id].yzw) : prev[id]; 117 | prev[id] = (id.x == 0 && id.y == 0 && id.z == d-1) ? float4((prev[uint3(1,0,d-1)].x + prev[uint3(0,1,d-1)].x + prev[uint3(0,0,d-2)].x) / 3, prev[id].yzw) : prev[id]; 118 | prev[id] = (id.x == 0 && id.y == h-1 && id.z != 0 && id.z != d-1) ? float4(0.5 * (prev[uint3(1,h-1,id.z)].x + prev[uint3(0,h-2,id.z)].x), prev[id].yzw) : prev[id]; 119 | prev[id] = (id.x == 0 && id.y == h-1 && id.z == 0) ? float4((prev[uint3(1,h-1,0)].x + prev[uint3(0,h-2,0)].x + prev[uint3(0,h-1,1)].x) / 3, prev[id].yzw) : prev[id]; 120 | prev[id] = (id.x == 0 && id.y == h-1 && id.z == d-1) ? float4((prev[uint3(1,h-1,d-1)].x + prev[uint3(0,h-2,d-1)].x + prev[uint3(0,h-1,d-2)].x) / 3, prev[id].yzw) : prev[id]; 121 | prev[id] = (id.x == w-1 && id.y == 0 && id.z != 0 && id.z != d-1) ? float4(0.5 * (prev[uint3(w-2,0,id.z)].x + prev[uint3(w-1,1,id.z)].x), prev[id].yzw) : prev[id]; 122 | prev[id] = (id.x == w-1 && id.y == 0 && id.z == 0) ? float4((prev[uint3(w-2,0,0)].x + prev[uint3(w-1,1,0)].x + prev[uint3(w-1,0,1)].x) / 3, prev[id].yzw) : prev[id]; 123 | prev[id] = (id.x == w-1 && id.y == 0 && id.z == d-1) ? float4((prev[uint3(w-2,0,d-1)].x + prev[uint3(w-1,1,d-1)].x + prev[uint3(w-1,0,d-2)].x) / 3, prev[id].yzw) : prev[id]; 124 | prev[id] = (id.x == w-1 && id.y == h-1 && id.z != 0 && id.z != d-1) ? float4(0.5 * (prev[uint3(w-2,h-1,id.z)].x + prev[uint3(w-1,h-2,id.z)].x), prev[id].yzw) : prev[id]; 125 | prev[id] = (id.x == w-1 && id.y == h-1 && id.z == 0) ? float4((prev[uint3(w-2,h-1,0)].x + prev[uint3(w-1,h-2,0)].x + prev[uint3(w-1,h-1,1)].x) / 3, prev[id].yzw) : prev[id]; 126 | prev[id] = (id.x == w-1 && id.y == h-1 && id.z != d-1) ? float4((prev[uint3(w-2,h-1,d-1)].x + prev[uint3(w-1,h-2,d-1)].x + prev[uint3(w-1,h-1,d-2)].x) / 3, prev[id].yzw) : prev[id]; 127 | } 128 | 129 | //密度場外力項. 130 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 131 | void AddSourceDensity(uint3 id : SV_DispatchThreadID) 132 | { 133 | uint w, h, d; 134 | float3 uvw; 135 | density.GetDimensions(w, h, d); 136 | uvw = float3(id.x/w, id.y/h, id.z/d); 137 | 138 | if (id.x < w && id.y < h && id.z < d) 139 | { 140 | density[id] += source.SampleLevel(_PointClamp, uvw, 0).w * densityCoef * dt; 141 | prev[id] = float4(prev[id].xyz, source.SampleLevel(_PointClamp, uvw, 0).w * densityCoef * dt); 142 | } 143 | } 144 | 145 | //速度場外力項. 146 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 147 | void AddSourceVelocity(uint3 id : SV_DispatchThreadID) 148 | { 149 | uint w, h, d; 150 | float3 uvw; 151 | velocity.GetDimensions(w, h, d); 152 | uvw = float3(id.x/w, id.y/h, id.z/d); 153 | 154 | if (id.x < w && id.y < h && id.z < d) 155 | { 156 | velocity[id] += source.SampleLevel(_PointClamp, uvw, 0).xyz * velocityCoef * dt; 157 | prev[id] = float4(source.SampleLevel(_PointClamp, uvw, 0).xyz * velocityCoef * dt, prev[id].w); 158 | } 159 | } 160 | 161 | //密度場拡散項.diff∇・∇densによる勾配・発散をGauss-Seidel法にて計算。diffは拡散係数. 162 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 163 | void DiffuseDensity(uint3 id : SV_DispatchThreadID) 164 | { 165 | uint w, h, d; 166 | density.GetDimensions(w, h, d); 167 | 168 | if (id.x < w && id.y < h && id.z < d) 169 | { 170 | float a = dt * diff * w * h * d; 171 | 172 | //TODO:Congugate gradient法でも試してみる 173 | [unroll] 174 | for (int k = 0; k < GS_ITERATE; k++) { 175 | density[id] = (prev[id].w + a * (density[int3(id.x - 1, id.yz)] + density[int3(id.x + 1, id.yz)] + density[int3(id.x, id.y - 1, id.z)] + density[int3(id.x, id.y + 1, id.z)] + density[int3(id.xy, id.z - 1)] + density[int3(id.xy, id.z + 1)])) / (1 + 6 * a); 176 | SetBoundaryDensity(id, w, h, d); 177 | } 178 | } 179 | } 180 | 181 | //速度場拡散(粘性)項.visc∇・∇velocityによる勾配・発散をGauss-Seidel法にて計算。viscはkinematic visocity(動粘性摩擦係数). 182 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 183 | void DiffuseVelocity(uint3 id : SV_DispatchThreadID) 184 | { 185 | uint w, h, d; 186 | velocity.GetDimensions(w, h, d); 187 | 188 | if (id.x < w && id.y < h && id.x < d) 189 | { 190 | float a = dt * visc * w * h; 191 | 192 | //TODO:Congugate gradient法でも試してみる 193 | [unroll] 194 | for (int k = 0; k < GS_ITERATE; k++) { 195 | velocity[id] = (prev[id].xyz + a * (velocity[int3(id.x - 1, id.yz)] + velocity[int3(id.x + 1, id.yz)] + velocity[int3(id.x, id.y - 1, id.z)] + velocity[int3(id.x, id.y + 1, id.z)] + velocity[int3(id.xy, id.z - 1)] + velocity[int3(id.xy, id.z + 1)])) / (1 + 6 * a); 196 | SetBoundaryVelocity(id, w, h, d); 197 | } 198 | } 199 | } 200 | 201 | //密度場移流項. 202 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 203 | void AdvectDensity(uint3 id : SV_DispatchThreadID) 204 | { 205 | uint w, h, d; 206 | density.GetDimensions(w, h, d); 207 | 208 | if (id.x < w && id.y < h && id.x < d) 209 | { 210 | int ddx0, ddx1, ddy0, ddy1, ddz0, ddz1; 211 | float x, y, z, s0, t0, u0, s1, t1, u1, dfdt; 212 | 213 | dfdt = dt * (w + h + d) / 3; 214 | 215 | //各偏微分方向-(w*dt*速度場の各偏微分座標、つまり移流するポテンシャル座標を出す. 216 | x = (float)id.x - dfdt * velocity[id].x; 217 | y = (float)id.y - dfdt * velocity[id].y; 218 | z = (float)id.z - dfdt * velocity[id].z; 219 | //移流ポテンシャル座標xyzは0.5~横幅-0.5以内にクランプ. 220 | clamp(x, 0.5, w - 1.5); 221 | clamp(y, 0.5, h - 1.5); 222 | clamp(z, 0.5, d - 1.5); 223 | //xyzのそれぞれ近似の偏微分セルを求める. 224 | ddx0 = floor(x); 225 | ddx1 = ddx0 + 1; 226 | ddy0 = floor(y); 227 | ddy1 = ddy0 + 1; 228 | ddz0 = floor(z); 229 | ddz1 = ddz0 + 1; 230 | //intセルと目標座標の間に端数がある為、各偏微分方向の差分をx1,x0系という形で出す. 231 | s1 = x - ddx0; 232 | s0 = 1.0 - s1; 233 | t1 = y - ddy0; 234 | t0 = 1.0 - t1; 235 | u1 = z - ddz0; 236 | u0 = 1.0 - u1; 237 | 238 | //ポテンシャル座標の密度を1step前の密度場から持ってくる. 239 | //ただし、xyzがセルのど真ん中の値を指してる訳ではないので、セルとfloatとの差分と1-との値を近傍6セル分線形補完して算出する. 240 | density[id] = s0 * u0 * (t0 * prev[int3(ddx0, ddy0, ddz0)].z + t1 * prev[int3(ddx0, ddy1, ddz0)].z) + 241 | s1 * u0 * (t0 * prev[int3(ddx1, ddy0, ddz0)].z + t1 * prev[int3(ddx1, ddy1, ddz0)].z) + 242 | s0 * u1 * (t0 * prev[int3(ddx0, ddy0, ddz1)].z + t1 * prev[int3(ddx0, ddy1, ddz1)].z) + 243 | s1 * u1 * (t0 * prev[int3(ddx1, ddy0, ddz1)].z + t1 * prev[int3(ddx1, ddy1, ddz1)].z); 244 | SetBoundaryDensity(id, w, h, d); 245 | } 246 | } 247 | 248 | //密度場移流項(このカーネルはvelocity stepを用いず、速度場を外部からsource texにフェッチした物を参照する事によって軽量化を狙う為用意). 249 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 250 | void AdvectDensityFromExt(uint3 id : SV_DispatchThreadID) 251 | { 252 | uint w, h, d; 253 | float3 uvw; 254 | density.GetDimensions(w, h, d); 255 | uvw = float3(id.x/w, id.y/h, id.z/d); 256 | 257 | if (id.x < w && id.y < h && id.x < d) 258 | { 259 | int ddx0, ddx1, ddy0, ddy1, ddz0, ddz1; 260 | float x, y, z, s0, t0, u0, s1, t1, u1, dfdt; 261 | 262 | dfdt = dt * (w + h + d) / 3; 263 | 264 | //各偏微分方向-(w*dt*速度場の各偏微分座標、つまり移流するポテンシャル座標を出す. 265 | //NOTE:外部参照パターン. 266 | x = (float)id.x - dfdt * source.SampleLevel(_PointClamp, uvw, 0).x; 267 | y = (float)id.y - dfdt * source.SampleLevel(_PointClamp, uvw, 0).y; 268 | z = (float)id.z - dfdt * source.SampleLevel(_PointClamp, uvw, 0).z; 269 | //移流ポテンシャル座標xyzは0.5~横幅-0.5以内にクランプ. 270 | clamp(x, 0.5, w - 1.5); 271 | clamp(y, 0.5, h - 1.5); 272 | clamp(z, 0.5, d - 1.5); 273 | //xyzのそれぞれ近似の偏微分セルを求める. 274 | ddx0 = floor(x); 275 | ddx1 = ddx0 + 1; 276 | ddy0 = floor(y); 277 | ddy1 = ddy0 + 1; 278 | ddz0 = floor(z); 279 | ddz1 = ddz0 + 1; 280 | //intセルと目標座標の間に端数がある為、各偏微分方向の差分をx1,x0系という形で出す. 281 | s1 = x - ddx0; 282 | s0 = 1.0 - s1; 283 | t1 = y - ddy0; 284 | t0 = 1.0 - t1; 285 | u1 = z - ddz0; 286 | u0 = 1.0 - u1; 287 | 288 | //ポテンシャル座標の密度を1step前の密度場から持ってくる. 289 | //ただし、xyzがセルのど真ん中の値を指してる訳ではないので、セルとfloatとの差分と1-との値を近傍6セル分線形補完して算出する. 290 | density[id] = s0 * u0 * (t0 * prev[int3(ddx0, ddy0, ddz0)].z + t1 * prev[int3(ddx0, ddy1, ddz0)].z) + 291 | s1 * u0 * (t0 * prev[int3(ddx1, ddy0, ddz0)].z + t1 * prev[int3(ddx1, ddy1, ddz0)].z) + 292 | s0 * u1 * (t0 * prev[int3(ddx0, ddy0, ddz1)].z + t1 * prev[int3(ddx0, ddy1, ddz1)].z) + 293 | s1 * u1 * (t0 * prev[int3(ddx1, ddy0, ddz1)].z + t1 * prev[int3(ddx1, ddy1, ddz1)].z); 294 | SetBoundaryDensity(id, w, h, d); 295 | } 296 | } 297 | 298 | //速度場移流項. 299 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 300 | void AdvectVelocity(uint3 id : SV_DispatchThreadID) 301 | { 302 | uint w, h, d; 303 | density.GetDimensions(w, h, d); 304 | 305 | if (id.x < w && id.y < h && id.x < d) 306 | { 307 | int ddx0, ddx1, ddy0, ddy1, ddz0, ddz1; 308 | float x, y, z, s0, t0, u0, s1, t1, u1, dfdt; 309 | 310 | dfdt = dt * (w + h + d) / 3; 311 | 312 | //各偏微分方向-(w*dt*速度場の各偏微分座標、つまり移流するポテンシャル座標を出す. 313 | x = (float)id.x - dfdt * prev[id].x; 314 | y = (float)id.y - dfdt * prev[id].y; 315 | z = (float)id.z - dfdt * prev[id].z; 316 | //移流ポテンシャル座標xyzは0.5~横幅-0.5以内にクランプ. 317 | clamp(x, 0.5, w - 1.5); 318 | clamp(y, 0.5, h - 1.5); 319 | clamp(z, 0.5, d - 1.5); 320 | //xyzのそれぞれ近似の偏微分セルを求める. 321 | ddx0 = floor(x); 322 | ddx1 = ddx0 + 1; 323 | ddy0 = floor(y); 324 | ddy1 = ddy0 + 1; 325 | ddz0 = floor(z); 326 | ddz1 = ddz0 + 1; 327 | //intセルと目標座標の間に端数がある為、各偏微分方向の差分をx1,x0系という形で出す. 328 | s1 = x - ddx0; 329 | s0 = 1.0 - s1; 330 | t1 = y - ddy0; 331 | t0 = 1.0 - t1; 332 | u1 = z - ddz0; 333 | u0 = 1.0 - u1; 334 | 335 | //ポテンシャル座標の速度ベクトルを1step前の密度場から持ってくる. 336 | //ただし、xyzがセルのど真ん中の値を指してる訳ではないので、セルとfloatとの差分と1-との値を近傍6セル分線形補完して算出する. 337 | velocity[id] = s0 * u0 * (t0 * prev[int3(ddx0, ddy0, ddz0)].xyz + t1 * prev[int3(ddx0, ddy1, ddz0)].xyz) + 338 | s1 * u0 * (t0 * prev[int3(ddx1, ddy0, ddz0)].xyz + t1 * prev[int3(ddx1, ddy1, ddz0)].xyz) + 339 | s0 * u1 * (t0 * prev[int3(ddx0, ddy0, ddz1)].xyz + t1 * prev[int3(ddx0, ddy1, ddz1)].xyz) + 340 | s1 * u1 * (t0 * prev[int3(ddx1, ddy0, ddz1)].xyz + t1 * prev[int3(ddx1, ddy1, ddz1)].xyz); 341 | SetBoundaryVelocity(id, w, h, d); 342 | } 343 | } 344 | 345 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 346 | void SwapDensity(uint3 id : SV_DispatchThreadID) 347 | { 348 | uint w, h, d; 349 | density.GetDimensions(w, h, d); 350 | 351 | if (id.x < w && id.y < h && id.x < d) 352 | { 353 | float temp = density[id]; 354 | //density[id] = prev[id].z; 355 | prev[id] = float4(prev[id].xyz, temp); 356 | } 357 | } 358 | 359 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 360 | void SwapVelocity(uint3 id : SV_DispatchThreadID) 361 | { 362 | uint w, h, d; 363 | velocity.GetDimensions(w, h, d); 364 | 365 | if (id.x < w && id.y < h && id.x < d) 366 | { 367 | float3 temp = velocity[id]; 368 | //velocity[id] = prev[id].xy; 369 | prev[id] = float4(temp, prev[id].w); 370 | } 371 | } 372 | 373 | //非圧縮性流体の為、速度divergenceの流出入を∇・u = 0にする外圧pを求め、速度場に投影. 374 | //速度場圧力項Step1. 375 | //step1では、発散の算出まで. 376 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 377 | void ProjectStep1(uint3 id : SV_DispatchThreadID) 378 | { 379 | uint w, h, d; 380 | velocity.GetDimensions(w, h, d); 381 | 382 | if (id.x < w && id.y < h && id.x < d) 383 | { 384 | float3 uvd; 385 | uvd = float3(1.0 / w, 1.0 / h, 1.0 / d); 386 | //prev[id].yをdivergenceとして使用. 387 | prev[id] = float4(0.0, 388 | -0.5 * (uvd.x * (velocity[int3(id.x + 1, id.y, id.z)].x - velocity[int3(id.x - 1, id.y, id.z)].x)) + 389 | (uvd.y * (velocity[int3(id.x, id.y + 1, id.z)].y - velocity[int3(id.x, id.y - 1, id.z)].y)) + 390 | (uvd.z * (velocity[int3(id.x, id.y, id.z + 1)].z - velocity[int3(id.x, id.y, id.z - 1)].z)), 391 | prev[id].zw); 392 | 393 | SetBoundaryDiv(id, w, h, d); 394 | SetBoundaryP(id, w, h, d); 395 | } 396 | } 397 | 398 | //速度場圧力項Step2. 399 | //step2では、step1で求めた発散から外圧∇pを求める. 400 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 401 | void ProjectStep2(uint3 id : SV_DispatchThreadID) 402 | { 403 | uint w, h, d; 404 | velocity.GetDimensions(w, h, d); 405 | 406 | if (id.x < w && id.y < h && id.x < d) 407 | { 408 | for (int k = 0; k < GS_ITERATE; k++) 409 | { 410 | //prev[id].xを外圧∇pとして使用. 411 | prev[id] = float4( 412 | (prev[id].y + prev[uint3(id.x - 1, id.y, id.z)].x + prev[uint3(id.x + 1, id.y, id.z)].x + 413 | prev[uint3(id.x, id.y - 1, id.z)].x + prev[uint3(id.x, id.y + 1, id.z)].x + 414 | prev[uint3(id.x, id.y, id.z - 1)].x + prev[uint3(id.x, id.y, id.z + 1)].x) / 6, 415 | prev[id].yzw); 416 | SetBoundaryP(id, w, h, d); 417 | } 418 | } 419 | } 420 | 421 | //速度場圧力項Step3. 422 | //step3では、step2で求めた外圧∇pを現在の速度場に減算し、∇・u = 0にしている. 423 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 424 | void ProjectStep3(uint3 id : SV_DispatchThreadID) 425 | { 426 | uint w, h, d; 427 | velocity.GetDimensions(w, h, d); 428 | 429 | if (id.x < w && id.y < h && id.x < d) 430 | { 431 | float velX, velY, velZ; 432 | float3 uvd; 433 | uvd = float3(1.0 / w, 1.0 / h, 1.0 / d); 434 | 435 | velX = velocity[id].x; 436 | velY = velocity[id].y; 437 | velZ = velocity[id].z; 438 | 439 | velX -= 0.5 * (prev[uint3(id.x + 1, id.y, id.z)].x - prev[uint3(id.x - 1, id.y, id.z)].x) / uvd.x; 440 | velY -= 0.5 * (prev[uint3(id.x, id.y + 1, id.z)].x - prev[uint3(id.x, id.y - 1, id.z)].x) / uvd.y; 441 | velZ -= 0.5 * (prev[uint3(id.x, id.y, id.z + 1)].x - prev[uint3(id.x, id.y, id.z - 1)].x) / uvd.z; 442 | 443 | velocity[id] = float3(velX, velY, velZ); 444 | SetBoundaryVelocity(id, w, h, d); 445 | } 446 | } 447 | 448 | [numthreads(THREAD_X, THREAD_Y, THREAD_Z)] 449 | void Draw(uint3 id : SV_DispatchThreadID) 450 | { 451 | uint w, h, d; 452 | solver.GetDimensions(w, h, d); 453 | 454 | if (id.x < w && id.y < h && id.x < d) 455 | { 456 | solver[id] = float4(velocity[id].xyz, density[id]); 457 | } 458 | } -------------------------------------------------------------------------------- /Assets/StableFluid/ComputeShaders/Solver3D.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 98a53d1c593876240ba3fe84345d2f17 3 | timeCreated: 1493362868 4 | licenseType: Pro 5 | ComputeShaderImporter: 6 | currentAPIMask: 4 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/StableFluid/Material.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bfca5caff4ac6cc4ca81d679c2036bb9 3 | folderAsset: yes 4 | timeCreated: 1492766698 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/StableFluid/Material/AddSource.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/Assets/StableFluid/Material/AddSource.mat -------------------------------------------------------------------------------- /Assets/StableFluid/Material/AddSource.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c50ccf50d761fd543a108b1579e0055b 3 | timeCreated: 1493267834 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/StableFluid/Material/Debug.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/Assets/StableFluid/Material/Debug.mat -------------------------------------------------------------------------------- /Assets/StableFluid/Material/Debug.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c6014208ef1b22c43baca45cece86c1a 3 | timeCreated: 1493496755 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/StableFluid/Material/Sample.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/Assets/StableFluid/Material/Sample.mat -------------------------------------------------------------------------------- /Assets/StableFluid/Material/Sample.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8d3b631bf92818147b24cdc99d38a2a0 3 | timeCreated: 1499327481 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | mainObjectFileID: 2100000 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/StableFluid/Scene.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6fd2ab580f276574a8ded2388e830ad4 3 | folderAsset: yes 4 | timeCreated: 1492769258 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/StableFluid/Scene/sample.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/Assets/StableFluid/Scene/sample.unity -------------------------------------------------------------------------------- /Assets/StableFluid/Scene/sample.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 973ae194b2629384589d13a9ee387f98 3 | timeCreated: 1492769278 4 | licenseType: Pro 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/StableFluid/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c962fcdd58e5df54594f4b048c3f96d0 3 | folderAsset: yes 4 | timeCreated: 1492760925 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/StableFluid/Scripts/MouseSourceProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace StableFluid 5 | { 6 | public class MouseSourceProvider : MonoBehaviour 7 | { 8 | private string source2dProp = "_Source"; 9 | private string sourceRadiusProp = "_Radius"; 10 | private int source2dId, sourceRadiusId; 11 | private Vector3 lastMousePos; 12 | 13 | [SerializeField] 14 | private Material addSourceMat; 15 | 16 | [SerializeField] 17 | private float sourceRadius = 0.03f; 18 | 19 | public RenderTexture addSourceTex; 20 | public SourceEvent OnSourceUpdated; 21 | 22 | void Awake() 23 | { 24 | source2dId = Shader.PropertyToID(source2dProp); 25 | sourceRadiusId = Shader.PropertyToID(sourceRadiusProp); 26 | } 27 | 28 | void Update() 29 | { 30 | InitializeSourceTex(Screen.width, Screen.height); 31 | UpdateSource(); 32 | } 33 | 34 | void OnDestroy() 35 | { 36 | ReleaseForceField(); 37 | } 38 | 39 | void InitializeSourceTex(int width, int height) 40 | { 41 | if (addSourceTex == null || addSourceTex.width != width || addSourceTex.height != height) 42 | { 43 | ReleaseForceField(); 44 | addSourceTex = new RenderTexture(width, height, 0, RenderTextureFormat.ARGBFloat); 45 | } 46 | } 47 | 48 | void UpdateSource() 49 | { 50 | var mousePos = Input.mousePosition; 51 | var dpdt = UpdateMousePos(mousePos); 52 | var velocitySource = Vector2.zero; 53 | var uv = Vector2.zero; 54 | 55 | if (Input.GetMouseButton(0)) 56 | { 57 | uv = Camera.main.ScreenToViewportPoint(mousePos); 58 | velocitySource = Vector2.ClampMagnitude(dpdt, 1f); 59 | addSourceMat.SetVector(source2dId, new Vector4(velocitySource.x, velocitySource.y, uv.x, uv.y)); 60 | addSourceMat.SetFloat(sourceRadiusId, sourceRadius); 61 | Graphics.Blit(null, addSourceTex, addSourceMat); 62 | NotifySourceTexUpdate(); 63 | } 64 | else 65 | { 66 | NotifyNoSourceTexUpdate(); 67 | } 68 | } 69 | 70 | void NotifySourceTexUpdate() 71 | { 72 | OnSourceUpdated.Invoke(addSourceTex); 73 | } 74 | 75 | void NotifyNoSourceTexUpdate() 76 | { 77 | OnSourceUpdated.Invoke(null); 78 | } 79 | 80 | Vector3 UpdateMousePos(Vector3 mousePos) 81 | { 82 | var dpdt = mousePos - lastMousePos; 83 | lastMousePos = mousePos; 84 | return dpdt; 85 | } 86 | 87 | void ReleaseForceField() 88 | { 89 | Destroy(addSourceTex); 90 | } 91 | 92 | [Serializable] 93 | public class SourceEvent : UnityEngine.Events.UnityEvent { } 94 | } 95 | } -------------------------------------------------------------------------------- /Assets/StableFluid/Scripts/MouseSourceProvider.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d6027424a3a36ad4a8debccd22920a94 3 | timeCreated: 1493266982 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/StableFluid/Scripts/Render.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c8bc0091dc625114cb402d499fa86b6b 3 | folderAsset: yes 4 | timeCreated: 1492761758 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/StableFluid/Scripts/Render/RenderEffect.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Render 4 | { 5 | public class RenderEffect : MonoBehaviour 6 | { 7 | public TextureEvent OnCreateTex; 8 | public RenderTexture Output { get; private set; } 9 | 10 | [SerializeField] string propName = "_PropName"; 11 | [SerializeField] Material[] effects; 12 | [SerializeField] bool show = true; 13 | [SerializeField] RenderTextureFormat format = RenderTextureFormat.ARGBFloat; 14 | [SerializeField] TextureWrapMode wrapMode; 15 | [SerializeField] int downSample = 0; 16 | 17 | RenderTexture[] rts = new RenderTexture[2]; 18 | 19 | void Update() 20 | { 21 | if (Input.GetKeyDown(KeyCode.Alpha6)) 22 | show = !show; 23 | } 24 | 25 | void OnRenderImage(RenderTexture s, RenderTexture d) 26 | { 27 | CheckRTs(s); 28 | Graphics.Blit(s, rts[0]); 29 | foreach (var m in effects) 30 | { 31 | Graphics.Blit(rts[0], rts[1], m); 32 | SwapRTs(); 33 | } 34 | 35 | Graphics.Blit(rts[0], Output); 36 | Shader.SetGlobalTexture(propName, Output); 37 | if (show) 38 | Graphics.Blit(Output, d); 39 | else 40 | Graphics.Blit(s, d); 41 | } 42 | 43 | void CheckRTs(RenderTexture s) 44 | { 45 | if (rts[0] == null || rts[0].width != s.width >> downSample || rts[0].height != s.height >> downSample) 46 | { 47 | for (var i = 0; i < rts.Length; i++) 48 | { 49 | var rt = rts[i]; 50 | rts[i] = RenderUtility.CreateRenderTexture(s.width >> downSample, s.height >> downSample, 16, format, wrapMode, FilterMode.Bilinear, rt); 51 | } 52 | Output = RenderUtility.CreateRenderTexture(s.width >> downSample, s.height >> downSample, 16, format, wrapMode, FilterMode.Bilinear, Output); 53 | OnCreateTex.Invoke(Output); 54 | } 55 | } 56 | 57 | void SwapRTs() 58 | { 59 | var tmp = rts[0]; 60 | rts[0] = rts[1]; 61 | rts[1] = tmp; 62 | } 63 | 64 | void OnDisabled() 65 | { 66 | foreach (var rt in rts) 67 | RenderUtility.ReleaseRenderTexture(rt); 68 | RenderUtility.ReleaseRenderTexture(Output); 69 | } 70 | 71 | [System.Serializable] 72 | public class TextureEvent : UnityEngine.Events.UnityEvent { } 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /Assets/StableFluid/Scripts/Render/RenderEffect.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3b5841f782e494a489de3ff0ca3b975f 3 | timeCreated: 1492761548 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/StableFluid/Scripts/Render/RenderUtility.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEngine.Rendering; 5 | 6 | namespace Render 7 | { 8 | public class RenderUtility : MonoBehaviour 9 | { 10 | 11 | public static RenderTexture CreateRenderTexture(int width, int height, int depth, RenderTextureFormat format, TextureWrapMode wrapMode = TextureWrapMode.Repeat, FilterMode filterMode = FilterMode.Bilinear, RenderTexture rt = null) 12 | { 13 | if (rt != null) 14 | { 15 | if (rt.width == width && rt.height == height) return rt; 16 | } 17 | 18 | ReleaseRenderTexture(rt); 19 | rt = new RenderTexture(width, height, depth, format); 20 | rt.enableRandomWrite = true; 21 | rt.wrapMode = wrapMode; 22 | rt.filterMode = filterMode; 23 | rt.Create(); 24 | ClearRenderTexture(rt, Color.clear); 25 | return rt; 26 | } 27 | 28 | public static RenderTexture CreateVolumetricRenderTexture(int width, int height, int volumeDepth, int depth, RenderTextureFormat format, TextureWrapMode wrapMode = TextureWrapMode.Repeat, FilterMode filterMode = FilterMode.Bilinear, RenderTexture rt = null) 29 | { 30 | if (rt != null) 31 | { 32 | if (rt.width == width && rt.height == height) return rt; 33 | } 34 | 35 | ReleaseRenderTexture(rt); 36 | rt = new RenderTexture(width, height, depth, format); 37 | rt.dimension = TextureDimension.Tex3D; 38 | rt.volumeDepth = volumeDepth; 39 | rt.enableRandomWrite = true; 40 | rt.wrapMode = wrapMode; 41 | rt.filterMode = filterMode; 42 | rt.Create(); 43 | ClearRenderTexture(rt, Color.clear); 44 | return rt; 45 | } 46 | 47 | public static void ReleaseRenderTexture(RenderTexture rt) 48 | { 49 | if (rt == null) return; 50 | 51 | rt.Release(); 52 | Destroy(rt); 53 | } 54 | 55 | public static void ClearRenderTexture(RenderTexture target, Color bg) 56 | { 57 | var active = RenderTexture.active; 58 | RenderTexture.active = target; 59 | GL.Clear(true, true, bg); 60 | RenderTexture.active = active; 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Assets/StableFluid/Scripts/Render/RenderUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 98f7d519136c0c547b53f0623e7a0370 3 | timeCreated: 1499754254 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/StableFluid/Scripts/Solver2D.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace StableFluid 4 | { 5 | public class Solver2D : SolverBase 6 | { 7 | #region Initialize 8 | 9 | protected override void InitializeComputeShader() 10 | { 11 | width = Screen.width; 12 | height = Screen.height; 13 | solverTex = CreateRenderTexture(width >> lod, height >> lod, 0, RenderTextureFormat.ARGBFloat, solverTex); 14 | densityTex = CreateRenderTexture(width >> lod, height >> lod, 0, RenderTextureFormat.RHalf, densityTex); 15 | velocityTex = CreateRenderTexture(width >> lod, height >> lod, 0, RenderTextureFormat.RGHalf, velocityTex); 16 | prevTex = CreateRenderTexture(width >> lod, height >> lod, 0, RenderTextureFormat.ARGBHalf, prevTex); 17 | 18 | Shader.SetGlobalTexture(solverTexId, solverTex); 19 | 20 | computeShader.SetFloat(diffId, diff); 21 | computeShader.SetFloat(viscId, visc); 22 | computeShader.SetFloat(dtId, Time.deltaTime); 23 | computeShader.SetFloat(velocityCoefId, velocityCoef); 24 | computeShader.SetFloat(densityCoefId, densityCoef); 25 | } 26 | 27 | #endregion 28 | 29 | #region StableFluid gpu kernel steps 30 | 31 | protected override void DensityStep() 32 | { 33 | //Add density source to density field 34 | if (SorceTex != null) 35 | { 36 | computeShader.SetTexture(kernelMap[ComputeKernels.AddSourceDensity], sourceId, SorceTex); 37 | computeShader.SetTexture(kernelMap[ComputeKernels.AddSourceDensity], densityId, densityTex); 38 | computeShader.SetTexture(kernelMap[ComputeKernels.AddSourceDensity], prevId, prevTex); 39 | computeShader.Dispatch(kernelMap[ComputeKernels.AddSourceDensity], Mathf.CeilToInt(solverTex.width / gpuThreads.x), Mathf.CeilToInt(solverTex.height / gpuThreads.y), 1); 40 | } 41 | 42 | //Diffuse density 43 | computeShader.SetTexture(kernelMap[ComputeKernels.DiffuseDensity], densityId, densityTex); 44 | computeShader.SetTexture(kernelMap[ComputeKernels.DiffuseDensity], prevId, prevTex); 45 | computeShader.Dispatch(kernelMap[ComputeKernels.DiffuseDensity], Mathf.CeilToInt(solverTex.width / gpuThreads.x), Mathf.CeilToInt(solverTex.height / gpuThreads.y), 1); 46 | 47 | //Swap density 48 | computeShader.SetTexture(kernelMap[ComputeKernels.SwapDensity], densityId, densityTex); 49 | computeShader.SetTexture(kernelMap[ComputeKernels.SwapDensity], prevId, prevTex); 50 | computeShader.Dispatch(kernelMap[ComputeKernels.SwapDensity], Mathf.CeilToInt(solverTex.width / gpuThreads.x), Mathf.CeilToInt(solverTex.height / gpuThreads.y), 1); 51 | 52 | if (isDensityOnly) 53 | { 54 | //Advection using external velocity field via ForceTex. 55 | computeShader.SetTexture(kernelMap[ComputeKernels.AdvectDensityFromExt], densityId, densityTex); 56 | computeShader.SetTexture(kernelMap[ComputeKernels.AdvectDensityFromExt], prevId, prevTex); 57 | computeShader.SetTexture(kernelMap[ComputeKernels.AdvectDensityFromExt], velocityId, velocityTex); 58 | if (SorceTex != null) computeShader.SetTexture(kernelMap[ComputeKernels.AdvectDensityFromExt], sourceId, SorceTex); 59 | computeShader.Dispatch(kernelMap[ComputeKernels.AdvectDensity], Mathf.CeilToInt(solverTex.width / gpuThreads.x), Mathf.CeilToInt(solverTex.height / gpuThreads.y), 1); 60 | } 61 | else 62 | { 63 | //Advection using velocity solver 64 | computeShader.SetTexture(kernelMap[ComputeKernels.AdvectDensity], densityId, densityTex); 65 | computeShader.SetTexture(kernelMap[ComputeKernels.AdvectDensity], prevId, prevTex); 66 | computeShader.SetTexture(kernelMap[ComputeKernels.AdvectDensity], velocityId, velocityTex); 67 | computeShader.Dispatch(kernelMap[ComputeKernels.AdvectDensity], Mathf.CeilToInt(solverTex.width / gpuThreads.x), Mathf.CeilToInt(solverTex.height / gpuThreads.y), 1); 68 | } 69 | } 70 | 71 | protected override void VelocityStep() 72 | { 73 | //Add velocity source to velocity field 74 | if (SorceTex != null) 75 | { 76 | computeShader.SetTexture(kernelMap[ComputeKernels.AddSourceVelocity], sourceId, SorceTex); 77 | computeShader.SetTexture(kernelMap[ComputeKernels.AddSourceVelocity], velocityId, velocityTex); 78 | computeShader.SetTexture(kernelMap[ComputeKernels.AddSourceVelocity], prevId, prevTex); 79 | computeShader.Dispatch(kernelMap[ComputeKernels.AddSourceVelocity], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), 1); 80 | } 81 | 82 | //Diffuse velocity 83 | computeShader.SetTexture(kernelMap[ComputeKernels.DiffuseVelocity], velocityId, velocityTex); 84 | computeShader.SetTexture(kernelMap[ComputeKernels.DiffuseVelocity], prevId, prevTex); 85 | computeShader.Dispatch(kernelMap[ComputeKernels.DiffuseVelocity], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), 1); 86 | 87 | //Project 88 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep1], velocityId, velocityTex); 89 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep1], prevId, prevTex); 90 | computeShader.Dispatch(kernelMap[ComputeKernels.ProjectStep1], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), 1); 91 | 92 | //Project 93 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep2], prevId, prevTex); 94 | computeShader.Dispatch(kernelMap[ComputeKernels.ProjectStep2], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), 1); 95 | 96 | //Project 97 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep3], velocityId, velocityTex); 98 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep3], prevId, prevTex); 99 | computeShader.Dispatch(kernelMap[ComputeKernels.ProjectStep3], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), 1); 100 | 101 | //Swap velocity 102 | computeShader.SetTexture(kernelMap[ComputeKernels.SwapVelocity], velocityId, velocityTex); 103 | computeShader.SetTexture(kernelMap[ComputeKernels.SwapVelocity], prevId, prevTex); 104 | computeShader.Dispatch(kernelMap[ComputeKernels.SwapVelocity], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), 1); 105 | 106 | //Advection 107 | computeShader.SetTexture(kernelMap[ComputeKernels.AdvectVelocity], velocityId, velocityTex); 108 | computeShader.SetTexture(kernelMap[ComputeKernels.AdvectVelocity], prevId, prevTex); 109 | computeShader.Dispatch(kernelMap[ComputeKernels.AdvectVelocity], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), 1); 110 | 111 | //Project 112 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep1], velocityId, velocityTex); 113 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep1], prevId, prevTex); 114 | computeShader.Dispatch(kernelMap[ComputeKernels.ProjectStep1], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), 1); 115 | 116 | //Project 117 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep2], prevId, prevTex); 118 | computeShader.Dispatch(kernelMap[ComputeKernels.ProjectStep2], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), 1); 119 | 120 | //Project 121 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep3], velocityId, velocityTex); 122 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep3], prevId, prevTex); 123 | computeShader.Dispatch(kernelMap[ComputeKernels.ProjectStep3], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), 1); 124 | } 125 | 126 | #endregion 127 | } 128 | } -------------------------------------------------------------------------------- /Assets/StableFluid/Scripts/Solver2D.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c4234aa3aeedb7c4a97e164dbe948a47 3 | timeCreated: 1499009510 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/StableFluid/Scripts/Solver3D.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace StableFluid 4 | { 5 | public class Solver3D : SolverBase 6 | { 7 | #region Variables 8 | 9 | [SerializeField] 10 | private int depth; 11 | 12 | #endregion 13 | 14 | #region Initialize 15 | 16 | protected override void InitializeComputeShader() 17 | { 18 | width = Screen.width; 19 | height = Screen.height; 20 | solverTex = CreateVolumetricRenderTexture(width >> lod, height >> lod, depth >> lod, 0, RenderTextureFormat.ARGBFloat, solverTex); 21 | densityTex = CreateVolumetricRenderTexture(width >> lod, height >> lod, depth >> lod, 0, RenderTextureFormat.RHalf, densityTex); 22 | velocityTex = CreateVolumetricRenderTexture(width >> lod, height >> lod, depth >> lod, 0, RenderTextureFormat.RGHalf, velocityTex); 23 | prevTex = CreateVolumetricRenderTexture(width >> lod, height >> lod, depth >> lod, 0, RenderTextureFormat.ARGBHalf, prevTex); 24 | 25 | Shader.SetGlobalTexture(solverTexId, solverTex); 26 | 27 | computeShader.SetFloat(diffId, diff); 28 | computeShader.SetFloat(viscId, visc); 29 | computeShader.SetFloat(dtId, Time.deltaTime); 30 | computeShader.SetFloat(velocityCoefId, velocityCoef); 31 | computeShader.SetFloat(densityCoefId, densityCoef); 32 | } 33 | 34 | #endregion 35 | 36 | #region StableFluid gpu kernel steps 37 | 38 | protected override void DensityStep() 39 | { 40 | //Add density source to density field 41 | if (SorceTex != null) 42 | { 43 | computeShader.SetTexture(kernelMap[ComputeKernels.AddSourceDensity], sourceId, SorceTex); 44 | computeShader.SetTexture(kernelMap[ComputeKernels.AddSourceDensity], densityId, densityTex); 45 | computeShader.SetTexture(kernelMap[ComputeKernels.AddSourceDensity], prevId, prevTex); 46 | computeShader.Dispatch(kernelMap[ComputeKernels.AddSourceDensity], Mathf.CeilToInt(solverTex.width / gpuThreads.x), Mathf.CeilToInt(solverTex.height / gpuThreads.y), Mathf.CeilToInt(depth / gpuThreads.z)); 47 | } 48 | 49 | //Diffuse density 50 | computeShader.SetTexture(kernelMap[ComputeKernels.DiffuseDensity], densityId, densityTex); 51 | computeShader.SetTexture(kernelMap[ComputeKernels.DiffuseDensity], prevId, prevTex); 52 | computeShader.Dispatch(kernelMap[ComputeKernels.DiffuseDensity], Mathf.CeilToInt(solverTex.width / gpuThreads.x), Mathf.CeilToInt(solverTex.height / gpuThreads.y), Mathf.CeilToInt(depth / gpuThreads.z)); 53 | 54 | //Swap density 55 | computeShader.SetTexture(kernelMap[ComputeKernels.SwapDensity], densityId, densityTex); 56 | computeShader.SetTexture(kernelMap[ComputeKernels.SwapDensity], prevId, prevTex); 57 | computeShader.Dispatch(kernelMap[ComputeKernels.SwapDensity], Mathf.CeilToInt(solverTex.width / gpuThreads.x), Mathf.CeilToInt(solverTex.height / gpuThreads.y), Mathf.CeilToInt(depth / gpuThreads.z)); 58 | 59 | if (isDensityOnly) 60 | { 61 | //Advection using external velocity field via ForceTex. 62 | computeShader.SetTexture(kernelMap[ComputeKernels.AdvectDensityFromExt], densityId, densityTex); 63 | computeShader.SetTexture(kernelMap[ComputeKernels.AdvectDensityFromExt], prevId, prevTex); 64 | computeShader.SetTexture(kernelMap[ComputeKernels.AdvectDensityFromExt], velocityId, velocityTex); 65 | if (SorceTex != null) computeShader.SetTexture(kernelMap[ComputeKernels.AdvectDensityFromExt], sourceId, SorceTex); 66 | computeShader.Dispatch(kernelMap[ComputeKernels.AdvectDensity], Mathf.CeilToInt(solverTex.width / gpuThreads.x), Mathf.CeilToInt(solverTex.height / gpuThreads.y), Mathf.CeilToInt(depth / gpuThreads.z)); 67 | } 68 | else 69 | { 70 | //Advection using velocity solver 71 | computeShader.SetTexture(kernelMap[ComputeKernels.AdvectDensity], densityId, densityTex); 72 | computeShader.SetTexture(kernelMap[ComputeKernels.AdvectDensity], prevId, prevTex); 73 | computeShader.SetTexture(kernelMap[ComputeKernels.AdvectDensity], velocityId, velocityTex); 74 | computeShader.Dispatch(kernelMap[ComputeKernels.AdvectDensity], Mathf.CeilToInt(solverTex.width / gpuThreads.x), Mathf.CeilToInt(solverTex.height / gpuThreads.y), Mathf.CeilToInt(depth / gpuThreads.z)); 75 | } 76 | } 77 | 78 | protected override void VelocityStep() 79 | { 80 | //Add velocity source to velocity field 81 | if (SorceTex != null) 82 | { 83 | computeShader.SetTexture(kernelMap[ComputeKernels.AddSourceVelocity], sourceId, SorceTex); 84 | computeShader.SetTexture(kernelMap[ComputeKernels.AddSourceVelocity], velocityId, velocityTex); 85 | computeShader.SetTexture(kernelMap[ComputeKernels.AddSourceVelocity], prevId, prevTex); 86 | computeShader.Dispatch(kernelMap[ComputeKernels.AddSourceVelocity], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), Mathf.CeilToInt(depth / gpuThreads.z)); 87 | } 88 | 89 | //Diffuse velocity 90 | computeShader.SetTexture(kernelMap[ComputeKernels.DiffuseVelocity], velocityId, velocityTex); 91 | computeShader.SetTexture(kernelMap[ComputeKernels.DiffuseVelocity], prevId, prevTex); 92 | computeShader.Dispatch(kernelMap[ComputeKernels.DiffuseVelocity], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), Mathf.CeilToInt(depth / gpuThreads.z)); 93 | 94 | //Project 95 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep1], velocityId, velocityTex); 96 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep1], prevId, prevTex); 97 | computeShader.Dispatch(kernelMap[ComputeKernels.ProjectStep1], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), Mathf.CeilToInt(depth / gpuThreads.z)); 98 | 99 | //Project 100 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep2], prevId, prevTex); 101 | computeShader.Dispatch(kernelMap[ComputeKernels.ProjectStep2], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), Mathf.CeilToInt(depth / gpuThreads.z)); 102 | 103 | //Project 104 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep3], velocityId, velocityTex); 105 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep3], prevId, prevTex); 106 | computeShader.Dispatch(kernelMap[ComputeKernels.ProjectStep3], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), Mathf.CeilToInt(depth / gpuThreads.z)); 107 | 108 | //Swap velocity 109 | computeShader.SetTexture(kernelMap[ComputeKernels.SwapVelocity], velocityId, velocityTex); 110 | computeShader.SetTexture(kernelMap[ComputeKernels.SwapVelocity], prevId, prevTex); 111 | computeShader.Dispatch(kernelMap[ComputeKernels.SwapVelocity], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), Mathf.CeilToInt(depth / gpuThreads.z)); 112 | 113 | //Advection 114 | computeShader.SetTexture(kernelMap[ComputeKernels.AdvectVelocity], velocityId, velocityTex); 115 | computeShader.SetTexture(kernelMap[ComputeKernels.AdvectVelocity], prevId, prevTex); 116 | computeShader.Dispatch(kernelMap[ComputeKernels.AdvectVelocity], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), Mathf.CeilToInt(depth / gpuThreads.z)); 117 | 118 | //Project 119 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep1], velocityId, velocityTex); 120 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep1], prevId, prevTex); 121 | computeShader.Dispatch(kernelMap[ComputeKernels.ProjectStep1], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), Mathf.CeilToInt(depth / gpuThreads.z)); 122 | 123 | //Project 124 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep2], prevId, prevTex); 125 | computeShader.Dispatch(kernelMap[ComputeKernels.ProjectStep2], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), Mathf.CeilToInt(depth / gpuThreads.z)); 126 | 127 | //Project 128 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep3], velocityId, velocityTex); 129 | computeShader.SetTexture(kernelMap[ComputeKernels.ProjectStep3], prevId, prevTex); 130 | computeShader.Dispatch(kernelMap[ComputeKernels.ProjectStep3], Mathf.CeilToInt(velocityTex.width / gpuThreads.x), Mathf.CeilToInt(velocityTex.height / gpuThreads.y), Mathf.CeilToInt(depth / gpuThreads.z)); 131 | } 132 | 133 | #endregion 134 | } 135 | } -------------------------------------------------------------------------------- /Assets/StableFluid/Scripts/Solver3D.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 200e648b64770c741bfd0a7aad51d5df 3 | timeCreated: 1499351914 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/StableFluid/Scripts/SolverBase.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using UnityEngine; 4 | using UnityEngine.Assertions; 5 | using UnityEngine.Rendering; 6 | 7 | namespace StableFluid 8 | { 9 | public struct GPUThreads 10 | { 11 | public int x; 12 | public int y; 13 | public int z; 14 | 15 | public GPUThreads(uint x, uint y, uint z) 16 | { 17 | this.x = (int)x; 18 | this.y = (int)y; 19 | this.z = (int)z; 20 | } 21 | } 22 | 23 | public static class DirectCompute5_0 24 | { 25 | //Use DirectCompute 5.0 on DirectX11 hardware. 26 | public const int MAX_THREAD = 1024; 27 | public const int MAX_X = 1024; 28 | public const int MAX_Y = 1024; 29 | public const int MAX_Z = 64; 30 | public const int MAX_DISPATCH = 65535; 31 | public const int MAX_PROCESS = MAX_DISPATCH * MAX_THREAD; 32 | } 33 | 34 | public abstract class SolverBase : MonoBehaviour 35 | { 36 | #region Variables 37 | 38 | protected enum ComputeKernels 39 | { 40 | AddSourceDensity, 41 | DiffuseDensity, 42 | AdvectDensity, 43 | AdvectDensityFromExt, 44 | SwapDensity, 45 | 46 | AddSourceVelocity, 47 | DiffuseVelocity, 48 | AdvectVelocity, 49 | SwapVelocity, 50 | ProjectStep1, 51 | ProjectStep2, 52 | ProjectStep3, 53 | 54 | Draw 55 | } 56 | 57 | protected Dictionary kernelMap = new Dictionary(); 58 | protected GPUThreads gpuThreads; 59 | protected RenderTexture solverTex; 60 | protected RenderTexture densityTex; 61 | protected RenderTexture velocityTex; 62 | protected RenderTexture prevTex; 63 | protected string solverProp = "solver"; 64 | protected string densityProp = "density"; 65 | protected string velocityProp = "velocity"; 66 | protected string prevProp = "prev"; 67 | protected string sourceProp = "source"; 68 | protected string diffProp = "diff"; 69 | protected string viscProp = "visc"; 70 | protected string dtProp = "dt"; 71 | protected string velocityCoefProp = "velocityCoef"; 72 | protected string densityCoefProp = "densityCoef"; 73 | protected int solverId, densityId, velocityId, prevId, sourceId, diffId, viscId, dtId, velocityCoefId, densityCoefId, solverTexId; 74 | protected int width, height; 75 | 76 | 77 | [SerializeField] 78 | protected ComputeShader computeShader; 79 | 80 | [SerializeField] 81 | protected string solverTexProp = "SolverTex"; 82 | 83 | [SerializeField] 84 | protected float diff; 85 | 86 | [SerializeField] 87 | protected float visc; 88 | 89 | [SerializeField] 90 | protected float velocityCoef; 91 | 92 | [SerializeField] 93 | protected float densityCoef; 94 | 95 | [SerializeField] 96 | protected bool isDensityOnly = false; 97 | 98 | [SerializeField] 99 | protected int lod = 0; 100 | 101 | [SerializeField] 102 | protected bool debug = false; 103 | 104 | [SerializeField] 105 | protected Material debugMat; 106 | 107 | [SerializeField] RenderTexture sourceTex; 108 | public RenderTexture SorceTex { set { sourceTex = value; } get { return sourceTex; } } 109 | 110 | #endregion 111 | 112 | #region unity builtin 113 | 114 | protected virtual void Start() 115 | { 116 | Initialize(); 117 | } 118 | 119 | protected virtual void Update() 120 | { 121 | if (width != Screen.width || height != Screen.height) InitializeComputeShader(); 122 | computeShader.SetFloat(diffId, diff); 123 | computeShader.SetFloat(viscId, visc); 124 | computeShader.SetFloat(diffId, diff); 125 | computeShader.SetFloat(viscId, visc); 126 | computeShader.SetFloat(dtId, Time.deltaTime); 127 | computeShader.SetFloat(velocityCoefId, velocityCoef); 128 | computeShader.SetFloat(densityCoefId, densityCoef); 129 | 130 | if (!isDensityOnly) VelocityStep(); 131 | DensityStep(); 132 | 133 | computeShader.SetTexture(kernelMap[ComputeKernels.Draw], densityId, densityTex); 134 | computeShader.SetTexture(kernelMap[ComputeKernels.Draw], velocityId, velocityTex); 135 | computeShader.SetTextureFromGlobal(kernelMap[ComputeKernels.Draw], solverId, solverTexId); 136 | computeShader.Dispatch(kernelMap[ComputeKernels.Draw], Mathf.CeilToInt(solverTex.width / gpuThreads.x), Mathf.CeilToInt(solverTex.height / gpuThreads.y), 1); 137 | 138 | Shader.SetGlobalTexture(solverTexId, solverTex); 139 | } 140 | 141 | void OnDestroy() 142 | { 143 | CleanUp(); 144 | } 145 | 146 | #endregion 147 | 148 | #region Initialize 149 | 150 | protected virtual void Initialize() 151 | { 152 | uint threadX, threadY, threadZ; 153 | 154 | InitialCheck(); 155 | 156 | kernelMap = System.Enum.GetValues(typeof(ComputeKernels)) 157 | .Cast() 158 | .ToDictionary(t => t, t => computeShader.FindKernel(t.ToString())); 159 | 160 | computeShader.GetKernelThreadGroupSizes(kernelMap[ComputeKernels.Draw], out threadX, out threadY, out threadZ); 161 | 162 | gpuThreads = new GPUThreads(threadX, threadY, threadZ); 163 | solverTexId = Shader.PropertyToID(solverTexProp); 164 | 165 | solverId = Shader.PropertyToID(solverProp); 166 | densityId = Shader.PropertyToID(densityProp); 167 | velocityId = Shader.PropertyToID(velocityProp); 168 | prevId = Shader.PropertyToID(prevProp); 169 | sourceId = Shader.PropertyToID(sourceProp); 170 | diffId = Shader.PropertyToID(diffProp); 171 | viscId = Shader.PropertyToID(viscProp); 172 | dtId = Shader.PropertyToID(dtProp); 173 | velocityCoefId = Shader.PropertyToID(velocityCoefProp); 174 | densityCoefId = Shader.PropertyToID(densityCoefProp); 175 | 176 | InitializeComputeShader(); 177 | 178 | if (debug) 179 | { 180 | if (debugMat == null) return; 181 | debugMat.mainTexture = solverTex; 182 | } 183 | } 184 | 185 | protected virtual void InitialCheck() 186 | { 187 | Assert.IsTrue(SystemInfo.graphicsShaderLevel >= 50, "Under the DirectCompute5.0 (DX11 GPU) doesn't work : StableFluid"); 188 | Assert.IsTrue(gpuThreads.x * gpuThreads.y * gpuThreads.z <= DirectCompute5_0.MAX_PROCESS, "Resolution is too heigh : Stablefluid"); 189 | Assert.IsTrue(gpuThreads.x <= DirectCompute5_0.MAX_X, "THREAD_X is too large : StableFluid"); 190 | Assert.IsTrue(gpuThreads.y <= DirectCompute5_0.MAX_Y, "THREAD_Y is too large : StableFluid"); 191 | Assert.IsTrue(gpuThreads.z <= DirectCompute5_0.MAX_Z, "THREAD_Z is too large : StableFluid"); 192 | } 193 | 194 | protected abstract void InitializeComputeShader(); 195 | 196 | #endregion 197 | 198 | 199 | #region StableFluid gpu kernel steps 200 | 201 | protected abstract void DensityStep(); 202 | 203 | protected abstract void VelocityStep(); 204 | 205 | #endregion 206 | 207 | #region render texture 208 | 209 | public RenderTexture CreateRenderTexture(int width, int height, int depth, RenderTextureFormat format, RenderTexture rt = null) 210 | { 211 | if (rt != null) 212 | { 213 | if (rt.width == width && rt.height == height) return rt; 214 | } 215 | 216 | ReleaseRenderTexture(rt); 217 | rt = new RenderTexture(width, height, depth, format); 218 | rt.enableRandomWrite = true; 219 | rt.wrapMode = TextureWrapMode.Clamp; 220 | rt.filterMode = FilterMode.Point; 221 | rt.Create(); 222 | ClearRenderTexture(rt, Color.clear); 223 | return rt; 224 | } 225 | 226 | public RenderTexture CreateVolumetricRenderTexture(int width, int height, int volumeDepth, int depth, RenderTextureFormat format, RenderTexture rt = null) 227 | { 228 | if (rt != null) 229 | { 230 | if (rt.width == width && rt.height == height) return rt; 231 | } 232 | 233 | ReleaseRenderTexture(rt); 234 | rt = new RenderTexture(width, height, depth, format); 235 | rt.dimension = TextureDimension.Tex3D; 236 | rt.volumeDepth = volumeDepth; 237 | rt.enableRandomWrite = true; 238 | rt.wrapMode = TextureWrapMode.Clamp; 239 | rt.filterMode = FilterMode.Point; 240 | rt.Create(); 241 | ClearRenderTexture(rt, Color.clear); 242 | return rt; 243 | } 244 | 245 | public void ReleaseRenderTexture(RenderTexture rt) 246 | { 247 | if (rt == null) return; 248 | 249 | rt.Release(); 250 | Destroy(rt); 251 | } 252 | 253 | public void ClearRenderTexture(RenderTexture target, Color bg) 254 | { 255 | var active = RenderTexture.active; 256 | RenderTexture.active = target; 257 | GL.Clear(true, true, bg); 258 | RenderTexture.active = active; 259 | } 260 | 261 | #endregion 262 | 263 | #region release 264 | 265 | void CleanUp() 266 | { 267 | ReleaseRenderTexture(solverTex); 268 | ReleaseRenderTexture(densityTex); 269 | ReleaseRenderTexture(velocityTex); 270 | ReleaseRenderTexture(prevTex); 271 | 272 | #if UNITY_EDITOR 273 | Debug.Log("Buffer released"); 274 | #endif 275 | } 276 | 277 | #endregion 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /Assets/StableFluid/Scripts/SolverBase.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9167428fcc81cff439fb3cdfe3d547e2 3 | timeCreated: 1499351954 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/StableFluid/Shaders.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5887f4fb90cf43f499ff6d7c14390cd7 3 | folderAsset: yes 4 | timeCreated: 1492760900 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/StableFluid/Shaders/AddSource.shader: -------------------------------------------------------------------------------- 1 | Shader "StableFluid/AddSource" { 2 | Properties { 3 | _Source ("Adding source", Vector) = (0, 1, 0.5, 0.5) //xy = velocity, zw = center pos 4 | _Radius ("Radius", Float) = 10 5 | } 6 | SubShader { 7 | Cull Off ZWrite Off ZTest Always 8 | 9 | Pass { 10 | CGPROGRAM 11 | #pragma vertex vert 12 | #pragma fragment frag 13 | 14 | #include "UnityCG.cginc" 15 | 16 | struct appdata { 17 | float4 vertex : POSITION; 18 | float2 uv : TEXCOORD0; 19 | }; 20 | 21 | struct v2f { 22 | float2 uv : TEXCOORD0; 23 | float4 vertex : SV_POSITION; 24 | }; 25 | 26 | float4 _Source; 27 | float _Radius; 28 | 29 | v2f vert (appdata v) { 30 | v2f o; 31 | o.vertex = UnityObjectToClipPos(v.vertex); 32 | o.uv = v.uv; 33 | return o; 34 | } 35 | 36 | float4 frag (v2f i) : SV_Target { 37 | float2 dpdt = (i.uv - _Source.zw) / _Radius; 38 | return float4(_Source.xy * saturate(1.0 - dot(dpdt, dpdt)), saturate(1.0 - dot(dpdt, dpdt)), 0); 39 | } 40 | ENDCG 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Assets/StableFluid/Shaders/AddSource.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2bf7b9de857590545861a2316f3ef4ff 3 | timeCreated: 1493267028 4 | licenseType: Pro 5 | ShaderImporter: 6 | defaultTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/StableFluid/Shaders/Sample.shader: -------------------------------------------------------------------------------- 1 | Shader "StableFluid/Sample" 2 | { 3 | Properties 4 | { 5 | _MainTex ("Texture", 2D) = "white" {} 6 | } 7 | SubShader 8 | { 9 | // No culling or depth 10 | Cull Off ZWrite Off ZTest Always 11 | 12 | Pass 13 | { 14 | CGPROGRAM 15 | #pragma vertex vert 16 | #pragma fragment frag 17 | 18 | #include "UnityCG.cginc" 19 | 20 | struct appdata 21 | { 22 | float4 vertex : POSITION; 23 | float2 uv : TEXCOORD0; 24 | }; 25 | 26 | struct v2f 27 | { 28 | float2 uv : TEXCOORD0; 29 | float4 vertex : SV_POSITION; 30 | }; 31 | 32 | v2f vert (appdata v) 33 | { 34 | v2f o; 35 | o.vertex = UnityObjectToClipPos(v.vertex); 36 | o.uv = v.uv; 37 | return o; 38 | } 39 | 40 | sampler2D _MainTex; 41 | sampler2D SolverTex; 42 | 43 | fixed4 frag (v2f i) : SV_Target 44 | { 45 | fixed3 solver = tex2D(SolverTex, i.uv); 46 | fixed4 col = tex2D(_MainTex, i.uv); 47 | col *= 1 - solver.z * 5; 48 | col.a = 1; 49 | return col; 50 | } 51 | ENDCG 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Assets/StableFluid/Shaders/Sample.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 282dcb7cfb3e90142a89ad33496fa1e9 3 | timeCreated: 1499326984 4 | licenseType: Pro 5 | ShaderImporter: 6 | defaultTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/ProjectSettings/AudioManager.asset -------------------------------------------------------------------------------- /ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/ProjectSettings/ClusterInputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/ProjectSettings/DynamicsManager.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/ProjectSettings/EditorBuildSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/ProjectSettings/EditorSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/ProjectSettings/GraphicsSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/ProjectSettings/InputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/ProjectSettings/NavMeshAreas.asset -------------------------------------------------------------------------------- /ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/ProjectSettings/NetworkManager.asset -------------------------------------------------------------------------------- /ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/ProjectSettings/Physics2DSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/ProjectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/ProjectSettings/ProjectSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 5.6.2f1 2 | -------------------------------------------------------------------------------- /ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/ProjectSettings/QualitySettings.asset -------------------------------------------------------------------------------- /ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/ProjectSettings/TagManager.asset -------------------------------------------------------------------------------- /ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/ProjectSettings/TimeManager.asset -------------------------------------------------------------------------------- /ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakope/StableFluid/670df06f5a7a8fb31389d76146c7f676748d65cb/ProjectSettings/UnityConnectSettings.asset -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stable Fluid 2 | 3 | Simulation of Stable Fluids by Unity. 4 | 5 | ### [Sample](https://youtu.be/maLvWXpnmSw) 6 | 7 | 8 | ## System requirements 9 | DirectX11 for Compute Shader. 10 | 11 | 12 | 13 | ##### Reference 14 | Jos Stam. SIGGRAPH 1999. Stable Fluids 15 | --------------------------------------------------------------------------------