|
Features

A Real-Time Procedural Universe,
Part Four:
Dynamic Ground Textures and Objects
Volumetric Clouds
The planet demo contains no clouds because I haven't been able to get them working on a planetary scale yet. I want detailed animated volumetric clouds with a climate/weather modeling engine driving them. This seems feasible at relatively small scales, but it has proven to be very difficult on a planetary scale.
GLCloud1 uses a brute-force rendering method. It uses a rectangular 3D grid (96x96x16) of overlapping spherical cloud “cells.” It sorts all nodes and shades them each time the light source or clouds move (press “r” or “m” to make them move). It then sorts all nodes and renders them all each frame in the worst possible way (589,824 calls to glVertex each frame). It looks pretty good and runs fast enough when it is impostored. However, I ran into a ton of problems trying to integrate this with the quad-tree to achieve a dynamic level of detail.
First, the cells had to be made ellipsoids because an individual quad-tree node can be very large. Let's assume we're dealing with a node that is 1,000 km wide and we try to put a 96x96xN grid in each node (which is a ludicrous number of cloud cells when the tree has over a thousand nodes). If N is 1, the smallest overlapping spherical cell would be 20-30 km tall, which would poke into the ground and out into space. You are forced to choose between a ludicrous number of spherical cells or “squashing” them down into very wide and short ellipsoids. Even squashed, the corners of the largest ellipsoids can poke into space because the longest axis of the ellipsoids are straight and the planet's surface curves. To make things worse, the cells from neighboring nodes overlap, making it impossible to render/impostor the cloud cells from each node together. When animating the clouds, either the cells move or the cloud density values shift from one cell to a neighboring cell. Either way, moving density values between nodes at different levels in the quad-tree presented problems.
GLCloud2 was an attempt to cut way back on the number of ellipsoids. It renders two very large ellipsoids and uses a 3D noise texture to add detail. However, 3D texture lookups are expensive, and using larger ellipses required several “slices” to be rendered into each ellipse to provide a solid look and feel. Plus, it is even more expensive to calculate lighting that is less accurate with this implementation. In the end, I didn't feel I had gained much. On the other hand, using a noise texture makes it easier to achieve a per-pixel detail level, and animation effects can be achieved easily by tweaking the texture matrix.
GLCloud3 was an attempt to get around the problems involved with overlapping cloud cells. I decided to try cube-shaped cells that didn't overlap. The algorithm is based on “projected tetrahedra” (Google it). A cube is made up of five tetrahedra, which uses too many triangles for a single cloud cell, so I extended the algorithm to create “projected cubes” without using tetrahedra. The demo draws 1000 cubes spread out a bit so you can make out each individual cube. When put together, they make a large volumetric cube. If I combined this with the 3D noise texture I used in GLCloud2, and impostor the cloud block in each quad-tree node, it might work well enough.
One problem with projected cubes is that my current implementation requires them to be perfectly square. This would work for a game where the “world” is flat, but quad-tree nodes are not square once they've been projected onto a sphere. Near the corners of each top-level cube face, the squares look very squashed. The projected cubes would need to support arbitrary 3D-trapezoidal shapes to match up seamlessly at quad-tree node edges. Another problem is that vertex positions in the cube change every frame when the camera is moving, which means adjusting its position and texture coordinates, and possibly recalculating the lighting for it, every frame. You may be able to avoid calculating the lighting for it by calculating the lighting of the cube's corners, and interpolating for points inside the cube.
In short, clouds are a real pain. Just being volumetric and translucent makes them very difficult. Trying to animate them and fit them into my LOD scheme makes them seem like a nightmare. It might be better to step back and remove clouds from the quad-tree. They should definitely be rendered in their own pass, most likely after everything else is rendered due to their translucency. So far nothing I have been able to dream up will give me the detail I get with GLCloud1, which is what I'd like to achieve.
Conclusion
At this point I'm not sure what else to say. I feel that this is a good start, but I haven't had much time to spend on fleshing it out. There are so many different factories you could create for different types of planets and moons, and I've just barely scratched the surface. If I could get volumetric clouds working, I'd also like to try implementing a gas giant where you could fly down into the swirling clouds. Then I'd work up to a randomly-generated star system, and then a galaxy of random star systems.
The source code is released under the BSD license, so you're free to use any of it in any derivative projects you want to create. If you do use it, please send me an email to let me know what you're using it for. I'll also do what I can to answer any questions you have.
_____________________________________________________
|