It’s been a long time since I last posted a (more or less) technical article. So today, I’ll talk about something I recently added to the game: polluted water.
I – What is polluted water?
It’s very simple: it’s some kind of dark water that you can’t go through. If you do, it harms you, and if you stay too long, it kills you. In the game you encounter the polluted water around the 1/2/3 chapter zones.
II – Why adding polluted water?
The ideas behind adding polluted water to the Great Sea in the game are multiple:
1 – The first goal is to be able to create “fordidden” zones, at least at the beginning of the game. This is somehow classical in adventure games: the player is not allowed to fully explore the world, because he could be lost very quickly without having any ideas about where he is supposed to go.
Thus, by creating some polluted water ring around the main first islands, the player has only access to a small world zone to start the game.
2 – Then, polluted water also has a meaning regarding to the scenario. It has a clear explanation as to why it’s there, but it also has consequences on living beings, especially animals (you might have already seen this in the demo).
3 – Finally, I chose to use polluted water instead of other kind of “invisible wall” (for example at some point, I thought about a huge coral barrier ring to stop the player) is that it has to be removable at some point in the game (so that the player can finally go beyond) and it has to be quite cheap on the CPU too. Using huge 3D meshes (such as coral trees) all around the main islands would definitely be too laggy.
III – How to add polluted water?
Technically, this is a difficult point, because the world is quite huge, and as I wanted to create a pollution ring around the first islands of the game, it had to be a huge object (many kilometers long in the game scale).
Like every other object in the game, the pollution ring has a visual appearance, but it also has collision and other properties. I had to work on both these aspects.
Appearance / Rendering / Shader
Regarding the visual appearance, I had a precise idea in my mind, so I designed the shader in a very special way:
- I wanted something that moves slowly and that has a liquid feel to it. Hence I create a shader based on multiple moving seamless noise textures that I blend together with different scales and speed direction.
- I wanted a solid pure black color that would clearly stand out of the blue of the ocean, so I didn’t use any lighting/shading calculations at all.
- I wanted very sharp edges, just as if it was some kind of black oil standing on top of the sea, so I used a “classic” alpha cutout on the mixed texture.
- I wanted to avoid obvious texture repetition. For this purpose, I created huge textures that are mixed with non multiple (prime) scale factors, so that the resulting visual appearance is quite unique for a very long distance.
- I wanted the creation of the mesh and the uv mapping part in Blender to be as easy as possible (I’ll have to create kilometers of this stuff!): I chose to create simple forms, and the uv mapping is automatic.
A section of polluted water in Blender. I can easily deform it and then applied automatic UV mapping without too much effort.
The power of automatic uv mapping.
- But at the same time, I want the edge to slowly scatter around as if there were smaller and smaller polluted stains as we get away from the polluted zone. So I chose to use vertex color as an alpha parameter to blend with the texture: at the center of the polluted zone, the whole texture is visible, so vertices are white. As we go near the edges, vertices are black, and the texture is invisible. The transition between those points is automatically computed thanks to vertex property linear interpolation. And because of the cutout rendering, it won’t show a smooth faded transition, instead it will slowly change the size of the cutout stains.
The vertex colors in Blender: full opacity at the center, and full transparency on the outside.
…resulting in the game in full opacity pollution at the center (on the right side here), and more and more scattered pollution stains on the outside (left side here).
- Moreover, at some point, I want the player to be able to get rid of this polluted zone, so that he could explore the whole world without restriction. This means I also have to add custom parameters to animate the “amount” of visible polluted water, and this should be continuous and integrated well with other parameters.
Collision and properties
When I created this pollution ring, it rises many questions about the gameplay:
1 – Can the player swim through it? if not, this means I just have to put some invisible wall to stop him from going there. I don’t wan’t this. This goes against the “freedom” I want to put in the game. Hence, the player should be able to swim through it.
This means I have to deal damage to the player if he starts to travel a polluted zone. This means I have to set an awfully precise collision test. Here I can’t use the mesh colliders that have almost no details; this would be very unsettling for the player to take damage when he’s at the edge of the polluted zone: visually there would be no black water, but because he would be inside the collision mesh, he would take damage. I would hate that as a player.
So, I have to code a pixel perfect collision test. Then, I must find a way to know if the player position is on a polluted stain. Maybe I could sample the screen at the 2D position of the player before displaying it, but this would require quite some work in the rendering pass, and it’s already quite complicated with all the crazy graphics effects that are already set up. So I chose to re-compute the black/polluted water material shader on the CPU, with the exact same parameters. Hence I ended up writing the shader both for GPU and CPU. I was quite scared of the precision results, but for the moment, this works quite nicely, and it is surprisingly accurate.
2 – But dealing damage is not enough: I must ensure that the player can’t cross the zone even if he has plenty of energy (and apples, and all that stuff). How to do this? This forces me to computed a minimal length for the polluted ring to be sure that the player can’t cross it.
3 – And finally, I also have to deal with the turtle: what happens if the player wants to cross the pollution on the back of his turtle? Does this kill the turtle? I don’t wan’t such a thing to be possible, so I chose to make the turtle refuse to go there. As soon as the turtle approaches the polluted zone, it will fade away any move in the direction of the pollution. This was pretty technical because I had to detect the nearest face normal, which is not straight forward.
Of course this is some kind of invisible wall which may go against the “freedom” philosophy. But it also has some meaning in the game, because the turtle obeys you, unless you start to threaten its life. In this case, it makes sense to me. Moreover, I added a warning from the turtle to make it easier to understand. And, once more, you can still go swim in there if you really want to, but that’s your choice, not the turtle’s.
So that’s all for this post… They are always muuuuch longer than I expect. I hope this was interesting to some of you guys! Don’t hesitate to tell me what you think.
PS: At the moment, I haven’t created the whole polluted zone. I’m pretty sure, given the scale of the final object, that other problems will rise (computation precision with high range distances, z fighting, …)