Wednesday, June 24, 2009

This gets a friggin plug

I am back on game development (sort of). I just finished my alpha version of the first space station for this game, I wanted to see how huge objects worked and what sort of performance hit I was going to see. I ran into 3 problems that had not been a problem when dealing with smaller objects. This was also my first stab at rendering something near 100,000 polygons on the screen.
  1. The 3D model was made in Maya and consisted of several NURBS items I converted to polys. Some of these objects at the polygon level had their normals reversed. The problem wasn't very apparent at first until I started orbiting the camera around certain parts and realized I was seeing through them to the other side. The trickiest part was to identify in the modeler which parts were messed up since I am dealing with a symmetrical model.
  2. While facing the station, if I went in reverse, eventually the back polys of the station would pop out of view. This was because my far Z clipping plane was too close to the camera. I'm dealing with an object that is roughly 13km wide and 8km tall, but my camera clip was configured for only 30 km total view distance. Along with this....
  3. Z-Fighting!! YUCK! I just knew if I ever encountered this it would be a beast to fight. Z-fighting is possible whenever intersections occur on an object and the camera is moving. What happens is the depth buffer which determines which vertices are rendered and which are culled is translated to be in the range of 0.0 - 1.0. Because of the math that occurs (a non-linear formula) sometimes the values get evaluated incorrectly, of course this is slightly compounded by the fact that floating point numbers are not precise.
Fixing the 2nd problem usually makes the 3rd one worse... The larger of a region you define to be visible, the more likely you are to experience Z-fighting... so I had to come up with a solution to #3 or just bite the bullet and try scaling everything down in the world by a factor of 10 or so (in my game, 1 unit = 1 meter). I decided more research was in order before just giving in.

After doing some research as to how others solve the problem, I found this ingenious solution: http://www.mvps.org/directx/articles/linear_z/linearz.htm

It works by taking the original view matrix you construct and scaling the parameters that hold information pertinent to the near & far clip planes by the far clip plane value. Then in the vertex shader, the output Z position is multiplied by the output W value (calculated by taking the input position multiplied by the world-view-projection matrices). The result is that when the pixel goes through the rest of the rendering pipeline transformation, when its W value is divided, it basically undoes the multiply done by the shader, leaving you with the original value. Absolutely smart.

This solution is elegant on so many levels. First off, it leverages the power of the GPU and uses a vertex shader-based solution. Second, well, it obviously fixes the problem! Third, it makes my 2nd problem a non-issue: you can basically set the far clip plane as far away as you want (yes there needs to be some reasonableness of course).

I was able to increase my far clip plane to 100,000km and have no popping, and no Z-fighting! Also, several km back from the station (enough that it still filled about 75% of my view) I'm running at > 1000fps... That is with a fully wrapping star skydome background, just under 100k polys, a basic UI, and the camera code. By comparison, with a 10k poly count fighter on the screen, I was running at 2700fps, I'm very happy with how the performance is!

1 comment:

  1. I can't wait to see this in beta! What kind of system parameters are you going to need? I better start saving my money for a new computer now because it sounds like it will take a lot of horsepower.

    Have you thought about key layout and peripherals yet?

    Good Luck!

    ReplyDelete