download include files: solver.zip
more of this stuff: http://blog.mmacklin.com/2010/11/01/adv ... imulation/
it woks with 3D arrays const N must be a power of 2 eg. 16,32,64 ...
Velocity(0, N+1 ,N ,N) ' x forces
Velocity(1, N ,N+1 ,N) ' y forces
Velocity(2 ,N ,N, N+1) ' z forces
Bondaries(N,N,N) ' if <>0 it'a a bondary cell (the fluid can't flow in this cell)
Compression(N,N,N) ' represent the density of any fluid
inside of the sub Boundary you can setup your fluid (if it is first frame)
and you can set / modify cells of Velocity every frame of simulation.
The calculation of compression and flow are only one part of the whole story.
After every step of simulation you get as result the array Compression(N,N,N)
it's the current density of your fluid per cell.
I use a minimal ray tracer as renderer and one light for shadows.
If the ray hits a cell with compression > 0 it calculates the density of 3x3x2 neighbor cells.
If the ray hits the floor a new ray in direction of light tells the renderer if it should use the density between the floor and light as shadow.
bla bla bla :-)
Joshy
here are an example of smoke it's a god idea to compile it like:
fbc -gen gcc -O 3 smoke.bas
on win32 you can enable video capturing also (optional)
Code: Select all
#include once "solver.bi"
#include once "renderer.bi"
#ifdef __FB_WIN32__
#ifndef __FB_64BIT__
'#define CAPTURE_VIDEO ' on win32 you can eanble video capturing
#endif
#endif
#ifdef CAPTURE_VIDEO
#include once "XvidCapture.bi"
#endif
type Smoke3D
public:
declare constructor(byval DeltaTime as single)
declare sub Simulate(byval blnClearBoundary as integer=1)
declare sub Render(byval frame as integer, _
byval eyeXPos as single=0.0, _
byval eyeYPos as single=0.0, _
byval eyeZPos as single=0.0)
private:
declare sub Boundary(byval blnClearVelocity as integer)
declare sub Project
declare sub Advection
const as integer N3D = 32 ' cells(32,32,32)
const as integer N3DM = N3D-1
as Renderer3D ptr Renderer
as Solver3D ptr Solver
as P3D Velocity(2)
as P3D Boundaries
as P3D Compression
as P3D Divergence
as P3D Pressure
as integer physicsframe
as single DeltaTime
end type
constructor Smoke3D(byval TimeStep as single)
DeltaTime = TimeStep
Renderer = new Renderer3D(N3D)
Solver = new Solver3D(DeltaTime)
' Cell Memory Allocation
Velocity(0) = Alloc3D(N3D+1,N3D,N3D)
Velocity(1) = Alloc3D(N3D,N3D+1,N3D)
Velocity(2) = Alloc3D(N3D,N3D,N3D+1)
Compression = Alloc3D(N3D,N3D,N3D)
Boundaries = Alloc3D(N3D,N3D,N3D)
Divergence = Alloc3D(N3D,N3D,N3D)
Pressure = Alloc3D(N3D,N3D,N3D)
end constructor
sub Smoke3D.Project
const as single h = 1.0/N3D
' Compute Divergence
for i as integer=0 to N3DM
dim as integer ip=i+1
for j as integer=0 to N3DM
dim as integer jp=j+1
for k as integer=0 to N3DM
dim as integer kp=k+1
Divergence[i][j][k] = (velocity(0)[ip][j ][k ]- _
velocity(0)[i ][j ][k ]+ _
velocity(1)[i ][jp][k ]- _
velocity(1)[i ][j ][k ]+ _
velocity(2)[i ][j ][kp]- _
velocity(2)[i ][j ][k ]) / h
next
next
next
' Solve Pressure
solver->solve(Pressure, Divergence, boundaries, N3D )
' Subtract Pressure Gradient
for i as integer=0 to N3DM
dim as integer im=i-1
for j as integer=0 to N3DM
dim as integer jm=j-1
for k as integer=0 to N3DM
dim as integer km=k-1
if( i>0) then velocity(0)[i][j][k] -= (Pressure[i][j][k]-Pressure[im][j ][k ])/h
if( j>0) then velocity(1)[i][j][k] -= (Pressure[i][j][k]-Pressure[i ][jm][k ])/h
if( k>0) then velocity(2)[i][j][k] -= (Pressure[i][j][k]-Pressure[i ][j ][km])/h
next
next
next
end sub
sub Smoke3D.Advection
Solver->Advect( @Velocity(0), Compression, N3D)
end sub
sub Smoke3D.Render(byval frame as integer, _
byval eyeXPos as single, _
byval eyeYPos as single, _
byval eyeZPos as single)
Renderer->Render(frame,compression,eyeXPos,eyeYPos,eyeZPos)
end sub
sub Smoke3D.Boundary(byval blnClearVelocity as integer)
if blnClearVelocity then
for i as integer=0 to N3D
for j as integer=0 to N3DM
for k as integer=0 to N3DM
' x-velocity left and right wall
if (i=0 or i=N3D) then Velocity(0)[i][j][k] = 0.0
next
next
next
for i as integer=0 to N3DM
for j as integer=0 to N3D
for k as integer=0 to N3DM
' y-velocity bottom and top wall
if (j=0 or j=N3D) then Velocity(1)[i][j][k] = 0.0
next
next
next
for i as integer=0 to N3DM
for j as integer=0 to N3DM
for k as integer=0 to N3D
' z-velocity near and far wall
if(k=0 or k=N3D) then Velocity(2)[i][j][k] = 0.0
next
next
next
end if
'##############
'# init smoke #
'##############
' if first frame set some cells with initial Smoke
if( physicsframe < 1 ) then
for x as integer=1 to N3DM
for y as integer=N3D\2 to N3D\2
for z as integer =1 to N3DM
'Velocity(1)[x][y][z] = 0
Compression[x][y][z] = 1
next
next
next
end if
' Set cells marked as boundariy to 0
for i as integer=0 to N3DM
dim as integer ip=i+1
for j as integer=0 to N3DM
dim as integer jp=j+1
for k as integer=0 to N3DM
if( boundaries[i][j][k] )=1 then
dim as integer kp=k+1
Compression[i ][j ][k ] = 0.0
Velocity(0)[i ][j ][k ] = 0.0
Velocity(1)[i ][j ][k ] = 0.0
Velocity(2)[i ][j ][k ] = 0.0
Velocity(0)[ip][j ][k ] = 0.0
Velocity(1)[i ][jp][k ] = 0.0
Velocity(2)[i ][j ][kp] = 0.0
end if
next
next
next
' Give some external forces
for x as integer=1 to N3DM
for y as integer=1 to N3DM
for z as integer=1 to N3DM
if boundaries[x][y][z] then continue for
dim as single c=Compression[x][y][z]
'if c<0.1 then
' Compression[x][y][z]=c*0.99
'end if
if x<N3D\2 then
' left side +y velocty
Velocity(1)[x][y][z] += .01
else
' right side -y velocty
Velocity(1)[x][y][z] -= .01
end if
next
next
next
end sub
sub smoke3D.Simulate(byval blnClearBoundary as integer)
windowtitle "phy " & physicsframe
boundary(blnClearBoundary)
project()
advection()
physicsframe+=1
end sub
dim as integer w=512
dim as integer h=w
screenres w,h,32
#ifdef CAPTURE_VIDEO
' create video stream with 25 FPS
var avi = OpenVideoStream("smoke.avi",w,h,25,100)
#endif
dim as integer frame
dim as Smoke3D Smoke = Smoke3D(0.1)
while Inkey()="" andalso frame<24*30
Smoke.Simulate(0)
#ifdef CAPTURE_VIDEO
' render every frame
Smoke.Render frame
' capture frame
if avi then WriteRGBScreen
#else
' no video render only some frames
if frame mod 8=0 then
Smoke.Render frame
end if
#endif
frame+=1
wend
#ifdef CAPTURE_VIDEO
' important close the vide stream
if avi then CloseStream
#else
BSave "tmp.bmp",0
#endif
Windowtitle "ok ..."
sleep