Sunday, April 17, 2011

Sky's the Limit

After a long hiatus from programming, I've recently started back up with the terrain project. I've been working mostly with atmospheric effects. My first goal was to fix some annoying problems with the water shader. The worst one was where the normal map stopped doing its job when the directional light pointed straight down. Per-pixel Fresnel calculation turned out to be the solution. I spent some time tweaking the coloring of the water as well.

The biggest improvement is the new and improved sky shader complete with sun, moon, clouds, and stars. These are all procedurally drawn in the pixel shader. This allows for various visual characteristics to change depending on what's going on in the sky. The sun moves across the sky and changes color based on the diffuse sky color. I've included a sequence of screenshots, showing the effect throughout the sunset.

The clouds are just two octaves of perlin noise with a very subtle animation to give them some life. I've also added stars, which are procedurally generated by filtering/gating a perlin noise texture. The stars and clouds also happen to do an excellent job of disguising the ugly color banding that occurs at night.









Starry Night

Thursday, June 24, 2010

A Practical (But Simple) Model for Daylight

For the past couple months I've been working off and on, trying to figure out a daylight model for the sky dome. To be more specific, I was attempting to incorporate the model discussed in a paper titled 'A Practical Analytic Model for Daylight'. It's a very interesting read and the theory is useful, even if you don't actually use their approach.

Unfortunately, I wasn't able to get the color conversion to work. Something with the Luminosity value just wasn't coming out correct no matter what I did. So instead, I just took the color gradients I knew I was looking for and hard coded some values to interpolate and presto- a day/night system. It's not bad, considering how simple the color calculations are. The most noticeable problem with this new feature is color banding. At sunrise and sunset, there is not enough of a change in color in the sky gradient, so the colors form very noticeable bands on the sky dome. Even worse, the bands move around as the colors change, which draws attention to the issue. The solution is probably dithering or some other form of noise to break up the pattern.

Eventually I'd like to get a more realistic model working, but for now it's time to leave 'good enough' alone and move on. Below is a series of screenshots taken during sunset.





Sunday, June 20, 2010

I spent some time playing around with normal maps and stumbled upon a much better looking ripple effect. By scaling up the the x and z coordinates of the normal map, the waves are much more pronounced. Here's a screenshot of the water at dusk.



Saturday, June 19, 2010

More water improvements

I've logged some solid hours programming this weekend, continuing to work on water effects. The water shader has been almost completely rewritten to add such features as specular lighting, normal mapping, waves, and caustic effects.

The first thing that I added was a simple wave function implemented in the vertex shader. The formula is pretty much just y += sin(x)*sin(y). If you were to zoom way out, the resulting wave form would follow a very obvious pattern, but when you're at eye level looking at the shore line it looks pretty realistic. This shader isn't meant to look like waves, but rather to give the water level a little bit of an ebb and flow.

Next, I got specular lighting working. I actually haven't used specular lighting in DirectX 10, and never had to code the lighting calculation myself. Once I got it working, I realized that the water needs texture to make the specular light look right. A flat sheet of water just shows a single dot of specular light, which looks pretty lame. Fortunately, normal mapping is pretty easy do in DirectX 10. It only took about 5 minutes to incorporate this into my shader. I used a normal map of a ripple pattern and overlaid two octaves (two versions of the same texture scaled to different sizes) moving at different rates across the surface. The resulting ripples in the water look infinitely more complex than a single normal map on its own. I'm very satisfied with how realistic the ripple effect came out.

Another simple feature I added was Fresnel alpha blending. If you're on a boat in the middle of a lake and look out toward the horizon, you'll see a reflection on the surface of the water. If you look straight down at the water, you'll see fish/rocks/etc underneath the surface. This is because the amount of light that's transmitted vs. reflected off the surface is dependent on the angle of incidence. The fraction of light that is reflected is the Fresnel term. There are lots of different ways to calculate this term, but the simplest way is to take the dot product of the viewing vector (camera to surface) and the normal vector of the surface. This calculation has already been done to compute specular lighting, which saves time. The Fresnel term is then used to interpolate between the color of the reflected pixel vs. the color of what's underneath.

The last thing I added was a caustic effect superimposed on the terrain underwater. Many examples I've found simply render the pattern to the water surface and call it good. In reality, the pattern is projected onto whatever geometry is at the bottom of the body of water. This requires a bit more work, but I think the added realism pays off. The approach here is similar to how I did the water ripples. Two octaves of the caustic pattern are overlaid and move randomly. It took a little bit of tweaking the scaling and rate of motion of the two textures to get this to look right. You have to look pretty hard to figure out how the pattern is animated.

Viewing the Water from Eye Level


Close Up of Caustic Effect

Friday, June 18, 2010

Multi-textured Terrain

One more update for today... multi-textured terrain. In my opinion, this is probably the most important aspect of rendering a realistic outdoor scene. I got the basic shader working, which allows me to splat up to four different textures onto my terrain at a resolution of 10 feet. In the picture below, the terrain only uses a basic gradient between sand and grass, which already looks a million times better then the grassy screenshots featured in my previous post.

The tricky part will be adding the functionality to my terrain editor to spit out alpha maps for texturing. This will need to take into account elevation, slope, and a few other parameters in order to create an organic and realistic texture map.

Water Fog

I've added a new feature to my terrain shader that accounts for depth when rendering portions of the terrain that are underwater. Because the water "plane" has a constant alpha value, the deepest part of a body of water is just as visible as the ground that's only covered by a few inches of water. In reality, bodies of water such as lakes and oceans have dirt and other particles that obscure light from reaching the bottom.

My approach to this problem is basically just per-vertex fog. Instead of interpolating colors based on distance from the camera, the shader uses the 'y' coordinate of the vertex in world space, and calculates its distance below the surface. This simple effect definitely gives the water a more realistic sense of depth.

Without Water Fog

With water fog

Sunday, June 13, 2010

The new graphics engine is coming along slowly but surely. I spent a lot of time working out some very mysterious bugs that were causing things to either render in the wrong spot or just not at all. I was starting to worry for a while there that I would have to start over because things were getting so complicated. Got it worked out though and now it's working beautifully.

One big thing I've started to implement is a day/night system. I want this feature to be very detailed and realistic. The ambient/diffuse light color, along with the sky colors and angle of light are all dependent on the time of day. The sky color is sampled from a 2D texture. The U coordinate is determined by time of day, and V coordinate is determined by the vertical angle of the sky. So basically, at any given time, the sky gradient is sampled from one column of texels in the sky Texture. Below is the very rudimentary texture I'm working with right now. Eventually I'll get the correct color gradient for dawn/dusk/etc.


Another thing I've added is water. Very. very. basic water. It's a semi-transparent heightmap with a caustic pattern texture. Waves, reflections, etc to be added later. Even this basic effect I've got now has made the terrain look much more like a realistic outdoor scene.


Next steps:
  • Waves, reflections, and specular highlights for water effect.
  • Multi-textured terrain to add regions of sand/rock/etc.
  • True-to-life sky dome gradient colors