STORM AT SEA! I need help with waves.

Blitz3D Forums/Blitz3D Beginners Area/STORM AT SEA! I need help with waves.

WERDNA(Posted 2008) [#1]
Greetings mortals,
I am the Mighty WERDNA,(lord of darkness.)
And I am making a game that takes place at sea, during a storm.
I need help with adding massive waves, of varying size.
So if anyone can provide some code, or at least some tips on making waves, it would be appreciated.

Thanks mortals.

The Mighty WERDNA.(Lord of darkness)


Moraldi(Posted 2008) [#2]
This is from Archives but I don't remember where I founded. So take the code here:
; fxWater Module by Danny van der Ark - dendanny@...
;
; (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

	w\id		= 1
	w\name$		= name$
	
	w\active	= True
	
	;create rectangular grid mesh
	w\width		= width
	w\depth		= depth
	w\dampening#= 1 - damp#
	
	w\parent	= parent
	w\entity	= create_mesh_plane( w\width, w\depth, False, parent )
	w\surface	= GetSurface(w\entity,1)
	
	;store handle for quick retrieval during collision
	NameEntity w\entity, Handle(w)
	
	;reserve memory banks to hold vertex energy
	w\bank1		= fxWater_Create_Buffer()
	w\bank2		= 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 w\width-1
	        For z = 1 To w\depth-1
				fxWaterBank#(w\bank2,x,z) = (fxWaterBank#(w\bank1,x-1,z) + fxWaterBank#(w\bank1,x+1,z) + fxWaterBank#(w\bank1,x,z+1) + fxWaterBank#(w\bank1,x,z-1)) / 2.1-fxWaterBank#(w\bank2,x,z) 
				fxWaterBank#(w\bank2,x,z) = fxWaterBank#(w\bank2,x,z) * w\dampening#
				dyna# = dyna# + fxWaterBank#(w\bank2,x,z)
	        Next
	    Next

		;Only deform patch if necesary
		If dyna# <> 0 Then
		    ;PatchTransform
			k=0
			For i = 0 To w\depth
		        For j = 0 To w\width
					VertexCoords(w\surface,k,VertexX(w\surface,k),fxWaterBank#(w\bank2,j,i),VertexZ(w\surface,k))
		            k=k+1
		        Next
		    Next
		EndIf

		;should be optional - depending on type of texture (slows down seriously!)
		UpdateNormals w\entity
		
	    ;SwapWaterBuffer
		tmp = w\bank1
		w\bank1 = w\bank2
		w\bank2 = 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 < w\width And zg>0 And zg<w\depth Then
				fxWaterBank#(w\bank2, xg,zg) = force#
			EndIf
		Next
	Next

End Function

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

Function fxWater_get_surface( hand )

	w.fxWaterWave = Object.fxWaterWave( hand )
	Return w\surface

End Function

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

Function fxWater_get_entity( hand )

	w.fxWaterWave = Object.fxWaterWave( hand )
	Return w\entity

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



WERDNA(Posted 2008) [#3]
The Mighty WERDNA gives you his thanks.


chwaga(Posted 2008) [#4]
stop it with the mighty werdna thing, it's annoying

noobs have no right to be cocky :P


GfK(Posted 2008) [#5]
I agree with chwaga. If you're trying to annoy people you're going the right way about it.


WERDNA(Posted 2008) [#6]
Sorry, I'm not trying to annoy you.
I just like being the mighty WERDNA.


Whats My Face(Posted 2008) [#7]
Isn't that method slow for larger scenes? That looks like a lot of polys to me.


markcw(Posted 2008) [#8]
Get fredborg's Water.zip here.

http://www.blitzbasic.com/Community/posts.php?topic=53162


WERDNA(Posted 2008) [#9]
Thanks, I'll check it out.