[bb] Dynamic Water by Danny [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:39

Previous topic - Next topic

BlitzBot

Title : Dynamic Water
Author : Danny
Posted : 1+ years ago

Description : These functions can easily be used to have your characters footsteps cause ripples in the water.
This Demo shows a boucning ball between two liquid surfaces.
Not fully finished yet, but should get you going.
Hit the left-mouse button to create random splashes...

Heavily 'inspired' on previous samples by Reda Borchardt and Rob Cummings.

Have fun,-
Danny

Sample screen shot:


Code :
Code (blitzbasic) Select
; fxWater Module by Danny van der Ark - dendanny@xs4all.nl
;
; (Heavily) inpired by samples by Reda Borchardt and Rob Cummings.
; use as you like - send me a sample would be cool.
;
; april '04
;

;
; Usage:
;
; 1. Create a water surface using: fxWater_Create( name$, xsize, zsize, dampening#, parent )
;    This function returns the 'type-handle' to the water surface wich you will need later.
;
; 2. Obtain the entity handle (to apply color, texture, alpha, etc) using the function
; fxWater_get_entity( typehandle) -> typehandle is the value returned by fxWater_Create()
;
; 3. Then simply call 'fxWater_Update()' every frame during your main loop.
;
;
; 4. To create a splah in the water use the fxWater_Dimple() function. The function needs the
; type handle that was returned by 'fxWater_Create', the coordinates of the splash, the
; force/strength of the splash and the 'range' or size of the splash.
;
; fxWater_Dimple( hand, x,z, force#=1.0, range#=1.0)
;
; 5. Freeing stuff not done yet because I want to alter it to use memory banks in stead of
; a large static array to store the vertex data - wich should give a more efficient use
; of memory...
;
; You can create as many surfaces of any size as you wish. If you wish surfaces larger than 100x100
; then adjust the fxwater_max_depth/width globals. If you want more than 5 surfaces at the same time
; adjust the fxwater_max accordingly.
;
; It is necesary To 'UpdateNormals' every frame to ensure the highlights are re-calculated every
; frame. Without this the ripples are there, but just not visible. This slows things down
; dramatically ofcourse. Any other ideas welcome....
;
; He ho, enjoy!
;
; ooo
; (_) Danny v.d. Ark



Global fxWATER_MAX = 5 ;max number of active surfaces/effects at one time
Global fxWATER_NUM = 0 ;current number of active water effects.

Global FXWATER_MAX_WIDTH = 100 ;max sub-division for water meshes
Global FXWATER_MAX_DEPTH = 100 ;max sub-division for water meshes

Global FXWATER_MAX_BANKS = fxWATER_MAX * 2
Global FXWATER_NUM_BANKS = 0


Global DEMO_WATER_WIDTH = 40 ;--> Adjust these for different plane sizes / mesh resolution
Global DEMO_WATER_DEPTH  = 40


;reserve memory banks for vertice altitudes
Dim fxWaterBank#(FXWATER_MAX_BANKS, FXWATER_MAX_WIDTH, FXWATER_MAX_DEPTH )


Type fxWaterWave

Field id
Field name$

Field active ;if not ripples then fx is not actiave

Field parent ;parent entity (if any)
Field entity ;water mesh
Field surface ;water surface

Field bank1 ;pointers to array for mem storage
Field bank2

Field width ;width of plane / surface
Field depth ;depth of plane / surface
Field dampening# ;water dynamics

End Type

;Demo options
Global OPT_WIREFRAME = 0
Global OPT_REFRSH = 0
Global OPT_BALLFREEZE= 0
Global OPT_CEILING = 1

;--------------------------------------------------------------------------------------------------

;Graphics3D 640,480,32,1
Graphics3D 640,480,0,2

; Camera + Light
Global campivot = CreatePivot()
Global camera = CreateCamera(campivot)

PositionEntity camera, 0, 0, -35
PointEntity camera, campivot

light = CreateLight(2)
PositionEntity light,-60,0,100
LightColor light,240,240,210
PointEntity light, campivot

light = CreateLight(2)
PositionEntity light,50,0,-50
LightColor light,150,150,180
PointEntity light, campivot

AmbientLight 40,40,40

;load texture
;tex = LoadTexture ("water.tga",1+64)
tex = create_noise_map()

;create water planes
Global w1 = fxWater_Create( "floor",  DEMO_WATER_WIDTH, DEMO_WATER_DEPTH, 0.025 )
water = fxWater_get_entity( w1 )
PositionEntity water, 0, -10, 0
EntityColor water, 30,50,200
EntityShininess water, 0.1
EntityTexture water,tex

Global w2 = fxWater_Create( "ceiling",  DEMO_WATER_WIDTH, DEMO_WATER_DEPTH, 0.025 )
water = fxWater_get_entity( w2 )
FlipMesh water ; flip it because the camera is underneath it
PositionEntity water, 0, 10, 0
EntityColor water, 250,100,100
EntityColor water, 140,130,20
EntityShininess water, 0.1
EntityTexture water,tex

;force refresh
fxWater_dimple( w1, 1,1, 0.001, 0.001)
fxWater_dimple( w2, 1,1, 0.001, 0.001)

;set random ball direction/speed
Global bx#=  0.2
Global by#= -1.75
Global bz#= -0.25

Global bmaxx# =  DEMO_WATER_WIDTH * 0.5 ;half the width of the water plane
Global bmaxy# = 10.0
Global bmaxz# =  DEMO_WATER_DEPTH * 0.5 ;half the depth of the water plane

;create ball
ball = CreateSphere(6)
EntityColor ball, 0,0,0
EntityShininess ball, 1.0
EntityTexture ball, tex

SeedRnd MilliSecs()

; Main Loop
tstart = MilliSecs() + 1000
frame = 0

Global lastx# = 0
Global lasty# = 0
Global lastz# = 0

tim = CreateTimer(50)

l$ = "WavyWaterFx by Danny van der Ark"

While Not KeyHit(1)

;update bouncing ball
update_ball( ball )

;update fxWater
fxWater_update()

;render
    UpdateWorld
    RenderWorld

;debug
Color 000,000,000
Text 2,1, l$
Color 255,255,255
Text 2,0, l$
Color 100,100,100
Text 2,12, "based on samples from Reda Borchardt And Rob Cummings."
Color 20,140,255
Text 2,454, "[ESC] to quit - [D] for fast but dirty refresh(" + OPT_REFRESH + ") - [W] To toggle WireFrame (" + OPT_WIREFRAME + ")"
Text 2,466, "[P] To pause  - [B] to pause/reset ball - [C] to toggle ceiling"
Color 250,250,220
Text 10,220,"FPS  " + fps
Text 10,232,"TRIS " + TrisRendered()

;orbit camera
;TurnEntity campivot, 0, 0.25, 0

;check fps
frame = frame + 1
If MilliSecs() >= tstart Then
fps = frame
frame = 0
tstart = MilliSecs() + 1000
EndIf

;toggle ceiling [C]
If KeyHit(46) Then
OPT_CEILING = 1 - OPT_CEILING
If OPT_CEILING Then
water = fxWater_Get_Entity(w2)
ShowEntity water
Else
water = fxWater_Get_Entity(w2)
HideEntity water
EndIf
EndIf

;pause all [P]
If KeyHit(25) Then
FlushKeys
While Not KeyHit(25) Wend
EndIf

;pause ball [B]
If KeyHit(48) Then
OPT_BALLFREEZE = 1 - OPT_BALLFREEZE
If OPT_BALLFREEZE Then
PositionEntity ball, 0,0,0
bx# = 0
by# = 0
bz# = 0
Else
bx#=Rnd#(-1,1)
by#=Rnd#(-2,2)
bz#=Rnd#(-1,1)
EndIf
EndIf

;wireframe [W]
If KeyHit(17) Then
OPT_WIREFRAME = 1 - OPT_WIREFRAME
WireFrame OPT_WIREFRAME
EndIf

;Dirty refresh [D]
If KeyHit(32) Then
OPT_REFRESH = 1 - OPT_REFRESH
EndIf

;check refresh mode
If OPT_REFRESH Then
;fast and dirty (pot noodle style)
   Flip False
Else
;slow but clean
Flip True
WaitTimer(tim)
EndIf

If MouseHit(1) Then
x = Rnd(1,DEMO_WATER_WIDTH)
z = Rnd(1,DEMO_WATER_DEPTH)
fxWater_Dimple( w1, x, z, 1, 5)
EndIf
Wend

End

;--------------------------------------------------------------------------------------------------

Function update_ball( ent )

;move the ball
TranslateEntity ent, bx,by,bz

DoDimple = False

;check left/right walls
If EntityX#(ent) >  bmaxx-2 Then bx# = bx# * -1
If EntityX#(ent) < -bmaxx+2 Then bx# = bx# * -1

;check ceiling bounce
If EntityY#(ent) >  bmaxy-2 Then
;reverse vertical direction
by# = by# * -1.0
;create dimple
fxWater_Dimple(w2, EntityX(ent)+bmaxx,EntityZ(ent)+bmaxz, -1.0, 5.0)
;slightly alter direction
bx# = bx# + Rnd#(-0.25, 0.25)
bz# = bz# + Rnd#(-0.25, 0.25)
EndIf

;check floor bounce
If EntityY#(ent) < -bmaxy+2 Then
;reverse vertical direction
by# = by# * -1.0
;create dimple
fxWater_Dimple(w1, EntityX(ent)+bmaxx,EntityZ(ent)+bmaxz, 1.0, 5.0)
;slightly alter direction
bx# = bx# + Rnd#(-0.25, 0.25)
bz# = bz# + Rnd#(-0.25, 0.25)
EndIf

;check front/back walls
If EntityZ#(ent) >  bmaxz-2 Then bz# = bz# * -1
If EntityZ#(ent) < -bmaxz+2 Then bz# = bz# * -1

End Function

;--------------------------------------------------------------------------------------------------

Function fxWater_Create( name$="", width=1, depth=1, damp#=0.01, parent=0 )


;create new Wavy water effect plane
w.fxWaterWave = New fxWaterWave

wid = 1
w
ame$ = name$

wactive = True

;create rectangular grid mesh
wwidth = width
wdepth = depth
wdampening#= 1 - damp#

wparent = parent
wentity = create_mesh_plane( wwidth, wdepth, False, parent )
wsurface = GetSurface(wentity,1)

;store handle for quick retrieval during collision
NameEntity wentity, Handle(w)

;reserve memory banks to hold vertex energy
wank1 = fxWater_Create_Buffer()
wank2 = fxWater_Create_Buffer()

;return mesh handle
Return Handle(w)

End Function

;--------------------------------------------------------------------------------------------------

Function fxWater_update()

For w.fxWaterWave = Each fxWaterWave

;if the surface is perfectly flat then this value remains 0
dyna# = 0

;process water
   For x = 1 To wwidth-1
       For z = 1 To wdepth-1
fxWaterBank#(wank2,x,z) = (fxWaterBank#(wank1,x-1,z) + fxWaterBank#(wank1,x+1,z) + fxWaterBank#(wank1,x,z+1) + fxWaterBank#(wank1,x,z-1)) / 2.1-fxWaterBank#(wank2,x,z)
fxWaterBank#(wank2,x,z) = fxWaterBank#(wank2,x,z) * wdampening#
dyna# = dyna# + fxWaterBank#(wank2,x,z)
       Next
   Next

;Only deform patch if necesary
If dyna# <> 0 Then
   ;PatchTransform
k=0
For i = 0 To wdepth
       For j = 0 To wwidth
VertexCoords(wsurface,k,VertexX(wsurface,k),fxWaterBank#(wank2,j,i),VertexZ(wsurface,k))
           k=k+1
       Next
   Next
EndIf

;should be optional - depending on type of texture (slows down seriously!)
UpdateNormals wentity

   ;SwapWaterBuffer
tmp = wank1
wank1 = wank2
wank2 = tmp

Next

End Function

;--------------------------------------------------------------------------------------------------

Function fxWater_Dimple( hand, x,z, force#=1.0, range#=1.0)

w.fxWaterWave = Object.fxWaterWave(hand)

For xg = x - range# * 0.5 To x+range# * 0.5
For zg = z - range# * 0.5 To z+range# * 0.5
If xg> 0 And xg < wwidth And zg>0 And zg<wdepth Then
fxWaterBank#(wank2, xg,zg) = force#
EndIf
Next
Next

End Function

;--------------------------------------------------------------------------------------------------

Function fxWater_get_surface( hand )

w.fxWaterWave = Object.fxWaterWave( hand )
Return wsurface

End Function

;--------------------------------------------------------------------------------------------------

Function fxWater_get_entity( hand )

w.fxWaterWave = Object.fxWaterWave( hand )
Return wentity

End Function

;--------------------------------------------------------------------------------------------------

Function fxWater_Create_Buffer() ; xsize=1, zsize=1 )

If FXWATER_NUM_BANKS >= FXWATER_MAX_BANKS Then
RuntimeError "[fxWater::Create_buffer] Max amount of fxWater memory banks reached!"
Else
;create a new memory bank and resize it to fit
FXWATER_NUM_BANKS = FXWATER_NUM_BANKS + 1
;NOTE: convert array into memory bank
EndIf

Return FXWATER_NUM_BANKS

End Function

;--------------------------------------------------------------------------------------------------

Function fxWater_Free_Buffers( )

;| Frees all buffers. Call as a part of when scene/level is removed from memory.


;NOTE: resize memory banks to 0 (once implemented).

Return 0

End Function

;--------------------------------------------------------------------------------------------------

;Creates a flat grid mesh
Function create_mesh_plane(width=1,depth=1,doublesided=False,parent=0)

tot = width + (depth*width)
mix#= (width+depth) * 0.5

mesh=CreateMesh( parent )
surf=CreateSurface( mesh )

stx#=-.5
sty#=stx
stp#=Float(1)/Float(mix#)
y#=sty#

For a=0 To depth
x#=stx
v#=a/Float(depth)

For b=0 To width
u#=b/Float(width)
AddVertex(surf,x,0,y,u,v)
x=x+stp
Next
y=y+stp
Next

For a=0 To depth-1
For b=0 To width-1
v0=a*(width+1)+b:v1=v0+1
v2=(a+1)*(width+1)+b+1:v3=v2-1
AddTriangle( surf,v0,v2,v1 )
AddTriangle( surf,v0,v3,v2 )
Next
Next

UpdateNormals mesh

If doublesided=True Then EntityFX mesh,16

FitMesh mesh, -width*0.5, 0, -depth*0.5, width, 1, depth

Return mesh


End Function

;--------------------------------------------------------------------------------------------------

Function create_noise_map()

; creates a noise map to be used as a generic reflection map

sq = 128

tex = CreateTexture(sq,sq,65,1)
tbuf = TextureBuffer(tex)
SetBuffer(tbuf)

For x = 0 To sq-1
For y = 0 To sq-1
r = Rnd(100,120)
g = Rnd(100,130)
b = Rnd(190,240)
Color r,g,b
Rect x,y,1,1
Next
Next

SetBuffer(BackBuffer())

Return tex

End Function


;--------------------------------------------------------------------------------------------------
;[end of stuff]


Comments :


churchaxe(Posted 1+ years ago)

 looks very nice!


DJWoodgate(Posted 1+ years ago)

 Yes, very good.  You shoud be able to make it a bit faster by using that Calculate_normal routine SSwift put in the archives a little while ago.  You will need to add a Local statement to his routine though as I think it uses some variables you use as globals.  Comment out the bit where he normalises the normals as well, not required in this case. You may think of other ways to optimise it for use here.Another option I suppose is to fake something that looks somewhat convincing but runs pretty fast.  Not so easy to get something that looks convincing though as you can see from my rather poor effort :(
;Only deform patch if necesary
If Abs(dyna#) > 0.2 Then
    ;PatchTransform
    k=0
    For i = 0 To wdepth
       For j = 0 To wwidth
 h#=fxwaterbank(wank2,j,i)
 VertexCoords(wsurface,k,VertexX(wsurface,k),h,VertexZ(wsurface,k))
 VertexNormal(wsurface,k,-0.8-h*0.25,h*0.1,0.2-h*0.25)
 k=k+1
Next
    Next
EndIf



Ziltch(Posted 1+ years ago)

 Thanks


DJWoodgate(Posted 1+ years ago)

 I guess you could also try adding some noise into the mix.  This uses Rnd() but I expect there are better ways.VertexNormal(wsurface,k, -0.5-h*0.25+Rnd(0.1), 0.5+h*0.1, 0.2-h*0.25+Rnd(0.1))



Danny(Posted 1+ years ago)

 Cheers David,Yes I noticed I made a mistake in the part where it's "not" supposed to update the mesh when nothing is happening. I'll check out that 'vertex normal' stuff you're talking about, looks like good stuff. Also I want to have the 'vertex buffers' stored in variable-sized memory banks in steda of static (memory munching) arrays. I'll reposted when I get there..taDanny,-


explosive(Posted 1+ years ago)

 Very cool stuff.Thanks a lot Danny and all the others.yeah, and I'm gonna send you a sample, if I got something cool


Clyde(Posted 1+ years ago)

 That is amazing, welldone dude!


puki(Posted 1+ years ago)

 Now I have my new super-compuer, it actually runs very quick.


mrjh(Posted 1+ years ago)

 Does this work on animated meshes?


AJirenius(Posted 1+ years ago)

 [edit] [/i]