{"id":75,"date":"2015-09-27T10:59:36","date_gmt":"2015-09-27T10:59:36","guid":{"rendered":"http:\/\/magiteker.com\/?p=75"},"modified":"2019-04-06T13:57:45","modified_gmt":"2019-04-06T07:57:45","slug":"fluid-simulation","status":"publish","type":"post","link":"https:\/\/magiteker.com\/index.php\/2015\/09\/27\/fluid-simulation\/","title":{"rendered":"Fluid Simulation"},"content":{"rendered":"<p style=\"text-align: justify;\">Using cellular automata I implemented a simple fluid simulation into the Unity Engine. Each cell in this implementation represents a unit in space containing either fluid, air, or solid mass. For each frame of the simulation a calculation is made attempting to move all the fluid into a state of equilibrium, where the fluid in the surrounding cells roughly equals the fluid of the current cell.<\/p>\n<p style=\"text-align: justify;\">The physics of the simulation are modeled on the basics of fluid motion in a 2D environment, where fluid is first moved down then to the sides and finally up. The core implementation of the simulation is as follows<\/p>\n<pre><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n            for (int y = 1; y &amp;amp;lt; Row - 1f; ++y)\n            {\n                for (int x = 1; x &amp;amp;lt; Column -1f; ++x)\n                {\n                    curr = caFront&#x5B;x, y];\n                    flow = 0f;\n\n                    if (curr.cType != CellType.Solid &amp;amp;amp;&amp;amp;amp; curr.cellMass &amp;amp;gt; 0)\n                    {\n\n                        rMass = curr.cellMass;\n\n                        \/\/Below\n                        if (rMass &amp;amp;gt; 0 &amp;amp;amp;&amp;amp;amp; caFront&#x5B;x, y - 1].cType != CellType.Solid)\n                        {\n                            flow = stableMass(rMass + caFront&#x5B;x, y - 1].cellMass) - caFront&#x5B;x, y - 1].cellMass;\n                            if (flow &amp;amp;gt; MinMass) flow *= 0.5f;\n\n                            flow = Mathf.Clamp(flow, 0f, Mathf.Min(spd, rMass));\n\n                            caBack&#x5B;x, y].cellMass -= flow;\n                            caBack&#x5B;x, y - 1].cellMass += flow;\n                            flowScore += flow;\n                            rMass -= flow;\n                        }\n\n                        \/\/Left\n                        if (rMass &amp;amp;gt; 0 &amp;amp;amp;&amp;amp;amp; caFront&#x5B;x + 1, y].cType != CellType.Solid)\n                        {\n                            flow = (curr.cellMass - caFront&#x5B;x + 1, y].cellMass) * 0.5f;\n                            if (flow &amp;amp;gt; MinMass) flow *= 0.5f;\n\n                            flow = Mathf.Clamp(flow, 0f, rMass);\n\n                            caBack&#x5B;x, y].cellMass -= flow;\n                            caBack&#x5B;x + 1, y].cellMass += flow;\n                            flowScore += flow;\n                            rMass -= flow;\n                        }\n\n                        \/\/Right\n                        if (rMass &amp;amp;gt; 0 &amp;amp;amp;&amp;amp;amp; caFront&#x5B;x - 1, y].cType != CellType.Solid)\n                        {\n                            flow = (curr.cellMass - caFront&#x5B;x - 1, y].cellMass) * 0.5f;\n                            if (flow &amp;amp;gt; MinMass) flow *= 0.5f;\n\n                            flow = Mathf.Clamp(flow, 0f, rMass);\n\n                            caBack&#x5B;x, y].cellMass -= flow;\n                            caBack&#x5B;x - 1, y].cellMass += flow;\n                            flowScore += flow;\n                            rMass -= flow;\n                        }\n\n                        \/\/Above\n                        if (rMass &amp;amp;gt; 0 &amp;amp;amp;&amp;amp;amp; caFront&#x5B;x, y + 1].cType != CellType.Solid)\n                        {\n                            flow = rMass - stableMass(rMass + caFront&#x5B;x, y + 1].cellMass);\n                            if (flow &amp;amp;gt; MinMass) flow *= 0.5f;\n\n                            flow = Mathf.Clamp(flow, 0f, Mathf.Min(spd, rMass));\n\n                            caBack&#x5B;x, y].cellMass -= flow;\n                            caBack&#x5B;x, y + 1].cellMass += flow;\n                            flowScore += flow;\n                            rMass -= flow;\n                        }\n\n                    }\n                }\n            }\n\n<\/pre>\n<p style=\"text-align: justify;\">The determination of whether to move fluid happens using a calculation averaging the fluid mass of the currently considered neighbor cell and the current cell being processed like so<\/p>\n<pre><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n        private float stableMass(float mass)\n        {\n            if (mass &amp;amp;lt;= 1f)\n                return 1f;\n            else if (mass &amp;amp;lt; 2f * MaxMass + MaxCompress)\n                return (MaxMass * MaxMass + mass * MaxCompress) \/ (MaxMass + MaxCompress);\n            else\n                return (mass + MaxCompress) * 0.5f;\n        }\n\n<\/pre>\n<p style=\"text-align: justify;\">After processing a cell the resulting data is updated to the data structure for the next frame to be drawn. Once all the cells have been updated the data structures for the current and next frame are swapped and the cells are redrawn from new current frame.<\/p>\n<p style=\"text-align: justify;\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" data-attachment-id=\"495\" data-permalink=\"https:\/\/magiteker.com\/index.php\/2015\/09\/27\/fluid-simulation\/fluid1\/\" data-orig-file=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/09\/fluid1.png?fit=513%2C321&amp;ssl=1\" data-orig-size=\"513,321\" data-comments-opened=\"0\" data-image-title=\"fluid1\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/09\/fluid1.png?fit=513%2C321&amp;ssl=1\" class=\"aligncenter wp-image-495\" src=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/09\/fluid1.png?resize=617%2C386&#038;ssl=1\" alt=\"fluid1\" width=\"617\" height=\"386\" srcset=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/09\/fluid1.png?resize=512%2C320&amp;ssl=1 512w, https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/09\/fluid1.png?w=513&amp;ssl=1 513w\" sizes=\"auto, (max-width: 617px) 100vw, 617px\" \/><\/p>\n<p style=\"text-align: justify;\">\n<p><center><\/center><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Using cellular automata I implemented a simple fluid simulation into the Unity Engine. Each cell in this implementation represents a unit in space containing either fluid, air, or solid mass. For each frame of the simulation a calculation is made attempting to move all the fluid into a state of equilibrium, where the fluid in [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":498,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":true,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[21],"tags":[],"class_list":["post-75","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-code"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/09\/fluid0.png?fit=513%2C321&ssl=1","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p6MIgq-1d","jetpack-related-posts":[{"id":517,"url":"https:\/\/magiteker.com\/index.php\/2016\/09\/02\/unity-synthesizer\/","url_meta":{"origin":75,"position":0},"title":"Unity Audio Wave Tutorial","author":"Frank O'Hanlon","date":"September 2, 2016","format":false,"excerpt":"Games are dynamic systems responding on different types of data inputs to create interesting results for the player. One such source of data is Audio which can at its best help the player have an emotional connection to what's happening on screen. So with this in mind utilizing audio is\u2026","rel":"","context":"In &quot;Code&quot;","block_context":{"text":"Code","link":"https:\/\/magiteker.com\/index.php\/category\/code\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2016\/09\/SynthEffect.png?fit=1154%2C418&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2016\/09\/SynthEffect.png?fit=1154%2C418&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2016\/09\/SynthEffect.png?fit=1154%2C418&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2016\/09\/SynthEffect.png?fit=1154%2C418&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2016\/09\/SynthEffect.png?fit=1154%2C418&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":355,"url":"https:\/\/magiteker.com\/index.php\/2015\/10\/23\/unity-shader-experiments\/","url_meta":{"origin":75,"position":1},"title":"Unity Shader Primer","author":"Frank O'Hanlon","date":"October 23, 2015","format":false,"excerpt":"Shaders are one of the more obscure technologies within the Unity game engine, and while the documentation covers most of the shader language and functions it fails to provide comprehensive techniques that would result in compelling graphics. They're core focus appears to be that of treating shaders as a black\u2026","rel":"","context":"In &quot;Code&quot;","block_context":{"text":"Code","link":"https:\/\/magiteker.com\/index.php\/category\/code\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/shader_experiment.png?fit=822%2C463&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/shader_experiment.png?fit=822%2C463&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/shader_experiment.png?fit=822%2C463&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/shader_experiment.png?fit=822%2C463&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":1411,"url":"https:\/\/magiteker.com\/index.php\/2023\/06\/24\/dreambooth-kohya-ss-install\/","url_meta":{"origin":75,"position":2},"title":"Dreambooth Kohya SS Install","author":"Frank O'Hanlon","date":"June 24, 2023","format":false,"excerpt":"- Github Above is the repository for Kohya SS Dreambooth, to install simply clone the repository to a separate folder using Git then run the install.bat file. Note: For better training speed ( iterations per second ) using RTX 40xx GPU's it's advised to use CUDA 11.8 so that Xformers\u2026","rel":"","context":"In &quot;Code&quot;","block_context":{"text":"Code","link":"https:\/\/magiteker.com\/index.php\/category\/code\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1386,"url":"https:\/\/magiteker.com\/index.php\/2023\/06\/21\/resource-dreambooth-training-readme\/","url_meta":{"origin":75,"position":3},"title":"Resource: Dreambooth Training README","author":"Frank O'Hanlon","date":"June 21, 2023","format":false,"excerpt":"- Github README describing proper methods for constructing a dataset.According to the README Regularization images allow for prior preservation of a models existing dataset. Regularization images should be generated before training from the base model. Image classification should be a generic term ( i.e. person, cat, dog, man, woman ).\u2026","rel":"","context":"In &quot;Code&quot;","block_context":{"text":"Code","link":"https:\/\/magiteker.com\/index.php\/category\/code\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2023\/06\/image-1.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2023\/06\/image-1.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2023\/06\/image-1.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2023\/06\/image-1.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":1382,"url":"https:\/\/magiteker.com\/index.php\/2023\/06\/21\/resource-training-stable-diffusion-with-dreambooth\/","url_meta":{"origin":75,"position":4},"title":"Resource: Training Stable Diffusion with Dreambooth","author":"Frank O'Hanlon","date":"June 21, 2023","format":false,"excerpt":"-Blog Post This article describes experiments with different Learning Rates in training models using Dreambooth. FTA: Summary of Initial Results To get good results training Stable Diffusion with Dreambooth, it's important to tune the learning rate and training steps for your dataset. High learning rates and too many training steps\u2026","rel":"","context":"In &quot;Code&quot;","block_context":{"text":"Code","link":"https:\/\/magiteker.com\/index.php\/category\/code\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":739,"url":"https:\/\/magiteker.com\/index.php\/2016\/12\/11\/unity-design-patterns-memory-management\/","url_meta":{"origin":75,"position":5},"title":"Unity Design Patterns: Optimization","author":"Frank O'Hanlon","date":"December 11, 2016","format":false,"excerpt":"Some low level optimizations present at Unite Los Angeles and Unite Europe 2016. Unite Los Angeles 2016 Move configuration data to Scriptable Objects. Utilize the new instantiate call when parenting an object. Don't needlessly parent objects in production. Batch changes to Transforms in order to save on transform change message\u2026","rel":"","context":"In &quot;Code&quot;","block_context":{"text":"Code","link":"https:\/\/magiteker.com\/index.php\/category\/code\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2016\/10\/Unity_Pattern_Logo2.png?fit=1200%2C675&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2016\/10\/Unity_Pattern_Logo2.png?fit=1200%2C675&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2016\/10\/Unity_Pattern_Logo2.png?fit=1200%2C675&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2016\/10\/Unity_Pattern_Logo2.png?fit=1200%2C675&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2016\/10\/Unity_Pattern_Logo2.png?fit=1200%2C675&ssl=1&resize=1050%2C600 3x"},"classes":[]}],"_links":{"self":[{"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/posts\/75","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/comments?post=75"}],"version-history":[{"count":36,"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/posts\/75\/revisions"}],"predecessor-version":[{"id":1000,"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/posts\/75\/revisions\/1000"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/media\/498"}],"wp:attachment":[{"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/media?parent=75"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/categories?post=75"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/tags?post=75"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}