Page 1 of 1

fluid dynamics

Posted: Mon Aug 23, 2010 12:26 am
by gnasen
Hey guys,
I was very interested in calculating fluids and coded an include to calculate fluids very fast, so they can be used in games etc.
The theory comes from the paper: "Real-Time Fluid Dynamics for Games" by "Jos Stam" and describes, how to write it in c, so I just converted and enhanced it with some features like walls or different layers. The basic theory is given by the Navier-Stokes Equations.

Image

some more pics: pic 2 pic 3

Features:
-create different fluid boxes and calculate them
-create walls and emitters
-manipulate the input/output directly for much speed
-very easy to use
-examples and help file

Download

Maybe someone needs it / wants to play with it.
greetings, gnasen

Re: fluid dynamics

Posted: Mon Aug 23, 2010 7:06 pm
by idle
thanks.

Re: fluid dynamics

Posted: Mon Aug 23, 2010 7:49 pm
by djes
Great! Thank you :)

Re: fluid dynamics

Posted: Tue Aug 24, 2010 9:47 am
by pjay
Great stuff, really enjoyed playing with this, thanks for posting.

I had to change the drawing routine though, as it was really slow on my laptop & didn't do the fluid dynamics any justice.

Re: fluid dynamics

Posted: Tue Aug 24, 2010 9:55 am
by Joakim Christiansen
pjay wrote:I had to change the drawing routine though, as it was really slow on my laptop & didn't do the fluid dynamics any justice.
If you made it faster then it would be nice of you to share those changes to the code.

Re: fluid dynamics

Posted: Tue Aug 24, 2010 10:33 am
by pjay
Sure thing, I can only vouch that it's faster on my laptop though :)

Code: Select all

IncludeFile "fluid.pbi"

InitSprite()
InitKeyboard()
InitMouse()

Define X.i, Y.i
Define x1.f,y1.f,x2.f,y2.f,r.f,G.f,b.f
Global mouseX.i, mouseY.i, mouseX0.i, mouseY0.i

OpenScreen(800,600,32,"fluid")
#Fluid_Width = 40 : #Fluid_Height = 30
Global XSize = 800 / #Fluid_Width, YSize = 600 / #Fluid_Height
Global HXSize = XSize / 2, HYSize = YSize / 2
;/ create fluid: 
fluid_create(#Fluid_Width,#Fluid_Height,0.1,0,0,3,#True,10)

;/ create arrays to hold the output informations: !!! size must be (width+1)x(height+1) !!!
Global Dim *densR.f(#Fluid_Width + 1,#Fluid_Height + 1): Global Dim *densG.f(#Fluid_Width + 1,#Fluid_Height + 1) : Global Dim *densB.f(#Fluid_Width + 1,#Fluid_Height + 1)
Global Dim *velH.f(#Fluid_Width + 1,#Fluid_Height + 1) : Global Dim *velV.f(#Fluid_Width + 1,#Fluid_Height + 1)

Macro myMax(c)
  If c > 255
    c=255
  EndIf
EndMacro
Procedure input_stuff()
  
  Protected X.i,Y.i
  
  mouseX = MouseX() : mouseY = MouseY()
  
  *densR() = fluid_density_input(1)
  *densG() = fluid_density_input(2)
  *densB() = fluid_density_input(3)
  
  *velH() = fluid_velocity(#fluid_horizontal)
  *velV() = fluid_velocity(#fluid_vertical)
  
  X = mouseX * #Fluid_Width / 800 + 1
  Y = mouseY * #Fluid_Height / 600 + 1
  
  If KeyboardPushed(#PB_Key_1)
    *densR(X,Y) = 5000
  EndIf
  If KeyboardPushed(#PB_Key_2)
    *densG(X,Y) = 5000
  EndIf
  If KeyboardPushed(#PB_Key_3)
    *densB(X,Y) = 5000
  EndIf
  If KeyboardPushed(#PB_Key_4)
    fluid_wall_create(X,Y,2,2)
    fluid_wall_purge()
  EndIf
  If MouseButton(1)
    *velH(X-1,Y-1) = (mouseX-mouseX0)/2
    *velV(X-1,Y-1) = (mouseY-mouseY0)/2
    
    *densR(X-1,Y-1) = 5000
    If Random(1)
      *densG(X-1,Y-1) = 2500
    EndIf
  EndIf
  If MouseButton(2)

    *velH(X,Y) = (mouseX-mouseX0)/2
    *velV(X,Y) = (mouseY-mouseY0)/2
    *densB(X,Y) = 0
    *densR(X,Y) = 0
    *densG(X,Y) = 0
  EndIf
  If KeyboardReleased(#PB_Key_5)
    fluid_density_reset()
    fluid_wall_clear()
    For X = 1 To #Fluid_Width
      For Y = 1 To #Fluid_Height 
        *densR(X,Y) = 100
        *densG(X,Y) = 100
        *densB(X,Y) = 100
      Next
    Next
    
  EndIf
  If KeyboardReleased(#PB_Key_Up)
    fluid_emitter_velocity(X,Y,1,0,-1)
  EndIf
  If KeyboardReleased(#PB_Key_Down)
    fluid_emitter_velocity(X,Y,1,0,1)
  EndIf
  If KeyboardReleased(#PB_Key_Left)
    fluid_emitter_velocity(X,Y,1,-1,0)
  EndIf
  If KeyboardReleased(#PB_Key_Right)
    fluid_emitter_velocity(X,Y,1,1,0)
  EndIf
  
  mouseX0 = mouseX : mouseY0 = mouseY
  
EndProcedure

Repeat
  
  ExamineKeyboard()
  ExamineMouse()
  
  ;/ take out some density, otherwise it will get very full
  fluid_density_reset(1.000001)
  input_stuff()
  
  ;/ calculate the next density step. All emitters will be used automatically here.
  fluid_calc()

    ;/ Read out the density layers / velocity directions to draw some output
    *densR() = fluid_density(1)
    *densG() = fluid_density(2)
    *densB() = fluid_density(3)
    
    *velH() = fluid_velocity(#fluid_horizontal)
    *velV() = fluid_velocity(#fluid_vertical)
    
    CreateImage(1,#Fluid_Width,#Fluid_Height)
    StartDrawing(ImageOutput(1))
    
      For X=0 To #Fluid_Width-1
        For Y=0 To #Fluid_Height-1
        ; draw the density as boxes
        r  = *densR(X,Y) : G  =  *densG(X,Y) : b  =  *densB(X,Y)
        myMax(r) : myMax(G) : myMax(b) ;cut to high values
        
        ; check if wall
        If fluid_iswall(X,Y)
          Plot(X,Y,$FFFFFF)
        Else
          Plot(X,Y,RGB(r,G,b))
        EndIf
      Next
    Next
    StopDrawing()
    ResizeImage(1,800,600,1)
    
    StartDrawing(ScreenOutput())
      DrawImage(ImageID(1),0,0)
      For X = 1 To #Fluid_Width
        For Y = 1 To #Fluid_Height
          ; draw some velocity Vectors into the center of every box. We multiply them by a factor to get good visuals
          x1 = (X-1)*XSize + HXSize  : y1 = (Y-1)*YSize + HYSize
          x2 = x1+*velH(X,Y)*20 : y2 = y1+*velV(X,Y)*20
          LineXY(x1,y1,x2,y2,$FF3F3F)
        Next
      Next
      DrawingMode(#PB_2DDrawing_Transparent )
      DrawText(0,0,"Press following buttons: ",$FFFFFF,$0)
      DrawText(0,20,"1-3: add R/G/B density",$FFFFFF,$0)
      DrawText(0,40,"4: add wall",$FFFFFF,$0)
      DrawText(0,60,"5: clear",$FFFFFF,$0)
      DrawText(0,80,"arrow keys: Add velocity emitter in this direction",$FFFFFF,$0)
      DrawText(0,100,"L-Mouse: hold and move to 'create' velocity",$FFFFFF,$0)
      DrawText(0,120,"Disable Debugger!",$0000FF,$0)
      DrawingMode(#PB_2DDrawing_Default)
      Box(mouseX-1,mouseY-1,3,3,RGB(255,255,255))
    StopDrawing()
    FreeImage(1)
    
  FlipBuffers()
  
Until KeyboardPushed(#PB_Key_Escape)

Re: fluid dynamics

Posted: Tue Aug 24, 2010 11:16 am
by gnasen
yes sorry, in the examples I just used the drawing commands straight forward, without any speed enhancements.
The calculation of the fluid itself is very fast, in the include fluid.pbi itself is at the bottom a little speed benchmark without any graphics.

you changed the value of fluid_density_reset(1) to fluid_density_reset(1.000001). That means that the whole density gets bigger every step. If you want to see "more" of the color, I would suggest to increase this values:

Code: Select all

If KeyboardPushed(#PB_Key_1)
    *densR(x,y) = 10000 ;maybe 10.000 instead of 5.000
EndIf

Re: fluid dynamics

Posted: Tue Aug 24, 2010 11:49 am
by pjay
I've probably changed quite a few of the variable values, due to being a habitual tinkerer..... :)

Re: fluid dynamics

Posted: Wed Jan 19, 2011 3:21 pm
by OldSkoolGamer
Like an early version of Powder Toy to me, but I like it.

Re: fluid dynamics

Posted: Wed Jan 19, 2011 10:38 pm
by PureLust
Hi gnasen, ... very nice one, indeed. Image

remi_meier from the german forum has done a fluid dynamics example in 2006 as well, to which I added a simple GUI and improved the speed a bit.

It differs a bit to yours, because it's not a fluid simulation in a closed tank (like yours) - it's more like an "open sea" simulation.
Further you don't inject ink in his version, you just insert (or change) the "density" of the fluid.
Because of the Gravity, the more heavy fluid will sink which will generate fluctuation.
The display can be switched from showing the density to showing the flow velocity.

Because it seems to be a bit more performant (which could relay to the way it generates the graphical output), it may be of some interest to you: [Link]

Greetz, PL.

Re: fluid dynamics

Posted: Thu Jan 20, 2011 3:32 pm
by gnasen
Thx PureLust, I didnt know that there is existing another fluid dynamic simulation. It looks very good and interesting.

Youre right with your point, the example program is not that performant, because I just used the PB internal drawings on a "bruteforce way" without any speed improvements. Drawing velocity and density at the same time may be a little bit slow, too. Maybe I will improve that in future (or someone other has a look at it ;) ).
If I remember right, there is a speed test without any drawing on the bottom of the include commented.

Indeed you can switch the behaviour from "box" to "open" and create boundaries as you like them (like a ground, a cave...). Even gravity can be created, just modify the velocity with a vector pointing downside.

Im not sure about the "ink-thing" but maybe you (or me) overlooked something. He inserts stuff, which is shown as a color depending on the density. Im doing the same, but in the example I use 3 layers of density, each with its own color instead.

I think the whole topic is very interesting and if I have some time in future, I may rejoin this subject.