Cross engine (DX, OGL) Water surface/waves ?

BlitzMax Forums/BlitzMax Programming/Cross engine (DX, OGL) Water surface/waves ?

Derron(Posted 2016) [#1]
Hi,

before trying for ages (without result) I thought of asking you first:

Is there a way (with default modules) to have a polygon-set being displaced correctly to simulate some kind of water?

I want to avoid diving into "3d" at all, but still want a "bird's view" ocean/water with wave movement (not just ripples). Doing this by textures ends in having a huge amount of textures (animated -> and each 512x512). My intention is, to avoid this.

It would also be good if the ocean does take "y" as z-index, so a ship's trunk (in "birds view") would get partially hidden by the waves. Same for fish jumping out of the water. Maybe with some kind of "z-Mask" (which is then an "y-mask") instead of a "viewport".


I somehow doubt that this is possible easily, but who knows - maybe one of you already tackled this ages ago?


bye
Ron


col(Posted 2016) [#2]
Hiya,

Without thinking too hard about it and kind of throwing ideas in the air to see where they land, plus you may well have tried this already, but you can create your own grid mesh in your app and have a couple of sin / cos waves displace the vertices, and/or displace the uvs to achieve a wave like effect. With a good texture it may achieve the effect that youre looking for?

I've not done this myself but it sounds interesting.


Derron(Posted 2016) [#3]
I thought of such thing too (a grid and sin-wave-plus-whatever-vertice-movement).

While this might work: how to tackle the "overlapping" then? Wait... I have an old game prototype here... which could benefit from this:




See those ice blocks? and the top-icy-ground ?
They should be partially covered by the waves, to the blocks do not "float" on the water but are sunken in a bit.

In this very special case I could use multiple grids with each "starting" right below the ice blocks ... but then I need to make sure that the bottom part of the water-grid "above" fits exactly to the "top part" of the one below (like in a repeatable pattern).




So I need to see the "surface" covering parts of 2D sprites.
I assume it needs a "3D"-approach with the sprites being rotated planes, the ocean being a grid and the camera being in a position making it look as if it was "birds view 2D-rendered".

Is this doable in a way that I only tell "max2D" (+ little initialization code) to do that? I want to avoid recoding things then, when eg. switching to the SDL-graphics-driver of Brucey, or when using srs' DX11.mod .



bye
Ron


col(Posted 2016) [#4]
Ahh I see now, a picture is a thousand words eh :p

With regards to the icy blocks... could you not split the icy block into 2 sprites purely for animated texture reasons. The flat part that the character stands on would be one sprite with a 'fixed' texture, then you'd use another sprite that would be the vertical part that 'dips' into the water.

For the sprite that dips in the water...
With some math and knowing the animation pattern of the waves underneath, and also knowing the position of the 'ice block sprites' in relation to the water waves, can you then animate a texture which has a mix of the ice block and the water?
I imagine if you want random waves them you'd need one texture for each wave pattern that you use - 2 sin waves = 2 textures etc then mask/blend them.

Sounds initially complicated but maybe doable.

EDIT:- BTW is this a retro remake of 'Frostbite' from Acitivision? :p
Looks fun!


col(Posted 2016) [#5]
Doing it in 3d would probably give the best effect for sure - you can still use an orthographic projection to keep everything 2d but do the work in a 3d environment.

To have one poly 'intersect' with the other in the way that you're thinking then you need a depth buffer, however, I'm not sure if the DEPTH_BUFFER flag was implemented in any of the d3d graphics drivers though. Sure it's supposed to be implemented but from memory I'm sure d3d7, d3d9 and d3d11 don't do anything with that flag parameter.


Derron(Posted 2016) [#6]
Yes, Frostbite ;-)

Played this for hours on the Atari 2600.


@ multiple textures
It isn't just the ice blocks, it then needs to work with fish, jumping out and in of the water, and I believe there were crabs too :-)

Also I would like to see that water to be "versatile" (eg. a sandy-pirate-arcade-game).

So preparing multiple textures is very complex then: you need to know the block-dimensions, the space between blocks, the position of the blocks in the world... argh that is never working "easily" ;-)

So doing a "3D-thingy" is surely the better solution. if working directly with polygons in 3D space there should be no need for a depth_buffer (wasn't there a flag to enable it - defaulting to "GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER")).
I then would have it done this way:


    |   
    |  |       |       
       |       |
~~~~~~~|~~~~~~~~|

    A  B       CD

A = Sprite of figure
B = Sprite of ice block (affected by "wavy grid")
C = Sprite of tree
D = Sprite of coast (affected by "wavy grid")


The projection matrix / camera should then be located so the sprites look like "2D" and the wavy grid is correctly hiding and exposing parts of "B" and "C".
(A and C are offset to expose the "order of drawing" - most right is drawn first - at least when it comes to sprites)


Hope this "picture" explains it good enough.


bye
Ron


col(Posted 2016) [#7]
Oh my god, I used to play that for hours and hours too!
It was sooo addictive hehe.

Yeah when you then want to include the other sprites then things would get too complex and out of hand very quickly, so that's a no go :p

I'd definitely attempt 3d in that case then.

I still think that you would need the depth buffer if you want the water to be partially penetrated by the ice blocks ( and only because of this 'partial penetration effect' ), otherwise I'm sure that you will see what you have now. On top of which it looks as though the GRAPHICS_DEPTHBUFFER flag is completely disregarded in all of the d3d drivers. Unless I'm reading the source incorrectly - which is very possible nowadays :D


Derron(Posted 2016) [#8]
Away from "3D":

I know it is not the most realistic approach: but once knowing the water position and the lowest Y ("bottom start-position") of a sprite, we could use the "darkness/brightness" of the water texture to calculate some "waves".

Then we prepare a new spriteset for this very position. Cutting "off" what is a "non-wave-top" then. And also cutting things below a given "wave-height" (to save on sprite memory).

This new sprite is then drawn on top of the water and the blocks.

advantage:
- dynamically createable
- "relatively" simple to create
- does only rely on (Max)2D

disadvantage:
- the more y's used for objects on the water, the more you need
- you cannot use additional blend modes to add "shinyness, reflection-simulation ..." as they would become visible with the new sprite overlaying things then


BTW I tried to convert some c-code last night:

C-source: http://www.lousodrome.net/opengl/#water


But it only displays "nothing". Surely missed something (I do know nothing about OGL/3D-programming-stuff as I never done something with that directly).
So without knowing what "might be not working" I am lost a bit for now. Also the motivation to make it work is a bit lower, as it is - of course - not cross-engine, so it gets a bit "lower level" than desired.


@ Frostbite
Yes, I thought that time: it surely would do well on smartphones - and nowerdays I thought of using it to have it as test-case for BlitzMax-NG (the best thing to find bugs, is to use a tool in the real world).


bye
Ron


col(Posted 2016) [#9]
I can't run the code at the mo but initially it looks as though all vertice positions would be in the -1 to 1 range?, max2d would have set up an ortho matrix and viewport to put 0,0 to the top left with width/height of the screen/window so that you can use screen pixel coordinates.

You could try scaling the vertices to regular max2d screen pixel coordinates?

EDIT:
I just looked through the original source code... I think you should port over the ReshapeFunc function too, plug in the correct width and height and see if that helps. That reshape function looks like it will set the correct projection matrix for that specific demo to work.


Derron(Posted 2016) [#10]
Yes, adding the "reshape"-portion (without the glut***-code) made it display something ... of course untextured etc. but it displays something.

Thanks.


bye
Ron


Derron(Posted 2016) [#11]
Ok extended it a bit:


(instead of the noise written in the sample, I used "Simplex Noise" out of the code archives).

I tried to load the textures but must be doing something wrong... as it does not generate valid mipmaps (if the mipmap-command is run, the "surface" is invisible).

Any clues or hints?


bye
Ron


col(Posted 2016) [#12]
Cool that you're starting to get somewhere :p

If you're having texture issues the first thing I would check is that the BlitzMax format and the actual texture format are the same - same depth/pixel format etc. Reason I suggest this is looking at your code you've commented out the alpha channel of the pixels, does this mean that the image is 24bit? if so then try picking a format in the Build2DMipmaps function that matches the same endianess and bytes per pixel. At the moment you have GL_RGBA which is expecting a 32bit pixel layout? Try GL_RGB?


Brucey(Posted 2016) [#13]
Your GL is not portable, btw ;-)


col(Posted 2016) [#14]
I wouldn't have a clue what's portable or not in the world of GL.
:O)

What's the deal there? Less/more functions? Different functions/parameters? Government cutbacks? :D


Brucey(Posted 2016) [#15]
For example, things like glBegin() are not available on GLES 2. (and knowing that Derron would like to consider his game for (at least) Android...)

Therefore it would probably be better to implement something shader-based.


col(Posted 2016) [#16]
Ahh, so the fixed function pipeline is out, and only the programmable one is available?


Brucey(Posted 2016) [#17]
Yep :-)


Derron(Posted 2016) [#18]
The best option would be not to deal with all this gl stuff but having some generic access to vertices...aka cross-engine functions.

@crossplatform
I know...thought of getting it done first...and then trying to make it compatible to the rest.

Shaders...as long as it includes / handles all the hiding of sprite portions covered by waves..it. would be nice to have... but I doubt it ia that easy then.

With vertices I have my experiences...but with shaders...hmm and then I surely land in OGL/OGLES-country.


@textures even if I mix things up with rgb..it should at least show some odd colors then?!


Bye
Ron


col(Posted 2016) [#19]
@Brucey,
I can only see that as a good thing :p

@textures

Not necessarily, if the driver can't access all of the memory for the texture is may just quit the whole process.

Specifying that the texture is larger than whats available could get the texture upload kicked out altogether, whereas yes, if you said the pixel format was smaller then I would go with you school of thought with getting strange colour effects. My experience would suggest not to make any assumptions of what the driver is doing but be 100% certain everything is as expected.

To be honest I find shaders easier to know whats going on, instead of trying to remember state binding/settings for matrices - that's just me.

@crossplatform
You can wrap the lower level functionality that you need into some Types with a base Interface. There's only 1 gpu and it still does the same thing no matter which api is driving it. If using shaders, then sure the shader language syntax will be different but again, math is math, a vector is a vector and a matrix is still a matrix so the calculations are the same. You're only doing basic shader stuff, ie mimicking the fixed function pipeline, so I would think it's pretty straight forward.

You could possibly use this heirarchy

Type TGLShader Extends IShader
Field _vertexshader:IVertexShader
Field _pixelshader:IPixelShader

Method SetParameters( worldmatrix, vertices:float[] )
[....]
EndMethod
EndType

Type TD3D9Shader
Field _vertexshader:IVertexShader
Field _pixelshader:IPixelShader

Method SetParameters( worldmatrix, vertices:float[] )
[....]
EndMethod
EndType

Then would also do the same for each shader stage... the vertex shader, pixelshader etc.

Everything is always possible, just whether its worth investing the time. I personally think it would be as you can then reuse the shader codes for future projects.


Derron(Posted 2016) [#20]
> Try GL_RGB?

This indeed changed things...


@ extending types

Yes, I know that this would be possible then ... but I did not was enthusiastic about learning something new (shaders) "just for this single purpose" (I know, I could use it later for something I do not know yet).



bye
Ron


Derron(Posted 2016) [#21]
Ok, So I adjusted the code a bit, fixed some "to -vs.- until" thingies

(both images from the download/website linked above)


result:



At least it works somehow (think the slight "moire" comes from the simplex-noise).

So even if now tackling this via "shader", above's code might be helpful for someone else.


bye
Ron


col(Posted 2016) [#22]
That looks cool.
Good job!

For the moire effect you may be able to bias the wave noise function based on whatever axis you have setup for depth - to, in effect, lessen the noise as the distance/axis position increases.