Monday, December 22, 2008

Starfields & Nebulas

Instead of focusing on craters (which I implied I was going to do last time), I decided to look into generating starfields and distant (ie 2D) nebulas.

I started on simple starfields and I had a working solution in less than an hour by simply drawing star sprites in random positions.

This yields the following result:

Next, in order to make the stars more interesting, I looked into implementing nebula clouds. I knew that some summation of Perlin Noise would be the best solution. So, I decided to implement a Perlin Noise function in C#. I have a really fast implementation in HLSL, but I wanted the full power of breakpoints and variable watches. I ended up using a standard fBm summation with an exponential filter applied to it.

This helped to produce this nebula cloud image:

I still need to blend these two results together and construct them into a decent cubemap.

World of Warcraft + 360 Controller

All of that work done on the starfields and nebulas was done a couple weeks ago. My co-workers recently pressured me into playing World of Warcraft again. (About 6 months ago, I got up to level 18, and then quit.) As I was playing I kept thinking about how bad the controls were. I was moving my hands all over the keyboard to use all of my skills. It was fine for just grinding along and completing quests, but grouping and duels I always performed horribly. I desparately wanted to play with a game controller, however World of Warcraft didn't support them. There were a couple of applications that other people had written to allow gamepads, but I didn't care for them either. One was very ackward and built up macro commands that you had to then "submit" by pulling the right trigger. Another one seemed decent, but it had a subscription fee of $20 a year.

I decided that if I wanted something done right, I had to do it myself. So, I threw together a quick XNA application that read the 360 controller input. It would then use the Win32 function SendInput to place keyboard and mouse input events into the Windows input queue. I mapped out all of the controls and I was then able to play World of Warcraft using a 360 controller! I can target enemies, target allies, use all 12 skills on the current action bar, switch action bars, loot corpses, and even move the camera with full analog control using the 360 controller! It has completely changed the game for me and I even won my first duel last night.

I have now taken the app and added in mappings for Call of Duty 4 for my brother. I'm planning on converting the project to be more generalized so that the input mapping can be defined in XML and easily changed without recompiling.

Thursday, December 4, 2008

Lighting Revisited (AKA I'm Back!)

So, after almost 3 months of being sidetracked with various other projects I came up with, I finally decided to come back to C# and XNA with welcome arms.

And I have come back in a big way, in my opinion. After discussing it with one of my friends, I decided that it would be best to procedurally generate a moon instead of a planet. This greatly simplifies many things; no atmosphere, no fog, no water, no vegetation, etc. However, this meant that I needed to figure out how to properly do two things: generate craters and have realistic lighting.

You may recall that I had a previous blog entry about my attempts with realistic lighting. [] In the end, I determined that it would be too difficult to do now, and easy to do in the future once I had geometry shader support. So, I had settled with simple spherical lighting across the entire planet.

So, it took me quite a bit of effort to even start looking at alternative ways to render realistic lighting. In the past I was trying to calculate the other two vertices of the triangle in the vertex shader. It was with a great facepalm that I realized that what I was trying to find was the tangent of the surface and then I could use that to adjust the spherical normal. Well, as you may remember from your math classes, a tangent is calculated by taking the derivative of the original function. So, I looked into quite a few articles about how to find the derivative of a Perlin Noise function.

This article was very informative, but I wasn't quite sure on what speeds would be on the GPU:

Finally, I found an article by Ken Perlin himself that shows how to approximate the derivative: (Section 5.6)

With this little nugget of knowlege I went into my shader and wrote a function to do exactly that.

float3 NoiseDerivative(float3 position, float e)
//calculate the height values using Perlin Noise
float F0 = ridgedmf(position*noiseScale, 8);
float Fx = ridgedmf(float3(position.x+e, position.y, position.z)*noiseScale, 8);
float Fy = ridgedmf(float3(position.x, position.y+e, position.z)*noiseScale, 8);
float Fz = ridgedmf(float3(position.x, position.y, position.z+e)*noiseScale, 8);
float3 dF = float3(Fx-F0, Fy-F0, Fz-F0) / e;

//calculate the actual normal
return normalize(position - dF);

Then I simply added a call to this function in my pixel shader:
input.Normal = NoiseDerivative(input.Normal, 0.000001);

Lo and behold, it worked!

Check out the pics: