Putting it Back Together, Next Steps

Finally after converting from XNA4 (DirectX9) to SharpDX (DirectX11) its all back together again. Is it faster ? Because I limit my rendering to 60fps I dont see any difference, but I can believe there is a lot more power available to me than previously. Ultimately the task was to get off the dead technology onto something more useful.

If you are ever thinking about doing this it will probably take you about 2 months. If you have extensively used the XNA (or SlimDX) Game library, it will take longer than that.

My next step will be either to implement Shadows or use a Geometry Shader to generate my grass, which is currently generated from a repeated vertex buffer patch. Shadows seems to be the better “return on investment” because, although its more efficient to use a GS for grass, my grass does actually work – inefficiently.

The problem with Shadows is that there is not perfect implementation. There are plenty of guides (including the ever reliable Rastertek) and the basic approach is simple; to repeat –

  1. Render your whole scene (or at least those objects who might cast a shadow) from the viewpoint of the light source. Record the depth of each pixel into a texture.
  2. Send the texture from (1) as a texture parameter to (2).
  3. Render your whole scene (everything this time) and test every pixel’s depth – if it is more than the equivalent depth recorded in (1) then this pixel is in shadow.

Simple enough but pretty problematic in execution, espcially the need to render the whole scene twice. You can get away with this by only rendering a shadow texture for the nearer objects but then distant woodlands etc. cast no shadows and dont get the “gloom” effect that real woods do. This is compounded by the fact that distant woods are only Imposters so rendering them as geometry to calculate their shadows would be prohibitively expensive.

Add in the complexity of the fact that a Depth Buffer doesn’t have an infinite range of values for each pixel, which needs you to implement Cascaded Shadow Maps and it all seems too “contrived” to me. There seems no getting away from the need to build all this infrastructure. Time to get my thinking cap on.




Rivers using A* Path Finding

Because I’m lazy I dont want to have to describe the river courses on my landscape in terms of really detailed control points, so I decided to try using the popular A* pathfinding algorithm to do the work.

All I have to do is define the start location and the end location of the river, and then let the magic of A* do the rest. A* requires two basic parameters

  • The estimated cost of a given step
  • The true cost of a given step

In my case the estimate cost is just the distance between two given points;

Vector3 pointA;

Vector3 pointB;

float estimatedCost = (pointA – pointB).Length();

This will allow A* to rapidly reject the most expensive routes.

The true cost between two points is more complex, but based on the same algorithm. The true cost is the Estimated Cost (which is also the lowest cost) plus a modifier based on the particular kind of dynamics affecting river flow. In my case a really simple implementation is to check the relative heights of the two points; a river never flows Uphill so the cost of any particular step where the river would flow Uphill becomes float.MaxValue. Rivers like flowing downhill, and like to flow downhill the quickest way; so the cost of the step is EstimatedValue – (pointA.Y – pointB.Y) . This means the pathfinder will favour the steeper downhill slopes.

Because there are a LOT of options in making a river flow between two distant points (in fact in theory every possible route across the landscape needs to be checked) you might need to give it a hand by breaking rivers down in to a few control points, but this is far quicker than describing the river route by hand.

I got my A* library and some background information from this helpful blog;

A Wealth of new Texture Formats

One huge advantage of making the jump from XNA4 to SharpDX (and DirectX 11) is the huge number of new texture formats I have to play with. Not only can I use the BC* textures (DXT1, DXT3 etc) but I can now much better match my textures to their usage.

Visual Texture : BC1_UNORM / BC3_UNORM

Heightmap : R32_FLOAT (probably way too precise)

Planting Mask : R8_UNORM

Normal Map : R8G8B8A8_FLOAT

Also the ability to save as UINT format for most textures and use the Load instead of Sample gives me an ability to do pixel perfect texture sampling with ease.