Home       About Me       Contact       Downloads       Part 36    Part 38   

Part 37: Fog

October 16, 2011

Well, I still have a few bugs in the demo, but it has been 10 days since the last part, and it works well enough. So let's talk about fog.

Fog is caused by water droplets in the air, which both reflect light from the sun and block light from objects you can see. Fog would be useful in the game if we wanted a really foggy area, but for two other reasons as well. First, a small amount of fog or mist washes out distant scenery. Your eyes expect that and so it becomes another visual cue that an object is distant. Second, in a game where we are loading distant scenery as you move, a dense fog at the view distance could hide the loading operation.

We can implement a simple version of fog by taking the distance to a pixel when we draw it, and dividing that by the maximum fog distance. Then we just blend in a fog color in this proportion -- zero fog at the minimum distance, and 100% fog at the maximum. Doing this in the demo gets Figures 1, 2 and 3.

Fig 1: Low Fog
Fig 2: Medium Fog
Fig 3: High Fog

Figure 3 is what it would take to hide all the chunk loading beyond the view distance. As it turns out, even this isn't good enough. I could still see chunks being loaded at the edge of the fog. So I added some logic to fade them in over .75 seconds. Since we are used to things appearing in a fog, this seems to work well. Unfortunately, I don't really want to play in foggy, overcast areas (I'm from San Diego, not Seattle).

Another issue is what to do underground. If you use white fog in those areas, distant dark areas get brighter. See Figures 4 and 5. A comment on the last post said Minecraft just uses black fog color for underground areas. But you would have the same problem above ground in a large dark cave or a building.

Fig 4: Bright Fog (wrong!)
Fig 5: Dark Fog (right!)

Then it occurred to me that I have Minecraft lighting values on all the vertexes, so why not use that as the fog color? Then I'd have bright fog up in the sun, and dark fog down underground or in an unlit building. But using this technique does weird things to shadows, as you can see in Figure 6.

Fig 6: Fog color is light color

I'm not sure how I want to fix this problem. In the demo, there is no fog underground.

Ground Fog

Fig 7: Casting rays through fog
Since I didn't like a completely foggy world, it occurred to me to try a different kind of fog. What if I just had fog near the ground? Then it wouldn't white out the sky.

Figure 7 shows what I tried. There's a layer near the ground, and the thickness of fog is computed by how much of a ray from the eye to the landscape point is within the fog bank. Since the fog is between two y values, it's easy to calculate. This produces the landscape in Figure 8.

I'm implementing this algorithm in the vertex shader for the land, but that didn't work for the water or the sky. The water is a single big polygon, so there aren't enough vertexes. The skybox can have sun, moon or stars as well as the blue sky dome.

To fog this, I have a shell painted after all the rest of the sky, and the shader blends fog in the fragment shader, calculating the correct alpha at each point.

Fig 8: A bit of mist on the landscape

That looked pretty good, so I moved the code into McrView. Here's a video, which starts with clear skies so you can see how chunks fade in, and then switches to foggy skies, at 160m distance, and then at 300m distance. In SeaOfMemes, where I won't be drawing the entire landscape as cubes, I think I'll be able to extend the view distance considerably.

Display Memory

Fig 9: Expensive rails
In Part 34, I added 3D shapes to replace the cube-based rails, chests, etc. that Minecraft uses. When I test the code, I have the display memory and system memory options set at 800meg. I had no problem loading the large save file from the TwentyMine server, which is full of rail tracks and other shapes.

On my more limited Linux box, and on the Mac, I was just displaying the simple worlds you get when Minecraft creates a new world. I added a few shapes in creative mode just to make sure they worked. And so it never occurred to me to add up all the display memory being used by the 3D shapes. Its turns out to be a lot -- over 500 meg for the initial view in the TwentyMine world.

One problem I created for myself by using more complex shapes than I needed. In Figure 9 you can see the shape of the rails by looking at the ends. A simple box would have been good enough. Some of the other shapes are also a bit more elaborate than needed. I went back and edited some of them down, but only cut the size by 20%.

Another problem is that SketchUp generates double-sided triangles some of the time. I haven't figured out what causes it to do this, but it seems related to how the object is created, not its final shape. Sometimes I can delete and recreate an edge and it will suddenly realize the shape is solid and drop all the inside faces. Other times, I haven't been able to get it right.

Back in Parts 16 and 17, I explained how I could use the shader language to implement a compressed vertex for my cubes. The idea is that since I only need integers from 0 to 32 for a chunk of cubes, it makes no sense to use floating point numbers. The position (x,y,z) and texture coordinates (tu,tv,texture number), and three lighting values (ambient, sky and torch) take 9 floating point numbers, or 36 bytes. Using 6 bits for each coordinate and compressing the other fields, I fit the vertex in 8 bytes.

That means the initial view in TwentyMine requires only 42 megabytes for the cubes, which will fit in any display out there.

Unfortunately, I couldn't do that for the 3D shapes. They have arbitrary values, not cube edges. So I was using the full 36 bytes per vertex. On top of that, the shapes are more complicated. A section of rail or a flower could have 300 triangles, or nearly 1000 vertexes, compared to the 24 a cube has. In practice, the cube will have even fewer, since I don't draw the hidden sides. With the 3D shapes, there are no hidden sides. So a single curved rail section or chest might take as much display memory as a 100 cubes.

I fussed over this a bit and managed to compress the shape vertexes down to 12 bytes each. That cuts the initial scene down to 162 meg total, which is acceptable. (I'd like this to run on a display with only 256 meg of memory.)

The vertex compression code requires features of the OpenGL 3 shading language. Under OpenGL 2.1, which is what I have on the Mac, you can't send integers to the shader as vertex components, and there are no bit shift operators. I can't implement these compressed vertexes.

That leaves me stuck with the situation that a more modern display, which has a lot of memory, will also support OpenGL 3 or better and I can compress the vertexes, and need less memory. But an older display, which has less memory, will also not have the GL version I need, and so vertexes will take more memory.

If you run the demo and distant scenery flickers in and out, or the performance is terrible, edit the options and cut the view distance down to 80, from the default 160. I haven't decided what to do about this in future versions. I'd like to know what the size of display memory actually is, rather than relying on an option, but from Google searches, there doesn't seem to be a good way to find out on all three platforms.

The Demo

For Windows, download McrView Part 37 - Windows.

For Linux, download McrView Part 37 - Linux.

For Mac, download McrView Part 37 - Mac.

The UI now allows you to toggle night/day and fog:

  • N to toggle night/day.
  • F to toggle fog.
  • WASD for movement. Arrow keys also turn and move.
  • Page up/Page down to change your height. Blank and X also work.
  • + and - to change your speed.

You'll need to edit options.xml and point it at the Minecraft world you want to view. The save files are in different directories for each OS:

  • Windows 7: C:\Users\UserName\AppData\Roaming\.minecraft\saves
  • Windows XP: C:\Users\UserName\Application Data\.minecraft\saves
  • Linux: ~/.minecraft/saves
  • Mac: ~/Library/Application Support/minecraft/saves

If the world directory is "New World", set the option line to world="New World". Then run McrView.

For those pitiful few who don't run Minecraft and want to try the demo, I've uploaded a small piece of the TwentyMine world I test on. It's at SampleWorld.zip (32.8 meg). Unzip this into your Minecraft/saves directory, or wherever. If your unzip program creates a directory to contain the unzipped files, make sure you point the options to the TwentyMine directory, not the directory created by Extract/unzip.

Change the world option in options.xml to point to the "TwentyMine" directory (fully qualified if not in the Minecraft dir.)

Source code is at McrView Part 37 - Source.

You can also pull it from GitHub at https://github.com/mgoodfel/McrView. You'll need the framework at https://github.com/mgoodfel/mgFramework to build the project.

Thanks to Alan Hauck for the artwork he's added to the project -- a dandelion, a rose, a cactus and tall grass.

I'm going on a short trip with family next week, so Part 38 will be delayed.

Update - What To Do Next?

Since we haven't had a poll in awhile, I'll let you decide what I work on next. Here are the choices:

  1. Complete the Look.

    The ground fog is fine for McrView and Crafty, but for SeaOfMemes, I need foggy planets (with a horizon), foggy asteroids, and foggy generation ships. For all the demos, I need sunrise/sunset, clouds and some weather (rain, snow, and blowing sand? lightning?)

    I could also try some other lighting techniques like shadow maps instead of the Minecraft style brick counting.

  2. Where's that GUI?

    I don't really need a UI for any of the code yet, although help screens would be nice. I would have to implement 2D text on Linux and Mac, and then some GUI layer. I need file dialogs to complete the export/import functions, and a brick palette for editing the landscape.

    On the other hand, it's a lot of work, and I could just hardcode dialogs and help with low-level 2D text and get moving on the demos.

  3. Better Landscape.

    Currently, I have the spiky mountain islands in the landscape demo. For Crafty, I need something more varied, and for SeaOfMemes, I need planet and moon terrain.

    If I leave this alone and people start to really use Crafty or SeaOfMemes to build, it will be a problem later when I do a real landscape and all the mountains move around. So it would be better to do this sooner rather than later.

    Of course, with an import/export function built in to the game, you could just export all your old buildings and import them into the new landscape. And perhaps no one really wants to build on this until it gets more developed as a game.

  4. Get Crafty Working Again.

    This would allow people to build Minecraft style. It's the same drawing code as McrView, but with editing functions, and a saved world.

  5. Sea Of Memes!

    I need to build out the solar system, so that you can move from planet to asteroid to generation ship to moon and ringworld. And you should be able to create structures everywhere, which means working with distorted topology. On the inside of a cylinder, the bricks will be curved to match the surface. Same with the asteroids.

    This will look bland without better terrain first, but you would get the idea.

Here's the poll. I'll check back whenever I have WiFi access on my trip.

Home       About Me       Contact       Downloads       Part 36    Part 38   

blog comments powered by Disqus