Defluid - 2D fluid simulation

Hi! :smiley:

I would like to share with you DEFLUID - my asset to create 2D fluid simulation based on metaballs:

(Logo made with DesignEvo)

It contains a premade game object that serves as an emitter of metaballs - game objects with a sprite and a special material that uses a custom fragment program to simulate viscosity of the fluid.

Set the Defluid script properties as you wish or even copy the Defluid game object and create your own metaballs - for example with different collision objects, etc.

Defluid emitter properties:

Num of metaballs - number of created at once game objects
Scale of metaballs - uniform scale of a metaball game object
Emitter width - width of the box in which the metaballs are created
Emitter height - height of the box in which the metaballs are created
Dry Each After - will “dry” - animate each object’s scale down and at the end delete it after each amount of time (in seconds, set to 0 to turn drying off)
Create at init - create num_of_metaballs objects at the defluid object creation
Debug physics - turn on Defold built-in physics debug visualisation

You can then send messages to this game objects:

activate – create metaballs based on object’s properties
change – change object’s properties: num_of_metaballs, emitter_width, emitter_height, dry_each_after
force – apply one force vector to each metaball
dry – “dry” fluid - animate each metaball’s scale down to zero and at the end delete that object
remove – delete all metaballs instantly

Additionaly you can set up the property of defluid_plane:
Fluid Color - allows to change the color of metaballs

and send message to defluid_plane to change the color of metaballs:
change_color – message.color [vmath.vector4()] - change tint of rendered metaballs

The best option to get familiar with this is to check out my example :wink:

-- DEFLUID example
-- This example shows how can you modify defluid game object by sending messages to its script.

function init(self)"/defluid", "activate")	-- activate creation of metaballs (fluid)"/defluid", "change", { dry_each_after = 1 })	-- change param of defluid
	timer.delay(3.5, false, function() 	-- after 3.5 s push up all metaballs"/defluid", "force", { force = vmath.vector3(0,10000000,0) })
	end)"/defluid", "dry")			-- activate drying (dry a metaball every second)

function final(self)"/defluid", "remove")		-- if needed you can destroy metaballs anytime

To make it work:

  • use included render with a custom render script (modify Render to /defluid/defluid.render in your game.project)
  • add Rendercam library dependency in your game.project (I used
  • add Rendercam camera object to your collection
  • add defluid_plane object (which has a render target plane) to your collection
  • adjust your game.project to your needs - modify gravity, max collisions and max contacts (in example I used respectively -1000, 4096, 4096)
  • add defluid object(s) to your collection and adjust its properties

Note: Defluid metaballs have its default collision objects with:
group: defluid
masks: defluid, ground, mob

Enjoy it and create awesome games with Defluid! :wink:
May Deforce be with you!



whoah! looks nice.
Do you have a project where you’re using it already?

1 Like

For now, only the example, but I want to implement it of course in my Pixel Art Witchcrafter as one of the elements - water :smiley: Aaaand I was thinking about our Jam too, but no promises :smiley:

1 Like

I haven’t looked inside yet. So did you write everything in C or was lua fast enough in your tests?

It’s all based technically on Defold’s components such as material, render target, fragment program, collision objects and game objects :smiley: It’s not a native extension, it’s just the example of what you can actually create in Defold and that’s amazing :smiley: In that way any user can modify it willingly! :wink:


Maybe I’ll explain a little bit how it works:

Defluid base is a particle (metaball) game object consisted of the collision object and the built-in sprite - particle_blob. It has its alpha gradually dropping to zero and it’s the main trick behind metaballs.
image image

If you create a lot of those metaballs they are interacting with each other and walls and other obstacles as the normal dynamic collision object do. So no coding here, everything is handled by Defold physics (Box2D)

The sprite have a custom material and it is rendered separated from other objects - sprites, tiles, particles and gui.

The trick is in the render_script - Metaballs and everything else is there drawn on the other render target - a plane which has a special material with custom fragment program, its core is very simple:

void main()
    vec4 metaball = texture2D(tex_metaball, var_texcoord0.xy);
    vec4 base = texture2D(tex_base, var_texcoord0.xy);

    float threshold = 0.9999;

    if (metaball.a > threshold) {
    	metaball = color;
    else {
    	metaball = vec4(0,0,0,1);

    base += metaball;
    gl_FragColor = base;

In above you can see that two textures are taken into consideration and for metaballs there is a condition that must be fulfilled to draw it on the plane - the sum of all alpha in the currently calculated pixel must be above the threshold - if not, the pixel’s color is changed.

At the end the textures are overlaped (added into each other) and displayed. It creates the effect of viscosity whenever the sprites are ‘strongly’ overlaping.


thanks! Once again, this looks cool.

1 Like

Thanks for doing the hard work for me of creating fluid physics in Chemaria. :laughing:

1 Like

Yeah, it will suite Chemaria very well! :smiley:

1 Like

But on mobile chrome, I cannot see any water.

Wow, on my mobile browsers there isn’t even demo to click on to run :stuck_out_tongue: this regards others assets too, I honestly don’t know how Defold should work on mobile browsers, because it isn’t supported on them at all

It requires your mobile browser to support WebGL I think.

The above issue is probably related to a shader problem where on desktop it’s more forgiving.

@COCO is it possible to look at console output of your browser? It would give a clue.

@Pawel try to click … and ask for Desktop version of site. For some reason the CSS disables the demo on mobile layout. @Axel

I tested on Nexus S8 and it also does not show the liquid. I’ll try to do remote debugging now to see if I can get the error…

1 Like

Just a shot in the dark, but might be this line:
metaball = vec4(0,0,0,1);

Dont think webgl allows non-float initializer in vectors, so try replacing It with ”… = vec4(0.0, 0.0, 0.0, 1.0);” and see if it works.


Here’s output from remote debugging mobile browser

I’ll download project and see if I can get it to run right on my phone.


I tried to add .0 to everything in the shaders and it made no difference. I know Defold proejcts work on this phone… the console doesn’t seem to give enough useful info for what is wrong?

Yeah doesn’t look like serious errors if its running but not displaying correctly. It’s likely a shader issue: low precision perhaps?

Shaders are always my hurts.

1 Like

Tried testing changing everything to highp and made no difference, water didn’t show up.

Have you tried debugging through Safari?

I have not, only tried Chrome remote debugging with Android phone. I don’t have an iOS device handy at the moment so someone else will have to try and see if it gives any more useful info.