Ooops
November 28, 2020, 02:23:38 PM

Author Topic: [bb] Dynamic Water by Danny [ 1+ years ago ]  (Read 517 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
[bb] Dynamic Water by Danny [ 1+ years ago ]
« on: June 29, 2017, 12:28:39 AM »
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
  1. ; fxWater Module by Danny van der Ark - dendanny@xs4all.nl
  2. ;
  3. ; (Heavily) inpired by samples by Reda Borchardt and Rob Cummings.
  4. ; use as you like - send me a sample would be cool.
  5. ;
  6. ; april '04
  7. ;
  8.  
  9. ;
  10. ; Usage:
  11. ;
  12. ; 1. Create a water surface using: fxWater_Create( name$, xsize, zsize, dampening#, parent )
  13. ;    This function returns the 'type-handle' to the water surface wich you will need later.
  14. ;
  15. ; 2. Obtain the entity handle (to apply color, texture, alpha, etc) using the function
  16. ;        fxWater_get_entity( typehandle) -> typehandle is the value returned by fxWater_Create()
  17. ;
  18. ; 3. Then simply call 'fxWater_Update()' every frame during your main loop.
  19. ;
  20. ;
  21. ; 4. To create a splah in the water use the fxWater_Dimple() function. The function needs the
  22. ;        type handle that was returned by 'fxWater_Create', the coordinates of the splash, the
  23. ;        force/strength of the splash and the 'range' or size of the splash.
  24. ;
  25. ;        fxWater_Dimple( hand, x,z, force#=1.0, range#=1.0)
  26. ;
  27. ; 5. Freeing stuff not done yet because I want to alter it to use memory banks in stead of
  28. ;        a large static array to store the vertex data - wich should give a more efficient use
  29. ;        of memory...
  30. ;
  31. ; You can create as many surfaces of any size as you wish. If you wish surfaces larger than 100x100
  32. ; then adjust the fxwater_max_depth/width globals. If you want more than 5 surfaces at the same time
  33. ; adjust the fxwater_max accordingly.
  34. ;
  35. ; It is necesary To 'UpdateNormals' every frame to ensure the highlights are re-calculated every
  36. ; frame. Without this the ripples are there, but just not visible. This slows things down
  37. ; dramatically ofcourse. Any other ideas welcome....
  38. ;
  39. ; He ho, enjoy!
  40. ;
  41. ; ooo
  42. ; (_) Danny v.d. Ark
  43.  
  44.  
  45.  
  46. Global fxWATER_MAX = 5                          ;max number of active surfaces/effects at one time
  47. Global fxWATER_NUM = 0                          ;current number of active water effects.
  48.  
  49. Global FXWATER_MAX_WIDTH = 100          ;max sub-division for water meshes
  50. Global FXWATER_MAX_DEPTH = 100          ;max sub-division for water meshes
  51.  
  52. Global FXWATER_MAX_BANKS = fxWATER_MAX * 2
  53. Global FXWATER_NUM_BANKS = 0
  54.  
  55.  
  56. Global DEMO_WATER_WIDTH  = 40   ;--> Adjust these for different plane sizes / mesh resolution
  57. Global DEMO_WATER_DEPTH  = 40
  58.  
  59.  
  60. ;reserve memory banks for vertice altitudes
  61. Dim fxWaterBank#(FXWATER_MAX_BANKS, FXWATER_MAX_WIDTH, FXWATER_MAX_DEPTH )
  62.  
  63.  
  64. Type fxWaterWave
  65.  
  66.         Field id
  67.         Field name$
  68.        
  69.         Field active            ;if not ripples then fx is not actiave
  70.        
  71.         Field parent            ;parent entity (if any)
  72.         Field entity            ;water mesh
  73.         Field surface           ;water surface
  74.  
  75.         Field bank1                     ;pointers to array for mem storage
  76.         Field bank2
  77.  
  78.         Field width                     ;width of plane / surface
  79.         Field depth                     ;depth of plane / surface
  80.         Field dampening#        ;water dynamics
  81.  
  82. End Type
  83.  
  84. ;Demo options
  85. Global OPT_WIREFRAME = 0
  86. Global OPT_REFRSH        = 0
  87. Global OPT_BALLFREEZE= 0
  88. Global OPT_CEILING       = 1
  89.  
  90. ;--------------------------------------------------------------------------------------------------
  91.  
  92. ;Graphics3D 640,480,32,1
  93. Graphics3D 640,480,0,2
  94.  
  95. ; Camera + Light
  96. Global campivot = CreatePivot()
  97. Global camera = CreateCamera(campivot)
  98.  
  99. PositionEntity camera, 0, 0, -35
  100. PointEntity camera, campivot
  101.  
  102. light = CreateLight(2)
  103. PositionEntity light,-60,0,100
  104. LightColor light,240,240,210
  105. PointEntity light, campivot
  106.  
  107. light = CreateLight(2)
  108. PositionEntity light,50,0,-50
  109. LightColor light,150,150,180
  110. PointEntity light, campivot
  111.  
  112. AmbientLight 40,40,40
  113.  
  114. ;load texture
  115. ;tex = LoadTexture ("water.tga",1+64)
  116. tex = create_noise_map()
  117.  
  118. ;create water planes
  119. Global w1 = fxWater_Create( "floor",  DEMO_WATER_WIDTH, DEMO_WATER_DEPTH, 0.025 )
  120. water = fxWater_get_entity( w1 )
  121. PositionEntity water, 0, -10, 0
  122. EntityColor water, 30,50,200
  123. EntityShininess water, 0.1
  124. EntityTexture water,tex
  125.  
  126. Global w2 = fxWater_Create( "ceiling",  DEMO_WATER_WIDTH, DEMO_WATER_DEPTH, 0.025 )
  127. water = fxWater_get_entity( w2 )
  128. FlipMesh water ; flip it because the camera is underneath it
  129. PositionEntity water, 0, 10, 0
  130. EntityColor water, 250,100,100
  131. EntityColor water, 140,130,20
  132. EntityShininess water, 0.1
  133. EntityTexture water,tex
  134.  
  135. ;force refresh
  136. fxWater_dimple( w1, 1,1, 0.001, 0.001)
  137. fxWater_dimple( w2, 1,1, 0.001, 0.001)
  138.  
  139. ;set random ball direction/speed
  140. Global bx#=  0.2
  141. Global by#= -1.75
  142. Global bz#= -0.25
  143.  
  144. Global bmaxx# =  DEMO_WATER_WIDTH * 0.5 ;half the width of the water plane
  145. Global bmaxy# = 10.0
  146. Global bmaxz# =  DEMO_WATER_DEPTH * 0.5 ;half the depth of the water plane
  147.  
  148. ;create ball
  149. ball = CreateSphere(6)
  150. EntityColor ball, 0,0,0
  151. EntityShininess ball, 1.0
  152. EntityTexture ball, tex
  153.  
  154. SeedRnd MilliSecs()
  155.  
  156. ; Main Loop
  157. tstart = MilliSecs() + 1000
  158. frame = 0
  159.  
  160. Global lastx# = 0
  161. Global lasty# = 0
  162. Global lastz# = 0
  163.  
  164. tim = CreateTimer(50)
  165.  
  166. l$ = "WavyWaterFx by Danny van der Ark"
  167.  
  168. While Not KeyHit(1)
  169.  
  170.         ;update bouncing ball
  171.         update_ball( ball )
  172.        
  173.         ;update fxWater
  174.         fxWater_update()
  175.        
  176.         ;render
  177.     UpdateWorld
  178.     RenderWorld
  179.  
  180.         ;debug
  181.         Color 000,000,000
  182.         Text 2,1, l$
  183.         Color 255,255,255
  184.         Text 2,0, l$
  185.         Color 100,100,100
  186.         Text 2,12, "based on samples from Reda Borchardt And Rob Cummings."
  187.         Color 20,140,255
  188.         Text 2,454, "[ESC] to quit - [D] for fast but dirty refresh(" + OPT_REFRESH + ") - [W] To toggle WireFrame (" + OPT_WIREFRAME + ")"
  189.         Text 2,466, "[P] To pause  - [B] to pause/reset ball - [C] to toggle ceiling"
  190.         Color 250,250,220
  191.         Text 10,220,"FPS  " + fps
  192.         Text 10,232,"TRIS " + TrisRendered()
  193.  
  194.         ;orbit camera
  195.         ;TurnEntity campivot, 0, 0.25, 0
  196.  
  197.         ;check fps
  198.         frame = frame + 1
  199.         If MilliSecs() >= tstart Then
  200.                 fps = frame
  201.                 frame = 0
  202.                 tstart = MilliSecs() + 1000
  203.         EndIf
  204.  
  205.         ;toggle ceiling [C]
  206.         If KeyHit(46) Then
  207.                 OPT_CEILING = 1 - OPT_CEILING
  208.                 If OPT_CEILING Then
  209.                         water = fxWater_Get_Entity(w2)
  210.                         ShowEntity water
  211.                 Else
  212.                         water = fxWater_Get_Entity(w2)
  213.                         HideEntity water
  214.                 EndIf
  215.         EndIf
  216.        
  217.         ;pause all [P]
  218.         If KeyHit(25) Then
  219.                 FlushKeys
  220.                 While Not KeyHit(25) Wend
  221.         EndIf
  222.  
  223.         ;pause ball [B]
  224.         If KeyHit(48) Then
  225.                 OPT_BALLFREEZE = 1 - OPT_BALLFREEZE
  226.                 If OPT_BALLFREEZE Then
  227.                         PositionEntity ball, 0,0,0
  228.                         bx# = 0
  229.                         by# = 0
  230.                         bz# = 0
  231.                 Else
  232.                         bx#=Rnd#(-1,1)
  233.                         by#=Rnd#(-2,2)
  234.                         bz#=Rnd#(-1,1)
  235.                 EndIf
  236.         EndIf
  237.  
  238.         ;wireframe [W]
  239.         If KeyHit(17) Then
  240.                 OPT_WIREFRAME = 1 - OPT_WIREFRAME
  241.                 WireFrame OPT_WIREFRAME
  242.         EndIf
  243.        
  244.         ;Dirty refresh [D]
  245.         If KeyHit(32) Then
  246.                 OPT_REFRESH = 1 - OPT_REFRESH
  247.         EndIf  
  248.  
  249.         ;check refresh mode
  250.         If OPT_REFRESH Then
  251.                 ;fast and dirty (pot noodle style)
  252.             Flip False
  253.         Else
  254.                 ;slow but clean
  255.                 Flip True
  256.                 WaitTimer(tim)
  257.         EndIf
  258.  
  259.         If MouseHit(1) Then
  260.                 x = Rnd(1,DEMO_WATER_WIDTH)
  261.                 z = Rnd(1,DEMO_WATER_DEPTH)
  262.                 fxWater_Dimple( w1, x, z, 1, 5)
  263.         EndIf
  264. Wend
  265.  
  266. End
  267.  
  268. ;--------------------------------------------------------------------------------------------------
  269.  
  270. Function update_ball( ent )
  271.  
  272.         ;move the ball
  273.         TranslateEntity ent, bx,by,bz
  274.  
  275.         DoDimple = False
  276.        
  277.         ;check left/right walls
  278.         If EntityX#(ent) >  bmaxx-2 Then bx# = bx# * -1
  279.         If EntityX#(ent) < -bmaxx+2 Then bx# = bx# * -1
  280.  
  281.         ;check ceiling bounce
  282.         If EntityY#(ent) >  bmaxy-2 Then
  283.                 ;reverse vertical direction
  284.                 by# = by# * -1.0
  285.                 ;create dimple
  286.                 fxWater_Dimple(w2, EntityX(ent)+bmaxx,EntityZ(ent)+bmaxz, -1.0, 5.0)
  287.                 ;slightly alter direction
  288.                 bx# = bx# + Rnd#(-0.25, 0.25)
  289.                 bz# = bz# + Rnd#(-0.25, 0.25)
  290.         EndIf
  291.  
  292.         ;check floor bounce
  293.         If EntityY#(ent) < -bmaxy+2 Then
  294.                 ;reverse vertical direction
  295.                 by# = by# * -1.0
  296.                 ;create dimple
  297.                 fxWater_Dimple(w1, EntityX(ent)+bmaxx,EntityZ(ent)+bmaxz, 1.0, 5.0)
  298.                 ;slightly alter direction
  299.                 bx# = bx# + Rnd#(-0.25, 0.25)
  300.                 bz# = bz# + Rnd#(-0.25, 0.25)
  301.         EndIf
  302.  
  303.         ;check front/back walls
  304.         If EntityZ#(ent) >  bmaxz-2 Then bz# = bz# * -1
  305.         If EntityZ#(ent) < -bmaxz+2 Then bz# = bz# * -1
  306.  
  307. End Function
  308.  
  309. ;--------------------------------------------------------------------------------------------------
  310.  
  311. Function fxWater_Create( name$="", width=1, depth=1, damp#=0.01, parent=0 )
  312.  
  313.  
  314.         ;create new Wavy water effect plane
  315.         w.fxWaterWave = New fxWaterWave
  316.  
  317.         wid             = 1
  318.         w
  319. ame$            = name$
  320.        
  321.         wactive = True
  322.        
  323.         ;create rectangular grid mesh
  324.         wwidth          = width
  325.         wdepth          = depth
  326.         wdampening#= 1 - damp#
  327.        
  328.         wparent = parent
  329.         wentity = create_mesh_plane( wwidth, wdepth, False, parent )
  330.         wsurface        = GetSurface(wentity,1)
  331.        
  332.         ;store handle for quick retrieval during collision
  333.         NameEntity wentity, Handle(w)
  334.        
  335.         ;reserve memory banks to hold vertex energy
  336.         wank1          = fxWater_Create_Buffer()
  337.         wank2          = fxWater_Create_Buffer()
  338.        
  339.         ;return mesh handle
  340.         Return Handle(w)
  341.        
  342. End Function
  343.  
  344. ;--------------------------------------------------------------------------------------------------
  345.  
  346. Function fxWater_update()
  347.  
  348.         For w.fxWaterWave = Each fxWaterWave
  349.  
  350.                 ;if the surface is perfectly flat then this value remains 0
  351.                 dyna# = 0
  352.                
  353.                 ;process water
  354.             For x = 1 To wwidth-1
  355.                 For z = 1 To wdepth-1
  356.                                 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)
  357.                                 fxWaterBank#(wank2,x,z) = fxWaterBank#(wank2,x,z) * wdampening#
  358.                                 dyna# = dyna# + fxWaterBank#(wank2,x,z)
  359.                 Next
  360.             Next
  361.  
  362.                 ;Only deform patch if necesary
  363.                 If dyna# <> 0 Then
  364.                     ;PatchTransform
  365.                         k=0
  366.                         For i = 0 To wdepth
  367.                         For j = 0 To wwidth
  368.                                         VertexCoords(wsurface,k,VertexX(wsurface,k),fxWaterBank#(wank2,j,i),VertexZ(wsurface,k))
  369.                             k=k+1
  370.                         Next
  371.                     Next
  372.                 EndIf
  373.  
  374.                 ;should be optional - depending on type of texture (slows down seriously!)
  375.                 UpdateNormals wentity
  376.                
  377.             ;SwapWaterBuffer
  378.                 tmp = wank1
  379.                 wank1 = wank2
  380.                 wank2 = tmp
  381.  
  382.         Next
  383.  
  384. End Function
  385.  
  386. ;--------------------------------------------------------------------------------------------------
  387.  
  388. Function fxWater_Dimple( hand, x,z, force#=1.0, range#=1.0)
  389.        
  390.         w.fxWaterWave = Object.fxWaterWave(hand)
  391.  
  392.         For xg = x - range# * 0.5 To x+range# * 0.5
  393.                 For zg = z - range# * 0.5 To z+range# * 0.5
  394.                         If xg> 0 And xg < wwidth And zg>0 And zg<wdepth Then
  395.                                 fxWaterBank#(wank2, xg,zg) = force#
  396.                         EndIf
  397.                 Next
  398.         Next
  399.  
  400. End Function
  401.  
  402. ;--------------------------------------------------------------------------------------------------
  403.  
  404. Function fxWater_get_surface( hand )
  405.  
  406.         w.fxWaterWave = Object.fxWaterWave( hand )
  407.         Return wsurface
  408.  
  409. End Function
  410.  
  411. ;--------------------------------------------------------------------------------------------------
  412.  
  413. Function fxWater_get_entity( hand )
  414.  
  415.         w.fxWaterWave = Object.fxWaterWave( hand )
  416.         Return wentity
  417.  
  418. End Function
  419.  
  420. ;--------------------------------------------------------------------------------------------------
  421.  
  422. Function fxWater_Create_Buffer() ; xsize=1, zsize=1 )
  423.  
  424.         If FXWATER_NUM_BANKS >= FXWATER_MAX_BANKS Then
  425.                 RuntimeError "[fxWater::Create_buffer] Max amount of fxWater memory banks reached!"
  426.         Else
  427.                 ;create a new memory bank and resize it to fit
  428.                 FXWATER_NUM_BANKS = FXWATER_NUM_BANKS + 1
  429.                 ;NOTE: convert array into memory bank
  430.         EndIf
  431.  
  432.         Return FXWATER_NUM_BANKS
  433.        
  434. End Function
  435.  
  436. ;--------------------------------------------------------------------------------------------------
  437.  
  438. Function fxWater_Free_Buffers( )
  439.  
  440. ;| Frees all buffers. Call as a part of when scene/level is removed from memory.
  441.  
  442.  
  443.         ;NOTE: resize memory banks to 0 (once implemented).
  444.  
  445.         Return 0
  446.        
  447. End Function
  448.  
  449. ;--------------------------------------------------------------------------------------------------
  450.  
  451. ;Creates a flat grid mesh
  452. Function create_mesh_plane(width=1,depth=1,doublesided=False,parent=0)
  453.  
  454.         tot = width + (depth*width)
  455.         mix#= (width+depth) * 0.5
  456.        
  457.         mesh=CreateMesh( parent )
  458.         surf=CreateSurface( mesh )
  459.        
  460.         stx#=-.5
  461.         sty#=stx
  462.         stp#=Float(1)/Float(mix#)
  463.         y#=sty#
  464.        
  465.         For a=0 To depth
  466.                 x#=stx
  467.                 v#=a/Float(depth)
  468.                
  469.                 For b=0 To width
  470.                         u#=b/Float(width)
  471.                         AddVertex(surf,x,0,y,u,v)
  472.                         x=x+stp
  473.                 Next
  474.                 y=y+stp
  475.         Next
  476.        
  477.         For a=0 To depth-1
  478.                 For b=0 To width-1
  479.                         v0=a*(width+1)+b:v1=v0+1
  480.                         v2=(a+1)*(width+1)+b+1:v3=v2-1
  481.                         AddTriangle( surf,v0,v2,v1 )
  482.                         AddTriangle( surf,v0,v3,v2 )
  483.                 Next
  484.         Next
  485.        
  486.         UpdateNormals mesh
  487.  
  488.         If doublesided=True Then EntityFX mesh,16
  489.        
  490.         FitMesh mesh, -width*0.5, 0, -depth*0.5, width, 1, depth
  491.        
  492.         Return mesh
  493.  
  494.        
  495. End Function
  496.  
  497. ;--------------------------------------------------------------------------------------------------
  498.  
  499. Function create_noise_map()
  500.  
  501. ; creates a noise map to be used as a generic reflection map
  502.  
  503.         sq = 128
  504.  
  505.         tex = CreateTexture(sq,sq,65,1)
  506.         tbuf = TextureBuffer(tex)
  507.         SetBuffer(tbuf)
  508.        
  509.         For x = 0 To sq-1
  510.                 For y = 0 To sq-1
  511.                         r = Rnd(100,120)
  512.                         g = Rnd(100,130)
  513.                         b = Rnd(190,240)
  514.                         Color r,g,b
  515.                         Rect x,y,1,1
  516.                 Next
  517.         Next   
  518.        
  519.         SetBuffer(BackBuffer())
  520.        
  521.         Return tex
  522.  
  523. End Function
  524.  
  525.  
  526. ;--------------------------------------------------------------------------------------------------
  527. ;[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 :(
Code: [Select]
;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.
Code: [Select]
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]

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal