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

Wednesday, May 12, 2010

New Graphics Engine


The GUI is coming along nicely, but I'm taking a break and moving back into some graphics stuff. It will be easier to test additions to the GUI later on when I have more uses for it.

Lately, I've been working on a new graphics engine. The central idea of the new engine is that everything is customizable and modular. It manages all of the resources, buffers, shaders, etc. Various entities in the game that need to be rendered check in with the graphics engine upon initialization and give it the details on how/when they need to be rendered.

So far I've got the terrain loading from a height map, per-vertex fog, and a fairly convincing skydome. The sky colors are actually sampled from a 2D texture. The sampled U value is proportional to the angle from the horizon (phi), and the V value is determined by the time of day. This 2D texture is calculated using the Preetham paper, A Practical Analytic Model for Daylight. Each column of pixels in the texture is a gradient of colors at a particular time of day. Tasks that remain for the skydome include clouds, stars, sun/moon sprites, and lens flare.

Friday, May 7, 2010

New GUI


I've been spending the past few weeks working on a custom GUI in DirectX. I modeled the GUI after MFC, making heavy use of inheritance. Gotta love c++. I went with this approach because it gives me (and potentially other developers) the freedom to derive modified versions of existing controls, along with creating new ones down the road.

The first week was pretty much spent getting the basic framework put together and getting a basic window drawn to the screen. Then I moved on to adding buttons, checkbox, edit box, and slider controls. The text box is capable of being assigned a value, but I haven't gotten around to allowing the user to enter values into it.

The next big tasks are to complete the edit box control and move on to list boxes.