├── .github └── FUNDING.yml ├── .gitignore ├── Assets ├── FluidSim.asmdef ├── FluidSim.asmdef.meta ├── LiquidShader.meta ├── LiquidShader │ ├── Advect.cs │ ├── Advect.cs.meta │ ├── AdvectCellByCell.cs │ ├── AdvectCellByCell.cs.meta │ ├── AdvectPartials.cs │ ├── AdvectPartials.cs.meta │ ├── ColorAdder.cs │ ├── ColorAdder.cs.meta │ ├── CopyBuffer.cs │ ├── CopyBuffer.cs.meta │ ├── DesignLoader.cs │ ├── DesignLoader.cs.meta │ ├── DivergenceCalculator.cs │ ├── DivergenceCalculator.cs.meta │ ├── Draw.cs │ ├── Draw.cs.meta │ ├── Fill.cs │ ├── Fill.cs.meta │ ├── LiquidShaderRenderer.cs │ ├── LiquidShaderRenderer.cs.meta │ ├── LiquidShaderScene.unity │ ├── LiquidShaderScene.unity.meta │ ├── LiquidShaderTests.meta │ ├── LiquidShaderTests │ │ ├── LiquidShaderTests.asmdef │ │ ├── LiquidShaderTests.asmdef.meta │ │ ├── TestAdvectVelocity.cs │ │ ├── TestAdvectVelocity.cs.meta │ │ ├── TestBuf2.cs │ │ ├── TestBuf2.cs.meta │ │ ├── TestCopy.cs │ │ ├── TestCopy.cs.meta │ │ ├── TestProject.cs │ │ ├── TestProject.cs.meta │ │ ├── TestUtils.cs │ │ └── TestUtils.cs.meta │ ├── MousePointer.prefab │ ├── MousePointer.prefab.meta │ ├── NoDivergenceIcon1.png │ ├── NoDivergenceIcon1.png.meta │ ├── NoiseAdder.cs │ ├── NoiseAdder.cs.meta │ ├── Pooling.cs │ ├── Pooling.cs.meta │ ├── ProjectCellByCell.cs │ ├── ProjectCellByCell.cs.meta │ ├── ProjectDraw.cs │ ├── ProjectDraw.cs.meta │ ├── ProjectGaussSeidelClean.cs │ ├── ProjectGaussSeidelClean.cs.meta │ ├── ProjectGaussSeidelGeneral.cs │ ├── ProjectGaussSeidelGeneral.cs.meta │ ├── ProjectJacobi.cs │ ├── ProjectJacobi.cs.meta │ ├── ProjectJacobiInPlace.cs │ ├── ProjectJacobiInPlace.cs.meta │ ├── ProjectSelected.cs │ ├── ProjectSelected.cs.meta │ ├── ProjectSingleCell.cs │ ├── ProjectSingleCell.cs.meta │ ├── RenderArrows.cs │ ├── RenderArrows.cs.meta │ ├── RenderDivergenceSpiral.cs │ ├── RenderDivergenceSpiral.cs.meta │ ├── RenderSelected.cs │ ├── RenderSelected.cs.meta │ ├── Rendering.cs │ ├── Rendering.cs.meta │ ├── Resources.meta │ ├── Resources │ │ ├── LiquidShader.meta │ │ └── LiquidShader │ │ │ ├── AddColor.compute │ │ │ ├── AddColor.compute.meta │ │ │ ├── AddNoise.compute │ │ │ ├── AddNoise.compute.meta │ │ │ ├── Advect.compute │ │ │ ├── Advect.compute.meta │ │ │ ├── AdvectCellByCell.compute │ │ │ ├── AdvectCellByCell.compute.meta │ │ │ ├── AdvectFloat4.compute │ │ │ ├── AdvectFloat4.compute.meta │ │ │ ├── AdvectPartials.compute │ │ │ ├── AdvectPartials.compute.meta │ │ │ ├── AdvectTests.compute │ │ │ ├── AdvectTests.compute.meta │ │ │ ├── CellSelection.compute │ │ │ ├── CellSelection.compute.meta │ │ │ ├── Copy.compute │ │ │ ├── Copy.compute.meta │ │ │ ├── Divergence.compute │ │ │ ├── Divergence.compute.meta │ │ │ ├── Draw.compute │ │ │ ├── Draw.compute.meta │ │ │ ├── Fill.compute │ │ │ ├── Fill.compute.meta │ │ │ ├── Pooling.compute │ │ │ ├── Pooling.compute.meta │ │ │ ├── ProjectGaussSeidelClean.compute │ │ │ ├── ProjectGaussSeidelClean.compute.meta │ │ │ ├── ProjectGaussSeidelGeneral.compute │ │ │ ├── ProjectGaussSeidelGeneral.compute.meta │ │ │ ├── ProjectJacobi.compute │ │ │ ├── ProjectJacobi.compute.meta │ │ │ ├── ProjectJacobiInplace.compute │ │ │ ├── ProjectJacobiInplace.compute.meta │ │ │ ├── ProjectSelected.compute │ │ │ ├── ProjectSelected.compute.meta │ │ │ ├── ProjectSingleCell.compute │ │ │ ├── ProjectSingleCell.compute.meta │ │ │ ├── RenderDivergenceSpiral.compute │ │ │ ├── RenderDivergenceSpiral.compute.meta │ │ │ ├── RenderingArrows.compute │ │ │ ├── RenderingArrows.compute.meta │ │ │ ├── RenderingCenters.compute │ │ │ ├── RenderingCenters.compute.meta │ │ │ ├── RenderingGrid.compute │ │ │ ├── RenderingGrid.compute.meta │ │ │ ├── RenderingSelectedCells.compute │ │ │ ├── RenderingSelectedCells.compute.meta │ │ │ ├── RenderingVelocityCenters.compute │ │ │ ├── RenderingVelocityCenters.compute.meta │ │ │ ├── ShaderUtils.cginc │ │ │ ├── ShaderUtils.cginc.meta │ │ │ ├── TwoIntoOne.compute │ │ │ ├── TwoIntoOne.compute.meta │ │ │ ├── interpolate.cginc │ │ │ ├── interpolate.cginc.meta │ │ │ ├── positions.cginc │ │ │ └── positions.cginc.meta │ ├── SpeedTestingScene.unity │ ├── SpeedTestingScene.unity.meta │ ├── SpeedTests.meta │ ├── SpeedTests │ │ ├── SpeedTestController.cs │ │ ├── SpeedTestController.cs.meta │ │ ├── SpeedTestMax.cs │ │ └── SpeedTestMax.cs.meta │ ├── TwoIntoOne.cs │ ├── TwoIntoOne.cs.meta │ ├── Types.meta │ ├── Types │ │ ├── SimulationState.cs │ │ └── SimulationState.cs.meta │ ├── UIController.cs │ ├── UIController.cs.meta │ ├── Utils.meta │ ├── Utils │ │ ├── ArrayUtils.cs │ │ ├── ArrayUtils.cs.meta │ │ ├── CellByCell.cs │ │ └── CellByCell.cs.meta │ ├── Water_texture_v2.png │ ├── Water_texture_v2.png.meta │ ├── mouseicon.png │ └── mouseicon.png.meta ├── TextMesh Pro.meta ├── Utils.meta └── Utils │ ├── Buf2.cs │ ├── Buf2.cs.meta │ ├── ButtonGroupExclusiveSelected.cs │ ├── ButtonGroupExclusiveSelected.cs.meta │ ├── ClickFilter.cs │ ├── ClickFilter.cs.meta │ ├── ClickUtils.cs │ ├── ClickUtils.cs.meta │ ├── DisplayConfig.cs │ ├── DisplayConfig.cs.meta │ ├── IBuf2.cs │ ├── IBuf2.cs.meta │ ├── SubBuf2.cs │ └── SubBuf2.cs.meta ├── LICENSE ├── Packages ├── manifest.json └── packages-lock.json ├── ProjectSettings ├── AudioManager.asset ├── ClusterInputManager.asset ├── DynamicsManager.asset ├── EditorBuildSettings.asset ├── EditorSettings.asset ├── GraphicsSettings.asset ├── InputManager.asset ├── MemorySettings.asset ├── NavMeshAreas.asset ├── PackageManagerSettings.asset ├── Packages │ └── com.unity.testtools.codecoverage │ │ └── Settings.json ├── Physics2DSettings.asset ├── PresetManager.asset ├── ProjectSettings.asset ├── ProjectVersion.txt ├── QualitySettings.asset ├── SceneTemplateSettings.json ├── TagManager.asset ├── TimeManager.asset ├── UnityConnectSettings.asset ├── VFXManager.asset ├── VersionControlSettings.asset └── XRSettings.asset ├── README.md └── UserSettings ├── EditorUserSettings.asset ├── Layouts └── default-2022.dwlt └── Search.settings /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | buy_me_a_coffee: rlhugh 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | gitdiff.txt 2 | gitlog.txt 3 | 4 | results/ 5 | 6 | __pycache__/ 7 | __pycache__.meta 8 | 9 | 10 | **/[Ll]ibrary/ 11 | **/Logs/ 12 | **/[Tt]emp/ 13 | **/[Oo]bj/ 14 | **/[Bb]uild/ 15 | **/[Bb]uilds/ 16 | /Assets/AssetStoreTools* 17 | /Assets/Plugins* 18 | /Assets/Demonstrations* 19 | /Assets/ML-Agents/Timers* 20 | /csharp_timers.json 21 | 22 | # Environemnt logfile 23 | *Project.log 24 | 25 | # Visual Studio 2015 cache directory 26 | /.vs/ 27 | 28 | # Autogenerated VS/MD/Consulo solution and project files 29 | /ProjectExportedObj/ 30 | /Project.consulo/ 31 | *.csproj 32 | *.unityproj 33 | *.sln 34 | *.suo 35 | *.tmp 36 | *.user 37 | *.userprefs 38 | *.pidb 39 | *.booproj 40 | *.svd 41 | *.pdb 42 | 43 | # Unity3D generated meta files 44 | *.pidb.meta 45 | 46 | # Unity3D Generated File On Crash Reports 47 | /sysinfo.txt 48 | 49 | # Builds 50 | *.apk 51 | *.unitypackage 52 | *.app 53 | *.exe 54 | *.x86_64 55 | *.x86 56 | 57 | # Plugins 58 | /Assets/VideoRecorder* 59 | 60 | # Mac hidden files 61 | *.DS_Store 62 | */.ipynb_checkpoints 63 | */.idea 64 | *.pyc 65 | *.idea/misc.xml 66 | *.idea/modules.xml 67 | *.idea/ 68 | *.iml 69 | *.cache 70 | */build/ 71 | */dist/ 72 | *.egg-info* 73 | *.eggs* 74 | *.gitignore.swp 75 | 76 | # VSCode hidden files 77 | *.vscode/ 78 | 79 | .DS_Store 80 | 81 | # my added 82 | **/python/logs/ 83 | **/bin/ 84 | **/project-cache/ 85 | 86 | # TMPRO in package 87 | **/Assets/TextMesh Pro/ 88 | 89 | mono_crash*.json 90 | 91 | 92 | Recordings/ 93 | -------------------------------------------------------------------------------- /Assets/FluidSim.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "FluidSim", 3 | "rootNamespace": "", 4 | "references": [ 5 | "GUID:6055be8ebefd69e48b49212b09b47b2f", 6 | "GUID:13a6fdc14ca9df84eb8019bc66fa9e5d" 7 | ], 8 | "includePlatforms": [], 9 | "excludePlatforms": [], 10 | "allowUnsafeCode": false, 11 | "overrideReferences": false, 12 | "precompiledReferences": [], 13 | "autoReferenced": true, 14 | "defineConstraints": [], 15 | "versionDefines": [], 16 | "noEngineReferences": false 17 | } -------------------------------------------------------------------------------- /Assets/FluidSim.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5c4d7bdcd026c4de595270582f2f6ba0 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/LiquidShader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f3bad2cb5f7b34068bf73a1be48b5587 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Advect.cs: -------------------------------------------------------------------------------- 1 | using LiquidShader.Types; 2 | using UnityEngine; 3 | using Utils; 4 | 5 | namespace LiquidShader { 6 | 7 | public class Advect : MonoBehaviour { 8 | ComputeShader _advectShader; 9 | ComputeShader _advectFloat4Shader; 10 | 11 | int _kAdvectFloat4; 12 | int _kAdvectVelocity; 13 | 14 | CopyBuffer _copyBuffer; 15 | 16 | public ComputeShader TestingGetShader() { 17 | return _advectShader; 18 | } 19 | 20 | void OnEnable() { 21 | _copyBuffer = new CopyBuffer(); 22 | _advectShader = (ComputeShader)Resources.Load("LiquidShader/Advect"); 23 | _advectFloat4Shader = (ComputeShader)Resources.Load("LiquidShader/AdvectFloat4"); 24 | } 25 | 26 | public void AdvectVelocity(SimulationState simulationState, float simDeltaTime, float speed) { 27 | var shader = _advectShader; 28 | var kernel = shader.FindKernel("AdvectVelocity"); 29 | shader.SetBuffer(kernel, "_horizVel", simulationState.uBuf.GetComputeBuffer()); 30 | shader.SetBuffer(kernel, "_vertVel", simulationState.vBuf.GetComputeBuffer()); 31 | shader.SetBuffer(kernel, "_newHorizVel", simulationState.u23BufParent.GetComputeBuffer()); 32 | shader.SetBuffer(kernel, "_newVertVel", simulationState.v23BufParent.GetComputeBuffer()); 33 | shader.SetBuffer(kernel, "_isFluid", simulationState.sBuf.GetComputeBuffer()); 34 | shader.SetFloat("_deltaTime", simDeltaTime); 35 | shader.SetFloat("_speedDeltaTime", simDeltaTime * speed); 36 | shader.SetInt("_simResX", simulationState.simResX); 37 | shader.SetInt("_simResY", simulationState.simResY); 38 | shader.Dispatch(kernel, (simulationState.simResX + 8 - 1) / 8, (simulationState.simResY + 8 - 1) / 8, 1); 39 | _copyBuffer.CopyFloats(simulationState.simResX, simulationState.simResY, simulationState.u2Buf, simulationState.uBuf); 40 | _copyBuffer.CopyFloats(simulationState.simResX, simulationState.simResY, simulationState.v2Buf, simulationState.vBuf); 41 | } 42 | 43 | public void AdvectFloat4(SimulationState simulationState, float simDeltaTime, float speed, Buf2 target, Buf2 targetCopy) { 44 | var shader = _advectFloat4Shader; 45 | var kernel = shader.FindKernel("AdvectFloat4"); 46 | shader.SetBuffer(kernel, "_isFluid", simulationState.sBuf.GetComputeBuffer()); 47 | shader.SetBuffer(kernel, "_srcFloat4", target.GetComputeBuffer()); 48 | shader.SetBuffer(kernel, "_destFloat4", targetCopy.GetComputeBuffer()); 49 | shader.SetBuffer(kernel, "_horizVel", simulationState.uBuf.GetComputeBuffer()); 50 | shader.SetBuffer(kernel, "_vertVel", simulationState.vBuf.GetComputeBuffer()); 51 | shader.SetBuffer(kernel, "_debug", simulationState.debugBuf.GetComputeBuffer()); 52 | shader.SetFloat("_deltaTime", simDeltaTime); 53 | shader.SetFloat("_speedDeltaTime", simDeltaTime * speed); 54 | shader.SetInt("_simResX", simulationState.simResX); 55 | shader.SetInt("_simResY", simulationState.simResY); 56 | shader.Dispatch(kernel, (simulationState.simResX + 8 - 1) / 8, (simulationState.simResY + 8 - 1) / 8, 1); 57 | 58 | _copyBuffer.CopyFloat4S(targetCopy, target); 59 | } 60 | } 61 | 62 | } // namespace LiquidShader 63 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Advect.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c133d89eb2d8843ba81224f3543528d9 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/AdvectCellByCell.cs: -------------------------------------------------------------------------------- 1 | using LiquidShader.Types; 2 | using UnityEngine; 3 | using Utils; 4 | 5 | namespace LiquidShader { 6 | 7 | enum AdvectDirection { 8 | FromCenter, 9 | ToCenter, 10 | ToEdges 11 | } 12 | 13 | enum UpdateDirections { 14 | U, 15 | V, 16 | Both 17 | } 18 | 19 | public class AdvectCellByCell : MonoBehaviour { 20 | [SerializeField] AdvectDirection advectDirection = AdvectDirection.FromCenter; 21 | [SerializeField] bool doubleBuffered = false; 22 | [SerializeField] bool removeSourceVelocity = false; 23 | // [SerializeField] UpdateDirections updateDirections = UpdateDirections.U; 24 | 25 | public CellByCell cellByCell; 26 | CopyBuffer _copyBufer; 27 | 28 | ComputeShader _advectShader; 29 | 30 | public ComputeShader TestingGetShader() { 31 | return _advectShader; 32 | } 33 | 34 | void Awake() { 35 | cellByCell = new CellByCell(); 36 | _copyBufer = new CopyBuffer(); 37 | 38 | _advectShader = (ComputeShader)Resources.Load("LiquidShader/AdvectCellByCell"); 39 | } 40 | 41 | public void AdvectVelocity(SimulationState simulationState, float simDeltaTime, float speed) { 42 | string kernelName; 43 | switch(advectDirection) { 44 | case AdvectDirection.FromCenter: 45 | kernelName = doubleBuffered ? 46 | removeSourceVelocity ? 47 | "AdvectVelocityFromCenterDoubleBufferedRemoveSrcVel" 48 | : "AdvectVelocityFromCenterDoubleBuffered" 49 | : "AdvectVelocityFromCenter"; 50 | break; 51 | case AdvectDirection.ToCenter: 52 | case AdvectDirection.ToEdges: 53 | default: 54 | throw new System.Exception($"unhandled advectDirection {advectDirection}"); 55 | } 56 | if(cellByCell.updateX == 0 && cellByCell.updateY == 0) { 57 | // initialize at start of sweep 58 | _copyBufer.CopyFloats(simulationState.simResX, simulationState.simResY, simulationState.uBuf, simulationState.u2Buf); 59 | _copyBufer.CopyFloats(simulationState.simResX, simulationState.simResY, simulationState.vBuf, simulationState.v2Buf); 60 | } 61 | var kernel = _advectShader.FindKernel(kernelName); 62 | _advectShader.SetBuffer(kernel, "_horizVel", simulationState.uBuf.GetComputeBuffer()); 63 | _advectShader.SetBuffer(kernel, "_vertVel", simulationState.vBuf.GetComputeBuffer()); 64 | _advectShader.SetBuffer(kernel, "_newHorizVel", simulationState.u2Buf.GetComputeBuffer()); 65 | _advectShader.SetBuffer(kernel, "_newVertVel", simulationState.v2Buf.GetComputeBuffer()); 66 | _advectShader.SetBuffer(kernel, "_isFluid", simulationState.sBuf.GetComputeBuffer()); 67 | _advectShader.SetBuffer(kernel, "_debug", simulationState.debugBuf.GetComputeBuffer()); 68 | _advectShader.SetFloat("_deltaTime", simDeltaTime); 69 | _advectShader.SetFloat("_speedDeltaTime", simDeltaTime * speed); 70 | _advectShader.SetInt("_updateX", cellByCell.updateX); 71 | _advectShader.SetInt("_updateY", cellByCell.updateY); 72 | _advectShader.SetInt("_simResX", simulationState.simResX); 73 | _advectShader.SetInt("_simResY", simulationState.simResY); 74 | _advectShader.Dispatch(kernel, 1, 1, 1); 75 | 76 | cellByCell.Inc(simulationState); 77 | 78 | if(cellByCell.updateX == 0 && cellByCell.updateY == 0) { 79 | // copy back at end of sweep 80 | _copyBufer.CopyFloats(simulationState.simResX, simulationState.simResY, simulationState.u2Buf, simulationState.uBuf); 81 | _copyBufer.CopyFloats(simulationState.simResX, simulationState.simResY, simulationState.v2Buf, simulationState.vBuf); 82 | } 83 | } 84 | } 85 | 86 | } // namespace LiquidShader 87 | -------------------------------------------------------------------------------- /Assets/LiquidShader/AdvectCellByCell.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 44e243259fdcb475199c14ca60fb8dae 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/AdvectPartials.cs: -------------------------------------------------------------------------------- 1 | using LiquidShader.Types; 2 | using UnityEngine; 3 | 4 | namespace LiquidShader { 5 | 6 | public class AdvectPartials : MonoBehaviour { 7 | /* 8 | Use the discrete formulation of (\v \cdot \nabla)\v to handle projection. 9 | */ 10 | ComputeShader _advectShader; 11 | 12 | // int kAdvectFloat4; 13 | int _kAdvectVelocity; 14 | 15 | CopyBuffer _copyBuffer; 16 | 17 | public ComputeShader TestingGetShader() { 18 | return _advectShader; 19 | } 20 | 21 | void Awake() { 22 | _copyBuffer = new CopyBuffer(); 23 | _advectShader = (ComputeShader)Resources.Load("LiquidShader/AdvectPartials"); 24 | 25 | // kAdvectFloat4 = AdvectShader.FindKernel("AdvectFloat4"); 26 | _kAdvectVelocity = _advectShader.FindKernel("AdvectVelocity"); 27 | } 28 | 29 | public void AdvectVelocity(SimulationState simulationState, float simDeltaTime, float speed) { 30 | // Debug.Log("AdvectVelocity"); 31 | var kernel = _kAdvectVelocity; 32 | _advectShader.SetBuffer(kernel, "_horizVel", simulationState.uBuf.GetComputeBuffer()); 33 | _advectShader.SetBuffer(kernel, "_vertVel", simulationState.vBuf.GetComputeBuffer()); 34 | _advectShader.SetBuffer(kernel, "_newHorizVel", simulationState.u23BufParent.GetComputeBuffer()); 35 | _advectShader.SetBuffer(kernel, "_newVertVel", simulationState.v23BufParent.GetComputeBuffer()); 36 | _advectShader.SetBuffer(kernel, "_isFluid", simulationState.sBuf.GetComputeBuffer()); 37 | _advectShader.SetBuffer(kernel, "_debug", simulationState.debugBuf.GetComputeBuffer()); 38 | _advectShader.SetFloat("_deltaTime", simDeltaTime); 39 | _advectShader.SetFloat("_speedDeltaTime", simDeltaTime * speed); 40 | _advectShader.SetInt("_simResX", simulationState.simResX); 41 | _advectShader.SetInt("_simResY", simulationState.simResY); 42 | _advectShader.Dispatch(kernel, (simulationState.simResX + 8 - 1) / 8, (simulationState.simResY + 8 - 1) / 8, 1); 43 | _copyBuffer.CopyFloats(simulationState.simResX, simulationState.simResY, simulationState.u2Buf, simulationState.uBuf); 44 | _copyBuffer.CopyFloats(simulationState.simResX, simulationState.simResY, simulationState.v2Buf, simulationState.vBuf); 45 | } 46 | 47 | // public void AdvectFloat4(SimulationState simulationState, float simDeltaTime, float speed, Buf2 target, Buf2 targetCopy) { 48 | // int kernel = kAdvectFloat4; 49 | // AdvectShader.SetBuffer(kernel, "_isFluid", simulationState.sBuf.GetComputeBuffer()); 50 | // AdvectShader.SetBuffer(kernel, "_srcFloat4", target.GetComputeBuffer()); 51 | // AdvectShader.SetBuffer(kernel, "_destFloat4", targetCopy.GetComputeBuffer()); 52 | // AdvectShader.SetBuffer(kernel, "_horizVel", simulationState.uBuf.GetComputeBuffer()); 53 | // AdvectShader.SetBuffer(kernel, "_vertVel", simulationState.vBuf.GetComputeBuffer()); 54 | // AdvectShader.SetFloat("_deltaTime", simDeltaTime); 55 | // AdvectShader.SetFloat("_speedDeltaTime", simDeltaTime * speed); 56 | // AdvectShader.SetInt("_simResX", simulationState.SimResX); 57 | // AdvectShader.SetInt("_simResY", simulationState.SimResY); 58 | // AdvectShader.Dispatch(kernel, (simulationState.SimResX + 8 - 1) / 8, (simulationState.SimResY + 8 - 1) / 8, 1); 59 | 60 | // copyBuffer.CopyFloat4s(targetCopy, target); 61 | // } 62 | } 63 | 64 | } // namespace LiquidShader 65 | -------------------------------------------------------------------------------- /Assets/LiquidShader/AdvectPartials.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c328abd5f38c147cdbe19148387f6801 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/ColorAdder.cs: -------------------------------------------------------------------------------- 1 | using LiquidShader.Types; 2 | using UnityEngine; 3 | using Utils; 4 | 5 | namespace LiquidShader { 6 | 7 | public class ColorAdder: MonoBehaviour { 8 | [SerializeField] bool hardSetColor = false; 9 | [Range(0.1f, 10.0f)] [SerializeField] float colorAddSpeed = 0.1f; 10 | // [Range(0.0f, 1.0f)][SerializeField] float colorAddNoise = 0.0f; 11 | 12 | ComputeShader _shader; 13 | 14 | void Awake() { 15 | this._shader = (ComputeShader)Resources.Load("LiquidShader/AddColor"); 16 | } 17 | 18 | public void AddColor(SimulationState simulationState, float simDeltaTime, float speed) { 19 | var kernel = _shader.FindKernel("AddColor"); 20 | _shader.SetBuffer(kernel, "_horizVel", simulationState.uBuf.GetComputeBuffer()); 21 | _shader.SetBuffer(kernel, "_vertVel", simulationState.vBuf.GetComputeBuffer()); 22 | _shader.SetBuffer(kernel, "_isFluid", simulationState.sBuf.GetComputeBuffer()); 23 | _shader.SetFloat("_speedDeltaTime", simDeltaTime * speed); 24 | _shader.SetInt("_simResX", simulationState.simResX); 25 | _shader.SetInt("_simResY", simulationState.simResY); 26 | _shader.SetFloat("_colorAddSpeed", colorAddSpeed); 27 | _shader.SetBool("_colorSet", hardSetColor); 28 | _shader.SetBuffer(kernel, "_m", simulationState.mBuf.GetComputeBuffer()); 29 | _shader.SetBuffer(kernel, "_colorSources", simulationState.colorSourcesBuf.GetComputeBuffer()); 30 | _shader.Dispatch(kernel,(simulationState.simResX + 8 - 1) / 8, (simulationState.simResY + 8 -1) / 8, 1); 31 | } 32 | } 33 | 34 | } // namespace LiquidShader 35 | -------------------------------------------------------------------------------- /Assets/LiquidShader/ColorAdder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eb7f79aeac58f4a949bf64c17102269d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/CopyBuffer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using Utils; 4 | 5 | namespace LiquidShader { 6 | 7 | public class CopyBuffer { 8 | ComputeShader _copyShader; 9 | 10 | public CopyBuffer() { 11 | this._copyShader = (ComputeShader)Resources.Load("LiquidShader/Copy"); 12 | } 13 | 14 | public void CopyFloat4S(Buf2 src, Buf2 dest) { 15 | if(src.ResX != dest.ResX) { 16 | throw new Exception($"width of src and dest mismach {src.ResX} vs {dest.ResX}"); 17 | } 18 | if(src.ResY != dest.ResY) { 19 | throw new Exception($"height of src and dest mismach {src.ResY} vs {dest.ResY}"); 20 | } 21 | var kernel = _copyShader.FindKernel("CopyFloat4s"); 22 | _copyShader.SetBuffer(kernel, "_srcFloat4s", src.GetComputeBuffer()); 23 | _copyShader.SetBuffer(kernel, "_destFloat4s", dest.GetComputeBuffer()); 24 | _copyShader.SetInt("_simResX", src.ResX); 25 | _copyShader.SetInt("_simResY", src.ResY); 26 | _copyShader.Dispatch(kernel, (src.ResX + 8 - 1) / 8, (src.ResY + 8 - 1 ) / 8, 1); 27 | } 28 | 29 | public void CopyFloats(int simResX, int simResY, IBuf2 src, IBuf2 dest) { 30 | var kernel = _copyShader.FindKernel("CopyFloats"); 31 | _copyShader.SetBuffer(kernel, "_srcFloats", src.GetComputeBuffer()); 32 | _copyShader.SetBuffer(kernel, "_destFloats", dest.GetComputeBuffer()); 33 | _copyShader.SetInt("_srcOffset", src.Offset); 34 | _copyShader.SetInt("_destOffset", dest.Offset); 35 | _copyShader.SetInt("_simResX", simResX); 36 | _copyShader.SetInt("_simResY", simResY); 37 | _copyShader.Dispatch(kernel, (simResX + 8 - 1) / 8, (simResY + 8 - 1 ) / 8, 1); 38 | } 39 | } 40 | 41 | } // namespace LiquidShader 42 | -------------------------------------------------------------------------------- /Assets/LiquidShader/CopyBuffer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e85535351ceb544449373b98566f0932 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/DesignLoader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using UnityEngine; 4 | using UnityEngine.SceneManagement; 5 | using Utils; 6 | 7 | namespace LiquidShader { 8 | 9 | public class DesignLoader : MonoBehaviour { 10 | [SerializeField] Texture2D fixedVelocitiesTex; 11 | [SerializeField] Texture2D colorSourcesTex; 12 | 13 | Texture2D ResizeTexture(int destResY, Texture2D texture) { 14 | var destResX = (destResY * 16) / 9; 15 | if (destResX == 853) destResX = 854; 16 | var newTexture = new Texture2D(destResX, destResY); 17 | var newPixels = newTexture.GetPixels(0); 18 | for (var j = 0; j < destResY; j++) { 19 | for (var i = 0; i < destResX; i++) { 20 | var destIdx = j * destResX + i; 21 | var srcU = (float)i / destResX; 22 | var srcV = (float)j / destResY; 23 | var value = texture.GetPixelBilinear(srcU, srcV); 24 | newPixels[destIdx] = value; 25 | } 26 | } 27 | newTexture.SetPixels(newPixels, 0); 28 | newTexture.Apply(); 29 | return newTexture; 30 | } 31 | 32 | public void LoadDesign( 33 | int resY, 34 | out int[,] s, out float[,] u, out float[,] v, out Vector4[,] colorSources, 35 | out Vector3[,] velocitySources) { 36 | var srcResX = fixedVelocitiesTex.width; 37 | var srcResY = fixedVelocitiesTex.height; 38 | var destResY = resY; 39 | var destResX = (16 * resY) / 9; 40 | if (destResX == 853) destResX = 854; 41 | // var destResX = destResX; 42 | // var destResY = destResY; 43 | u = new float[destResX, destResY]; 44 | v = new float[destResX, destResY]; 45 | s = new int[destResX, destResY]; 46 | colorSources = new Vector4[destResX, destResY]; 47 | velocitySources = new Vector3[destResX, destResY]; 48 | // var fixedVelData = fixedVelocitiesTex.GetPixels(); 49 | for(var j = 0; j < destResY; j++) { 50 | var jOffset = j * destResX; 51 | for(var i = 0; i < destResX; i++) { 52 | var offset = jOffset + i; 53 | var srcU = (float)i / destResX; 54 | var srcV = (float)j / destResY; 55 | var srcX = (int)(srcU * srcResX); 56 | var srcY = (int)(srcV * srcResY); 57 | var color = fixedVelocitiesTex.GetPixel(srcX, srcY); 58 | // var color = fixedVelData[offset]; 59 | velocitySources[i, j] = new Vector4(color.r, color.g, color.b, color.a); 60 | if(color == Color.red) { 61 | s[i, j] = 0; 62 | 63 | v[i, j] = 1; 64 | v[i, j + 1] = 1; 65 | } else if(color == Color.blue) { 66 | s[i, j] = 0; 67 | 68 | if(v[i, j] == 1) { 69 | throw new Exception($"v is already 1 at {i} {j}"); 70 | } 71 | if(v[i, j + 1] == 1) { 72 | throw new Exception($"v is already 1 at {i} {j} + 1"); 73 | } 74 | v[i, j] = -1; 75 | v[i, j + 1] = -1; 76 | } else if( color == Color.black) { 77 | s[i, j] = 0; 78 | 79 | // v[i, j] = 0; 80 | // if(j < simResY - 1) v[i, j + 1] = 0; 81 | } else { 82 | // treat as white 83 | s[i, j] = 1; 84 | } 85 | } 86 | } 87 | // var colorSourcesData = colorSourcesTex.GetPixels(); 88 | for(var j = 1; j < destResY - 1; j++) { 89 | var jOffset = j * destResX; 90 | for(var i = 1; i < destResX - 1; i++) { 91 | var offset = jOffset + i; 92 | if(s[i, j] != 1) { 93 | continue; 94 | } 95 | var srcU = (float)i / destResX; 96 | var srcV = (float)j / destResY; 97 | var srcX = (int)(srcU * srcResX); 98 | var srcY = (int)(srcV * srcResY); 99 | var csCol = colorSourcesTex.GetPixel(srcX, srcY); 100 | // var csCol = colorSourcesData[offset]; 101 | if(csCol.a != 1) { 102 | continue; 103 | } 104 | // only add on boundaries 105 | // bool addColor = 106 | // s[i - 1, j] == 0 || 107 | // s[i + 1, j] == 0 || 108 | // s[i, j - 1] == 0 || 109 | // s[i, j + 1] == 0; 110 | // if(!addColor) { 111 | // continue; 112 | // } 113 | colorSources[i, j] = new Vector4(csCol.r, csCol.g, csCol.b, csCol.a); 114 | } 115 | } 116 | } 117 | 118 | } 119 | 120 | } // namespace Liquid2Tex 121 | -------------------------------------------------------------------------------- /Assets/LiquidShader/DesignLoader.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cfb4589c9ede945c68640ed4356bc26a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/DivergenceCalculator.cs: -------------------------------------------------------------------------------- 1 | using LiquidShader.Types; 2 | using UnityEngine; 3 | 4 | namespace LiquidShader { 5 | 6 | [RequireComponent(typeof(Pooling))] 7 | public class DivergenceCalculator : MonoBehaviour { 8 | ComputeShader _computeShader; 9 | 10 | Pooling _pooling; 11 | 12 | void OnEnable() { 13 | _computeShader = (ComputeShader)Resources.Load("LiquidShader/Divergence"); 14 | 15 | _pooling = GetComponent(); 16 | } 17 | 18 | public void CalcDivergence(SimulationState simulationState) { 19 | var kernel = _computeShader.FindKernel("CalcDivergence"); 20 | 21 | _computeShader.SetInt("_simResX", simulationState.simResX); 22 | _computeShader.SetInt("_simResY", simulationState.simResY); 23 | 24 | _computeShader.SetBuffer(kernel, "_horizVel", simulationState.uBuf.GetComputeBuffer()); 25 | _computeShader.SetBuffer(kernel, "_vertVel", simulationState.vBuf.GetComputeBuffer()); 26 | _computeShader.SetBuffer(kernel, "_isFluid", simulationState.sBuf.GetComputeBuffer()); 27 | _computeShader.SetBuffer(kernel, "_divergence", simulationState.divergenceBuf.GetComputeBuffer()); 28 | _computeShader.Dispatch(kernel, (simulationState.simResX + 8 - 1) / 8, (simulationState.simResY + 8 - 1) / 8, 1); 29 | 30 | _pooling.AbsThresholdFloats(simulationState.divergenceBuf, simulationState.chunkDivergenceBuffer, 31 | threshold: _pooling.noRunProjectDivergenceThreshold); 32 | _pooling.AbsThresholdFloats(simulationState.chunkDivergenceBuffer, simulationState.chunkDivergenceL2Buf, 33 | threshold: _pooling.noRunProjectDivergenceThreshold); 34 | } 35 | } 36 | 37 | } // namespace LiquidShader 38 | -------------------------------------------------------------------------------- /Assets/LiquidShader/DivergenceCalculator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eb557fed933624272bda82713419272b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Draw.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9087e663ee1264ac9a6cbee586ff2a81 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Fill.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using Utils; 3 | 4 | namespace LiquidShader { 5 | 6 | public class Fill { 7 | ComputeShader _copyShader; 8 | 9 | public Fill() { 10 | this._copyShader = (ComputeShader)Resources.Load("LiquidShader/Fill"); 11 | } 12 | 13 | public void FillFloats(int simResX, int simResY, IBuf2 tgt, float value) { 14 | var kernel = _copyShader.FindKernel("FillFloats"); 15 | _copyShader.SetBuffer(kernel, "_tgtFloats", tgt.GetComputeBuffer()); 16 | _copyShader.SetInt("_tgtOffset", tgt.Offset); 17 | _copyShader.SetFloat("_valueFloat", value); 18 | _copyShader.SetInt("_simResX", simResX); 19 | _copyShader.SetInt("_simResY", simResY); 20 | _copyShader.Dispatch(kernel, (simResX + 8 - 1) / 8, (simResY + 8 - 1 ) / 8, 1); 21 | } 22 | } 23 | 24 | } // namespace LiquidShader 25 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Fill.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aa214d3040de248d9a355179989e0320 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/LiquidShaderRenderer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b6893d827b0f64da8862a4dcb5497d87 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/LiquidShaderScene.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7e4282002d87a455e8668904406fdb21 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/LiquidShader/LiquidShaderTests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6c40800186fd54a41b0848ec01ce7f45 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/LiquidShaderTests/LiquidShaderTests.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "LiquidShaderTests", 3 | "rootNamespace": "", 4 | "references": [ 5 | "UnityEngine.TestRunner", 6 | "UnityEditor.TestRunner", 7 | "FluidSim" 8 | ], 9 | "includePlatforms": [], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": false, 12 | "overrideReferences": true, 13 | "precompiledReferences": [ 14 | "nunit.framework.dll" 15 | ], 16 | "autoReferenced": false, 17 | "defineConstraints": [ 18 | "UNITY_INCLUDE_TESTS" 19 | ], 20 | "versionDefines": [], 21 | "noEngineReferences": false 22 | } -------------------------------------------------------------------------------- /Assets/LiquidShader/LiquidShaderTests/LiquidShaderTests.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1a3d73bed1ba34207b59ea8405302156 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/LiquidShader/LiquidShaderTests/TestAdvectVelocity.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 197a027f37fc541e081fc35ce829384f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/LiquidShaderTests/TestBuf2.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using NUnit.Framework; 4 | using UnityEngine; 5 | using UnityEngine.TestTools; 6 | using UnityEngine.TestTools.Utils; 7 | 8 | using LiquidShader; 9 | using Utils; 10 | 11 | class TestBuf2 { 12 | // float requiresArray(float[,] tgt) { 13 | // return tgt[1, 2]; 14 | // } 15 | 16 | [Test] 17 | public void Test1(){ 18 | Buf2 cf = new Buf2(5, 7); 19 | Buf2 cf3 = new Buf2(5, 7); 20 | Buf2 ci = new Buf2(5, 7); 21 | Buf2 ci3 = new Buf2(5, 7); 22 | Buf2 cf4 = new Buf2(5, 7); 23 | 24 | float input = 3.5f; 25 | float input2 = 5.7f; 26 | float input3 = 222; 27 | cf[2, 4] = input; 28 | cf[1, 2] = input2; 29 | cf[4, 6] = 222; 30 | Assert.AreEqual(input, cf[2, 4]); 31 | Assert.AreEqual(input2, cf[1, 2]); 32 | Assert.AreEqual(input3, cf[4, 6]); 33 | 34 | // requiresArray(cf); 35 | 36 | cf.ToGPU(); 37 | cf[2, 4] = 123f; 38 | cf[4, 6] = 124f; 39 | Assert.AreEqual(123, cf[2, 4]); 40 | Assert.AreEqual(124, cf[4, 6]); 41 | 42 | cf.FromGPU(); 43 | Assert.AreEqual(input, cf[2, 4]); 44 | Assert.AreEqual(input3, cf[4, 6]); 45 | } 46 | 47 | [Test] 48 | public void Testf3(){ 49 | Buf2 cf3 = new Buf2(5, 7); 50 | 51 | Vector3 in1 = new Vector3(0.1f, 2.2f, 5.4f); 52 | Vector3 in2 = new Vector3(3.2f, 5.1f, 3.9f); 53 | 54 | cf3[1, 4] = in1; 55 | cf3[2, 3] = in2; 56 | 57 | Assert.AreEqual(in1, cf3[1, 4]); 58 | Assert.AreEqual(in2, cf3[2, 3]); 59 | 60 | cf3.ToGPU(); 61 | Vector3 in1a = new Vector3(0, 123f, 0); 62 | Vector3 in2a = new Vector3(0, 0, 124f); 63 | cf3[1, 4] = in1a; 64 | cf3[2, 3] = in2a; 65 | Assert.AreEqual(in1a, cf3[1, 4]); 66 | Assert.AreEqual(in2a, cf3[2, 3]); 67 | 68 | cf3.FromGPU(); 69 | Assert.AreEqual(in1, cf3[1, 4]); 70 | Assert.AreEqual(in2, cf3[2, 3]); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Assets/LiquidShader/LiquidShaderTests/TestBuf2.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 57cf1a92d890d40c1bc2993351d9b85c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/LiquidShaderTests/TestCopy.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using NUnit.Framework; 4 | using UnityEngine; 5 | using UnityEngine.TestTools; 6 | using UnityEngine.TestTools.Utils; 7 | 8 | using LiquidShader; 9 | using Utils; 10 | 11 | public class TestCopy 12 | { 13 | [Test] 14 | public void TestCopyFloatsSimple() { 15 | Buf2 srcBuf = new Buf2(1, 5); 16 | Buf2 destBuf = new Buf2(1, 5); 17 | float[,] inputs = new float[,]{{1.3f, 2.8f, 0.3f, 4.9f, -2.111f}}; 18 | srcBuf.SetData(inputs); 19 | float[,] outputs = new float[1, 5]; 20 | // destBuffer.SetData(outputs); 21 | CopyBuffer copyBuffer = new CopyBuffer(); 22 | copyBuffer.CopyFloats(5, 1, srcBuf, destBuf); 23 | destBuf.GetData(outputs); 24 | 25 | for(int i = 0; i < 5; i++) { 26 | Debug.Log($"{i} {outputs[0, i]}"); 27 | Assert.That(outputs[0, i], Is.EqualTo(inputs[0, i]).Using(FloatEqualityComparer.Instance)); 28 | } 29 | } 30 | 31 | [Test] 32 | public void TestCopyFloat4sSimple() { 33 | int numInputs = 5; 34 | Buf2 srcBuffer = new Buf2(1, numInputs); 35 | Buf2 destBuffer = new Buf2(1, numInputs); 36 | Vector4[,] inputs = new Vector4[,]{{ 37 | new Vector4(0.1f, 0.4f, -1.2f, 0), 38 | new Vector4(1.1f, 0.4f, -1.2f, 1), 39 | new Vector4(0.1f, 3.4f, -1.2f, 1), 40 | new Vector4(0.1f, 0.4f, -5.2f, 0), 41 | new Vector4(5.1f, 3.4f, -2.2f, 4), 42 | } 43 | }; 44 | srcBuffer.SetData(inputs); 45 | Vector4[,] outputs = new Vector4[1, numInputs]; 46 | // destBuffer.SetData(outputs); 47 | CopyBuffer copyBuffer = new CopyBuffer(); 48 | copyBuffer.CopyFloat4S(srcBuffer, destBuffer); 49 | destBuffer.GetData(outputs); 50 | 51 | for(int i = 0; i < numInputs; i++) { 52 | Debug.Log($"{i} {outputs[0, i]}"); 53 | // Assert.That(outputs[i], Is.EqualTo(inputs[i]).Using(FloatEqualityComparer.Instance)); 54 | TestUtils.AssertEqual(inputs[0, i], outputs[0, i]); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Assets/LiquidShader/LiquidShaderTests/TestCopy.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 40d0061045f6c4887948ed854e198872 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/LiquidShaderTests/TestProject.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7171254f675e8484ea5579174b4fd165 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/LiquidShaderTests/TestUtils.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 70887295ebf3d49ff9f6e6fcbda87a9f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/MousePointer.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &8910106546125978001 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 8851763308004663984} 12 | - component: {fileID: 7620905988425744022} 13 | - component: {fileID: 851282387135203212} 14 | - component: {fileID: 5628164264929864766} 15 | m_Layer: 5 16 | m_Name: MousePointer 17 | m_TagString: Untagged 18 | m_Icon: {fileID: 0} 19 | m_NavMeshLayer: 0 20 | m_StaticEditorFlags: 0 21 | m_IsActive: 1 22 | --- !u!224 &8851763308004663984 23 | RectTransform: 24 | m_ObjectHideFlags: 0 25 | m_CorrespondingSourceObject: {fileID: 0} 26 | m_PrefabInstance: {fileID: 0} 27 | m_PrefabAsset: {fileID: 0} 28 | m_GameObject: {fileID: 8910106546125978001} 29 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 30 | m_LocalPosition: {x: 0, y: 0, z: 0} 31 | m_LocalScale: {x: 1, y: 1, z: 1} 32 | m_ConstrainProportionsScale: 0 33 | m_Children: [] 34 | m_Father: {fileID: 0} 35 | m_RootOrder: -1 36 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 37 | m_AnchorMin: {x: 0.5, y: 0.5} 38 | m_AnchorMax: {x: 0.5, y: 0.5} 39 | m_AnchoredPosition: {x: 0, y: 0} 40 | m_SizeDelta: {x: 16, y: 16} 41 | m_Pivot: {x: 0.5, y: 0.5} 42 | --- !u!222 &7620905988425744022 43 | CanvasRenderer: 44 | m_ObjectHideFlags: 0 45 | m_CorrespondingSourceObject: {fileID: 0} 46 | m_PrefabInstance: {fileID: 0} 47 | m_PrefabAsset: {fileID: 0} 48 | m_GameObject: {fileID: 8910106546125978001} 49 | m_CullTransparentMesh: 1 50 | --- !u!114 &851282387135203212 51 | MonoBehaviour: 52 | m_ObjectHideFlags: 0 53 | m_CorrespondingSourceObject: {fileID: 0} 54 | m_PrefabInstance: {fileID: 0} 55 | m_PrefabAsset: {fileID: 0} 56 | m_GameObject: {fileID: 8910106546125978001} 57 | m_Enabled: 1 58 | m_EditorHideFlags: 0 59 | m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} 60 | m_Name: 61 | m_EditorClassIdentifier: 62 | m_Material: {fileID: 0} 63 | m_Color: {r: 1, g: 1, b: 1, a: 1} 64 | m_RaycastTarget: 1 65 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 66 | m_Maskable: 1 67 | m_OnCullStateChanged: 68 | m_PersistentCalls: 69 | m_Calls: [] 70 | m_Sprite: {fileID: 21300000, guid: 938db63ebc77c4d829904330b0945bfd, type: 3} 71 | m_Type: 0 72 | m_PreserveAspect: 0 73 | m_FillCenter: 1 74 | m_FillMethod: 4 75 | m_FillAmount: 1 76 | m_FillClockwise: 1 77 | m_FillOrigin: 0 78 | m_UseSpriteMesh: 0 79 | m_PixelsPerUnitMultiplier: 1 80 | --- !u!114 &5628164264929864766 81 | MonoBehaviour: 82 | m_ObjectHideFlags: 0 83 | m_CorrespondingSourceObject: {fileID: 0} 84 | m_PrefabInstance: {fileID: 0} 85 | m_PrefabAsset: {fileID: 0} 86 | m_GameObject: {fileID: 8910106546125978001} 87 | m_Enabled: 1 88 | m_EditorHideFlags: 0 89 | m_Script: {fileID: 11500000, guid: 26c6adcb29a544d7bb07ec2c3a246ea5, type: 3} 90 | m_Name: 91 | m_EditorClassIdentifier: 92 | camera: {fileID: 0} 93 | -------------------------------------------------------------------------------- /Assets/LiquidShader/MousePointer.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a3417a3485e514ba99d5025fcde27ea8 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/LiquidShader/NoDivergenceIcon1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hughperkins/UnityFluidSim-pub/67a431c53f8328818ef6d2fcbab2fffd5e7a87ba/Assets/LiquidShader/NoDivergenceIcon1.png -------------------------------------------------------------------------------- /Assets/LiquidShader/NoDivergenceIcon1.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4b29c88c0bcac4af8b432080ea6e606d 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | flipGreenChannel: 0 24 | isReadable: 0 25 | streamingMipmaps: 0 26 | streamingMipmapsPriority: 0 27 | vTOnly: 0 28 | ignoreMipmapLimit: 0 29 | grayScaleToAlpha: 0 30 | generateCubemap: 6 31 | cubemapConvolution: 0 32 | seamlessCubemap: 0 33 | textureFormat: 1 34 | maxTextureSize: 2048 35 | textureSettings: 36 | serializedVersion: 2 37 | filterMode: 1 38 | aniso: 1 39 | mipBias: 0 40 | wrapU: 0 41 | wrapV: 0 42 | wrapW: 0 43 | nPOTScale: 1 44 | lightmap: 0 45 | compressionQuality: 50 46 | spriteMode: 0 47 | spriteExtrude: 1 48 | spriteMeshType: 1 49 | alignment: 0 50 | spritePivot: {x: 0.5, y: 0.5} 51 | spritePixelsToUnits: 100 52 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 53 | spriteGenerateFallbackPhysicsShape: 1 54 | alphaUsage: 1 55 | alphaIsTransparency: 0 56 | spriteTessellationDetail: -1 57 | textureType: 0 58 | textureShape: 1 59 | singleChannelComponent: 0 60 | flipbookRows: 1 61 | flipbookColumns: 1 62 | maxTextureSizeSet: 0 63 | compressionQualitySet: 0 64 | textureFormatSet: 0 65 | ignorePngGamma: 0 66 | applyGammaDecoding: 0 67 | swizzle: 50462976 68 | cookieLightType: 0 69 | platformSettings: 70 | - serializedVersion: 3 71 | buildTarget: DefaultTexturePlatform 72 | maxTextureSize: 2048 73 | resizeAlgorithm: 0 74 | textureFormat: -1 75 | textureCompression: 1 76 | compressionQuality: 50 77 | crunchedCompression: 0 78 | allowsAlphaSplitting: 0 79 | overridden: 0 80 | ignorePlatformSupport: 0 81 | androidETC2FallbackOverride: 0 82 | forceMaximumCompressionQuality_BC6H_BC7: 0 83 | - serializedVersion: 3 84 | buildTarget: Standalone 85 | maxTextureSize: 2048 86 | resizeAlgorithm: 0 87 | textureFormat: -1 88 | textureCompression: 1 89 | compressionQuality: 50 90 | crunchedCompression: 0 91 | allowsAlphaSplitting: 0 92 | overridden: 0 93 | ignorePlatformSupport: 0 94 | androidETC2FallbackOverride: 0 95 | forceMaximumCompressionQuality_BC6H_BC7: 0 96 | - serializedVersion: 3 97 | buildTarget: Server 98 | maxTextureSize: 2048 99 | resizeAlgorithm: 0 100 | textureFormat: -1 101 | textureCompression: 1 102 | compressionQuality: 50 103 | crunchedCompression: 0 104 | allowsAlphaSplitting: 0 105 | overridden: 0 106 | ignorePlatformSupport: 0 107 | androidETC2FallbackOverride: 0 108 | forceMaximumCompressionQuality_BC6H_BC7: 0 109 | spriteSheet: 110 | serializedVersion: 2 111 | sprites: [] 112 | outline: [] 113 | physicsShape: [] 114 | bones: [] 115 | spriteID: 116 | internalID: 0 117 | vertices: [] 118 | indices: 119 | edges: [] 120 | weights: [] 121 | secondaryTextures: [] 122 | nameFileIdTable: {} 123 | mipmapLimitGroupName: 124 | pSDRemoveMatte: 0 125 | userData: 126 | assetBundleName: 127 | assetBundleVariant: 128 | -------------------------------------------------------------------------------- /Assets/LiquidShader/NoiseAdder.cs: -------------------------------------------------------------------------------- 1 | using LiquidShader.Types; 2 | using UnityEngine; 3 | using Utils; 4 | 5 | namespace LiquidShader { 6 | 7 | enum NoiseType { 8 | Velocity, 9 | Color 10 | } 11 | 12 | enum NoiseOp { 13 | Add, 14 | Mul 15 | } 16 | 17 | // enum DecayType { 18 | // Linear, 19 | // Squared 20 | // } 21 | 22 | public class NoiseAdder: MonoBehaviour { 23 | [SerializeField] bool enableNoise = true; 24 | [SerializeField] NoiseType noiseType = NoiseType.Color; 25 | [SerializeField] NoiseOp noiseOp = NoiseOp.Mul; 26 | [SerializeField] bool sqrtNoise = true; 27 | [Range(-10f, 0.0f)] [SerializeField] float logNoiseAmount = -3; 28 | // [SerializeField] DecayType decayType = DecayType.Linear; 29 | [SerializeField][Range(-10, 0)] float logDecay = -1; 30 | 31 | ComputeShader _shader; 32 | 33 | void Awake() { 34 | this._shader = (ComputeShader)Resources.Load("LiquidShader/AddNoise"); 35 | } 36 | 37 | public void AddNoise(SimulationState simulationState) { 38 | if (!enableNoise) return; 39 | var noiseAmount = Mathf.Exp(logNoiseAmount); 40 | if (noiseType == NoiseType.Velocity) { 41 | // noise u 42 | AddNoiseFloats( 43 | frame: simulationState.frame, 44 | noiseAmount: noiseAmount, 45 | seed: 0, 46 | simResX: simulationState.simResX, 47 | simResY: simulationState.simResY, 48 | s: simulationState.sBuf, 49 | tgt: simulationState.uBuf 50 | ); 51 | // noise v 52 | AddNoiseFloats( 53 | frame: simulationState.frame, 54 | noiseAmount: noiseAmount, 55 | seed: 100, 56 | simResX: simulationState.simResX, 57 | simResY: simulationState.simResY, 58 | s: simulationState.sBuf, 59 | tgt: simulationState.vBuf 60 | ); 61 | } else if (noiseType == NoiseType.Color) { 62 | AddNoiseFloat4s( 63 | frame: simulationState.frame, 64 | noiseAmount: noiseAmount, 65 | seed: 100, 66 | simResX: simulationState.simResX, 67 | simResY: simulationState.simResY, 68 | s: simulationState.sBuf, 69 | tgt: simulationState.mBuf 70 | ); 71 | } 72 | } 73 | 74 | void AddNoiseFloats(int frame, float noiseAmount, int seed, int simResX, int simResY, Buf2 s, Buf2 tgt) { 75 | var kernel = _shader.FindKernel("AddNoiseFloats"); 76 | _shader.SetBuffer(kernel, "_isFluid", s.GetComputeBuffer()); 77 | _shader.SetBuffer(kernel, "_tgt", tgt.GetComputeBuffer()); 78 | _shader.SetInt("_simResX", simResX); 79 | _shader.SetInt("_simResY", simResY); 80 | _shader.SetInt("_frame", frame); 81 | _shader.SetInt("_seed", seed); 82 | _shader.SetFloat("_noiseAmount", noiseAmount); 83 | _shader.Dispatch(kernel, (simResX + 8 - 1) / 8, (simResY + 8 - 1 ) / 8, 1); 84 | } 85 | void AddNoiseFloat4s(int frame, float noiseAmount, int seed, int simResX, int simResY, Buf2 s, Buf2 tgt) { 86 | var kernel = _shader.FindKernel("AddNoiseFloat4s"); 87 | _shader.SetBuffer(kernel, "_isFluid", s.GetComputeBuffer()); 88 | _shader.SetBuffer(kernel, "_tgtFloat4s", tgt.GetComputeBuffer()); 89 | _shader.SetInt("_simResX", simResX); 90 | _shader.SetInt("_simResY", simResY); 91 | _shader.SetInt("_frame", frame); 92 | _shader.SetInt("_seed", seed); 93 | _shader.SetBool("_addNoise", noiseOp == NoiseOp.Add); 94 | _shader.SetBool("_sqrtNoise", sqrtNoise); 95 | _shader.SetFloat("_noiseAmount", noiseAmount); 96 | var decay = Mathf.Exp(logDecay); 97 | _shader.SetFloat("_decay", decay); 98 | // _shader.SetBool("_decaySquared", decayType == DecayType.Squared); 99 | _shader.Dispatch(kernel, (simResX + 8 - 1) / 8, (simResY + 8 - 1 ) / 8, 1); 100 | } 101 | 102 | } 103 | 104 | } // namespace LiquidShader 105 | -------------------------------------------------------------------------------- /Assets/LiquidShader/NoiseAdder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ef9d009ecbd6642f5a6c232c4433b174 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Pooling.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using Utils; 4 | 5 | namespace LiquidShader { 6 | 7 | public class Pooling : MonoBehaviour { 8 | [SerializeField] public bool useDivergenceChunks = false; 9 | [SerializeField] public float startDivergenceThreshold = 0.3f; 10 | [SerializeField] public float endDivergenceThreshold = 0.01f; 11 | [SerializeField] public float noRunProjectDivergenceThreshold = 0.01f; 12 | public int chunkOverlap = 0; 13 | [SerializeField] public bool runMaxAbs = false; 14 | 15 | ComputeShader _shader; 16 | 17 | // these have to match what is in the shader 18 | public const int ChunkSize = 8; 19 | const int THREAD_BLOCK_SIZE = 8; 20 | 21 | private void Awake() { 22 | this._shader = Resources.Load("LiquidShader/Pooling"); 23 | } 24 | 25 | public static int DivergenceChunkSizeLog2 { 26 | get{ 27 | var divergenceChunkSizeLog2 = (int)(Mathf.Log(ChunkSize) / Mathf.Log(2)); 28 | if((int)Mathf.Pow(2, divergenceChunkSizeLog2) != ChunkSize) { 29 | throw new Exception($"Invalid divergence chunk size: should be power of 2"); 30 | } 31 | return divergenceChunkSizeLog2; 32 | } 33 | } 34 | 35 | public void MaxAbsFloats(Buf2 src, Buf2 dest) { 36 | if(dest.ResX != (src.ResX + ChunkSize - 1) / ChunkSize) { 37 | throw new Exception($"width of dest should be {ChunkSize} smaller than dest {src.ResX} vs {dest.ResX}"); 38 | } 39 | if(dest.ResY != (src.ResY + ChunkSize - 1) / ChunkSize) { 40 | throw new Exception($"width of dest should be {ChunkSize} smaller than dest {src.ResY} vs {dest.ResY}"); 41 | } 42 | var kernel = _shader.FindKernel("MaxAbsBuffer"); 43 | _shader.SetBuffer(kernel, "_src", src.GetComputeBuffer()); 44 | _shader.SetBuffer(kernel, "_dest", dest.GetComputeBuffer()); 45 | _shader.SetInts("_simRes", new int[]{src.ResX, src.ResY}); 46 | _shader.Dispatch(kernel, (dest.ResX + THREAD_BLOCK_SIZE - 1) / THREAD_BLOCK_SIZE, (dest.ResY + THREAD_BLOCK_SIZE - 1 ) / THREAD_BLOCK_SIZE, 1); 47 | } 48 | 49 | public void AbsThresholdFloats(Buf2 src, Buf2 dest, float threshold) { 50 | if(dest.ResX != (src.ResX + ChunkSize - 1) / ChunkSize) { 51 | throw new Exception($"width of dest should be {ChunkSize} smaller than dest {src.ResX} vs {dest.ResX}"); 52 | } 53 | if(dest.ResY != (src.ResY + ChunkSize - 1) / ChunkSize) { 54 | throw new Exception($"width of dest should be {ChunkSize} smaller than dest {src.ResY} vs {dest.ResY}"); 55 | } 56 | var kernel = _shader.FindKernel("AbsThresholdPooling"); 57 | _shader.SetBuffer(kernel, "_src", src.GetComputeBuffer()); 58 | _shader.SetBuffer(kernel, "_dest", dest.GetComputeBuffer()); 59 | _shader.SetInts("_simRes", new int[]{src.ResX, src.ResY}); 60 | _shader.SetFloat("_divergenceThreshold", threshold); 61 | _shader.SetInt("_chunkOverlap", chunkOverlap); 62 | _shader.Dispatch(kernel, (dest.ResX + THREAD_BLOCK_SIZE - 1) / THREAD_BLOCK_SIZE, (dest.ResY + THREAD_BLOCK_SIZE - 1 ) / THREAD_BLOCK_SIZE, 1); 63 | } 64 | } 65 | 66 | } // namespace LiquidShader 67 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Pooling.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d98cfc6f12a1345c2a6bb5fc2180a721 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/ProjectCellByCell.cs: -------------------------------------------------------------------------------- 1 | using LiquidShader.Types; 2 | using Utils; 3 | using UnityEngine; 4 | 5 | namespace LiquidShader { 6 | 7 | [RequireComponent(typeof(ProjectSingleCell))] 8 | public class ProjectCellByCell : MonoBehaviour { 9 | public CellByCell cellByCell; 10 | 11 | ProjectSingleCell _projectSingleCell; 12 | 13 | public void Reset() { 14 | cellByCell.Reset(); 15 | } 16 | 17 | void OnEnable() { 18 | cellByCell = new CellByCell(); 19 | _projectSingleCell = GetComponent(); 20 | } 21 | 22 | public void RunProject(SimulationState simulationState) { 23 | _projectSingleCell.ProjectCell(simulationState, cellByCell.updateX, cellByCell.updateY); 24 | cellByCell.Inc(simulationState); 25 | } 26 | } 27 | 28 | } // namespace LiquidShader 29 | -------------------------------------------------------------------------------- /Assets/LiquidShader/ProjectCellByCell.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8c2b170aa0797427aa0c57761f65d104 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/ProjectDraw.cs: -------------------------------------------------------------------------------- 1 | using LiquidShader.Types; 2 | using Utils; 3 | using UnityEngine; 4 | 5 | namespace LiquidShader { 6 | 7 | [RequireComponent(typeof(Draw))] 8 | [RequireComponent(typeof(Rendering))] 9 | [RequireComponent(typeof(LiquidShaderRenderer))] 10 | [RequireComponent(typeof(ProjectSingleCell))] 11 | public class ProjectDraw : MonoBehaviour { 12 | Draw _draw; 13 | Rendering _rendering; 14 | LiquidShaderRenderer _liquidShaderRenderer; 15 | ProjectSingleCell _projectSingleCell; 16 | 17 | void OnEnable() { 18 | _draw = GetComponent(); 19 | _rendering = GetComponent(); 20 | // needed to get the simulation state for mouse drawing 21 | _liquidShaderRenderer = GetComponent(); 22 | _projectSingleCell = GetComponent(); 23 | } 24 | 25 | void Update() { 26 | if (_draw.drawType != DrawType.RemoveDivergence) return; 27 | if (!Input.GetMouseButtonDown(0) || ClickFilter.HitUI() || Input.GetKey(KeyCode.LeftCommand)) return; 28 | var relX = Input.mousePosition.x / Screen.width; 29 | var relY = Input.mousePosition.y / Screen.height; 30 | if(_rendering.IsSplitScreen) { 31 | relX *= 2; 32 | } 33 | var simulationState = _liquidShaderRenderer.simulationState; 34 | var simX = (int)(relX * simulationState.simResX); 35 | var simY = (int)(relY * simulationState.simResY); 36 | if (simX >= 0 && simY >= 0 && simX < simulationState.simResX && simY < simulationState.simResY) { 37 | _projectSingleCell.ProjectCell(simulationState, simX, simY); 38 | } 39 | } 40 | } 41 | 42 | } // namespace LiquidShader 43 | -------------------------------------------------------------------------------- /Assets/LiquidShader/ProjectDraw.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ed939d0f94be4892baecfca31b9b3104 3 | timeCreated: 1689071572 -------------------------------------------------------------------------------- /Assets/LiquidShader/ProjectGaussSeidelClean.cs: -------------------------------------------------------------------------------- 1 | // using LiquidShaderColo; 2 | using UnityEngine; 3 | using Utils; 4 | using SimulationState = LiquidShader.Types.SimulationState; 5 | 6 | namespace LiquidShader { 7 | 8 | public class ProjectGaussSeidelClean : MonoBehaviour { 9 | [Range(1, 500)][SerializeField] public int solverIterations = 100; 10 | [SerializeField] bool stepSubPasses = false; 11 | 12 | ComputeShader _computeShader; 13 | int[] _subPassPos; 14 | bool _lastStepSubPasses; 15 | 16 | RenderSelected _renderSelected; 17 | LiquidShaderRenderer _liquidShaderRenderer; 18 | 19 | void OnEnable() { 20 | _computeShader = (ComputeShader)Resources.Load("LiquidShader/ProjectGaussSeidelClean"); 21 | _subPassPos = new []{0, 0}; 22 | _renderSelected = GetComponent(); 23 | _liquidShaderRenderer = GetComponent(); 24 | } 25 | 26 | void RunPass(SimulationState simulationState, int[] passOffset) { 27 | var kernel = _computeShader.FindKernel("ProjectGaussSeidel"); 28 | _computeShader.SetInt("_simResX", simulationState.simResX); 29 | _computeShader.SetInt("_simResY", simulationState.simResY); 30 | _computeShader.SetInts("_passOffset", passOffset); 31 | _computeShader.SetBuffer(kernel, "_horizVel", simulationState.uBuf.GetComputeBuffer()); 32 | _computeShader.SetBuffer(kernel, "_vertVel", simulationState.vBuf.GetComputeBuffer()); 33 | 34 | _computeShader.SetBuffer(kernel, "_isFluid", simulationState.sBuf.GetComputeBuffer()); 35 | // halve the number of horizontal and vertical threads because each sub-pass only processes one quarter of all cells 36 | _computeShader.Dispatch( 37 | kernel, 38 | (simulationState.simResX + 8 * 2 - 1) / 8 / 2, 39 | (simulationState.simResY + 8 * 2 - 1) / 8 / 2, 40 | 1); 41 | } 42 | 43 | void IncrementSubPassPos() { 44 | _subPassPos[1] += 1; 45 | if (_subPassPos[1] == 2) { 46 | _subPassPos[1] = 0; 47 | _subPassPos[0] += 1; 48 | } 49 | if (_subPassPos[0] == 2) { 50 | _subPassPos = new int[] { 51 | 0, 0 52 | }; 53 | } 54 | } 55 | 56 | void LoadSelectedCells() { 57 | var simulationState = _liquidShaderRenderer.simulationState; 58 | var simRes = simulationState.SimResInts; 59 | var newSelected = new int[simRes[0], simRes[1]]; 60 | for (var i = _subPassPos[0]; i < simRes[0]; i += 2) { 61 | for (var j = _subPassPos[1]; j < simRes[1]; j += 2) { 62 | newSelected[i, j] = 1; 63 | } 64 | } 65 | simulationState.selected.SetData(newSelected); 66 | } 67 | 68 | void ClearSelectedCells() { 69 | var simulationState = _liquidShaderRenderer.simulationState; 70 | var simRes = simulationState.SimResInts; 71 | var newSelected = new int[simRes[0], simRes[1]]; 72 | simulationState.selected.SetData(newSelected); 73 | } 74 | 75 | void RunSubPass(SimulationState simulationState) { 76 | RunPass(simulationState, _subPassPos); 77 | IncrementSubPassPos(); 78 | LoadSelectedCells(); 79 | } 80 | 81 | void RunIterations(SimulationState simulationState) { 82 | for (var it = 0; it < solverIterations; it++) { 83 | for (var passI = 0; passI < 2; passI++) { 84 | for (var passJ = 0; passJ < 2; passJ++) { 85 | RunPass(simulationState, new[] { 86 | passI, passJ 87 | }); 88 | } 89 | } 90 | } 91 | } 92 | 93 | void Update() { 94 | if (_lastStepSubPasses != stepSubPasses) { 95 | _lastStepSubPasses = stepSubPasses; 96 | if (stepSubPasses) { 97 | LoadSelectedCells(); 98 | } else { 99 | ClearSelectedCells(); 100 | } 101 | } 102 | } 103 | 104 | public void RunProject(SimulationState simulationState) { 105 | if (stepSubPasses) { 106 | RunSubPass(simulationState); 107 | } else { 108 | RunIterations(simulationState); 109 | } 110 | } 111 | } 112 | 113 | } // namespace LiquidShader 114 | -------------------------------------------------------------------------------- /Assets/LiquidShader/ProjectGaussSeidelClean.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d527d9a7558c46dd98574c582a85311d 3 | timeCreated: 1688771497 -------------------------------------------------------------------------------- /Assets/LiquidShader/ProjectGaussSeidelGeneral.cs: -------------------------------------------------------------------------------- 1 | using LiquidShader.Types; 2 | using UnityEngine; 3 | using Utils; 4 | 5 | namespace LiquidShader { 6 | 7 | public class ProjectGaussSeidelGeneral : MonoBehaviour { 8 | [Range(1, 500)][SerializeField] public int solverIterations = 100; 9 | 10 | ComputeShader _computeShader; 11 | 12 | Pooling _pooling; 13 | CopyBuffer _copyBuffer; 14 | 15 | void Awake() { 16 | Debug.Log("Project.Awake"); 17 | _computeShader = (ComputeShader)Resources.Load("LiquidShader/ProjectGaussSeidelGeneral"); 18 | Debug.Log($"computeshader {_computeShader}"); 19 | 20 | _pooling = GetComponent(); 21 | 22 | _copyBuffer = new CopyBuffer(); 23 | } 24 | 25 | void RunPass(SimulationState simulationState, float simDeltaTime, float speed, bool debug, int[] passOffset, bool useDivergenceChunks, 26 | bool saveDivergence) { 27 | var divergenceChunkSizeLog2 = (int)(Mathf.Log(Pooling.ChunkSize) / Mathf.Log(2)); 28 | if((int)Mathf.Pow(2, divergenceChunkSizeLog2) != Pooling.ChunkSize) { 29 | throw new System.Exception($"Invalid divergence chunk size: should be power of 2"); 30 | } 31 | 32 | var kernel = _computeShader.FindKernel("ProjectGaussSeidelGeneral"); 33 | _computeShader.SetInt("_simResX", simulationState.simResX); 34 | _computeShader.SetInt("_simResY", simulationState.simResY); 35 | 36 | _computeShader.SetInts("_passOffset", passOffset); 37 | 38 | _computeShader.SetBool("_useDivergenceChunks", useDivergenceChunks); 39 | _computeShader.SetInt("_divergenceChunkSizeLog2", divergenceChunkSizeLog2); 40 | _computeShader.SetBuffer(kernel, "_divergence", simulationState.divergenceBuf.GetComputeBuffer()); 41 | _computeShader.SetBuffer(kernel, "_divergenceChunks", simulationState.chunkDivergenceBuffer.GetComputeBuffer()); 42 | 43 | _computeShader.SetBuffer(kernel, "_horizVel", simulationState.uBuf.GetComputeBuffer()); 44 | _computeShader.SetBuffer(kernel, "_vertVel", simulationState.vBuf.GetComputeBuffer()); 45 | 46 | _computeShader.SetBuffer(kernel, "_isFluid", simulationState.sBuf.GetComputeBuffer()); 47 | _computeShader.SetBuffer(kernel, "_debug", simulationState.debugBuf.GetComputeBuffer()); 48 | _computeShader.SetInt("_saveDivergence", saveDivergence ? 1 : 0); 49 | // we halve the number of horizontal and vertical threads because each subpass only processes one quarter of all cells 50 | _computeShader.Dispatch(kernel, (simulationState.simResX + 8 * 2 - 1) / 8 / 2, (simulationState.simResY + 8 * 2 - 1) / 8 / 2, 1); 51 | } 52 | 53 | public void RunProject( 54 | SimulationState simulationState, float simDeltaTime, float speed, bool debug = false 55 | ) { 56 | /* 57 | So, in this one, we update one of 4 possible grids of cells that are not touching, each grid 58 | comprising of cells in rows and columns with a row or column of unprocessed cells in between 59 | each adjacent pair of processed cells 60 | 61 | Coloring of each pass similar to as follows: 62 | |1|2|1|2| 63 | |3|4|3|4| 64 | |1|2|1|2| 65 | 66 | We'll just iterate over passI in {0, 1} and passJ in {0, 1} for each complete pass 67 | */ 68 | 69 | 70 | for(var it = 0; it < solverIterations; it++) { 71 | var t = (float)it / (float)(solverIterations - 1); 72 | var divergenceThreshold = (1 - t) * _pooling.startDivergenceThreshold + t * _pooling.endDivergenceThreshold; 73 | for(var passI = 0; passI < 2; passI++) { 74 | for(var passJ = 0; passJ < 2; passJ++) { 75 | RunPass( 76 | simulationState, simDeltaTime, speed, debug, new int[]{passI, passJ}, 77 | _pooling.useDivergenceChunks && it > 0, 78 | it == solverIterations - 1 || _pooling.useDivergenceChunks); 79 | } 80 | } 81 | 82 | if(_pooling.useDivergenceChunks || it == solverIterations - 1) { 83 | _pooling.AbsThresholdFloats(simulationState.divergenceBuf, simulationState.chunkDivergenceBuffer, threshold: divergenceThreshold); 84 | } 85 | 86 | if(_pooling.runMaxAbs) { 87 | _pooling.MaxAbsFloats(simulationState.divergenceBuf, simulationState.chunkDivergenceBuffer); 88 | _pooling.MaxAbsFloats(simulationState.chunkDivergenceBuffer, simulationState.chunkDivergenceL2Buf); 89 | _pooling.MaxAbsFloats(simulationState.chunkDivergenceL2Buf, simulationState.chunkDivergenceL3Buf); 90 | _copyBuffer.CopyFloats(1, 1, simulationState.chunkDivergenceL2Buf, simulationState.uBuf); 91 | } 92 | } 93 | } 94 | } 95 | 96 | } // namespace LiquidShader 97 | -------------------------------------------------------------------------------- /Assets/LiquidShader/ProjectGaussSeidelGeneral.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9d186acc5b69643c180570f398e14574 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/ProjectJacobi.cs: -------------------------------------------------------------------------------- 1 | using LiquidShader.Types; 2 | using UnityEngine; 3 | using Utils; 4 | 5 | namespace LiquidShader { 6 | 7 | [RequireComponent(typeof(Pooling))] 8 | public class ProjectJacobi : MonoBehaviour { 9 | [Range(1, 500)][SerializeField] public int solverIterations = 100; 10 | 11 | ComputeShader _computeShader; 12 | 13 | Pooling _pooling; 14 | 15 | CopyBuffer _copyBuffer; 16 | 17 | void Awake() { 18 | Debug.Log("Project.Awake"); 19 | _computeShader = (ComputeShader)Resources.Load("LiquidShader/ProjectJacobi"); 20 | Debug.Log($"computeshader {_computeShader}"); 21 | 22 | _pooling = GetComponent(); 23 | 24 | _copyBuffer = new CopyBuffer(); 25 | } 26 | 27 | public void RunProject( 28 | SimulationState simulationState, float simDeltaTime, float speed, bool debug = false 29 | ) { 30 | var kernel1 = _computeShader.FindKernel("Project1"); 31 | var kernel2 = _computeShader.FindKernel("Project2"); 32 | 33 | for(var it = 0; it < solverIterations; it++) { 34 | var t = (float)it / (float)(solverIterations - 1); 35 | var divergenceThreshold = (1 - t) * _pooling.startDivergenceThreshold + t * _pooling.endDivergenceThreshold; 36 | var kernel = kernel1; 37 | _computeShader.SetInt("_simResX", simulationState.simResX); 38 | _computeShader.SetInt("_simResY", simulationState.simResY); 39 | 40 | _computeShader.SetBool("_useDivergenceChunks", _pooling.useDivergenceChunks && it > 0); 41 | _computeShader.SetInt("_divergenceChunkSizeLog2", Pooling.DivergenceChunkSizeLog2); 42 | _computeShader.SetBuffer(kernel, "_divergence", simulationState.divergenceBuf.GetComputeBuffer()); 43 | _computeShader.SetBuffer(kernel, "_divergenceChunks", simulationState.chunkDivergenceBuffer.GetComputeBuffer()); 44 | 45 | _computeShader.SetBuffer(kernel, "_horizVel", simulationState.uBuf.GetComputeBuffer()); 46 | _computeShader.SetBuffer(kernel, "_vertVel", simulationState.vBuf.GetComputeBuffer()); 47 | 48 | _computeShader.SetBuffer(kernel, "_u23", simulationState.u23BufParent.GetComputeBuffer()); 49 | _computeShader.SetBuffer(kernel, "_v23", simulationState.v23BufParent.GetComputeBuffer()); 50 | 51 | _computeShader.SetInt("_u2Offset", simulationState.u2Buf.Offset); 52 | _computeShader.SetInt("_u3Offset", simulationState.u3Buf.Offset); 53 | _computeShader.SetInt("_v2Offset", simulationState.v2Buf.Offset); 54 | _computeShader.SetInt("_v3Offset", simulationState.v3Buf.Offset); 55 | 56 | _computeShader.SetBuffer(kernel, "_isFluid", simulationState.sBuf.GetComputeBuffer()); 57 | _computeShader.SetBuffer(kernel, "_debug", simulationState.debugBuf.GetComputeBuffer()); 58 | _computeShader.SetInt("_saveDivergence", it == solverIterations - 1 || _pooling.useDivergenceChunks ? 1 : 0); 59 | _computeShader.Dispatch(kernel, (simulationState.simResX + 8 - 1) / 8, (simulationState.simResY + 8 - 1) / 8, 1); 60 | 61 | kernel = kernel2; 62 | _computeShader.SetInt("_simResX", simulationState.simResX); 63 | _computeShader.SetInt("_simResY", simulationState.simResY); 64 | 65 | _computeShader.SetBool("_useDivergenceChunks", _pooling.useDivergenceChunks && it > 0); 66 | _computeShader.SetInt("_divergenceChunkSizeLog2", Pooling.DivergenceChunkSizeLog2); 67 | _computeShader.SetBuffer(kernel, "_divergenceChunks", simulationState.chunkDivergenceBuffer.GetComputeBuffer()); 68 | 69 | _computeShader.SetBuffer(kernel, "_horizVel", simulationState.uBuf.GetComputeBuffer()); 70 | _computeShader.SetBuffer(kernel, "_vertVel", simulationState.vBuf.GetComputeBuffer()); 71 | _computeShader.SetBuffer(kernel, "_u23", simulationState.u23BufParent.GetComputeBuffer()); 72 | _computeShader.SetBuffer(kernel, "_v23", simulationState.v23BufParent.GetComputeBuffer()); 73 | 74 | _computeShader.SetInt("_u2Offset", simulationState.u2Buf.Offset); 75 | _computeShader.SetInt("_u3Offset", simulationState.u3Buf.Offset); 76 | _computeShader.SetInt("_v2Offset", simulationState.v2Buf.Offset); 77 | _computeShader.SetInt("_v3Offset", simulationState.v3Buf.Offset); 78 | 79 | _computeShader.SetBuffer(kernel, "_isFluid", simulationState.sBuf.GetComputeBuffer()); 80 | _computeShader.Dispatch(kernel2, (simulationState.simResX + 8 - 1) / 8, (simulationState.simResY + 8 - 1) / 8, 1); 81 | 82 | if(_pooling.useDivergenceChunks || it == solverIterations - 1) { 83 | _pooling.AbsThresholdFloats(simulationState.divergenceBuf, simulationState.chunkDivergenceBuffer, threshold: divergenceThreshold); 84 | } 85 | } 86 | } 87 | } 88 | 89 | } // namespace LiquidShader 90 | -------------------------------------------------------------------------------- /Assets/LiquidShader/ProjectJacobi.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 099b90355b000472b90c49c011637fc8 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/ProjectJacobiInPlace.cs: -------------------------------------------------------------------------------- 1 | using LiquidShader.Types; 2 | using UnityEngine; 3 | using Utils; 4 | 5 | namespace LiquidShader { 6 | 7 | public class ProjectJacobiInPlace : MonoBehaviour { 8 | [Range(1, 500)][SerializeField] public int solverIterations = 100; 9 | 10 | ComputeShader _computeShader; 11 | 12 | Pooling _pooling; 13 | CopyBuffer _copyBuffer; 14 | 15 | void Awake() { 16 | Debug.Log("Project.Awake"); 17 | _computeShader = (ComputeShader)Resources.Load("LiquidShader/ProjectJacobiInPlace"); 18 | Debug.Log($"computeshader {_computeShader}"); 19 | 20 | _pooling = GetComponent(); 21 | 22 | _copyBuffer = new CopyBuffer(); 23 | } 24 | 25 | public void RunProject( 26 | SimulationState simulationState, float simDeltaTime, float speed, bool debug = false 27 | ) { 28 | /* 29 | So, in this one, we update one of 4 possible grids of cells that are not touching, each grid 30 | comprising of cells in rows and columns with a row or column of unprocessed cells in between 31 | each adjacent pair of processed cells 32 | 33 | Coloring of each pass similar to as follows: 34 | |1|2|1|2| 35 | |3|4|3|4| 36 | |1|2|1|2| 37 | 38 | We'll just iterate over passI in {0, 1} and passJ in {0, 1} for each complete pass 39 | */ 40 | var kernel = _computeShader.FindKernel("ProjectJacobiInPlace"); 41 | 42 | var divergenceChunkSizeLog2 = (int)(Mathf.Log(Pooling.ChunkSize) / Mathf.Log(2)); 43 | if(Mathf.Pow(2, divergenceChunkSizeLog2) != Pooling.ChunkSize) { 44 | throw new System.Exception($"Invalid divergence chunk size: should be power of 2"); 45 | } 46 | 47 | for(var it = 0; it < solverIterations; it++) { 48 | var t = (float)it / (float)(solverIterations - 1); 49 | var divergenceThreshold = (1 - t) * _pooling.startDivergenceThreshold + t * _pooling.endDivergenceThreshold; 50 | _computeShader.SetFloat("_deltaTime", simDeltaTime); 51 | _computeShader.SetFloat("_speedDeltaTime", simDeltaTime * speed); 52 | _computeShader.SetInt("_simResX", simulationState.simResX); 53 | _computeShader.SetInt("_simResY", simulationState.simResY); 54 | 55 | _computeShader.SetBool("_useDivergenceChunks", _pooling.useDivergenceChunks && it > 0); 56 | _computeShader.SetInt("_divergenceChunkSize", Pooling.ChunkSize); 57 | _computeShader.SetInt("_divergenceChunkSizeLog2", divergenceChunkSizeLog2); 58 | _computeShader.SetBuffer(kernel, "_divergence", simulationState.divergenceBuf.GetComputeBuffer()); 59 | _computeShader.SetBuffer(kernel, "_divergenceChunks", simulationState.chunkDivergenceBuffer.GetComputeBuffer()); 60 | 61 | _computeShader.SetBuffer(kernel, "_horizVel", simulationState.uBuf.GetComputeBuffer()); 62 | _computeShader.SetBuffer(kernel, "_vertVel", simulationState.vBuf.GetComputeBuffer()); 63 | 64 | _computeShader.SetBuffer(kernel, "_isFluid", simulationState.sBuf.GetComputeBuffer()); 65 | _computeShader.SetBuffer(kernel, "_debug", simulationState.debugBuf.GetComputeBuffer()); 66 | _computeShader.SetInt("_saveDivergence", it == solverIterations - 1 || _pooling.useDivergenceChunks ? 1 : 0); 67 | _computeShader.Dispatch(kernel, (simulationState.simResX + 8 - 1) / 8, (simulationState.simResY + 8 - 1) / 8, 1); 68 | 69 | if(_pooling.useDivergenceChunks || it == solverIterations - 1) { 70 | _pooling.AbsThresholdFloats(simulationState.divergenceBuf, simulationState.chunkDivergenceBuffer, threshold: divergenceThreshold); 71 | } 72 | 73 | if(_pooling.runMaxAbs) { 74 | _pooling.MaxAbsFloats(simulationState.divergenceBuf, simulationState.chunkDivergenceBuffer); 75 | _pooling.MaxAbsFloats(simulationState.chunkDivergenceBuffer, simulationState.chunkDivergenceL2Buf); 76 | _pooling.MaxAbsFloats(simulationState.chunkDivergenceL2Buf, simulationState.chunkDivergenceL3Buf); 77 | _copyBuffer.CopyFloats(1, 1, simulationState.chunkDivergenceL2Buf, simulationState.uBuf); 78 | } 79 | } 80 | } 81 | } 82 | 83 | } // namespace LiquidShader 84 | -------------------------------------------------------------------------------- /Assets/LiquidShader/ProjectJacobiInPlace.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 95d740faa4da5415bb59ea008454349b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/ProjectSelected.cs: -------------------------------------------------------------------------------- 1 | using LiquidShader.Types; 2 | using UnityEngine; 3 | #if UNITY_EDITOR 4 | using UnityEditor; 5 | #endif 6 | 7 | namespace LiquidShader { 8 | 9 | [RequireComponent(typeof(DivergenceCalculator))] 10 | public class ProjectSelected : MonoBehaviour { 11 | /* 12 | * clear divergence on selected cells 13 | */ 14 | ComputeShader _computeShader; 15 | DivergenceCalculator _divergenceCalculator; 16 | LiquidShaderRenderer _liquidShaderRenderer; // to get simulation state 17 | 18 | void OnEnable() { 19 | _divergenceCalculator = GetComponent(); 20 | _computeShader = Resources.Load("LiquidShader/ProjectSelected"); 21 | _liquidShaderRenderer = GetComponent(); 22 | } 23 | 24 | public void RunProjection() { 25 | var simulationState = _liquidShaderRenderer.simulationState; 26 | 27 | var kernel = _computeShader.FindKernel("ProjectSelected"); 28 | 29 | _computeShader.SetInt("_simResX", simulationState.simResX); 30 | _computeShader.SetInt("_simResY", simulationState.simResY); 31 | 32 | _computeShader.SetBuffer(kernel, "_horizVel", simulationState.uBuf.GetComputeBuffer()); 33 | _computeShader.SetBuffer(kernel, "_vertVel", simulationState.vBuf.GetComputeBuffer()); 34 | _computeShader.SetBuffer(kernel, "_selected", simulationState.selected.GetComputeBuffer()); 35 | _computeShader.SetBuffer(kernel, "_isFluid", simulationState.sBuf.GetComputeBuffer()); 36 | _computeShader.SetBuffer(kernel, "_debug", simulationState.debugBuf.GetComputeBuffer()); 37 | 38 | _computeShader.Dispatch( 39 | kernel, 40 | (simulationState.simResX + 8 - 1) / 8, 41 | (simulationState.simResY + 8 - 1) / 8, 42 | 1); 43 | 44 | _divergenceCalculator.CalcDivergence(simulationState); 45 | } 46 | 47 | #if UNITY_EDITOR 48 | [CustomEditor(typeof(ProjectSelected))] 49 | class ProjectSelectedEditor : Editor { 50 | public override void OnInspectorGUI() { 51 | base.OnInspectorGUI(); 52 | var projectSelected = (ProjectSelected)target; 53 | if (GUILayout.Button("Clear divergence on selected")) { 54 | projectSelected.RunProjection(); 55 | } 56 | } 57 | } 58 | #endif 59 | } 60 | 61 | } // namespace LiquidShader 62 | -------------------------------------------------------------------------------- /Assets/LiquidShader/ProjectSelected.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b0898c2ecc084e8597d55217d6bc6284 3 | timeCreated: 1689072427 -------------------------------------------------------------------------------- /Assets/LiquidShader/ProjectSingleCell.cs: -------------------------------------------------------------------------------- 1 | using LiquidShader.Types; 2 | using Utils; 3 | using UnityEngine; 4 | 5 | namespace LiquidShader { 6 | 7 | [RequireComponent(typeof(DivergenceCalculator))] 8 | public class ProjectSingleCell : MonoBehaviour { 9 | ComputeShader _computeShader; 10 | DivergenceCalculator _divergenceCalculator; 11 | 12 | void OnEnable() { 13 | _divergenceCalculator = GetComponent(); 14 | _computeShader = Resources.Load("LiquidShader/ProjectSingleCell"); 15 | } 16 | 17 | public void ProjectCell(SimulationState simulationState, int cellX, int cellY) { 18 | var kernel = _computeShader.FindKernel("ProjectSingleCell"); 19 | 20 | _computeShader.SetBuffer(kernel, "_horizVel", simulationState.uBuf.GetComputeBuffer()); 21 | _computeShader.SetBuffer(kernel, "_vertVel", simulationState.vBuf.GetComputeBuffer()); 22 | _computeShader.SetBuffer(kernel, "_isFluid", simulationState.sBuf.GetComputeBuffer()); 23 | _computeShader.SetBuffer(kernel, "_debug", simulationState.debugBuf.GetComputeBuffer()); 24 | 25 | _computeShader.SetInt("_simResX", simulationState.simResX); 26 | _computeShader.SetInt("_simResY", simulationState.simResY); 27 | _computeShader.SetInt("_updateX", cellX); 28 | _computeShader.SetInt("_updateY", cellY); 29 | 30 | _computeShader.Dispatch(kernel, 1, 1, 1); 31 | 32 | _divergenceCalculator.CalcDivergence(simulationState); 33 | } 34 | } 35 | 36 | } // namespace LiquidShader 37 | -------------------------------------------------------------------------------- /Assets/LiquidShader/ProjectSingleCell.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4eda0b932e57491fa20016179125ac0e 3 | timeCreated: 1689071644 -------------------------------------------------------------------------------- /Assets/LiquidShader/RenderArrows.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LiquidShader.Types; 3 | using UnityEngine; 4 | using Utils; 5 | 6 | namespace LiquidShader { 7 | public class RenderArrows : MonoBehaviour { 8 | [SerializeField] bool cellArrows = false; 9 | [SerializeField] bool staggeredArrows = false; 10 | [SerializeField] bool scaleArrowsWithSpeed = false; 11 | [SerializeField][Range(0f, 1f)] float arrowPushPullLambda = 0; 12 | // [SerializeField] bool arrowsInbound = false; 13 | // [SerializeField] bool arrowsCentered = false; 14 | [SerializeField] ArrowVelocityType arrowVelocityType = ArrowVelocityType.CellCenter; 15 | 16 | ComputeShader _renderingArrowsShader; 17 | 18 | void OnEnable() { 19 | _renderingArrowsShader = Resources.Load("LiquidShader/RenderingArrows"); 20 | } 21 | 22 | void RenderArrowsSpecificKernel( 23 | string kernelName, RenderTexture renderTexture, SimulationState simulationState, float speedDeltaTime, int[] renderRes 24 | ) { 25 | var shader = _renderingArrowsShader; 26 | var kernel = shader.FindKernel(kernelName); 27 | shader.SetBuffer(kernel, "_isFluid", simulationState.sBuf.GetComputeBuffer()); 28 | shader.SetBuffer(kernel, "_horizVel", simulationState.uBuf.GetComputeBuffer()); 29 | shader.SetBuffer(kernel, "_vertVel", simulationState.vBuf.GetComputeBuffer()); 30 | shader.SetBuffer(kernel, "_debug", simulationState.debugBuf.GetComputeBuffer()); 31 | shader.SetFloat("_arrowPushPullLambda", arrowPushPullLambda); 32 | // shader.SetBool("_arrowsCentered", arrowsCentered); 33 | shader.SetBuffer(kernel, "_floatsToRender", simulationState.divergenceBuf.GetComputeBuffer()); 34 | shader.SetTexture(kernel, "_renderTexture", renderTexture); 35 | shader.SetInts("_simRes", simulationState.SimResInts); 36 | shader.SetInts("_renderRes", renderRes); 37 | shader.SetBool("_arrowsForU", arrowVelocityType == ArrowVelocityType.U); 38 | shader.SetBool("_arrowsForV", arrowVelocityType == ArrowVelocityType.V); 39 | shader.SetFloat("_time", Time.time); 40 | shader.SetFloat("_speedDeltaTime", scaleArrowsWithSpeed ? speedDeltaTime : 1); 41 | shader.Dispatch(kernel, (simulationState.simResX + 8 - 1) / 8, (simulationState.simResY + 8 - 1) / 8, 1); 42 | } 43 | 44 | public void Render(RenderTexture renderTexture, SimulationState simulationState, float speedDeltaTime, int[] renderRes) { 45 | if (cellArrows) { 46 | RenderArrowsSpecificKernel("RenderArrows", renderTexture, simulationState, speedDeltaTime, renderRes); 47 | } 48 | if (staggeredArrows) { 49 | RenderArrowsSpecificKernel("RenderStaggeredArrows", renderTexture, simulationState, speedDeltaTime, renderRes); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Assets/LiquidShader/RenderArrows.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2ae44dd69628435397c113e07f2d154a 3 | timeCreated: 1688309763 -------------------------------------------------------------------------------- /Assets/LiquidShader/RenderDivergenceSpiral.cs: -------------------------------------------------------------------------------- 1 | using LiquidShader.Types; 2 | using UnityEngine; 3 | using Utils; 4 | 5 | namespace LiquidShader { 6 | public class RenderDivergenceSpiral : MonoBehaviour { 7 | [SerializeField][Range(0.01f, 1.0f)] float spiralRadius = 1; 8 | [SerializeField][Range(0.01f, 3.0f)] float rotationSpeed = 1; 9 | [SerializeField][Range(0.01f, 3.0f)] float radialSpeed = 1; 10 | [SerializeField] bool renderPositive = true; 11 | [SerializeField] bool renderNegative = true; 12 | [SerializeField] bool render = false; 13 | [SerializeField] Texture waterTexture; 14 | 15 | ComputeShader _renderDivergenceSpiralShader; 16 | 17 | void OnEnable() { 18 | _renderDivergenceSpiralShader = Resources.Load("LiquidShader/RenderDivergenceSpiral"); 19 | } 20 | 21 | public void RenderSpiral(RenderTexture renderTexture, SimulationState simulationState, float speedDeltaTime, int[] renderRes) { 22 | if (!render) return; 23 | // Debug.Log("render divergencespiral"); 24 | var shader = _renderDivergenceSpiralShader; 25 | var kernel = shader.FindKernel("Render"); 26 | shader.SetBuffer(kernel, "_texPosBase", simulationState.texPosBase.GetComputeBuffer()); 27 | shader.SetInt("_divergenceTexPosOffset", simulationState.divergenceTexPos.Offset); 28 | shader.SetBuffer(kernel, "_divergence", simulationState.divergenceBuf.GetComputeBuffer()); 29 | shader.SetTexture(kernel, "_renderTexture", renderTexture); 30 | shader.SetTexture(kernel, "_waterTexture", waterTexture); 31 | shader.SetInts("_simRes", simulationState.SimResInts); 32 | shader.SetBool("_renderPositive", renderPositive); 33 | shader.SetBool("_renderNegative", renderNegative); 34 | shader.SetInts("_renderRes", renderRes); 35 | shader.SetFloat("_speedDeltaTime", speedDeltaTime); 36 | shader.SetFloat("_spiralRadius", spiralRadius); 37 | shader.SetFloat("_rotationSpeed", rotationSpeed); 38 | shader.SetFloat("_radialSpeed", radialSpeed); 39 | shader.Dispatch(kernel, (renderRes[0] + 8 - 1) / 8, (renderRes[1] + 8 - 1) / 8, 1); 40 | } 41 | 42 | void UpdateDivergenceTexPos(SimulationState simulationState, float deltaTime, int[] renderRes) { 43 | var shader = _renderDivergenceSpiralShader; 44 | var kernel = shader.FindKernel("UpdateDivergenceTexPos"); 45 | shader.SetBuffer(kernel, "_texPosBase", simulationState.texPosBase.GetComputeBuffer()); 46 | shader.SetInt("_divergenceTexPosOffset", simulationState.divergenceTexPos.Offset); 47 | shader.SetBuffer(kernel, "_divergence", simulationState.divergenceBuf.GetComputeBuffer()); 48 | shader.SetFloat("_deltaTime", deltaTime); 49 | shader.SetInts("_renderRes", renderRes); 50 | shader.SetInts("_simRes", simulationState.SimResInts); 51 | shader.Dispatch( 52 | kernel, 53 | (simulationState.simResX + 8 - 1) / 8, 54 | (simulationState.simResY + 8 - 1) / 8, 55 | 1); 56 | } 57 | 58 | public void Render(RenderTexture renderTexture, SimulationState simulationState, float speed, float deltaTime, int[] renderRes) { 59 | float speedDeltaTime = speed * deltaTime; 60 | RenderSpiral(renderTexture, simulationState, speedDeltaTime, renderRes); 61 | UpdateDivergenceTexPos(simulationState, deltaTime, renderRes); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Assets/LiquidShader/RenderDivergenceSpiral.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 25c93e0c26eb4424a975f0601efd074f 3 | timeCreated: 1688338689 -------------------------------------------------------------------------------- /Assets/LiquidShader/RenderSelected.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LiquidShader.Types; 3 | using UnityEngine; 4 | using UnityEngine.UIElements; 5 | using Utils; 6 | 7 | namespace LiquidShader { 8 | public class RenderSelected : MonoBehaviour { 9 | [SerializeField] Color selectedColor = new Color(0, 0.5f, 1); 10 | [SerializeField] bool enable = false; 11 | 12 | LiquidShaderRenderer _liquidShaderRenderer; 13 | Rendering _rendering; 14 | 15 | ComputeShader _cellSelectionShader; 16 | ComputeShader _renderingSelectedCellsShader; 17 | 18 | void OnEnable() { 19 | _cellSelectionShader = Resources.Load("LiquidShader/CellSelection"); 20 | _renderingSelectedCellsShader = Resources.Load("LiquidShader/RenderingSelectedCells"); 21 | _rendering = GetComponent(); 22 | _liquidShaderRenderer = GetComponent(); 23 | } 24 | 25 | public void Render( 26 | RenderTexture renderTexture, SimulationState simulationState, int[] renderRes 27 | ) { 28 | if (!enable) return; 29 | var shader = _renderingSelectedCellsShader; 30 | var kernel = shader.FindKernel("RenderSelectedCells"); 31 | shader.SetInts("_simRes", simulationState.SimResInts); 32 | shader.SetInts("_renderRes", renderRes); 33 | shader.SetVector("_currentCellColor", selectedColor); 34 | shader.SetBuffer(kernel, "_selected", simulationState.selected.GetComputeBuffer()); 35 | shader.SetTexture(kernel, "_renderTexture", renderTexture); 36 | shader.Dispatch( 37 | kernel, 38 | (renderRes[0] + 8 - 1) / 8, 39 | (renderRes[1] + 8 - 1) / 8, 40 | 1); 41 | } 42 | 43 | public void SetSelected( 44 | SimulationState simulationState, int[] pos, int selected 45 | ) { 46 | if (!enable) return; 47 | var shader = _cellSelectionShader; 48 | var kernel = shader.FindKernel("SetSelected"); 49 | shader.SetInts("_simRes", simulationState.SimResInts); 50 | shader.SetInts("_tgtPos", pos); 51 | shader.SetInt("_newVal", selected); 52 | shader.SetBuffer(kernel, "_selected", simulationState.selected.GetComputeBuffer()); 53 | shader.Dispatch(kernel, 1, 1, 1); 54 | } 55 | 56 | void Update() { 57 | var simulationState = _liquidShaderRenderer.simulationState; 58 | if (Input.GetKey(KeyCode.LeftCommand) && Input.GetMouseButtonDown(0)) { 59 | if (ClickFilter.HitUI()) return; 60 | 61 | var simPos = ClickUtils.GetClickSimPos(_rendering, simulationState); 62 | var simPosInts = new int[] { 63 | simPos?.x ?? 0, simPos?.y ?? 0 64 | }; 65 | Debug.Log($"set selected {simPos} -1"); 66 | SetSelected(simulationState, simPosInts, -1); 67 | } else if (Input.GetKey(KeyCode.LeftCommand) && Input.GetKeyDown(KeyCode.Escape)) { 68 | Debug.Log("clearing selected"); 69 | var clearedSelected = new int[simulationState.simResX, simulationState.simResY]; 70 | simulationState.selected.SetData(clearedSelected); 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Assets/LiquidShader/RenderSelected.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c8ea5e4a9a7e48d3b2a441555a20b7f6 3 | timeCreated: 1688741830 -------------------------------------------------------------------------------- /Assets/LiquidShader/Rendering.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ed8444a5cb4a04c798a8055854619486 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3132288444da24a1aa87525241cb31a2 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1a6ba313d9534a59a62b04a1f956ea54 3 | timeCreated: 1688819364 -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/AddColor.compute: -------------------------------------------------------------------------------- 1 | #pragma kernel AddColor 2 | 3 | #define Buf RWStructuredBuffer 4 | 5 | Buf _horizVel; 6 | Buf _vertVel; 7 | Buf _isFluid; 8 | Buf _m; 9 | Buf _colorSources; 10 | 11 | int _simResX; 12 | int _simResY; 13 | 14 | float _speedDeltaTime; 15 | float _colorAddSpeed; 16 | bool _colorSet; 17 | 18 | #include "ShaderUtils.cginc" 19 | 20 | float4 mixColor(float4 cur, float4 col, float speed) { 21 | // cur = min(col, cur + speed * col * colorAddSpeed + 0.5f * rand(cur.xy)); 22 | if(_colorSet) { 23 | cur = col; 24 | } else { 25 | cur = min(col, cur + speed * col * _colorAddSpeed * (rand(cur.xy + float2(cur.z, 0.0)) * 0.5f + 0.5f)); 26 | } 27 | // cur = cur + speed * col * colorAddSpeed; 28 | // cur = col; 29 | return cur; 30 | } 31 | 32 | [numthreads(8,8,1)] 33 | void AddColor(uint3 id : SV_DispatchThreadID) 34 | { 35 | int2 pos = (int2)id; 36 | if(pos.x < _simResX && pos.y < _simResY) { 37 | int offset = pos.x * _simResY + pos.y; 38 | if(_isFluid[offset] == 1) { 39 | if(_colorSources[offset].w == 1) _m[offset] = mixColor(_m[offset], _colorSources[offset], length(float2(_horizVel[offset], _vertVel[offset])) * _speedDeltaTime); 40 | // if(s[L(offset)] == 0 && u[offset] > 0) m[offset] = mixColor(m[offset], colorSources[L(offset)], u[offset] * speedDeltaTime); 41 | // if(s[R(offset)] == 0 && u[R(offset)] < 0) m[offset] = mixColor(m[offset], colorSources[R(offset)], - u[R(offset)] * speedDeltaTime); 42 | // if(s[D(offset)] == 0 && v[offset] > 0) m[offset] = mixColor(m[offset], colorSources[D(offset)], v[offset] * speedDeltaTime); 43 | // if(s[U(offset)] == 0 && v[U(offset)] < 0) m[offset] = mixColor(m[offset], colorSources[U(offset)], -v[U(offset)] * speedDeltaTime); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/AddColor.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0d4594aee4d1840118075ff38b8ecd8d 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/AddNoise.compute: -------------------------------------------------------------------------------- 1 | /* 2 | Based on position and time/frame, add noise to a float buffer 3 | Only touch cells with s == 1 4 | */ 5 | 6 | // ReSharper disable CppInconsistentNaming 7 | #pragma kernel AddNoiseFloats 8 | #pragma kernel AddNoiseFloat4s 9 | 10 | #define Buf RWStructuredBuffer 11 | 12 | Buf _tgt; 13 | Buf _tgtFloat4s; 14 | 15 | Buf _isFluid; 16 | 17 | int _simResX; 18 | int _simResY; 19 | 20 | int _frame; 21 | int _seed; 22 | float _noiseAmount; 23 | bool _addNoise; 24 | float _decay; 25 | bool _sqrtNoise; 26 | 27 | #include "positions.cginc" 28 | #include "ShaderUtils.cginc" 29 | 30 | [numthreads(8,8,1)] 31 | void AddNoiseFloats(uint3 id: SV_DispatchThreadID) { 32 | if(_noiseAmount == 0) { 33 | return; 34 | } 35 | int2 pos = (int2)(id.xy); 36 | if(pos.x > 0 && pos.y > 0 && pos.x < _simResX - 1 && pos.y < _simResY - 1) { 37 | int offset = posiToIdx(pos); 38 | if(_isFluid[D(offset)] == 1 && _isFluid[offset] == 1) { 39 | float rand_v = rand(float2((float)pos.x / (float)_simResX, (float)pos.y / (float)_simResY) + 0.01 + frac(_frame / 100.0) / 5.0 + frac(_seed / 100.0) / 5.0); 40 | rand_v -= 0.5; 41 | // tgt[offset] *= 1 + (rand_v * noiseAmount); 42 | float noise = rand_v * _noiseAmount; 43 | // tgt[offset] *= 1 + noise; 44 | 45 | // tgt[offset] = min(1, max(-1, tgt[offset] + noise)); 46 | _tgt[offset] = _tgt[offset] + noise; 47 | /* 48 | y = (1 + a)x 49 | x = y / (1 + a) 50 | */ 51 | // if(noise > 0) { 52 | // rand_v -= 0.5; 53 | // tgt[offset] *= (1 + noise); 54 | // } else { 55 | // tgt[offset] *= (1 + noise); 56 | // } 57 | } 58 | } 59 | } 60 | 61 | [numthreads(8,8,1)] 62 | void AddNoiseFloat4s(uint3 id: SV_DispatchThreadID) { 63 | if(_noiseAmount == 0) { 64 | return; 65 | } 66 | int2 pos = (int2)(id.xy); 67 | if(pos.x > 0 && pos.y > 0 && pos.x < _simResX - 1 && pos.y < _simResY - 1) { 68 | int offset = posiToIdx(pos); 69 | if(_isFluid[D(offset)] == 1 && _isFluid[offset] == 1) { 70 | float4 rand_v = float4( 71 | rand(float2((float)pos.x / (float)_simResX, (float)pos.y / (float)_simResY) + 0.01 + frac(_frame / 100.0) / 5.0 + frac(_seed / 100.0) / 5.0), 72 | rand(float2((float)(pos.x + 47) / (float)_simResX, (float)pos.y / (float)_simResY) + 0.01 + frac(_frame / 100.0) / 5.0 + frac(_seed / 100.0) / 5.0), 73 | rand(float2((float)(pos.x + 101) / (float)_simResX, (float)pos.y / (float)_simResY) + 0.01 + frac(_frame / 100.0) / 5.0 + frac(_seed / 100.0) / 5.0), 74 | rand(float2((float)(pos.x + 137) / (float)_simResX, (float)pos.y / (float)_simResY) + 0.01 + frac(_frame / 100.0) / 5.0 + frac(_seed / 100.0) / 5.0) 75 | ); 76 | rand_v -= 0.5; 77 | float4 noise = rand_v; 78 | if(_sqrtNoise) { 79 | const bool sign = noise > 0; 80 | noise = noise * noise; 81 | noise = sign ? noise : - noise; 82 | } 83 | noise = noise * _noiseAmount; 84 | float4 newValue = _tgtFloat4s[offset]; 85 | if(_addNoise) { 86 | newValue = (newValue + noise); 87 | } else { 88 | newValue = newValue * (1 + noise); 89 | } 90 | // if(_decaySquared) { 91 | // newValue = newValue - _decay * newValue; 92 | // } else { 93 | newValue = (1 - _decay) * newValue; 94 | // } 95 | _tgtFloat4s[offset] = newValue; 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/AddNoise.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c5e71cbc6959c4efda4602a305dd2f33 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/Advect.compute: -------------------------------------------------------------------------------- 1 | #pragma kernel AdvectVelocity 2 | 3 | #define Buf RWStructuredBuffer 4 | 5 | Buf _horizVel; 6 | Buf _vertVel; 7 | Buf _newHorizVel; 8 | Buf _newVertVel; 9 | Buf _isFluid; 10 | 11 | int _simResX; 12 | int _simResY; 13 | 14 | float _speedDeltaTime; 15 | 16 | #include "positions.cginc" 17 | #include "interpolate.cginc" 18 | 19 | void AdvectHorizVelocity(int2 destPos, int destIdx) { 20 | if( 21 | destPos.x > 0 && destPos.y > 0 && destPos.y < _simResY - 1 && destPos.x < _simResX - 1 && 22 | _isFluid[destIdx] == 1 && _isFluid[L(destIdx)] == 1 23 | ) { 24 | float2 destVel = interpolateVelocityLeft(_horizVel, _vertVel, destPos, destIdx); 25 | float2 srcPosF = destPos - destVel * _speedDeltaTime; 26 | _newHorizVel[destIdx] = interpolateFractionalPosFloat(_horizVel, srcPosF); 27 | } else { 28 | _newHorizVel[destIdx] = _horizVel[destIdx]; 29 | } 30 | } 31 | 32 | void AdvectVertVelocity(int2 destPos, int destIdx) { 33 | if( 34 | destPos.x > 0 && destPos.y > 0 && destPos.y < _simResY - 1 && destPos.x < _simResX - 1 && 35 | _isFluid[destIdx] == 1 && _isFluid[D(destIdx)] == 1 36 | ) { 37 | float2 destVel = interpolateVelocityBottom(_horizVel, _vertVel, destPos, destIdx); 38 | float2 srcPosF = destPos - destVel * _speedDeltaTime; 39 | _newVertVel[destIdx] = interpolateFractionalPosFloat(_vertVel, srcPosF); 40 | } else { 41 | _newVertVel[destIdx] = _vertVel[destIdx]; 42 | } 43 | } 44 | 45 | [numthreads(8,8,1)] 46 | void AdvectVelocity(uint3 id: SV_DispatchThreadID) { 47 | int2 destPos = (int2)(id.xy); 48 | if(destPos.x >= _simResX || destPos.y >= _simResY) return; 49 | int destIdx = posiToIdx(destPos); 50 | AdvectHorizVelocity(destPos, destIdx); 51 | AdvectVertVelocity(destPos, destIdx); 52 | } 53 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/Advect.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ff05190ee757b407fa2e842edd555635 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/AdvectCellByCell.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e1b5a5cfc8a4f4a0b9cbf2f42e59ba31 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/AdvectFloat4.compute: -------------------------------------------------------------------------------- 1 | #pragma kernel AdvectFloat4 2 | 3 | #define Buf RWStructuredBuffer 4 | 5 | Buf _horizVel; 6 | Buf _vertVel; 7 | 8 | Buf _srcFloat4; 9 | Buf _destFloat4; 10 | 11 | Buf _debug; 12 | 13 | Buf _isFluid; 14 | 15 | int _simResX; 16 | int _simResY; 17 | 18 | float _speedDeltaTime; 19 | 20 | #define Buf RWStructuredBuffer 21 | 22 | #include "positions.cginc" 23 | #include "interpolate.cginc" 24 | 25 | [numthreads(8,8,1)] 26 | void AdvectFloat4(uint3 id: SV_DispatchThreadID) { 27 | int2 pos2 = (int2)(id.xy); 28 | if(pos2.x >= _simResX || pos2.y >= _simResY) return; 29 | 30 | int offset2 = posiToIdx(pos2); 31 | if(_isFluid[offset2] == 0) { 32 | _destFloat4[offset2] = _srcFloat4[offset2]; 33 | return; 34 | } 35 | 36 | float2 vel2 = getCellCenterVelocity(_horizVel, _vertVel, pos2, offset2); 37 | float2 pos1f = pos2.xy - vel2 * _speedDeltaTime; 38 | 39 | int2 pos1i; 40 | float2 lambda1; 41 | posfToPosiLambda(pos1f, pos1i, lambda1); 42 | int offset1 = posiToIdx(pos1i); 43 | if(pos1i.x <= 0 || pos1i.y <= 0 || pos1i.x >= _simResX - 1 || pos1i.y >= _simResY - 1) { 44 | _destFloat4[offset2] = 0; 45 | return; 46 | } 47 | 48 | float4 v = interpolateFloat4(_srcFloat4, offset1, lambda1); 49 | v = min(1, max(-1, v)); 50 | if(v[0] != v[0] || v[1] != v[1] || v[2] != v[2] || v[3] != v[3]) { 51 | // nan 52 | v = float4(0, 0,0,0); 53 | } 54 | _destFloat4[offset2] = v; 55 | } 56 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/AdvectFloat4.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 54048b6db93b43b69fce0111f3483ab2 3 | timeCreated: 1688818870 -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/AdvectPartials.compute: -------------------------------------------------------------------------------- 1 | #pragma kernel AdvectVelocity 2 | 3 | #define Buf RWStructuredBuffer 4 | 5 | Buf _horizVel; 6 | Buf _vertVel; 7 | Buf _newHorizVel; 8 | Buf _newVertVel; 9 | 10 | Buf _isFluid; 11 | 12 | Buf _debug; 13 | 14 | int _simResX; 15 | int _simResY; 16 | 17 | float _speedDeltaTime; 18 | 19 | #include "positions.cginc" 20 | #include "ShaderUtils.cginc" 21 | #include "interpolate.cginc" 22 | 23 | void AdvectVelocityU( 24 | int2 pos2, int offset2, 25 | Buf_newHorizVel, Buf _horizVel, Buf _vertVel, 26 | Buf_isFluid 27 | ) { 28 | if(pos2.x > 0 && pos2.y > 0 && pos2.y < _simResY - 1 && pos2.x < _simResX - 1 && _isFluid[offset2] == 1 && _isFluid[L(offset2)] == 1) { 29 | float2 vel_origin = interpolateVelocityLeftNoBoundsCheck(_horizVel, _vertVel, offset2); 30 | float2 vel_right = interpolateVelocityLeftNoBoundsCheck(_horizVel, _vertVel, R(offset2)); 31 | float2 vel_left = interpolateVelocityLeftNoBoundsCheck(_horizVel, _vertVel, L(offset2)); 32 | float2 vel_up = interpolateVelocityLeftNoBoundsCheck(_horizVel, _vertVel, U(offset2)); 33 | float2 vel_down = interpolateVelocityLeftNoBoundsCheck(_horizVel, _vertVel, D(offset2)); 34 | float du_dx = (vel_right.x - vel_left.x) / 2; 35 | float du_dy = (vel_up.y - vel_down.y) / 2; 36 | float u_du_dx = vel_origin.x * du_dx; 37 | _debug[offset2] = float3(u_du_dx, -u_du_dx, 0); 38 | // _debug[offset2] = float3(vel_origin.x, -vel_origin.x, 0); 39 | _newHorizVel[offset2] = _horizVel[offset2] - (vel_origin.x * du_dx - vel_origin.y * du_dy) * _speedDeltaTime; 40 | // float2 pos1f = pos2 - vel2 * _speedDeltaTime; 41 | // new_u[offset2] = interpolateFractionalPosFloat(u, pos1f); 42 | // new_u[offset2] = u[offset2]; 43 | } else { 44 | _newHorizVel[offset2] = _horizVel[offset2]; 45 | } 46 | } 47 | 48 | void AdvectVelocityV( 49 | int2 pos2, int offset2, 50 | Buf_newVertVel, Buf _vertVel, Buf _horizVel, 51 | Buf_isFluid 52 | ) { 53 | // if(pos2.x > 0 && pos2.y > 0 && pos2.y < _simResY - 1 && pos2.x < _simResX - 1 && s[offset2] == 1 && s[D(offset2)] == 1) { 54 | // float2 vel2 = interpolateVelocityBottom(u, v, pos2, offset2); 55 | // float2 pos1f = pos2 - vel2 * _speedDeltaTime; 56 | // new_v[offset2] = interpolateFractionalPosFloat(v, pos1f); 57 | // } else { 58 | _newVertVel[offset2] = _vertVel[offset2]; 59 | // } 60 | } 61 | 62 | [numthreads(8,8,1)] 63 | void AdvectVelocity(uint3 id: SV_DispatchThreadID) { 64 | int2 pos = (int2)(id.xy); 65 | if(pos.x < _simResX && pos.y < _simResY) { 66 | int offset = posiToIdx(pos); 67 | AdvectVelocityU(pos, offset, _newHorizVel, _horizVel, _vertVel, _isFluid); 68 | AdvectVelocityV(pos, offset, _newVertVel, _vertVel, _horizVel, _isFluid); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/AdvectPartials.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 69929112cfe8e4c2c8ab2326eba0e657 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/AdvectTests.compute: -------------------------------------------------------------------------------- 1 | #pragma kernel kGetCellCenterVelocity 2 | #pragma kernel kInterpolateVelocityLeft 3 | #pragma kernel kInterpolateVelocityBottom 4 | #pragma kernel kInterpolateFractionalPosFloat 5 | 6 | #define Buf RWStructuredBuffer 7 | 8 | Buf _horizVel; 9 | Buf _vertVel; 10 | Buf _newHorizVel; 11 | Buf _newVertVel; 12 | 13 | Buf _srcFloat4; 14 | Buf _destFloat4; 15 | 16 | Buf _debug; 17 | 18 | Buf _isFluid; 19 | 20 | int _simResX; 21 | int _simResY; 22 | 23 | float _speedDeltaTime; 24 | 25 | #define Buf RWStructuredBuffer 26 | 27 | #include "positions.cginc" 28 | #include "interpolate.cginc" 29 | 30 | [numthreads(1,1,1)] 31 | void kInterpolateVelocityBottom(uint3 id: SV_DispatchThreadID) { 32 | int2 pos = (int2)(id.xy); 33 | if(pos.x < _simResX && pos.y < _simResY) { 34 | int offset = posiToIdx(pos); 35 | float2 vInterp = interpolateVelocityBottom(_horizVel, _vertVel, pos, offset); 36 | _destFloat4[offset] = float4(vInterp, 0, 0); 37 | } 38 | } 39 | 40 | [numthreads(1,1,1)] 41 | void kGetCellCenterVelocity(uint3 id: SV_DispatchThreadID) { 42 | int2 pos = (int2)(id.xy); 43 | if(pos.x < _simResX && pos.y < _simResY) { 44 | int offset = posiToIdx(pos); 45 | // destFloat3[offset] = float3((float)(pos.x), (float)(pos.y), 0); 46 | _destFloat4[offset] = float4(getCellCenterVelocity(_horizVel, _vertVel, pos, offset), 0, 0); 47 | } 48 | } 49 | 50 | [numthreads(1,1,1)] 51 | void kInterpolateFractionalPosFloat(uint3 id: SV_DispatchThreadID) { 52 | /* 53 | We need: 54 | - src array (float) => map to u 55 | - fractional pos (float2) => map to srcFloat4.xy 56 | 57 | - output (float) => map to u2 58 | */ 59 | int2 pos = (int2)(id.xy); 60 | if(pos.x < _simResX && pos.y < _simResY) { 61 | int offset = posiToIdx(pos); 62 | float2 fracPos = _srcFloat4[offset].xy; 63 | float interpolated = interpolateFractionalPosFloat(_horizVel, fracPos); 64 | _newHorizVel[offset] = interpolated; 65 | } 66 | } 67 | 68 | [numthreads(1,1,1)] 69 | void kInterpolateVelocityLeft(uint3 id: SV_DispatchThreadID) { 70 | int2 pos = (int2)(id.xy); 71 | if(pos.x < _simResX && pos.y < _simResY) { 72 | int offset = posiToIdx(pos); 73 | float2 uInterp = interpolateVelocityLeft(_horizVel, _vertVel, pos, offset); 74 | _destFloat4[offset] = float4(uInterp, 0, 0); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/AdvectTests.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f570bc15c73e4153908063b87b8d25bd 3 | timeCreated: 1688819615 -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/CellSelection.compute: -------------------------------------------------------------------------------- 1 | 2 | // ReSharper disable CppInitializedValueIsAlwaysRewritten 3 | #pragma kernel SetSelected 4 | 5 | #define Buf RWStructuredBuffer 6 | 7 | Buf _selected; 8 | 9 | int2 _tgtPos; 10 | int _newVal; 11 | 12 | int2 _simRes; 13 | 14 | #define _simResX _simRes.x 15 | #define _simResY _simRes.y 16 | 17 | #include "positions.cginc" 18 | 19 | [numthreads(8,8,1)] 20 | void SetSelected(uint3 id : SV_DispatchThreadID) 21 | { 22 | if(id.x != 0 || id.y != 0) return; 23 | int offset = posiToIdx(_tgtPos); 24 | if(_newVal < 0) { 25 | _selected[offset] = 1 - _selected[offset]; 26 | } else { 27 | _selected[offset] = _newVal; 28 | } 29 | // _selected[offset] = 1; 30 | } 31 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/CellSelection.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ca8fefbfe9464c2fa606cf9f9fa86b3b 3 | timeCreated: 1688741714 -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/Copy.compute: -------------------------------------------------------------------------------- 1 | #pragma kernel CopyFloat4s 2 | #pragma kernel CopyFloats 3 | 4 | #define Buf RWStructuredBuffer 5 | 6 | Buf _srcFloat4s; 7 | Buf _destFloat4s; 8 | 9 | Buf _srcFloats; 10 | Buf _destFloats; 11 | 12 | int _srcOffset; 13 | int _destOffset; 14 | 15 | int _simResX; 16 | int _simResY; 17 | 18 | // #include "ShaderUtils.cginc" 19 | 20 | [numthreads(8,8,1)] 21 | void CopyFloat4s(uint3 id : SV_DispatchThreadID) 22 | { 23 | int2 pos = (uint2)(id.xy); 24 | if(pos.x < _simResX && pos.y < _simResY) { 25 | int simOffset = pos.x * _simResY + pos.y; 26 | _destFloat4s[_destOffset + simOffset] = _srcFloat4s[_srcOffset + simOffset]; 27 | } 28 | } 29 | 30 | [numthreads(8,8,1)] 31 | void CopyFloats(uint3 id : SV_DispatchThreadID) 32 | { 33 | int2 pos = (uint2)(id.xy); 34 | if(pos.x < _simResX && pos.y < _simResY) { 35 | int simOffset = pos.x * _simResY + pos.y; 36 | _destFloats[_destOffset + simOffset] = _srcFloats[_srcOffset + simOffset]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/Copy.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 305cdc845620b426aa3cfe9a7f83c414 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/Divergence.compute: -------------------------------------------------------------------------------- 1 | #pragma kernel CalcDivergence 2 | 3 | // ReSharper disable once CppInconsistentNaming 4 | #define Buf RWStructuredBuffer 5 | 6 | Buf _horizVel; 7 | Buf _vertVel; 8 | 9 | Buf _isFluid; 10 | Buf _divergence; 11 | 12 | int _simResX; 13 | int _simResY; 14 | 15 | #include "positions.cginc" 16 | 17 | [numthreads(8,8,1)] 18 | void CalcDivergence(uint3 id: SV_DispatchThreadID) { 19 | int2 pos = (int2)(id.xy); 20 | if(pos.x >= _simResX || pos.y >= _simResY) return; 21 | 22 | float divergence = 0; 23 | 24 | int idx = posiToIdx(pos); 25 | if(_isFluid[idx] == 1) { 26 | float horizVelRight = pos.x < _simResX - 1 ? _horizVel[RIGHT(idx)] : 0; 27 | float vertVelUp = pos.y < _simResY - 1 ? _vertVel [ UP(idx)] : 0; 28 | divergence = 29 | - _horizVel[idx] + horizVelRight 30 | - _vertVel [idx] + vertVelUp; 31 | } 32 | 33 | _divergence[idx] = divergence; 34 | } 35 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/Divergence.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fd01e38c88c404412b60585c20f9458a 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/Draw.compute: -------------------------------------------------------------------------------- 1 | /* 2 | */ 3 | #pragma kernel DrawFloat4 4 | #pragma kernel DrawFloat 5 | #pragma kernel DrawVelU 6 | #pragma kernel DrawVelV 7 | #pragma kernel DrawInt 8 | 9 | #define Buf RWStructuredBuffer 10 | 11 | Buf _isFluid; 12 | Buf _tgtFloat4; 13 | Buf _tgtFloat; 14 | Buf _tgtInt; 15 | 16 | float4 _drawColor; 17 | float _drawFloatValue; 18 | int _drawIntValue; 19 | float2 _tgtPos; 20 | float _drawRadius; 21 | bool _drawPersistVel; 22 | 23 | int _simResX; 24 | int _simResY; 25 | 26 | float _colorDrawLambda; 27 | 28 | #define _SimResX _simResX 29 | #define _SimResY _simResY 30 | 31 | #include "positions.cginc" 32 | 33 | float4 mixColor(float4 cur, const float4 col, const float lambda) { 34 | // cur = min(col, cur + speed * col); 35 | cur = (1 - lambda) * cur + lambda * col; 36 | return cur; 37 | } 38 | 39 | float mixFloat(float cur, const float col, float lambda) { 40 | cur = (1 - lambda) * cur + lambda * col; 41 | return cur; 42 | } 43 | 44 | [numthreads(8,8,1)] 45 | void DrawFloat4(uint3 id : SV_DispatchThreadID) 46 | { 47 | /* 48 | Takes in a float4, and a position, and draws that color at that position, 49 | within a radius radius 50 | 51 | Each thread handles updating its own pixel in tgt 52 | 53 | Only draws where s == 1 54 | 55 | Inputs: 56 | - Buf tgtFloat4 57 | - int2 tgtPos 58 | - int SimResX 59 | - int SimResY 60 | - float drawRadius 61 | - float4 drawColor 62 | - Buf s 63 | - float colorAddSpeed 64 | 65 | Outputs: 66 | - Buf tgt 67 | */ 68 | int2 pos = (int2)id; 69 | if(pos.x < _simResX && pos.y < _simResY) { 70 | int offset = pos.x * _simResY + pos.y; 71 | if(_isFluid[offset] == 1) { 72 | if(length(pos - _tgtPos) <= _drawRadius) { 73 | _tgtFloat4[offset] = mixColor(_tgtFloat4[offset], _drawColor, _colorDrawLambda); 74 | } 75 | } 76 | } 77 | } 78 | 79 | 80 | [numthreads(8,8,1)] 81 | void DrawFloat(uint3 id : SV_DispatchThreadID) 82 | { 83 | /* 84 | Takes in a float4, and a position, and draws that color at that position, 85 | within a radius radius 86 | 87 | Each thread handles updating its own pixel in tgt 88 | 89 | Only draws where s == 1 90 | 91 | Inputs: 92 | - Buf tgtFloat 93 | - int2 tgtPos 94 | - int SimResX 95 | - int SimResY 96 | - float drawRadius 97 | - float drawFloatValue 98 | - Buf s 99 | - float colorAddSpeed 100 | 101 | Outputs: 102 | - Buf tgt 103 | */ 104 | int2 pos = (int2)id; 105 | if(pos.x > 0 && pos.y > 0 && pos.x < _simResX && pos.y < _simResY) { 106 | int offset = pos.x * _simResY + pos.y; 107 | if(_isFluid[offset] == 1) { 108 | if(length(pos - _tgtPos) <= _drawRadius) { 109 | _tgtFloat[offset] = mixFloat(_tgtFloat[offset], _drawFloatValue, _colorDrawLambda); 110 | } 111 | } 112 | } 113 | } 114 | 115 | [numthreads(8,8,1)] 116 | void DrawVelU(uint3 id : SV_DispatchThreadID) 117 | { 118 | int2 pos = (int2)id; 119 | if(pos.x > 0 && pos.y > 0 && pos.x < _simResX && pos.y < _simResY) { 120 | int offset = pos.x * _simResY + pos.y; 121 | if(!_drawPersistVel && !(_isFluid[offset] && _isFluid[L(offset)])) return; 122 | if(length(pos - _tgtPos) > _drawRadius) return; 123 | _tgtFloat[offset] = mixFloat(_tgtFloat[offset], _drawFloatValue, _colorDrawLambda); 124 | // if(_drawPersistVel) _isFluid[offset] = 0; 125 | } 126 | } 127 | 128 | [numthreads(8,8,1)] 129 | void DrawVelV(uint3 id : SV_DispatchThreadID) 130 | { 131 | int2 pos = (int2)id; 132 | if(pos.x > 0 && pos.y > 0 && pos.x < _simResX && pos.y < _simResY) { 133 | int offset = pos.x * _simResY + pos.y; 134 | // if(_isFluid[offset] == 1 && _isFluid[D(offset)] == 1) { 135 | // if(length(pos - _tgtPos) <= _drawRadius) { 136 | if(!_drawPersistVel && !(_isFluid[offset] && _isFluid[D(offset)])) return; 137 | if(length(pos - _tgtPos) > _drawRadius) return; 138 | _tgtFloat[offset] = mixFloat(_tgtFloat[offset], _drawFloatValue, _colorDrawLambda); 139 | } 140 | } 141 | 142 | [numthreads(8,8,1)] 143 | void DrawInt(uint3 id : SV_DispatchThreadID) 144 | { 145 | /* 146 | Takes in a float4, and a position, and draws that color at that position, 147 | within a radius radius 148 | 149 | Each thread handles updating its own pixel in tgt 150 | 151 | ignores s (since designed mostly to draw in s...) 152 | 153 | Inputs: 154 | - int2 tgtPos 155 | - int SimResX 156 | - int SimResY 157 | - float drawRadius 158 | - int drawIntValue 159 | 160 | Outputs: 161 | - Buf tgtInt 162 | */ 163 | int2 pos = (int2)id; 164 | if(pos.x > 0 && pos.y > 0 && pos.x < _simResX - 1 && pos.y < _simResY - 1) { 165 | int offset = pos.x * _simResY + pos.y; 166 | if(length(pos - _tgtPos) <= _drawRadius) { 167 | _tgtInt[offset] = _drawIntValue; 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/Draw.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 03ec3afd708e842ca814687f5ddf73ce 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/Fill.compute: -------------------------------------------------------------------------------- 1 | #pragma kernel FillFloats 2 | 3 | #define Buf RWStructuredBuffer 4 | 5 | Buf _tgtFloats; 6 | 7 | float _valueFloat; 8 | 9 | int _tgtOffset; 10 | 11 | int _simResX; 12 | int _simResY; 13 | 14 | [numthreads(8,8,1)] 15 | void FillFloats(uint3 id : SV_DispatchThreadID) 16 | { 17 | int2 pos = (uint2)(id.xy); 18 | if(pos.x < _simResX && pos.y < _simResY) { 19 | int simOffset = pos.x * _simResY + pos.y; 20 | _tgtFloats[_tgtOffset + simOffset] = _valueFloat;; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/Fill.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: effce33648b6642238afe990542e30ff 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/Pooling.compute: -------------------------------------------------------------------------------- 1 | #pragma kernel MaxAbsBuffer 2 | #pragma kernel AbsThresholdPooling 3 | 4 | #define Buf RWStructuredBuffer 5 | 6 | #define THREAD_BLOCK_SIZE 8 // assume they are squared, to simplify 7 | #define CHUNK_SIZE 8 // assume they are squared, to simplify 8 | #define LOG2_CHUNK_SIZE 3 // for division 9 | 10 | Buf _src; 11 | Buf _dest; 12 | 13 | int2 _simRes; 14 | 15 | int _chunkOverlap; 16 | 17 | float _divergenceThreshold; 18 | 19 | #define _simResX (_simRes.x) 20 | #define _simResY (_simRes.y) 21 | 22 | [numthreads(THREAD_BLOCK_SIZE, THREAD_BLOCK_SIZE, 1)] 23 | void MaxAbsBuffer(uint3 id : SV_DispatchThreadID) 24 | { 25 | int2 pos = (int2)id; 26 | 27 | int2 chunkPos = pos; 28 | int2 chunkRes = (_simRes + CHUNK_SIZE - 1) >> LOG2_CHUNK_SIZE; 29 | if(chunkPos.x < chunkRes.x && chunkPos.y < chunkRes.y) { 30 | int2 chunkStart = max(0, chunkPos << LOG2_CHUNK_SIZE - _chunkOverlap); 31 | int2 chunkEndExcl = min(_simRes, chunkStart + CHUNK_SIZE + _chunkOverlap); 32 | float maxValue = 0.0; 33 | for(int i = chunkStart.x; i < chunkEndExcl.x; i++) { 34 | int srcOffsetI = i * _simRes.y; 35 | for(int j = chunkStart.y; j < chunkEndExcl.y; j++) { 36 | int srcOffset = srcOffsetI + j; 37 | float currentValue = abs(_src[srcOffset]); 38 | maxValue = max(maxValue, currentValue); 39 | } 40 | } 41 | int tgtOffset = chunkPos.x * chunkRes.y + chunkPos.y; 42 | _dest[tgtOffset] = maxValue; 43 | } 44 | } 45 | 46 | [numthreads(THREAD_BLOCK_SIZE, THREAD_BLOCK_SIZE, 1)] 47 | void AbsThresholdPooling(uint3 id : SV_DispatchThreadID) 48 | { 49 | int2 pos = (int2)id; 50 | 51 | int2 chunkPos = pos; 52 | int2 chunkRes = (_simRes + CHUNK_SIZE - 1) >> LOG2_CHUNK_SIZE; 53 | if(chunkPos.x < chunkRes.x && chunkPos.y < chunkRes.y) { 54 | int2 chunkStart = chunkPos << LOG2_CHUNK_SIZE; 55 | // first use chunkStart to calculate chunkEndExcl... 56 | int2 chunkEndExcl = min(_simRes, chunkStart + CHUNK_SIZE + _chunkOverlap); 57 | // ... and then subtract chunkOverlap 58 | chunkStart = max(0, chunkStart - _chunkOverlap); 59 | float maxValue = 0.0; 60 | for(int i = chunkStart.x; i < chunkEndExcl.x; i++) { 61 | int srcOffsetI = i * _simRes.y; 62 | for(int j = chunkStart.y; j < chunkEndExcl.y; j++) { 63 | int srcOffset = srcOffsetI + j; 64 | float currentValue = abs(_src[srcOffset]); 65 | if(currentValue >= _divergenceThreshold) { 66 | maxValue = 1; 67 | } 68 | } 69 | } 70 | int tgtOffset = chunkPos.x * chunkRes.y + chunkPos.y; 71 | _dest[tgtOffset] = maxValue; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/Pooling.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5a1624e15de4c437fbe80621586dc656 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/ProjectGaussSeidelClean.compute: -------------------------------------------------------------------------------- 1 | #pragma kernel ProjectGaussSeidel 2 | 3 | #define Buf RWStructuredBuffer 4 | Buf _horizVel; 5 | Buf _vertVel; 6 | Buf _isFluid; 7 | 8 | int2 _passOffset; 9 | int _simResX; 10 | int _simResY; 11 | 12 | #include "positions.cginc" 13 | 14 | [numthreads(8,8,1)] 15 | void ProjectGaussSeidel(uint3 threadId: SV_DispatchThreadID) { 16 | int2 pos = (threadId.xy << 1) + _passOffset; 17 | if(pos.x <= 0 || pos.y <= 0 || pos.x >= _simResX - 1 || pos.y >= _simResY - 1) return; 18 | 19 | int idx = posiToIdx(pos); 20 | if(_isFluid[idx] == 0) return; 21 | 22 | int numFluidNeighbors = _isFluid[LEFT(idx)] + _isFluid[RIGHT(idx)] + _isFluid[UP(idx)] + _isFluid[DOWN(idx)]; 23 | if(numFluidNeighbors == 0) return; 24 | 25 | float divergence = - _horizVel[idx] + _horizVel[RIGHT(idx)] - _vertVel[idx] + _vertVel [UP(idx)]; 26 | float deltaVel = divergence / numFluidNeighbors; 27 | 28 | if (_isFluid[ LEFT(idx)]) _horizVel[ idx ] += deltaVel; 29 | if (_isFluid[RIGHT(idx)]) _horizVel[RIGHT(idx)] -= deltaVel; 30 | if (_isFluid[ DOWN(idx)]) _vertVel [ idx ] += deltaVel; 31 | if (_isFluid[ UP(idx)]) _vertVel [ UP(idx)] -= deltaVel; 32 | } 33 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/ProjectGaussSeidelClean.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 52ed3b1a0f004971bdfe6e1a31dc1d42 3 | timeCreated: 1688760920 -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/ProjectGaussSeidelGeneral.compute: -------------------------------------------------------------------------------- 1 | #pragma kernel ProjectGaussSeidelGeneral 2 | 3 | #define Buf RWStructuredBuffer 4 | 5 | Buf _horizVel; 6 | Buf _vertVel; 7 | 8 | Buf _isFluid; 9 | Buf _divergence; 10 | Buf _divergenceChunks; 11 | 12 | Buf _debug; 13 | 14 | int2 _passOffset; 15 | 16 | int _simResX; 17 | int _simResY; 18 | 19 | int _useDivergenceChunks; 20 | int _divergenceChunkSizeLog2; 21 | 22 | int _saveDivergence; 23 | 24 | #include "positions.cginc" 25 | 26 | [numthreads(8,8,1)] 27 | void ProjectGaussSeidelGeneral(uint3 id: SV_DispatchThreadID) { 28 | int2 pos = (int2)(id.xy); 29 | 30 | pos = (pos << 1) + _passOffset; 31 | 32 | if(pos.x >= _simResX || pos.y >= _simResY) { 33 | return; 34 | } 35 | 36 | int2 simRes = int2(_simResX, _simResY); 37 | int offset = pos.x * _simResY + pos.y; 38 | 39 | if(_useDivergenceChunks) { 40 | int2 chunkPos = pos >> _divergenceChunkSizeLog2; 41 | int2 chunkRes = simRes >> _divergenceChunkSizeLog2; 42 | int chunkOffset = chunkPos.x * chunkRes.y + chunkPos.y; 43 | float div = _divergenceChunks[chunkOffset]; 44 | if(div == 0) { 45 | return; 46 | } 47 | } 48 | 49 | float divergence = 0; 50 | if(pos.x > 0 && pos.y > 0 && pos.x < _simResX - 1 && pos.y < _simResY - 1) { 51 | if(_isFluid[offset] == 1) { 52 | int s_sum = _isFluid[L(offset)] + _isFluid[R(offset)] + _isFluid[U(offset)] + _isFluid[D(offset)]; 53 | if(s_sum > 0) { 54 | divergence = - _horizVel[offset] + _horizVel[R(offset)] - _vertVel[offset] + _vertVel[U(offset)]; 55 | float correction = divergence / s_sum; 56 | if (_isFluid[L(offset)]) _horizVel[offset] += correction; 57 | if (_isFluid[R(offset)]) _horizVel[R(offset)] -= correction; 58 | if (_isFluid[D(offset)]) _vertVel[offset] += correction; 59 | if (_isFluid[U(offset)]) _vertVel[U(offset)] -= correction; 60 | } 61 | } 62 | } 63 | if(_saveDivergence) { 64 | _divergence[offset] = divergence; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/ProjectGaussSeidelGeneral.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 43ec8801611254134a5448a2e18bf0dc 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/ProjectJacobi.compute: -------------------------------------------------------------------------------- 1 | #pragma kernel Project1 2 | #pragma kernel Project2 3 | 4 | #define Buf RWStructuredBuffer 5 | 6 | Buf _horizVel; 7 | Buf _vertVel; 8 | Buf _u23; 9 | Buf _v23; 10 | 11 | int _u2Offset; 12 | int _u3Offset; 13 | int _v2Offset; 14 | int _v3Offset; 15 | 16 | Buf _isFluid; 17 | Buf _divergence; 18 | Buf _divergenceChunks; 19 | 20 | Buf _debug; 21 | 22 | int _simResX; 23 | int _simResY; 24 | 25 | int _useDivergenceChunks; 26 | int _divergenceChunkSizeLog2; 27 | 28 | int _saveDivergence; 29 | 30 | #include "positions.cginc" 31 | 32 | [numthreads(8,8,1)] 33 | void Project1(uint3 id: SV_DispatchThreadID) { 34 | /* 35 | inputs: 36 | - u 37 | - v 38 | - s 39 | - simResX 40 | - simResY 41 | - divergence chunks 42 | 43 | outputs: 44 | - u2 45 | - v2 46 | - u3 47 | - v3 48 | */ 49 | int2 pos = (int2)(id.xy); 50 | 51 | if(pos.x >= _simResX || pos.y >= _simResY) { 52 | return; 53 | } 54 | int2 simRes = int2(_simResX, _simResY); 55 | int offset = pos.x * _simResY + pos.y; 56 | 57 | if(_useDivergenceChunks) { 58 | int2 chunkPos = pos >> _divergenceChunkSizeLog2; 59 | int2 chunkRes = simRes >> _divergenceChunkSizeLog2; 60 | int chunkOffset = chunkPos.x * chunkRes.y + chunkPos.y; 61 | float div = _divergenceChunks[chunkOffset]; 62 | if(div == 0) { 63 | return; 64 | } 65 | } 66 | 67 | float d = 0; 68 | float u_right = 0; 69 | float u_here = 0; 70 | float v_up = 0; 71 | float v_here = 0; 72 | if(pos.x > 0 && pos.y > 0 && pos.x < _simResX - 1 && pos.y < _simResY - 1) { 73 | if(_isFluid[offset] == 1) { 74 | int s_sum = 75 | _isFluid[L(offset)] + 76 | _isFluid[R(offset)] + 77 | _isFluid[U(offset)] + 78 | _isFluid[D(offset)]; 79 | if(s_sum != 0) { 80 | d = 81 | - _horizVel[offset] + _horizVel[R(offset)] 82 | - _vertVel[offset] + _vertVel[U(offset)]; 83 | float d_pre = d * 0.5 / s_sum; 84 | u_here = _isFluid[L(offset)] == 1 ? d_pre : 0; 85 | u_right = _isFluid[R(offset)] == 1 ? - d_pre : 0; 86 | v_here = _isFluid[D(offset)] == 1 ? d_pre : 0; 87 | v_up = _isFluid[U(offset)] == 1 ? - d_pre : 0; 88 | } 89 | } 90 | } 91 | if(pos.x < _simResX && pos.y < _simResY) { 92 | if(pos.x < _simResX - 1) _u23[_u2Offset + R(offset)] = u_right; 93 | if(pos.y < _simResY - 1) _v23[_v2Offset + U(offset)] = v_up; 94 | _u23[_u3Offset + offset] = _horizVel[offset] + u_here; 95 | _v23[_v3Offset + offset] = _vertVel[offset] + v_here; 96 | 97 | if(_saveDivergence) { 98 | _divergence[offset] = d; 99 | } 100 | } 101 | } 102 | 103 | [numthreads(8,8,1)] 104 | void Project2(uint3 id: SV_DispatchThreadID) { 105 | /* 106 | inputs: 107 | - u2 108 | - v2 109 | - u3 110 | - v3 111 | - s 112 | - simResX 113 | - simResY 114 | - divergence chunks 115 | 116 | outputs: 117 | - u 118 | - v 119 | */ 120 | int2 pos = (int2)(id.xy); 121 | 122 | if(pos.x >= _simResX || pos.y >= _simResY) { 123 | return; 124 | } 125 | int2 simRes = int2(_simResX, _simResY); 126 | int offset = pos.x * _simResY + pos.y; 127 | 128 | if(_useDivergenceChunks) { 129 | int2 chunkPos = pos >> _divergenceChunkSizeLog2; 130 | int2 chunkRes = simRes >> _divergenceChunkSizeLog2; 131 | int chunkOffset = chunkPos.x * chunkRes.y + chunkPos.y; 132 | float div = _divergenceChunks[chunkOffset]; 133 | if(div == 0) { 134 | return; 135 | } 136 | } 137 | 138 | if(pos.x < _simResX && pos.y < _simResY) { 139 | if(_isFluid[offset] == 1) { 140 | float u2_offset = pos.x > 1 ? _u23[_u2Offset + offset] : 0; 141 | float v2_offset = pos.y > 1 ? _v23[_v2Offset + offset] : 0; 142 | _horizVel[offset] = u2_offset + _u23[_u3Offset + offset]; 143 | _vertVel[offset] = v2_offset + _v23[_v3Offset + offset]; 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/ProjectJacobi.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ecd5117c707b64da3b1d04560453c2c8 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/ProjectJacobiInplace.compute: -------------------------------------------------------------------------------- 1 | #pragma kernel ProjectJacobiInPlace 2 | 3 | #define Buf RWStructuredBuffer 4 | 5 | Buf _horizVel; 6 | Buf _vertVel; 7 | 8 | Buf _isFluid; 9 | Buf _divergence; 10 | Buf _divergenceChunks; 11 | 12 | Buf _debug; 13 | 14 | int _simResX; 15 | int _simResY; 16 | 17 | int _useDivergenceChunks; 18 | int _divergenceChunkSize; 19 | int _divergenceChunkSizeLog2; 20 | float _divergenceThreshold; 21 | 22 | int _saveDivergence; 23 | 24 | float _speedDeltaTime; 25 | float _deltaTime; 26 | 27 | #include "positions.cginc" 28 | 29 | [numthreads(8,8,1)] 30 | void ProjectJacobiInPlace(uint3 id: SV_DispatchThreadID) { 31 | /* 32 | inputs: 33 | - u 34 | - v 35 | - s 36 | - simResX 37 | - simResY 38 | - divergence chunks 39 | 40 | outputs: 41 | - u 42 | - v 43 | */ 44 | int2 pos = (int2)(id.xy); 45 | 46 | if(pos.x >= _simResX || pos.y >= _simResY) { 47 | return; 48 | } 49 | 50 | int2 simRes = int2(_simResX, _simResY); 51 | int offset = pos.x * _simResY + pos.y; 52 | 53 | if(_useDivergenceChunks) { 54 | int2 chunkPos = pos >> _divergenceChunkSizeLog2; 55 | int2 chunkRes = simRes >> _divergenceChunkSizeLog2; 56 | int chunkOffset = chunkPos.x * chunkRes.y + chunkPos.y; 57 | float div = _divergenceChunks[chunkOffset]; 58 | if(div == 0) { 59 | return; 60 | } 61 | } 62 | 63 | float d = 0; 64 | float u_right = 0; 65 | float u_here = 0; 66 | float v_up = 0; 67 | float v_here = 0; 68 | if(pos.x > 0 && pos.y > 0 && pos.x < _simResX - 1 && pos.y < _simResY - 1) { 69 | if(_isFluid[offset] == 1) { 70 | int s_sum = 71 | _isFluid[L(offset)] + 72 | _isFluid[R(offset)] + 73 | _isFluid[U(offset)] + 74 | _isFluid[D(offset)]; 75 | if(s_sum != 0) { 76 | d = 77 | - _horizVel[offset] + _horizVel[R(offset)] 78 | - _vertVel[offset] + _vertVel[U(offset)]; 79 | float d_pre = d / s_sum; 80 | u_here = _isFluid[L(offset)] == 1 ? d_pre : 0; 81 | u_right = _isFluid[R(offset)] == 1 ? - d_pre : 0; 82 | v_here = _isFluid[D(offset)] == 1 ? d_pre : 0; 83 | v_up = _isFluid[U(offset)] == 1 ? - d_pre : 0; 84 | } 85 | } 86 | } 87 | GroupMemoryBarrierWithGroupSync(); 88 | if(pos.x < _simResX - 1) _horizVel[R(offset)] += u_right; 89 | if(pos.y < _simResY - 1) _vertVel[U(offset)] += v_up; 90 | GroupMemoryBarrierWithGroupSync(); 91 | _horizVel[offset] = _horizVel[offset] + u_here; 92 | _vertVel[offset] = _vertVel[offset] + v_here; 93 | GroupMemoryBarrierWithGroupSync(); 94 | 95 | if(_saveDivergence) { 96 | _divergence[offset] = d; 97 | } 98 | // } 99 | } 100 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/ProjectJacobiInplace.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 66ec395bfe27c44329ba19b9c5638165 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/ProjectSelected.compute: -------------------------------------------------------------------------------- 1 | #pragma kernel ProjectSelected 2 | 3 | #define Buf RWStructuredBuffer 4 | 5 | Buf _horizVel; 6 | Buf _vertVel; 7 | Buf _selected; 8 | Buf _isFluid; 9 | 10 | Buf _debug; 11 | 12 | int _simResX; 13 | int _simResY; 14 | 15 | #include "positions.cginc" 16 | 17 | [numthreads(8,8,1)] 18 | void ProjectSelected(uint3 id: SV_DispatchThreadID) { 19 | int2 pos = (int2)(id.xy); 20 | 21 | if(pos.x >= _simResX || pos.y >= _simResY) return; 22 | 23 | int offset = pos.x * _simResY + pos.y; 24 | if(_selected[offset] != 1) return; 25 | 26 | float u_right = 0; 27 | float u_here = 0; 28 | float v_up = 0; 29 | float v_here = 0; 30 | if(pos.x > 0 && pos.y > 0 && pos.x < _simResX - 1 && pos.y < _simResY - 1) { 31 | if(_isFluid[offset] == 1) { 32 | int s_sum = 33 | _isFluid[L(offset)] + 34 | _isFluid[R(offset)] + 35 | _isFluid[U(offset)] + 36 | _isFluid[D(offset)]; 37 | if(s_sum != 0) { 38 | float divergence = 39 | - _horizVel[offset] + _horizVel[R(offset)] 40 | - _vertVel[offset] + _vertVel[U(offset)]; 41 | float d_pre = divergence / s_sum; 42 | u_here = _isFluid[L(offset)] == 1 ? d_pre : 0; 43 | u_right = _isFluid[R(offset)] == 1 ? - d_pre : 0; 44 | v_here = _isFluid[D(offset)] == 1 ? d_pre : 0; 45 | v_up = _isFluid[U(offset)] == 1 ? - d_pre : 0; 46 | } 47 | } 48 | } 49 | if(pos.x < _simResX - 1) _horizVel[R(offset)] += u_right; 50 | if(pos.y < _simResY - 1) _vertVel[U(offset)] += v_up; 51 | _horizVel[offset] = _horizVel[offset] + u_here; 52 | _vertVel[offset] = _vertVel[offset] + v_here; 53 | } 54 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/ProjectSelected.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 392c5c65b3484c12afc56c044faa566b 3 | timeCreated: 1689073452 -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/ProjectSingleCell.compute: -------------------------------------------------------------------------------- 1 | #pragma kernel ProjectSingleCell 2 | 3 | #define Buf RWStructuredBuffer 4 | 5 | Buf _horizVel; 6 | Buf _vertVel; 7 | 8 | Buf _isFluid; 9 | 10 | Buf _debug; 11 | 12 | int _simResX; 13 | int _simResY; 14 | 15 | int _updateX; 16 | int _updateY; 17 | 18 | #include "positions.cginc" 19 | 20 | [numthreads(1,1,1)] 21 | void ProjectSingleCell(uint3 id: SV_DispatchThreadID) { 22 | int2 pos = int2(_updateX, _updateY); 23 | 24 | if(pos.x >= _simResX || pos.y >= _simResY) { 25 | return; 26 | } 27 | 28 | int2 simRes = int2(_simResX, _simResY); 29 | int offset = pos.x * _simResY + pos.y; 30 | 31 | float d = 0; 32 | float u_right = 0; 33 | float u_here = 0; 34 | float v_up = 0; 35 | float v_here = 0; 36 | if(pos.x > 0 && pos.y > 0 && pos.x < _simResX - 1 && pos.y < _simResY - 1) { 37 | if(_isFluid[offset] == 1) { 38 | int s_sum = 39 | _isFluid[L(offset)] + 40 | _isFluid[R(offset)] + 41 | _isFluid[U(offset)] + 42 | _isFluid[D(offset)]; 43 | if(s_sum != 0) { 44 | d = 45 | - _horizVel[offset] + _horizVel[R(offset)] 46 | - _vertVel[offset] + _vertVel[U(offset)]; 47 | float d_pre = d / s_sum; 48 | u_here = _isFluid[L(offset)] == 1 ? d_pre : 0; 49 | u_right = _isFluid[R(offset)] == 1 ? - d_pre : 0; 50 | v_here = _isFluid[D(offset)] == 1 ? d_pre : 0; 51 | v_up = _isFluid[U(offset)] == 1 ? - d_pre : 0; 52 | } 53 | } 54 | } 55 | if(pos.x < _simResX - 1) _horizVel[R(offset)] += u_right; 56 | if(pos.y < _simResY - 1) _vertVel[U(offset)] += v_up; 57 | _horizVel[offset] = _horizVel[offset] + u_here; 58 | _vertVel[offset] = _vertVel[offset] + v_here; 59 | } 60 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/ProjectSingleCell.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 222168b7f47e04d39bac7fa8df15023c 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/RenderDivergenceSpiral.compute: -------------------------------------------------------------------------------- 1 | // ReSharper disable CppLocalVariableMayBeConst 2 | #pragma kernel Render 3 | #pragma kernel UpdateDivergenceTexPos 4 | 5 | #define Buf RWStructuredBuffer 6 | 7 | float _spiralRadius; 8 | float _rotationSpeed; 9 | float _radialSpeed; 10 | bool _renderPositive; 11 | bool _renderNegative; 12 | 13 | Texture2D _waterTexture; 14 | SamplerState sampler_waterTexture; 15 | RWTexture2D _renderTexture; 16 | Buf _texPosBase; 17 | int _divergenceTexPosOffset; 18 | Buf _divergence; 19 | 20 | int2 _simRes; 21 | int2 _renderRes; 22 | float _deltaTime; 23 | 24 | [numthreads(8,8,1)] 25 | void UpdateDivergenceTexPos (uint3 id : SV_DispatchThreadID) { 26 | int2 cellId = id.xy; 27 | if(cellId.x >= _simRes.x || cellId.y >= _simRes.y) return; 28 | const int cellOffset = cellId.x * _simRes.y + cellId.y; 29 | const float divergence = _divergence[cellOffset]; 30 | const float divIncr = _deltaTime * divergence / 20; 31 | _texPosBase[_divergenceTexPosOffset + cellOffset] -= float2(divIncr * _rotationSpeed, divIncr * _radialSpeed); 32 | } 33 | 34 | [numthreads(8,8,1)] 35 | void Render (uint3 id : SV_DispatchThreadID) 36 | { 37 | int2 renderXY = (int2)id; 38 | if(renderXY.x >= _renderRes.x || renderXY.y >= _renderRes.y) return; 39 | float2 _cellSize = (float2)_renderRes / (float2)_simRes; 40 | int2 cellId = (int2)(id.xy / _cellSize); 41 | const int cellOffset = cellId.x * _simRes.y + cellId.y; 42 | const float divergence = min(1, max(-1, _divergence[cellOffset])); 43 | 44 | const float2 cellCenter = (cellId + 0.5) * _cellSize; 45 | float2 velFromCenter = id.xy - cellCenter; 46 | 47 | const float v_len = length(velFromCenter); 48 | float radiusAbs = _spiralRadius * _cellSize.y * 0.5 * abs(divergence); 49 | // radiusAbs = _cellSize.y * 2; // debug 50 | if(v_len > radiusAbs) return; 51 | float angle = acos(velFromCenter.x / v_len); 52 | if(velFromCenter.y < 0) { 53 | angle = 6.28319 - angle; 54 | } 55 | 56 | const float2 uv_base = float2(angle / 2 / 3.141593 * 1, v_len / _cellSize.x * 1); 57 | 58 | const float2 uv = uv_base + (float2)_texPosBase[_divergenceTexPosOffset + cellOffset]; 59 | float4 sample = _waterTexture.SampleLevel(sampler_waterTexture, ((float2)uv), 0 ); 60 | const float radialT = v_len / radiusAbs; 61 | float alpha = min(1, max(0, 1 - radialT)); 62 | alpha = sqrt(alpha); 63 | alpha = alpha > 0.5 ? 1 : alpha; 64 | // alpha *= abs(divergence); 65 | if(divergence < 0) { 66 | sample *= radialT; 67 | } else { 68 | sample /= radialT; 69 | } 70 | if((divergence < 0 && !_renderNegative) || (divergence > 0 && !_renderPositive)) return; 71 | _renderTexture[id.xy] = (1 - alpha) * _renderTexture[id.xy] + alpha * float4(sample.xyz, 0); 72 | } 73 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/RenderDivergenceSpiral.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 846cb106e93544aeacbccea45ddb2915 3 | timeCreated: 1688338090 -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/RenderingArrows.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 31067966eb1747a8b995975d8b9cecae 3 | timeCreated: 1688290775 -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/RenderingCenters.compute: -------------------------------------------------------------------------------- 1 | #pragma kernel RenderFloat3s 2 | #pragma kernel RenderFloat4s 3 | #pragma kernel RenderFloats 4 | #pragma kernel RenderInts 5 | #pragma kernel RenderBools 6 | #pragma kernel CheckDesign 7 | 8 | #define Buf RWStructuredBuffer 9 | 10 | Buf _horizVel; 11 | Buf _vertVel; 12 | Buf _isFluid; 13 | Buf _float3sToRender; 14 | Buf _float4sToRender; 15 | Buf _velocitySources; 16 | 17 | int _uOffset; 18 | 19 | RWTexture2D _renderTexture; 20 | 21 | int2 _simRes; 22 | int2 _renderRes; 23 | 24 | #define _simResX (_simRes.x) 25 | #define _simResY (_simRes.y) 26 | #define renderResX (_renderRes.x) 27 | #define renderResY (_renderRes.y) 28 | 29 | #include "positions.cginc" 30 | 31 | [numthreads(8,8,1)] 32 | void RenderFloat3s(uint3 id : SV_DispatchThreadID) 33 | { 34 | int2 renderXY = id.xy; 35 | int2 simXY = int2(id.x * _simResX / renderResX, id.y * _simResY / renderResY); 36 | int simOffset = simXY.x * _simResY + simXY.y; 37 | float3 col = _float3sToRender[simOffset]; 38 | _renderTexture[renderXY] = float4(col, 1); 39 | } 40 | 41 | 42 | [numthreads(8,8,1)] 43 | void RenderFloat4s(uint3 id : SV_DispatchThreadID) 44 | { 45 | int2 renderXY = id.xy; 46 | int2 simXY = int2(id.x * _simResX / renderResX, id.y * _simResY / renderResY); 47 | int simOffset = simXY.x * _simResY + simXY.y; 48 | float4 col = _float4sToRender[simOffset]; 49 | _renderTexture[renderXY] = col; 50 | } 51 | 52 | [numthreads(8,8,1)] 53 | void RenderInts(uint3 id : SV_DispatchThreadID) 54 | { 55 | /* 56 | use u as source 57 | */ 58 | int2 renderXY = id.xy; 59 | int2 simXY = int2(id.x * _simResX / renderResX, id.y * _simResY / renderResY); 60 | int simOffset = simXY.x * _simResY + simXY.y; 61 | int value = _isFluid[simOffset]; 62 | _renderTexture[renderXY] = float4(value.xxx, 1); 63 | } 64 | 65 | [numthreads(8,8,1)] 66 | void RenderBools(uint3 id : SV_DispatchThreadID) 67 | { 68 | /* 69 | use u as source 70 | */ 71 | int2 renderXY = id.xy; 72 | int2 simXY = int2(id.x * _simResX / renderResX, id.y * _simResY / renderResY); 73 | int simOffset = simXY.x * _simResY + simXY.y; 74 | int value = _isFluid[simOffset]; 75 | if(value == 1) { 76 | _renderTexture[renderXY] = float4(0.8, 0.8, 0.8, 1); 77 | } else if( value == 0) { 78 | _renderTexture[renderXY] = float4(0, 0, 0, 1); 79 | } else { 80 | _renderTexture[renderXY] = float4(1, 0, 0, 1); 81 | } 82 | } 83 | 84 | [numthreads(8,8,1)] 85 | void RenderFloats(uint3 id : SV_DispatchThreadID) 86 | { 87 | /* 88 | use u as source 89 | */ 90 | int2 renderXY = id.xy; 91 | int2 simXY = int2(id.x * _simResX / renderResX, id.y * _simResY / renderResY); 92 | int simOffset = simXY.x * _simResY + simXY.y + _uOffset; 93 | float value = _horizVel[simOffset]; 94 | float red = value < 0 ? - value : 0; 95 | float green = value >=0 ? value : 0; 96 | float blue = 0; 97 | if(abs(value) > 1.001) { 98 | // red = 0; 99 | // green = 0; 100 | // blue = 1; 101 | } 102 | if((int)id.x < renderResX && (int)id.y < renderResY) { 103 | _renderTexture[renderXY] = float4(red, green, blue, 1); 104 | } 105 | } 106 | 107 | [numthreads(8,8,1)] 108 | void CheckDesign(uint3 id : SV_DispatchThreadID) 109 | { 110 | /* 111 | renders discrepancies only 112 | 113 | inputs: 114 | - velocitySources 115 | - u 116 | - v 117 | - s 118 | - simResX 119 | - simResY 120 | - renderResX 121 | - renderResY 122 | 123 | outputs: 124 | - renderTexture 125 | */ 126 | int2 renderXY = id.xy; 127 | if(renderXY.x < renderResX && renderXY.y < renderResY) { 128 | int2 simXY = int2(id.x * _simResX / renderResX, id.y * _simResY / renderResY); 129 | int simOffset = simXY.x * _simResY + simXY.y; 130 | float3 design = _velocitySources[simOffset]; 131 | float4 renderValue = float4(0, 0, 0, 1); 132 | if(length(design - float3(1, 0, 0)) == 0) { 133 | if(_isFluid[simOffset] == 1) { 134 | renderValue.x = 1; 135 | } 136 | if(_vertVel[simOffset] != 1) { 137 | renderValue.x = 0; 138 | renderValue.y = 1; 139 | } 140 | if(_vertVel[U(simOffset)] != 1) { 141 | renderValue.x = 0.5; 142 | renderValue.y = 0.5; 143 | } 144 | if(_vertVel[U(simOffset)] != 1 && _vertVel[simOffset] != 1) { 145 | renderValue.x = 0.5; 146 | renderValue.y = 0.5; 147 | renderValue.z = 0.5; 148 | } 149 | } else if(length(design - float3(0, 0, 1)) == 0) { 150 | if(_isFluid[simOffset] == 1) { 151 | renderValue.x = 1; 152 | } 153 | if(_vertVel[simOffset] != -1 || _vertVel[U(simOffset)] != -1) { 154 | renderValue.z = 1; 155 | } 156 | } 157 | 158 | _renderTexture[renderXY] = renderValue; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/RenderingCenters.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 84d192b3db10d447390ff030e45efa44 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/RenderingGrid.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 277fd0b96bab4cbcb06b3dbe6b39bc9f 3 | timeCreated: 1688290698 -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/RenderingSelectedCells.compute: -------------------------------------------------------------------------------- 1 | 2 | // ReSharper disable CppInitializedValueIsAlwaysRewritten 3 | #pragma kernel RenderSelectedCells 4 | 5 | #define Buf RWStructuredBuffer 6 | 7 | Buf _selected; 8 | RWTexture2D _renderTexture; 9 | 10 | int2 _simRes; 11 | int2 _renderRes; 12 | 13 | float3 _currentCellColor; 14 | 15 | #define _simResX _simRes.x 16 | #define _simResY _simRes.y 17 | 18 | #include "positions.cginc" 19 | 20 | [numthreads(8,8,1)] 21 | void RenderSelectedCells(uint3 id : SV_DispatchThreadID) 22 | { 23 | uint2 renderXY = id.xy; 24 | float2 simPosF = (float2)renderXY * _simRes / _renderRes; 25 | int2 simXY = (int2)simPosF; 26 | int offset = posiToIdx(simXY); 27 | if(_selected[offset] != 1) return; 28 | float2 subT = frac(simPosF); 29 | if(! (subT.x < 0.1 || subT.y < 0.1 || subT.x > 0.9 || subT.y > 0.9) ) { 30 | return; 31 | } 32 | _renderTexture[renderXY] = float4(_currentCellColor, 0); 33 | } 34 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/RenderingSelectedCells.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8c57fbc2c5524a2aac2242b6a9029df4 3 | timeCreated: 1688740927 -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/RenderingVelocityCenters.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fa2a763822b243039b360a2251c1c710 3 | timeCreated: 1688493306 -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/ShaderUtils.cginc: -------------------------------------------------------------------------------- 1 | float max3(float a, float b, float c) { 2 | return max(a, max(b, c)); 3 | } 4 | 5 | float minaxes(float3 v) { 6 | return min(min(v.x, v.y), v.z); 7 | } 8 | 9 | float maxaxes(float3 v) { 10 | return max(max(v.x, v.y), v.z); 11 | } 12 | 13 | float2 getRayBoxIntersection(float3 rayStart, float3 rayDirection, float3 boundsMin, float3 boundsMax) { 14 | float3 invDir = 1 / rayDirection; 15 | float3 t1 = (boundsMin - rayStart) * invDir; 16 | float3 t2 = (boundsMax - rayStart) * invDir; 17 | float3 t1a = min(t1, t2); 18 | float3 t2b = max(t1, t2); 19 | float t1max = maxaxes(t1a); 20 | float t2min = minaxes(t2b); 21 | return float2(t1max, t2min); 22 | } 23 | 24 | // from https://stackoverflow.com/questions/12964279/whats-the-origin-of-this-glsl-rand-one-liner 25 | float rand(float2 co){ 26 | return frac(sin(dot(co.xy ,float2(12.9898,78.233))) * 43758.5453); 27 | } 28 | 29 | float4 colorFromObjectPos(float3 objectPos) { 30 | /* 31 | Take position within object, -0.5 <= x/y/z <= 0.5, and change that 32 | into a color, one color channel per axis. 33 | */ 34 | float margin = 0; 35 | float4 col = float4(0, 0, 0, 1); 36 | if(objectPos.x >= -5 + margin && objectPos.x <= 5 - margin) { 37 | col.x = objectPos.x + 0.5; 38 | } 39 | if(objectPos.y >= -5 + margin && objectPos.y <= 5 - margin) { 40 | col.y = objectPos.y + 0.5; 41 | } 42 | if(objectPos.z >= -5 + margin && objectPos.z <= 5 - margin) { 43 | col.z = objectPos.z + 0.5; 44 | } 45 | return col; 46 | } 47 | 48 | float3 HSVtoRGB(float3 hsv) { 49 | float h = min(1, max(0, hsv.x)); 50 | float s = hsv.y; 51 | float v = hsv.z; 52 | 53 | float c = v * s; 54 | float x = c * (1.0 - abs(fmod(h * 6.0, 2.0) - 1.0)); 55 | float m = v - c; 56 | 57 | float3 col; 58 | 59 | if (h < 0.16666) { 60 | col = float3(c, x, 0.0); 61 | } else if (h < 0.33333) { 62 | col = float3(x, c, 0.0); 63 | } else if (h < 0.5) { 64 | col = float3(0.0, c, x); 65 | } else if (h < 0.66666) { 66 | col = float3(0.0, x, c); 67 | } else if (h < 0.83333) { 68 | col = float3(x, 0.0, c); 69 | } else { 70 | col = float3(c, 0.0, x); 71 | } 72 | 73 | return col + m; 74 | } 75 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/ShaderUtils.cginc.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d1b59d884616e4279a8a35eddc19d181 3 | ShaderIncludeImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/TwoIntoOne.compute: -------------------------------------------------------------------------------- 1 | #pragma kernel SquashHoriz 2 | 3 | #define Buf RWStructuredBuffer 4 | 5 | RWTexture2D _renderTexture; 6 | RWTexture2D _renderTexture2; 7 | 8 | int2 _renderRes; 9 | int _toRight; 10 | 11 | [numthreads(8,8,1)] 12 | void SquashHoriz(uint3 id : SV_DispatchThreadID) 13 | { 14 | // should run with x threads half total x res 15 | int2 tgtRenderXY = (int2)id.xy; 16 | int2 halfRenderRes = _renderRes >> 1; 17 | if((int)tgtRenderXY.x < halfRenderRes.x && tgtRenderXY.y < _renderRes.y) { 18 | int2 srcRenderXY = float2(tgtRenderXY.x << 1, tgtRenderXY.y); 19 | if(_toRight) { 20 | tgtRenderXY.x += halfRenderRes.x; 21 | } 22 | _renderTexture[tgtRenderXY] = (_renderTexture2[srcRenderXY] + _renderTexture2[srcRenderXY + float2(1, 0)]) / 2; 23 | } 24 | } 25 | 26 | // [numthreads(8,8,1)] 27 | // void TwoIntoOne(uint3 id : SV_DispatchThreadID) 28 | // { 29 | // // should run with x threads half total x res 30 | // int2 srcRenderXY = (int2)id.xy; 31 | // int2 halfRenderRes = _renderRes >> 1; 32 | // if((int)srcRenderXY.x < halfRenderRes.x && srcRenderXY.y < _renderRes.y) { 33 | // int2 tgtRenderXY = srcRenderXY + int2(halfRenderRes.x, 0); 34 | // _renderTexture[tgtRenderXY] = _renderTexture2[srcRenderXY]; 35 | // } 36 | // } 37 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/TwoIntoOne.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b6f04438bed754a3b9bc569cb19b15da 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | preprocessorOverride: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/interpolate.cginc.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1e319051f98d24bc1aee328753ea7ba3 3 | ShaderIncludeImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/positions.cginc: -------------------------------------------------------------------------------- 1 | #define L(idx) ((idx) - _simResY) 2 | #define R(idx) ((idx) + _simResY) 3 | #define D(idx) ((idx) - 1) 4 | #define U(idx) ((idx) + 1) 5 | 6 | #define LEFT(idx) ((idx) - _simResY) 7 | #define RIGHT(idx) ((idx) + _simResY) 8 | #define DOWN(idx) ((idx) - 1) 9 | #define UP(idx) ((idx) + 1) 10 | 11 | inline int posiToIdx(int2 pos) { 12 | return pos.x * _simResY + pos.y; 13 | } 14 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Resources/LiquidShader/positions.cginc.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 26ad70ba1ca9e4a7b992937f565edc34 3 | ShaderIncludeImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/LiquidShader/SpeedTestingScene.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 862a71d696cc348c090d184449f6c57c 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/LiquidShader/SpeedTests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 52ca2e9a0242344ab83dab6bab0d3243 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/SpeedTests/SpeedTestController.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using UnityEngine; 3 | using System.Diagnostics; 4 | using Utils; 5 | 6 | namespace LiquidShader { 7 | 8 | public class SpeedTestController : MonoBehaviour 9 | { 10 | [SerializeField] bool doSync = true; 11 | [SerializeField] bool doCopyBuffer = false; 12 | [SerializeField] int numIts = 100; 13 | 14 | ComputeBuffer _syncSrcBuffer; 15 | ComputeBuffer _syncDstBuffer; 16 | 17 | CopyBuffer _copyBuffer; 18 | Pooling _maxAbsBuffer; 19 | 20 | // Start is called before the first frame update 21 | void Start() 22 | { 23 | _copyBuffer = new CopyBuffer(); 24 | _maxAbsBuffer = new Pooling(); 25 | 26 | _syncSrcBuffer = new ComputeBuffer(1, sizeof(int), ComputeBufferType.Counter); 27 | _syncDstBuffer = new ComputeBuffer(1, sizeof(int), ComputeBufferType.Counter); 28 | } 29 | 30 | void Sync() { 31 | ComputeBuffer.CopyCount(_syncSrcBuffer, _syncDstBuffer, 0); 32 | } 33 | 34 | void RunMaxOnce(Buf2 someBuf, Buf2 dest) { 35 | _maxAbsBuffer.MaxAbsFloats(someBuf, dest); 36 | if(doSync) { 37 | Sync(); 38 | } 39 | if(doCopyBuffer) { 40 | _copyBuffer.CopyFloats(1, 1, dest, someBuf); 41 | } 42 | } 43 | 44 | void RunMaxI() { 45 | UnityEngine.Debug.Log("start"); 46 | var simResY = 480; 47 | var simResX = (simResY * 16) / 9; 48 | // Vector2Int simRes = new Vector2Int(simResX, simResY); 49 | var someBuf = new Buf2(simResX, simResY); 50 | var chunksResX = (simResX + 8 - 1) / 8; 51 | var chunksResY = (simResY + 8 - 1) / 8; 52 | var dest = new Buf2(chunksResX, chunksResY); 53 | // float startTime = Time.time; 54 | var stopwatch = new Stopwatch(); 55 | // UnityEngine.Debug.Log($"start {stopwatch.}"); 56 | stopwatch.Start(); 57 | // int numIts = 100; 58 | for(var i = 0; i < numIts; i++) { 59 | // Debug.Log("."); 60 | RunMaxOnce(someBuf, dest); 61 | } 62 | stopwatch.Stop(); 63 | // float endTime = Time.time; 64 | // float elapsed = endTime - startTime; 65 | float elapsedMills = stopwatch.ElapsedMilliseconds; 66 | var averageMills = elapsedMills / (float)numIts; 67 | UnityEngine.Debug.Log($"End total {elapsedMills}ms averarge {averageMills}ms"); 68 | // UnityEngine.Debug.Log($"End {Time.time}"); 69 | 70 | someBuf.Release(); 71 | dest.Release(); 72 | } 73 | 74 | IEnumerator WaitingTask() { 75 | for(var i = 0; i < 10; i++) { 76 | UnityEngine.Debug.Log("."); 77 | yield return new WaitForSeconds(0.2f); 78 | } 79 | } 80 | 81 | IEnumerator WaitForTask() { 82 | UnityEngine.Debug.Log("Start waiting for task"); 83 | yield return StartCoroutine(WaitingTask()); 84 | UnityEngine.Debug.Log("Finished waiting for task"); 85 | } 86 | 87 | public void BtnRunMax() { 88 | RunMaxI(); 89 | // StartCoroutine(WaitForTask()); 90 | } 91 | 92 | // Update is called once per frame 93 | void Update() 94 | { 95 | 96 | } 97 | } 98 | 99 | } // namespace LiquidShader 100 | -------------------------------------------------------------------------------- /Assets/LiquidShader/SpeedTests/SpeedTestController.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 091d067cfeccb4c979fe72b7dcb99d47 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/SpeedTests/SpeedTestMax.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | public class SpeedTestMax : MonoBehaviour 4 | { 5 | // Start is called before the first frame update 6 | void Start() 7 | { 8 | 9 | } 10 | 11 | // Update is called once per frame 12 | void Update() 13 | { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Assets/LiquidShader/SpeedTests/SpeedTestMax.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0d72aca22734345a99f16833bc9cc8db 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/TwoIntoOne.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace LiquidShader { 4 | 5 | public class TwoIntoOne { 6 | ComputeShader _shader; 7 | 8 | public TwoIntoOne() { 9 | _shader = Resources.Load("TwoIntoOne"); 10 | } 11 | 12 | void SquashHoriz(RenderTexture tgt, RenderTexture src, bool toRight) { 13 | // squishes src horizontally to fit into half the texture tgt 14 | // 15 | // puts on left hand side, unless toRight is true, in which case right hand side 16 | var resX = tgt.width; 17 | var resY = tgt.height; 18 | if(src.width != resX) { 19 | throw new System.Exception($"target and source resolutions should match {src.width} vs {resX}"); 20 | } 21 | if(src.height != resY) { 22 | throw new System.Exception($"target and source resolutions should match {src.height} vs {resY}"); 23 | } 24 | var kernel = _shader.FindKernel("SquashHoriz"); 25 | _shader.SetInts("_renderRes", new int[]{resX, resY}); 26 | _shader.SetBool("_toRight", toRight); 27 | _shader.SetTexture(kernel, "_renderTexture", tgt); 28 | _shader.SetTexture(kernel, "_renderTexture2", src); 29 | _shader.Dispatch(kernel, resX / 8, resY / 8, 1); 30 | } 31 | 32 | // void _Merge(RenderTexture tgt, RenderTexture src) { 33 | // // squishes src horizontally to fit into half the texture tg 34 | // int resX = tgt.width; 35 | // int resY = tgt.height; 36 | // if(src.width != resX) { 37 | // throw new System.Exception($"target and source resolutions should match {src.width} vs {resX}"); 38 | // } 39 | // if(src.height != resY) { 40 | // throw new System.Exception($"target and source resolutions should match {src.height} vs {resY}"); 41 | // } 42 | // int kernel = shader.FindKernel("Merge"); 43 | // shader.SetInts("_renderRes", new int[]{resX, resY}); 44 | // shader.SetTexture(kernel, "_renderTexture", tgt); 45 | // shader.SetTexture(kernel, "_renderTexture2", src); 46 | // shader.Dispatch(kernel, resX / 8, resY / 8, 1); 47 | // } 48 | 49 | public void RunTwoToOne(RenderTexture lhs, RenderTexture rhs, RenderTexture tgt) { 50 | var resX = tgt.width; 51 | var resY = tgt.height; 52 | if(lhs.width != resX) { 53 | throw new System.Exception($"target and source resolutions should match {lhs.width} vs {resX}"); 54 | } 55 | if(lhs.height != resY) { 56 | throw new System.Exception($"target and source resolutions should match {lhs.height} vs {resY}"); 57 | } 58 | if(rhs.width != resX) { 59 | throw new System.Exception($"target and source resolutions should match {rhs.width} vs {resX}"); 60 | } 61 | if(rhs.height != resY) { 62 | throw new System.Exception($"target and source resolutions should match {rhs.height} vs {resY}"); 63 | } 64 | SquashHoriz(tgt, lhs, false); 65 | SquashHoriz(tgt, rhs, true); 66 | } 67 | } 68 | 69 | } // namespace LiquidShader 70 | -------------------------------------------------------------------------------- /Assets/LiquidShader/TwoIntoOne.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 58cff32d4ad3549948fdfb652dd9b078 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Types.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ea4b2048fb470497a908959ac9d5d21c 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Types/SimulationState.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1deb0b64a567e4501b63ceeec7c7e272 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/UIController.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 844a06a8cb54449a3bd463550b643d88 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Utils.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 98715b2eeb4cd490fac2b90e4d42a058 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Utils/ArrayUtils.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Utils { 4 | 5 | public class ArrayUtils { 6 | public static void Print2D(T[,] tgt) { 7 | var w = tgt.GetLength(0); 8 | var h = tgt.GetLength(1); 9 | var output = ""; 10 | for(var y = h - 1; y >=0; y--) { 11 | var row = ""; 12 | for(var x = 0; x < w; x++) { 13 | row += tgt[x, y] + ", "; 14 | } 15 | output += row + "\n"; 16 | } 17 | Debug.Log(output); 18 | } 19 | } 20 | 21 | } // namespace LiquidShader 22 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Utils/ArrayUtils.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 976e249adcd224206bcd7ac3be41cfad 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Utils/CellByCell.cs: -------------------------------------------------------------------------------- 1 | using LiquidShader.Types; 2 | 3 | namespace Utils { 4 | 5 | public class CellByCell { 6 | public int updateX = 1; 7 | public int updateY = 1; 8 | 9 | public int lastUpdateX = 1; 10 | public int lastUpdateY = 1; 11 | 12 | public void Reset() { 13 | updateX = 1; 14 | updateY = 1; 15 | 16 | lastUpdateX = 1; 17 | lastUpdateY = 1; 18 | } 19 | 20 | public int[] LastUpdatePos { 21 | get { 22 | return new int[]{ lastUpdateX, lastUpdateY }; 23 | } 24 | } 25 | 26 | public int[] UpdatePos { 27 | get { 28 | return new int[]{ updateX, updateY }; 29 | } 30 | } 31 | 32 | void CheckBounds(SimulationState simulationState) { 33 | // in case the resolution has changed recently 34 | if(updateX >= simulationState.simResX) { 35 | updateX = simulationState.simResX - 1; 36 | } 37 | if(updateY >= simulationState.simResY) { 38 | updateY = simulationState.simResY - 1; 39 | } 40 | } 41 | 42 | public void Inc(SimulationState simulationState) { 43 | CheckBounds(simulationState); 44 | 45 | lastUpdateX = updateX; 46 | lastUpdateY = updateY; 47 | 48 | updateX += 1; 49 | if(updateX >= simulationState.simResX - 1) { 50 | updateX = 1; 51 | updateY += 1; 52 | if(updateY >= simulationState.simResY - 1) { 53 | updateY = 1; 54 | } 55 | } 56 | } 57 | 58 | public void Dec(SimulationState simulationState) { 59 | CheckBounds(simulationState); 60 | 61 | lastUpdateX = updateX; 62 | lastUpdateY = updateY; 63 | 64 | updateX -= 1; 65 | if(updateX <= -1) { 66 | updateX = simulationState.simResX - 1; 67 | updateY -= 1; 68 | if(updateY <= -1) { 69 | updateY = simulationState.simResY - 1; 70 | } 71 | } 72 | 73 | } 74 | } 75 | 76 | } // namespace LiquidShader 77 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Utils/CellByCell.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bca8e44ea748747f0b70d887c01ed52e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/LiquidShader/Water_texture_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hughperkins/UnityFluidSim-pub/67a431c53f8328818ef6d2fcbab2fffd5e7a87ba/Assets/LiquidShader/Water_texture_v2.png -------------------------------------------------------------------------------- /Assets/LiquidShader/Water_texture_v2.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f6d7f9938bdca429f9f0b6cddd9ccd25 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | flipGreenChannel: 0 24 | isReadable: 0 25 | streamingMipmaps: 0 26 | streamingMipmapsPriority: 0 27 | vTOnly: 0 28 | ignoreMipmapLimit: 0 29 | grayScaleToAlpha: 0 30 | generateCubemap: 6 31 | cubemapConvolution: 0 32 | seamlessCubemap: 0 33 | textureFormat: 1 34 | maxTextureSize: 2048 35 | textureSettings: 36 | serializedVersion: 2 37 | filterMode: 1 38 | aniso: 1 39 | mipBias: 0 40 | wrapU: 0 41 | wrapV: 0 42 | wrapW: 0 43 | nPOTScale: 1 44 | lightmap: 0 45 | compressionQuality: 50 46 | spriteMode: 0 47 | spriteExtrude: 1 48 | spriteMeshType: 1 49 | alignment: 0 50 | spritePivot: {x: 0.5, y: 0.5} 51 | spritePixelsToUnits: 100 52 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 53 | spriteGenerateFallbackPhysicsShape: 1 54 | alphaUsage: 1 55 | alphaIsTransparency: 0 56 | spriteTessellationDetail: -1 57 | textureType: 0 58 | textureShape: 1 59 | singleChannelComponent: 0 60 | flipbookRows: 1 61 | flipbookColumns: 1 62 | maxTextureSizeSet: 0 63 | compressionQualitySet: 0 64 | textureFormatSet: 0 65 | ignorePngGamma: 0 66 | applyGammaDecoding: 0 67 | swizzle: 50462976 68 | cookieLightType: 0 69 | platformSettings: 70 | - serializedVersion: 3 71 | buildTarget: DefaultTexturePlatform 72 | maxTextureSize: 2048 73 | resizeAlgorithm: 0 74 | textureFormat: -1 75 | textureCompression: 1 76 | compressionQuality: 50 77 | crunchedCompression: 0 78 | allowsAlphaSplitting: 0 79 | overridden: 0 80 | ignorePlatformSupport: 0 81 | androidETC2FallbackOverride: 0 82 | forceMaximumCompressionQuality_BC6H_BC7: 0 83 | - serializedVersion: 3 84 | buildTarget: Standalone 85 | maxTextureSize: 2048 86 | resizeAlgorithm: 0 87 | textureFormat: -1 88 | textureCompression: 1 89 | compressionQuality: 50 90 | crunchedCompression: 0 91 | allowsAlphaSplitting: 0 92 | overridden: 0 93 | ignorePlatformSupport: 0 94 | androidETC2FallbackOverride: 0 95 | forceMaximumCompressionQuality_BC6H_BC7: 0 96 | - serializedVersion: 3 97 | buildTarget: Server 98 | maxTextureSize: 2048 99 | resizeAlgorithm: 0 100 | textureFormat: -1 101 | textureCompression: 1 102 | compressionQuality: 50 103 | crunchedCompression: 0 104 | allowsAlphaSplitting: 0 105 | overridden: 0 106 | ignorePlatformSupport: 0 107 | androidETC2FallbackOverride: 0 108 | forceMaximumCompressionQuality_BC6H_BC7: 0 109 | spriteSheet: 110 | serializedVersion: 2 111 | sprites: [] 112 | outline: [] 113 | physicsShape: [] 114 | bones: [] 115 | spriteID: 116 | internalID: 0 117 | vertices: [] 118 | indices: 119 | edges: [] 120 | weights: [] 121 | secondaryTextures: [] 122 | nameFileIdTable: {} 123 | mipmapLimitGroupName: 124 | pSDRemoveMatte: 0 125 | userData: 126 | assetBundleName: 127 | assetBundleVariant: 128 | -------------------------------------------------------------------------------- /Assets/LiquidShader/mouseicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hughperkins/UnityFluidSim-pub/67a431c53f8328818ef6d2fcbab2fffd5e7a87ba/Assets/LiquidShader/mouseicon.png -------------------------------------------------------------------------------- /Assets/LiquidShader/mouseicon.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 938db63ebc77c4d829904330b0945bfd 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | flipGreenChannel: 0 24 | isReadable: 0 25 | streamingMipmaps: 0 26 | streamingMipmapsPriority: 0 27 | vTOnly: 0 28 | ignoreMipmapLimit: 0 29 | grayScaleToAlpha: 0 30 | generateCubemap: 6 31 | cubemapConvolution: 0 32 | seamlessCubemap: 0 33 | textureFormat: 1 34 | maxTextureSize: 2048 35 | textureSettings: 36 | serializedVersion: 2 37 | filterMode: 1 38 | aniso: 1 39 | mipBias: 0 40 | wrapU: 1 41 | wrapV: 1 42 | wrapW: 0 43 | nPOTScale: 0 44 | lightmap: 0 45 | compressionQuality: 50 46 | spriteMode: 1 47 | spriteExtrude: 1 48 | spriteMeshType: 1 49 | alignment: 0 50 | spritePivot: {x: 0.5, y: 0.5} 51 | spritePixelsToUnits: 100 52 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 53 | spriteGenerateFallbackPhysicsShape: 1 54 | alphaUsage: 1 55 | alphaIsTransparency: 1 56 | spriteTessellationDetail: -1 57 | textureType: 8 58 | textureShape: 1 59 | singleChannelComponent: 0 60 | flipbookRows: 1 61 | flipbookColumns: 1 62 | maxTextureSizeSet: 0 63 | compressionQualitySet: 0 64 | textureFormatSet: 0 65 | ignorePngGamma: 0 66 | applyGammaDecoding: 0 67 | swizzle: 50462976 68 | cookieLightType: 0 69 | platformSettings: 70 | - serializedVersion: 3 71 | buildTarget: DefaultTexturePlatform 72 | maxTextureSize: 2048 73 | resizeAlgorithm: 0 74 | textureFormat: -1 75 | textureCompression: 1 76 | compressionQuality: 50 77 | crunchedCompression: 0 78 | allowsAlphaSplitting: 0 79 | overridden: 0 80 | ignorePlatformSupport: 0 81 | androidETC2FallbackOverride: 0 82 | forceMaximumCompressionQuality_BC6H_BC7: 0 83 | - serializedVersion: 3 84 | buildTarget: Standalone 85 | maxTextureSize: 2048 86 | resizeAlgorithm: 0 87 | textureFormat: -1 88 | textureCompression: 1 89 | compressionQuality: 50 90 | crunchedCompression: 0 91 | allowsAlphaSplitting: 0 92 | overridden: 0 93 | ignorePlatformSupport: 0 94 | androidETC2FallbackOverride: 0 95 | forceMaximumCompressionQuality_BC6H_BC7: 0 96 | - serializedVersion: 3 97 | buildTarget: Server 98 | maxTextureSize: 2048 99 | resizeAlgorithm: 0 100 | textureFormat: -1 101 | textureCompression: 1 102 | compressionQuality: 50 103 | crunchedCompression: 0 104 | allowsAlphaSplitting: 0 105 | overridden: 0 106 | ignorePlatformSupport: 0 107 | androidETC2FallbackOverride: 0 108 | forceMaximumCompressionQuality_BC6H_BC7: 0 109 | spriteSheet: 110 | serializedVersion: 2 111 | sprites: [] 112 | outline: [] 113 | physicsShape: [] 114 | bones: [] 115 | spriteID: 5e97eb03825dee720800000000000000 116 | internalID: 0 117 | vertices: [] 118 | indices: 119 | edges: [] 120 | weights: [] 121 | secondaryTextures: [] 122 | nameFileIdTable: {} 123 | mipmapLimitGroupName: 124 | pSDRemoveMatte: 0 125 | userData: 126 | assetBundleName: 127 | assetBundleVariant: 128 | -------------------------------------------------------------------------------- /Assets/TextMesh Pro.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f54d1bd14bd3ca042bd867b519fee8cc 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Utils.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7108a48293bd4cdcaebf8c5712f17fe0 3 | timeCreated: 1718867831 -------------------------------------------------------------------------------- /Assets/Utils/Buf2.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using UnityEngine; 3 | 4 | namespace Utils { 5 | 6 | public class Buf2 : IBuf2 { 7 | ComputeBuffer _computeBuffer; 8 | 9 | public ComputeBuffer GetComputeBuffer() { 10 | return _computeBuffer; 11 | } 12 | 13 | int _numEls; 14 | int _stride; 15 | 16 | int _width; 17 | int _height; 18 | 19 | T[,] _data; 20 | 21 | public T[,] Data { 22 | get { 23 | return _data; 24 | } 25 | } 26 | 27 | public Buf2(int width, int height) { 28 | this._width = width; 29 | this._height = height; 30 | this._numEls = width * height; 31 | _stride = Marshal.SizeOf(); 32 | _computeBuffer = new ComputeBuffer(_numEls, _stride); 33 | _data = new T[width, height]; 34 | } 35 | 36 | public int Offset { 37 | get { 38 | return 0; 39 | } 40 | } 41 | 42 | public Vector2Int ResVec2 { 43 | get{ 44 | return new Vector2Int(_width, _height); 45 | } 46 | } 47 | 48 | public int[] ResInts { 49 | get{ 50 | return new int[]{_width, _height}; 51 | } 52 | } 53 | 54 | public int ResX { 55 | get { 56 | return _width; 57 | } 58 | } 59 | 60 | public int ResY { 61 | get { 62 | return _height; 63 | } 64 | } 65 | 66 | public void ToGPU() { 67 | _computeBuffer.SetData(_data); 68 | } 69 | 70 | public void FromGPU() { 71 | _computeBuffer.GetData(_data); 72 | } 73 | 74 | public void ApplyShader(ComputeShader shader, int kernel, string name) { 75 | shader.SetBuffer(kernel, name, _computeBuffer); 76 | } 77 | 78 | public T this[int i, int j] { 79 | get { 80 | return _data[i, j]; 81 | } 82 | set { 83 | _data[i, j] = value; 84 | } 85 | } 86 | 87 | public void GetData(T[,] tgt) { 88 | CheckDimensions(tgt); 89 | _computeBuffer.GetData(tgt); 90 | } 91 | 92 | void CheckDimensions(T[,] datat) { 93 | if(_data.Rank != 2) { 94 | throw new System.Exception($"data rank {_data.Rank} should be 2"); 95 | } 96 | if(_data.GetLength(0) != _width) { 97 | throw new System.Exception($"data length 0 {_data.GetLength(0)} should be {_width}"); 98 | } 99 | if(_data.GetLength(1) != _height) { 100 | throw new System.Exception($"data length 1 {_data.GetLength(1)} should be {_height}"); 101 | } 102 | } 103 | 104 | public void SetData(T[,] data) { 105 | CheckDimensions(data); 106 | this._data = data; 107 | ToGPU(); 108 | } 109 | 110 | public void Release() { 111 | if (_computeBuffer == null) return; 112 | _computeBuffer.Release(); 113 | _computeBuffer = null; 114 | } 115 | } 116 | 117 | } // namespace LiquidShader 118 | -------------------------------------------------------------------------------- /Assets/Utils/Buf2.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1a82184de63fe4bf4b6d429ff63c29b2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Utils/ButtonGroupExclusiveSelected.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using UnityEngine.UI; 4 | 5 | namespace Utils { 6 | public class ButtonGroupExclusiveSelected : MonoBehaviour 7 | { 8 | /* 9 | * Assumptions/requirements: 10 | * - the name of the button, with 'btn' removed, and in lowercase, should match the enum name, or at least, 11 | * the name passed into ShowButtonSelected(string buttonName) , which will typically be the enum name 12 | * used in the inspector 13 | */ 14 | [SerializeField] Button defaultButton; 15 | 16 | public void ShowButtonSelected(string buttonName) { 17 | var foundButton = false; 18 | foreach(var child in GetComponentsInChildren