How to get water height?

Everything related to 3D programming
User avatar
minimy
Enthusiast
Enthusiast
Posts: 551
Joined: Mon Jul 08, 2013 8:43 pm
Location: off world

How to get water height?

Post by minimy »

Is there any way to detect the height of the water created with 'CreateWater(' to simulate floating objects?
If translation=Error: reply="Sorry, Im Spanish": Endif
benubi
Enthusiast
Enthusiast
Posts: 215
Joined: Tue Mar 29, 2005 4:01 pm

Re: How to get water height?

Post by benubi »

Apparently the water height (base) is Y=0.

I have modified the Water.pb example to include a few floating barrels; took me some time to get them floating with water friction when under water. I added physics bodies to the entities, and move the ground plane from -5 to -50. When you set the plane to 0 there will be water-less surfaces.

To make it more realistic I suggest you should look into the boat physics example somewhere in this forum. This can be taken as a base for further improvements.

You would to have a list/array of points on the entity to query for submersion; there's also Pick() and raycast functions that can detect water collisions with more precision perhaps. This could be used to apply forces and (counter-) impulses to simulate friction/water contact and submersion, buoyancy. Similarly you could simulate wind on a sail or flat surface, with a set of points on the entity surface to apply wind impulses.


Code: Select all

; ------------------------------------------------------------
;
;   PureBasic - Water
;
;    (c) Fantaisie Software
;
; ------------------------------------------------------------
; with rusty barrels added

;#################################################################################################################

#end_distance=1024*4

Procedure ColorBlend(color1.l, color2.l, blend.f)
  Protected r.w,g.w,b.w,a.w
  r=  Red(color1) + (Red(color2)     - Red(color1)) * blend
  g=Green(color1) + (Green(color2) - Green(color1)) * blend
  b= Blue(color1) + (Blue(color2) -   Blue(color1)) * blend
  a=Alpha(color1) + (Alpha(color2) - Alpha(color1)) * blend
  ProcedureReturn  RGBA(r,g,b,a)
EndProcedure

InitEngine3D():InitSprite():InitKeyboard():InitMouse()

ExamineDesktops():dx=DesktopWidth(0)*0.9:dy=DesktopHeight(0)*0.9
OpenWindow(0, 0,0, DesktopUnscaledX(dx),DesktopUnscaledY(dy), " Water - [PageUp][PageDown] Sun height  [F12] Wireframe  [Esc] quit",#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0), 0, 0, dx, dy, 0, 0, 0)

Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Textures", #PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Models", #PB_3DArchive_FileSystem)
Parse3DScripts()

CreateCamera(0, 0, 0, 100, 100):MoveCamera(0,0,5,0):CameraLookAt(0,2,5,10)

;sky
tx_sky=LoadTexture(#PB_Any,"sky.png")
SkyDome(TextureID(tx_sky),$cc6600,$0088ff,3,400,-0.5,0)

;ocean
tx_water=LoadTexture(#PB_Any,"waternormal.png")
tx_foam=LoadTexture(#PB_Any,"foam.png")
CreateWater(TextureID(tx_water),TextureID(tx_foam),    $cc888800,$886666,  #end_distance,    1.5,1.2,0.2,0.7)

;ground
tx_ground=LoadTexture(#PB_Any,"Dirt.jpg")
CreateMaterial(2,TextureID(tx_ground))
CreatePlane(2,#end_distance*2,#end_distance*2,16,16,#end_distance/64,#end_distance/64)
CreateEntity(2,MeshID(2),MaterialID(2),0,-50,0)
CreateEntityBody(2, #PB_Entity_StaticBody,100)

; barrel
tx_barrel=LoadTexture(#PB_Any,"RustyBarrel.png")
tx_rusty =LoadTexture(#PB_Any,"RustySteel.jpg")
CreateMaterial(3, TextureID(tx_barrel))
CreateMaterial(4, TextureID(tx_rusty))

LoadMesh(3,"Barrel.mesh")
For i.i = 1 To 100
  CreateEntity(i+10, MeshID(3), MaterialID(3), Random(1000)-Random(1000),Random(1000,1),Random(1000)-Random(1000))
  CreateEntityBody(i+10, #PB_Entity_CylinderBody, 1, 0.5, 0.5)
  RotateEntity(i+10,Random(180)-Random(180),Random(180)-Random(180),Random(180)-Random(180))
Next 
EnableWorldPhysics(1)
EnableWorldCollisions(1)

Procedure CameraUserControl(camera,speed.f=0.2,smooth.f=0.1,yfixed.f=1e10)
  Static.f MouseX,Mousey,depx,depz,sdepx,sdepz
  
  depx=-speed*(KeyboardPushed(#PB_Key_Left)-KeyboardPushed(#PB_Key_Right))
  depz=-speed*(KeyboardPushed(#PB_Key_Down)-KeyboardPushed(#PB_Key_Up)-MouseWheel()*20)
  MouseX = -MouseDeltaX() *  0.05
  MouseY = -MouseDeltaY() *  0.05
  RotateCamera(camera, MouseY, MouseX, 0, #PB_Relative)
  sdepx+(depx-sdepx)*smooth
  sdepz+(depz-sdepz)*smooth
  MoveCamera  (camera, sdepX, 0, -sdepz)
  If yfixed<>1e10:MoveCamera(camera,CameraX(camera),yfixed,CameraZ(camera),#PB_Absolute):EndIf
EndProcedure


WorldGravity(0)
Define.f r=1,rr
Repeat
  While WindowEvent():Wend
  ExamineKeyboard()
  ExamineMouse()
  If KeyboardReleased(#PB_Key_F12):fdf=1-fdf:If fdf:CameraRenderMode(0,#PB_Camera_Wireframe):Else:CameraRenderMode(0,#PB_Camera_Textured):EndIf:EndIf
  
  CameraUserControl(0,0.2,0.1)
  
  ; sun height
  r+(KeyboardPushed(#PB_Key_PageUp)-KeyboardPushed(#PB_Key_PageDown))*0.004:If r<0:r=0:ElseIf r>1:r=1:EndIf:rr=Pow(r,0.25)
  CreateLight(0,ColorBlend($0088ff,$ffffff,rr),20000, r*40000,20000)
  AmbientColor($010101*Int(r*48+64))
  Fog(ColorBlend($004488,$ffccaa,r),1,0,#end_distance)

  For i=1 To 100
    If EntityY(i+10)<0
      
      EntityRenderMode(i+10,#PB_Entity_DisplaySkeleton)
      EntityVelocity(i+10,0.99 * GetEntityAttribute(i+10, #PB_Entity_LinearVelocityX),0.99 * GetEntityAttribute(i+10, #PB_Entity_LinearVelocityY),0.99 * GetEntityAttribute(i+10, #PB_Entity_LinearVelocityZ))
      ApplyEntityForce(i+10,0,5.4,0)
    
      
      SetEntityMaterial(i+10,MaterialID(4))
    Else 
      ApplyEntityForce(i+10,0,-9.8,0)                
      EntityRenderMode(i+10,#PB_Entity_CastShadow)      
      SetEntityMaterial(i+10,MaterialID(3))
    EndIf 
  Next 
  RenderWorld()
  FlipBuffers()    
Until KeyboardReleased(#PB_Key_Escape) Or MouseButton(3)
User avatar
minimy
Enthusiast
Enthusiast
Posts: 551
Joined: Mon Jul 08, 2013 8:43 pm
Location: off world

Re: How to get water height?

Post by minimy »

Very, very good your example berrnubi!
Thanks for share and thanks for help me with this.
When you say 'list of points', if im in the right, you refer to getMeshData()? Sorry for my ignorance, Idk other way to get the points. But what is the mesh when use CreateWater(), return value is none.
If translation=Error: reply="Sorry, Im Spanish": Endif
miso
Enthusiast
Enthusiast
Posts: 407
Joined: Sat Oct 21, 2023 4:06 pm
Location: Hungary

Re: How to get water height?

Post by miso »

The vertex shader positions the vertices using a wavelength parameter and a time parameter. The time is automatically updated. I think you must have a text of the shader, and change it to manually update the time parameter to be able to compute the closest 4 vertices (outside the shader) to your 3d entity to get a water height at a given point.
benubi
Enthusiast
Enthusiast
Posts: 215
Joined: Tue Mar 29, 2005 4:01 pm

Re: How to get water height?

Post by benubi »

@miso
I wish I knew how to do it but I believe I can follow you. This is very interesting! I believe it could work.
Height.f=GetWaveHeight(x,z) ; <- that would be nice

I've updated the example to use vertices, and the barrels behave "very well" now including underwater friction. The barrels balance themselves into a horizontal position quickly which looks more realistic. Check the position of each vertex in the world and apply the forces accordingly (gravity, buoyancy and friction).

F1-F3 keys are for resetting barrel positions and angular velocity (F1=random above water, F2=at bottom, F3=at water line). It's 350 barrels now some stick out with color to follow them over two cameras (one is fixed underwater). You can search & change the constant #MAX_BARRELS.

Hypothetical improvements I'd like to test would be to calculate the centroids from the faces of the mesh, and apply the forces there because these would be less calculations and I'd like to see the effect - but I see no CountMeshFaces() command in the help so I'm puzzled on how to find out (Faces=Vertices/3 maybe?).

I think the example could also be improved by checking meshradius and EntitY() vs. 0 Y height, so that we know when it's fully submerged or fully emerged, and then the vertex iterations can be skipped and the forces can be applied in one command (either up or down) and friction is then also predictable.

There are around 132 vertices per barrel; if we use more complex entities such optimizations could be very beneficial, especially if one could reduce the number of vertices checked; imagine a complex submarine with enterior submeshes, you probably want to check only the outer cylinder vertices from the shell and the tower, but not the inside. But I digress as I apparently try to get myself into a preventive burn-out.

Code: Select all

; WaterBarrels.pb
; Barrel boyancy example based on:
; ------------------------------------------------------------
;
;   PureBasic - Water
;
;    (c) Fantaisie Software
;
; ------------------------------------------------------------

;#################################################################################################################

#end_distance = 1024 * 4

Procedure ColorBlend(color1.l, color2.l, blend.f)
  Protected r.w, g.w, b.w, a.w
  r = Red(color1) + (Red(color2) - Red(color1)) * blend
  g = Green(color1) + (Green(color2) - Green(color1)) * blend
  b = Blue(color1) + (Blue(color2) - Blue(color1)) * blend
  a = Alpha(color1) + (Alpha(color2) - Alpha(color1)) * blend
  ProcedureReturn RGBA(r, g, b, a)
EndProcedure

InitEngine3D():InitSprite():InitKeyboard():InitMouse()

ExamineDesktops():dx = DesktopWidth(0) * 1:dy = DesktopHeight(0) * 1
OpenWindow(0, 0, 0, DesktopUnscaledX(dx), DesktopUnscaledY(dy), " Water - [PageUp][PageDown] Sun height  [F12] Wireframe  [Esc] quit", #PB_Window_ScreenCentered | #PB_Window_BorderLess)
OpenWindowedScreen(WindowID(0), 0, 0, dx, dy, 0, 0, 0)

Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Textures", #PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Models", #PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Scripts", #PB_3DArchive_FileSystem)
Parse3DScripts()

CreateCamera(0, 0, 0, 100, 100):MoveCamera(0, 0, 150, 350):CameraLookAt(0, 2, 5, 10)
CreateCamera(1, 80, 0, 20, 20):MoveCamera(1, 0,  -45, 150):CameraLookAt(1, 2, 0, 10)
;sky
tx_sky = LoadTexture(#PB_Any, "sky.png")
SkyDome(TextureID(tx_sky), $cc6600, $0088ff, 3, 400,  -0.5, 0)

;ocean
tx_water = LoadTexture(#PB_Any, "waternormal.png")
tx_foam  = LoadTexture(#PB_Any, "foam.png")
CreateWater(TextureID(tx_water), TextureID(tx_foam), $cc888800, $886666, #end_distance, 1.5, 1.2, 0.2, 0.7)

;ground
tx_ground = LoadTexture(#PB_Any, "Dirt.jpg")
CreateMaterial(2, TextureID(tx_ground))
CreatePlane(2, #end_distance * 2, #end_distance * 2, 16, 16, #end_distance / 64, #end_distance / 64)
CreateEntity(2, MeshID(2), MaterialID(2), 0,  -50, 0)
CreateEntityBody(2, #PB_Entity_StaticBody, 100)

; barrel
tx_barrel = LoadTexture(#PB_Any, "RustyBarrel.png")
tx_rusty  = LoadTexture(#PB_Any, "RustySteel.jpg")
CreateMaterial(3, TextureID(tx_barrel))
CreateMaterial(4, TextureID(tx_rusty))

;alternate material
mat_red    = GetScriptMaterial( - 1, "Color/Red")
mat_green  = GetScriptMaterial( - 1, "Color/Green")
mat_blue   = GetScriptMaterial( - 1, "Color/Blue")
mat_yellow = GetScriptMaterial( - 1, "Color/Yellow")

LoadMesh(3, "Barrel.mesh")
Define BarrelVertices
BarrelVertices = MeshVertexCount(3)
;Debug "Barrel has "+FormatNumber(BarrelVertices,0)+" vertices, "+FormatNumber(BarrelVertices/3)+" faces???"
Dim BarrelVertex.MeshVertex(BarrelVertices + 1)
GetMeshData(3, 0, BarrelVertex(), #PB_Mesh_Vertex, 0, BarrelVertices - 1)

;WorldShadows(#PB_Shadow_Modulative,500) ; DOESNT WORK :(

#MAX_BARRELS = 250

For i.i = 1 To #MAX_BARRELS
  CreateEntity(i + 10, MeshID(3), MaterialID(3), Random(200) - Random(200), Random(200, 1), Random(200) - Random(200), 1 << 7)
 ; ScaleEntity(i+10,0.334,0.334,0.334,#PB_Absolute)
  CreateEntityBody(i + 10, #PB_Entity_CylinderBody, 1, 0.5, 0.5)
  RotateEntity(i + 10, Random(180) - Random(180), Random(180) - Random(180), Random(180) - Random(180))
  SetEntityAttribute(i + 10, #PB_Entity_Restitution, 0.5)
  EntityRenderMode(i + 10, #PB_Entity_CastShadow)
Next

SetEntityMaterial(11, MaterialID(mat_red))
SetEntityMaterial(12, MaterialID(mat_blue))
SetEntityMaterial(13, MaterialID(mat_yellow))
SetEntityMaterial(14, MaterialID(mat_green))



EnableWorldPhysics(1)
EnableWorldCollisions(1)


Procedure CameraUserControl(camera, speed.f = 0.2, smooth.f = 0.1, yfixed.f = 1e10)
  Static.f MouseX, Mousey, depx, depz, sdepx, sdepz
  
  depx   = - speed * (KeyboardPushed(#PB_Key_Left) - KeyboardPushed(#PB_Key_Right))
  depz   = - speed * (KeyboardPushed(#PB_Key_Down) - KeyboardPushed(#PB_Key_Up) - MouseWheel() * 20)
  MouseX = - MouseDeltaX() * 0.05
  MouseY = - MouseDeltaY() * 0.05
  RotateCamera(camera, MouseY, MouseX, 0, #PB_Relative)
  sdepx + (depx - sdepx) * smooth
  sdepz + (depz - sdepz) * smooth
  MoveCamera (camera, sdepX, 0, - sdepz)
  If yfixed <> 1e10:MoveCamera(camera, CameraX(camera), yfixed, CameraZ(camera), #PB_Absolute):EndIf
EndProcedure

Procedure ApplyBarrelWaterForces(Entity, Boyancy.f, Gravity.f)
  Shared BarrelVertex()
  Shared BarrelVertices
  Protected i
  Protected id = EntityID(Entity)
  Protected wavesmall.f = GetWorldAttribute(#PB_Water_WaveHeight) + GetWorldAttribute(#PB_Water_WaveSmall)
  Protected bellow_count
  Protected friction_factor.f
  Protected final_friction.f
  Protected Boyancy2.f = Boyancy / BarrelVertices
  Protected Gravity2.f = Gravity / BarrelVertices
  Protected gx.f, gy.f, gz.f
  Protected e2
  ;  Check for every barrel vertex if it's bellow water surface (wavesmall) or above
  While i < BarrelVertices
    ConvertLocalToWorldPosition(id, BarrelVertex(i)\x, BarrelVertex(i)\y, BarrelVertex(i)\z)
    gx = GetX()
    gy = GetY()
    gz = GetZ()
   ; e2 = RayPick(gx,wavesmall+2,gz,gx,gy,gz,1) ; Raypick doesn't work for now
    If e2 = #PB_World_WaterPick Or gy <= wavesmall ; Bellow Water
      bellow_count + 1
      ; apply boyancy on local entity vertex
      ApplyEntityForce(Entity, 0, Boyancy2, 0, BarrelVertex(i)\x, BarrelVertex(i)\y, BarrelVertex(i)\z, #PB_World, #PB_Local)
    Else
      ; apply gravitation on local entity vertex
      ApplyEntityForce(Entity, 0, Gravity2, 0, BarrelVertex(i)\x, BarrelVertex(i)\y, BarrelVertex(i)\z, #PB_World, #PB_Local)
    EndIf
    i + 1
  Wend
  
  ; ratio of vertices bellow water (for global water
  friction_factor = bellow_count / BarrelVertices
  final_friction  = 1 - (friction_factor * 0.025) ; tweak here, seems ok
  EntityVelocity(Entity, final_friction * GetEntityAttribute(Entity, #PB_Entity_LinearVelocityX), final_friction * GetEntityAttribute(Entity, #PB_Entity_LinearVelocityY), final_friction * GetEntityAttribute(Entity, #PB_Entity_LinearVelocityZ))
  ApplyEntityTorque(Entity, - GetEntityAttribute(Entity, #PB_Entity_AngularVelocityX) * final_friction, - GetEntityAttribute(Entity, #PB_Entity_AngularVelocityY) * final_friction,  - GetEntityAttribute(Entity, #PB_Entity_AngularVelocityZ) * final_friction)
  
EndProcedure



WorldGravity(0)
Define.f r = 1, rr
Repeat
  While WindowEvent():Wend
  ExamineKeyboard()
  ExamineMouse()
  If KeyboardReleased(#PB_Key_F12):fdf = 1 - fdf:If fdf:CameraRenderMode(0, #PB_Camera_Wireframe):Else:CameraRenderMode(0, #PB_Camera_Textured):EndIf:EndIf
  
  CameraUserControl(0, 0.2, 0.1)
  
  ; sun height
  r + (KeyboardPushed(#PB_Key_PageUp) - KeyboardPushed(#PB_Key_PageDown)) * 0.004:If r < 0:r = 0:ElseIf r > 1:r = 1:EndIf:rr = Pow(r, 0.25)
  CreateLight(0, ColorBlend($0088ff, $ffffff, rr), 20000, r * 40000, 20000)
  AmbientColor($010101*Int(r * 48 + 64))
  Fog(ColorBlend($004488, $ffccaa, r), 1, 0, #end_distance)
  
  
  ; Reset barrel positions
  If KeyboardReleased(#PB_Key_F1)
    ; immerge all entities
    For i = 11 To #MAX_BARRELS + 10
      MoveEntity(i, EntityX(i), Random(500, 50), EntityZ(i), #PB_Absolute)
      ApplyEntityTorque(i, Random(3600) - Random(3600), Random(3600) - Random(3600), Random(3600) - Random(3600))
    Next
  ElseIf KeyboardReleased(#PB_Key_F2)
    ; submerge all entities
    For i = 11 To #MAX_BARRELS + 10
      MoveEntity(i, EntityX(i), -45 , EntityZ(i), #PB_Absolute)
      ApplyEntityTorque(i, Random(3600) - Random(3600), Random(3600) - Random(3600), Random(3600) - Random(3600))
    Next
  ElseIf KeyboardReleased(#PB_Key_F3)
    For i = 11 To #MAX_BARRELS + 10
      MoveEntity(i, EntityX(i), 0, EntityZ(i), #PB_Absolute)
      ApplyEntityTorque(i, Random(3600) - Random(3600), Random(3600) - Random(3600), Random(3600) - Random(3600))
    Next
  EndIf  
  
  ; Apply forces
  For i = 1 To #MAX_BARRELS
    ApplyBarrelWaterForces(i + 10, 7.4, -9.8)
  Next
  
  RenderWorld()
  FlipBuffers()
Until KeyboardReleased(#PB_Key_Escape) Or MouseButton(3) Or event = #PB_Event_CloseWindow
User avatar
minimy
Enthusiast
Enthusiast
Posts: 551
Joined: Mon Jul 08, 2013 8:43 pm
Location: off world

Re: How to get water height?

Post by minimy »

Thanks benubi and miso.
Where is WaterHeight(#Camera, x, y)?
Will be nice to have any thing like getWaterHeight(x,z) in PB6.2x
I think this was more easy. :lol:
If translation=Error: reply="Sorry, Im Spanish": Endif
Post Reply