Islands and Land

Published February 08, 2019
Advertisement

I've been slowly progressing on my boating game over the past few weeks, it's been great that I seem to have a few people interested on youtube, despite me having no firm idea on a game design. I guess once you have water and land and boats you can use it for everything from racing to pirates / trading type games.

Physics

Physics has (allegedly) improved since my last blog post, instead of taking just one height sample at the centre of a boat I now use 3 samples in a triangle, to get an idea of the normal at the sea surface. This means that boats can now more closely match the surface instead of just up / down.

triangle.jpg.0a8a5c87ba9765895fc72f5710189fea.jpg

The up / down motion is now working through the physics, rather than my previous approach of running the physics on a level ocean, then applying wave height to the displayed model only. There are disadvantages and advantages to this and it is subject to change. On the plus side it should eventually interact correctly with things like land masses, but currently the impulses to push the boats to sea level cause mad jitter on beaches! :) Boats also can take off now if you drive them over waves over a certain speed.

 

Skybox

First I tried using the world environment to create a skybox in godot, but had very mixed success. It was easy to create a procedural sky but because of the PBR shaders, the boat models etc ended up having a horrible blue colour cast. I tried various methods to get rid of the cast but failed miserably.
In the end as I'm not really interested in PBR for this game I changed the world environment just to clear to a blue colour without a skybox, and I created a quick manual skybox in blender which I move around as the camera moves (needs a little tweaking). This looks good enough for my purposes and it means it doesn't get used in the PBR lighting so no colour cast (in fact I suspect it is defaulting to simpler shaders).

Moving Origin

As I was thinking of maybe having large worlds with a lot of sea to cover, I decided to have a 'moving origin' system to prevent floating point error in physics etc. It is quite easy to put in at an early stage, but more of a nightmare if you leave it till later, so I put it in early.

The third person camera is focused on a particular boat at any time (e.g. player), and if that boat moves more than a certain distance from the origin, the whole world resyncs so that the boat is now centred on the origin, and the objects around are all teleported to their offsets from the player. This seems to work fine providing it is done at the correct time in the physics.

Land

Originally I was thinking of a simple game at sea only, but then realised it would be a lot more flexible to have land too. First I experimented with a simple plane for a beach, with a static collision box underneath it for the physics. I was planning on having a few different variations of beach geography, then stitching them together.

The more I experimented the more I got dissatisfied with this approach, as it looked very inorganic, so I brainstormed for some other techniques. The difficulty was as well as looking right the approach had to work efficiently with the physics (and the moving origin).

I wondered about using Delauney triangulation with some random points to get some land masses, but having a nice c++ implementation already in my library, I couldn't quite face translating this to gdscript. Plus, how would I handle the physics? Maybe Godot handles some polygon soup, but it would probably not be pretty.

Next stop was a heightmap, but again I was worried about the efficiency of the physics and lots of special cases.

island_small.jpg.f04fc26615e8fe4b47d33dc16686be9f.jpg

Then this morning in bed I had a brainwave. Yesterday I had been experimenting and Godot has the ability to automatically build a convex hull physics rep around a mesh. I know from previous experience convex hulls work pretty good with physics, so instead of making e.g. a beach with this technique, why not create an entire island? Maybe I could just place islands on top of each other, interpenetrating, to create more complex coastline?

It probably will look awful on the joins but given the ease of implementation this is my current winning technique. I made a quick low poly island in blender this morning, used the 'convex hull' operator in blender to ensure it was convex, UV mapped it and then did a quick texture paint in 3d paint. Whapped it in the game, added a convex hull static collider, and it's working great!

Usually in these situations I'd also do procedural texturing but gdscript is a little slow for that, when I tried it in my frogger game, so probably just some manual textures for a few island types will do the trick.

Anyway the final result is shown in the video. There might be some physics jiggle on the beach in this, I have to work on the boat physics on land, there seems to be some crazy interpenetration physics bug even in simple circumstances with a box against convex hull, maybe it is a bullet bug or some scaling or epsilon that is wrong.

Next Entry Game of Chess
4 likes 13 comments

Comments

Rutin

Great work !! :)

February 08, 2019 09:02 PM
Awoken

There is something so peaceful about buoyancy and water.  Watching your video reminded me of that peace.  Do you find it a bit relaxing to work on a water game?

February 09, 2019 09:05 PM
lawnjelly
12 hours ago, Awoken said:

There is something so peaceful about buoyancy and water.  Watching your video reminded me of that peace.  Do you find it a bit relaxing to work on a water game?

I think most humans are fascinated by water, we have probably evolved that way, some animals like cats have a fear of it. It would have offered so much to early humans: food, safety (from land predators), a means of transport, maybe drinking water, washing, swimming etc. And if you go far enough back we evolved from sea creatures, so maybe there's still a little of that in our DNA.

Speaking for myself it is quite fun working on the game particularly as I've never lived by the sea / a lake and only experienced it on holiday, so I can experience boating without getting wet so to speak lol.

February 10, 2019 09:57 AM
jonri

A Reddit user sent me a link to your blog here, and you're doing some cool stuff!

I've been working on a Godot module to implement realistic watercraft physics, it started off as a fun little tech demo but it seems like something that people might actually find useful.  I had some great feedback on Reddit, and started a dev blog here if you're interested in my implementation.  I should be able to put my first release out next week, you're welcome to try it and I'd love to have your feedback on whether it might be valuable to you, any problems you encounter, etc.

I'm currently running flat-ocean only, but I have an idea how to handle waves given a user-provided wave function.  I was wondering wondering how complex your wave generation function is, and if overall the performance was acceptable or if you'd do it differently in the future.

February 13, 2019 05:46 PM
lawnjelly

It looks great from the video jonri! :) I'll try and give it a proper look and try out the release. Mine does not calculate the buoyancy accurately at all, it is just a cheap hack, so will be interested to see what method you use.. looks like the Archimedes method. Mine shortcuts all that and just pushes the boat towards being 'upright' if it is off axis. On the plus side it is super cheap so loads of objects is no problem.

Flat ocean I got working first too but I found things got considerably more interesting when I tried to have the boats move with the waves, that really tests things. My current wave function was very simple indeed, I mostly ripped it off a Godot water vertex shader tutorial on youtube (GDQuest maybe?), and is very cheap to calculate CPU side too. Sorry I am away from home for the next week so don't have access to post it, but it was just a couple of sin waves added together. I currently sample 3 points in a triangle around the boat to get an approximate normal for the sea. Intersecting the waves with the volume sounds tricky. Most implementations I have seen are stupidly expensive. If you are super cunning you might be able to use some lookup tables or something to speed it all up, I haven't thought it through.

Another snag is that in some boats I get water showing inside the hulls because of the hollow hull shape. I have read stencil buffer is a way around this but I don't think this is supported in Godot yet.

When I get back I'm going to investigate running the boats as kinematic bodies rather than rigid bodies, and doing the physics all myself because bullet doesn't seem to give any kind of reasonable results on land below 60 ticks per second and I prefer to use 20 or so, my last video on youtube shows this.

February 13, 2019 07:07 PM
jonri

Yes, it's essentially the Archimedes method.  My performance is better than I expected it to be, but I have yet to test it with lots of lower-poly objects (and I have yet to spend much time optimizing).  On a flat ocean, clipping to a plane is easy; clipping perfectly to a wave is indeed computationally expensive.  I like your 3-points method, I'll try doing that to define a clip plane that follows the wave and see how well it does.  If that fails, my other thought is to generate a mini heightmap covering the bounding box of the boat and clip against that.  Then you could tune the resolution of the heightmap to find a balance between performance and accuracy.  This method might also work better for extremely long and narrow boats.

If you have a resource talking about using the stencil buffer for deleting the water inside the boat, I'd be curious to read up on that in the future.  I don't know much about that sort of stuff, so my naive solution was going to be attempting to alter the water mesh around the boat.

Finally, physics.  I turned my physics ticks down to 20 and beached my boat without seeing the same issues you had.  My boat's collision mesh is a convex hull and the land is a trimesh, the only issue is the boat rocks without any damping once it's beached.  If both objects are trimesh, collisions appear to be ignored altogether.  You could try turning on continuous collisions to see if it helps, although mine works either way.  I should also note I've been using the Godot 3.1 betas, if you're on 3.0 there's a chance that they fixed something with the physics engine (but back up your project if you try it!).  And if you do end up switching to a kinematic body, the good news is that all this custom water physics should just keep working.

 

February 13, 2019 11:55 PM
lawnjelly
10 hours ago, jonri said:

I turned my physics ticks down to 20 and beached my boat without seeing the same issues you had.  My boat's collision mesh is a convex hull and the land is a trimesh, the only issue is the boat rocks without any damping once it's beached.  If both objects are trimesh, collisions appear to be ignored altogether.  You could try turning on continuous collisions to see if it helps, although mine works either way.  I should also note I've been using the Godot 3.1 betas, if you're on 3.0 there's a chance that they fixed something with the physics engine (but back up your project if you try it!).  And if you do end up switching to a kinematic body, the good news is that all this custom water physics should just keep working.

Ah that is encouraging. I will try some more collision types when I get back. I had been using an elongated box for the boat, and colliding against a convex hull 'island', a box island, and a trimesh island for testing. I did try with continuous collisions too but no joy. I seem to remember the box worked ok (but isn't useful as land masses aren't box shapes), the convex hull (which I was using) showed the sinking behaviour in the video, and the trimesh also had the boats collided with the triangle edges on flat planes. I think I did try with one of the Godot 3.1 betas, and it didn't solve for me .. but I've been putting off moving to 3.1 as it has been introduced some jitter issues for me, I will wait and see if this is improved once it has been tested more (there was a jitter hysteresis change that was put in which may be affecting this, even when turned off, not sure yet, have not fully investigated). The timing I found better in 3.06.

I went as far as reading through the Bullet docs and they suggest running at at least 60 ticks per second, and they seems to be making this assumption for some of their techniques.

Another thing I would recommend you try is look up tables. It strikes me that for a boat on a flat ocean, at a fixed depth at least, you can precalculate the forces as a result of the archimedes principle for any hull shape, and put this into a 2d lookup table, probably with quite low resolution then interpolate the lookup table results with something like bilinear filtering. If you want to bring depth into this you could also make a 3d lookup table. This would give a super fast and accurate behaviour on a flat surface I believe without any need for expensive checks.

Next thing which may be useful, instead of using a triangle to find the normal at a sea surface, you may also be able to directly calculate the normal at a position in a similar way to calculating the wave height. For instance in 1D if the wave height is sin (x), then the normal might be something simple like cos (x). I haven't tested this out but it might be useful in a simple wave function. Or again you might be able to use lookup tables in some cases.

In fact because different sized boats may be bigger than the size of the waves, approaches based on a few samples might fail badly due to sampling error.

Anyway back to the approximation .. if you have the sea normal, you can then use this to 'reorientate' you boat relative to this sea normal, then use that to look up in your archimedes lookup table, and hey presto, you have super cheap fairly accurate boat physics! :) I think. I haven't tried all this because I was more interested in something simple, but if you are doing an addon for Godot I would recommend investigating this avenue, as well as more brute force methods.

February 14, 2019 10:52 AM
jonri
On 2/13/2019 at 2:07 PM, lawnjelly said:

Another snag is that in some boats I get water showing inside the hulls because of the hollow hull shape. I have read stencil buffer is a way around this but I don't think this is supported in Godot yet.

I found this and thought of your comment here!  All you have to do is make a closed copy of your hull, apply this shader, and make sure your water is drawn afterwards on the transparent pass.  It worked for me without the refraction part, and the only change I had to make to my water shader was setting ALPHA.

This solution is great for me because I'll always need a closed copy of my hull for my buoyancy calculations anyways.  The only downside that I can anticipate is that it might not look correct if you were already looking through another transparent surface such as a window.

 

February 18, 2019 09:02 PM
lawnjelly

Oo I'll have to try that out. ? I'm not sure how expensive it will be yet, that reading back from the screen texture might be a thing.

February 19, 2019 10:29 AM
jonri

Good point.  I looked into it a little more and found it in the official documentation: http://docs.godotengine.org/en/3.0/tutorials/shading/screen-reading_shaders.html

I think it should perform the same as any other screen-space post-processing shader (although I wonder if that means it would interfere with those as well), and it will only capture the screen texture once so having several boats using this at the same time won't decrease performance.

February 19, 2019 02:41 PM
lawnjelly

It might work but usually stuff like that is a big red flag to take care in case of pipeline stalls etc I think. It is all a roundabout way of trying to write to the depth buffer without writing out colour as I understand it? There may be a way of using alpha blending with transparent pixels, and getting the sorting / render order correct, maybe this will be faster. I think there is some support for changing the render order in Godot (I did it for my skybox) but I don't know if you can force this even with blending where things are often sorted back to front.

Speaking for myself I'm also keen to have stuff that will work fast on mobile, so you have to be careful as things like that can kill the framerate for little visual gain. Also this is why my emphasis on shortcuts in the calculations, I saw from your latest version it was using 30-50% CPU. To give comparison, I think mine uses very low, figures around 0.1% CPU for 30 or so boats. However I think your approach could be optimized by using simplified hull (maybe a box or something) and lookup tables if you are feeling brave. I may get round to having a go at this when I eventually get home and can program again! :-)

February 19, 2019 03:40 PM
lawnjelly

Ahha! I have a solution, possibly.

Draw the hulls first using colour without blending. This draws the colour and depth, no blending and is cheap. Draw a skybox over this, without using depth testing or depth write. This will draw the colour over the previous result. Now draw the boats. Now draw the ocean.

I think this might work and would be super cheap. ?

/edit Ah darn this may interfere with the boat rendering. However you could use it to draw masked areas maybe, or get it to work with a cunning shader. I'm sure there must be a cheap solution! ?

February 19, 2019 03:52 PM
jonri
32 minutes ago, lawnjelly said:

It is all a roundabout way of trying to write to the depth buffer without writing out colour as I understand it?

Yes, that is the ideal situation but it's not currently supported.  There are some issue requests open for it, so hopefully it gets implemented eventually.

31 minutes ago, lawnjelly said:

Speaking for myself I'm also keen to have stuff that will work fast on mobile, so you have to be careful as things like that can kill the framerate for little visual gain. Also this is why my emphasis on shortcuts in the calculations, I saw from your latest version it was using 30-50% CPU. To give comparison, I think mine uses very low, figures around 0.1% CPU for 30 or so boats. However I think your approach could be optimized by using simplified hull (maybe a box or something) and lookup tables if you are feeling brave. I may get round to having a go at this when I eventually get home and can program again! ?

My latest CPU numbers were just under 50% all-in, including the rest of the physics, rendering, etc.  I'm not sure what I'm at for just my code.  In that scene, 2 of the 3 boats were unoptimized, there are probably around 2000 potentially-buoyant faces in total, so a simpler hull should make a significant difference.

I'm releasing what I have this week, and one of my goals for a future version will be to offer some options to trade accuracy for speed.  I'll be sure to give it a go on mobile to see how things hold up.

 

30 minutes ago, lawnjelly said:

Draw the hulls first using colour without blending. This draws the colour and depth, no blending and is cheap. Draw a skybox over this, without using depth testing or depth write. This will draw the colour over the previous result. Now draw the boats. Now draw the ocean.

As you noted, this would prevent the inside of the boat from rendering.  You need to sandwich the depth rendering of the closed hull between the rendering of the boat and the water.  If you do find a better workaround, I'd love to know!

February 19, 2019 04:25 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement