I spent quite a bit of time working on the weather system for 3089 & I thought I’d share how I implemented it. I had two goals: it must look good and it must be fast. I didn’t want 3089 to start lagging when the rain kicked in, even on lower-end machines, and I believe I accomplished that. On how it looks, take a look at this video (I know I already posted it, but it also is useful for this post!):
The first thing I discovered, is that rain can be accomplished by only being a camera effect. You don’t need to worry about rain in areas you are not looking at or cannot see. So, I just needed to figure out how to display falling rain infront of the player that is exposed to the sky.
The conventional method for implementing rain seemed to be with a particle system above the player’s head. The particle system would have needed to be rather large, since the player in 3089 is quick & we wouldn’t want the player outrunning falling rain particles. Another problem with a particle system is the resources required to handle it… each rain drop would need to be performing collision detection for roofs and trees. Particles would also need to be dropped behind you (since the player could quickly turn around and expect to see rain).
I decided to go with animated billboards. Basically, flat “quads” that will always point towards the player & be textured with falling rain. However, making this system look good & run fast took quite a bit of work. My terrain & buildings are all physics objects & collision detection is handled by the native bullet library that comes with jMonkeyEngine. Therefore, the original plan was to perform a bunch of physics ray tests, from the sky to the ground, infront of the camera to determine where to place the animated billboards of rain. Unfortunately, performing a ray test every frame for every spot infront of the player would require too much processing power than I was comfortable with. I could increase the width of each animated billboard to reduce the resolution of physics ray tests required, but that would too quickly make the rain look worse near edges.
To solve these problems, I did a few things. First, I made all columns of rain snap to a grid. Therefore, if a physics ray test was run on a spot infront of the player, another physics ray test would not need to be done near that area again (it also helps that the terrain doesn’t change, so that previous ray test will remain accurate). Secondly, if a column of rain is being rendered at a certain spot, I don’t need to worry about calculating rain behind that spot — since the closest rain column will obscure more distance rain effects anyway. To implement this system, I first calculate the angle the player is looking in. I then perform a sweep, from left to right, from about -45 degrees to +45 degrees from the player’s direction. For every grid point forward from the current direction being calculated, I perform a ray test from the sky to the ground. If a ray test shows that point is exposed to the sky, I place a rain column and move on to the next angle in the sweeping procedure. If I already had a rain column for that grid-snapped point, I would skip the ray test and also move on to the next angle in the sweeping procedure. Finally, I only do this procedure every tenth of a second instead of every frame.
To handle the falling rain effect, I started by drawing a 32×32 image of falling rain drops. I wrote a custom OpenGL shader that takes in the texture coordinates of the flat column and adds the current time to the vertical component. As time passes, the rain drops! I also added in some code in the shader to make the rain fade (by increasing the alpha) based on the distance from the camera.
This system works pretty good when the player is looking forward, but what happens when the player looks directly up or down? When the player looks up or down, rain needs to be falling around you in all directions. To solve this, I simply determine when the player looks up (or down) enough & modify the sweep procedure to do a full 360 degree scan around the player.
I’m sure there are better rain systems (and I may implement them if I find them!), but I am happy with how this system is working so far. I hope this helped some other developers out there determine how they will implement rain in their 3D games!