Wednesday, July 29, 2009

Infinite Depth Buffer

I've been planning out how I'm going to rewrite my planet algorithm once DirectX 11 is out. I've decided to focus on problems I have now that will still be a problem in DX11. One such problem that I've always been having in the past is the depth buffer.

My planet is Earth-sized so in order to keep it visible as you fly away from it, I pushed the far clipping plane way out. Obviously this destroyed the precision of my depth buffer and I had big problems with Z-fighting (far off mountains were being drawn in front of closer ones).

Rant: Why the heck are most GPUs these days still stuck with a 24-bit depth buffer? The Xbox 360 and my GeForce 9800M GT both only support up to a 24-bit depth buffer. DX11 level GPUs will have 64-bit floating point (double) support in shaders, so why not a 64-bit depth buffer?

In the videos and screenshots I have posted in the past, I did two different things to try and fix my problem with the depth buffer. First, I had a "sliding" far clipping plane that would have a minimum value, but as you flew away from the planet, it would extend out in order to continually show the planet. My second solution was to just disable the depth buffer. Both of these solutions only worked because I was drawing only 1 planet and there were no other objects being rendered. Obviously I want to keep my depth buffer around, keep the high precision for any near objects, but continue to draw far off planets (not have them clipped by the far clipping plane).

In order to fully understand my problem, I read about how exactly the depth buffer works and how a position is transfomed and then clipped. I found this article very informative about the inner workings of the GPU in terms of the depth buffer. I did not change my depth buffer to be linear like he does though. The article helped me to understand the relationship between the Z component and W component of the transformed vertex position.

Between the vertex shader and the pixel shader, the Z component is divided by W in order to "normalize" the depth (range 0-1). If the Z value is greater than 1 then it is clipped. So, I needed to make it so that the normalized Z value never exceeded 1. This was a very simple thing to fix, once I understood it. In my vertex shader I check the Z value to see if it is greater than the far clipping plane value (which I pass into the shader). If it is greater, then I simply set the W component equal to the Z component. This means that the Z / W calculation thus becomes Z / Z = 1. Now I can have good depth buffer precision for things close to the camera, but I will continue to draw things even if they are an infinite (theoretically) distance away!

Obviously this solution isn't perfect and there are some "gotchas". If I am drawing a planet and a moon, and the moon is behind the planet, and I am flying away from the planet, AND the moon is being drawn after the planet in the C# code, then the moon will suddenly pop in front of the planet once the planet exceeds the far clipping plane. That means I'll have to have a manager of large objects in the "local system" to make sure they are drawn in back to front order. That should be really easy to implement.

Hopefully this all makes sense and it helps someone else struggling with the same problem.

Until next time...

Update: I would now strongly encourage people to use a Logarithmic Depth Buffer to solve all of your depth buffer precision issues. You can read about it here:

Wednesday, July 1, 2009

Perlin Noise in JavaScript

I apologize for not having any update for the month of June, but I was gone on vacation for a majority of it.

I saw tons of places on the road trip. Illinois, Indiana, Michigan, Ontario, New York, Vermont, New Hampshire, Maine, Massachusetts, New Jersey, Delaware, Maryland, Virginia, Pennsylvania, West Virginia, and Ohio (in that order)! I had never been to the New England area of the country, so it was great being able to see it all.

In terms of development, I haven't really done any since I wrote that Perlin Noise article. I've been tossing around the idea in my head to go try out SlimDX again. I know, I know, I just can't make up my mind on things, right? It would just be very convenient to be writing C# again, and I found the great PhysX.Net wrapper that should allow me to continue to use PhysX with my C# development. Plus SlimDX already is supporting DirectX 11, which is awesome! (Tessellation, here I come!)

By the way, I was curious about JavaScript so I developed a simple little webpage that implements Perlin Noise in JavaScript.

You can find it here:
http://re-creationstudios.com/noise/

I used a Canvas element to display the result, so it won't work in Internet Explorer.

Be sure to check out the source code since I implemented several different types of summation as well (fBm, turbulence, and ridged multifractal). Enjoy!

Sunday, May 31, 2009

Perlin Noise on the GPU

I've written a tutorial on how to implement Perlin Noise in both a pixel shader and a vertex shader. The tutorial is available over at Ziggyware.

http://www.ziggyware.com/readarticle.php?article_id=246

Check it out! I welcome any feedback.

UPDATE
http://www.ziggyware.com/news.php?readmore=1125
I found out I have won first place in the Ziggyware contest! I'm very happy that my first XNA tutorial was such a success. Perhaps I will write up more in the future.

UPDATE 2
It appears that Ziggyware no longer exists, so I have shared the article, screenshots, and sample code on my server.  You can download it all here:
http://re-creationstudios.com/shared/PerlinNoiseGPU/

Friday, May 29, 2009

PhysX Planet



Creating planetary gravity with a force field was much easier than I was expecting. Especially after finding this thread on the official PhysX forum.
http://developer.nvidia.com/forums/index.php?showtopic=3201&pid=9249&st=0&#entry9249

After doing that, I got curious and I removed the sphere "planet" but I kept the gravity force field. As expected, all of the shapes grouped together to form their own planet.



After I kept watching it, the planet started pulsing back and forth and eventually tore itself apart in a vortex that alternated back and forth.



The debris vortex started stabilizing and turned into a spinning ring.



The ring kept expanding and getting bigger and bigger.



I added some more cubes to the center, which formed a cool looking planet with a ring.



The planet at the center eventually started breaking apart and forming a ring as well, but what was most interesting was that the inner ring was rotating in the opposite direction of the outer ring.

Thursday, May 28, 2009

PhysX and DirectX 10

For the past week or so, I've been working on getting PhysX working in DirectX 10. I ported over my Shape3D class from my previous blog post to C++ in order to draw the boxes and spheres (no cylinders because PhysX doesn't have a cylinder shape).

I set up a simple scene with a ground plane (not rendered), normal Earth gravity, two boxes and a sphere. The space bar spawns new boxes at the origin and the Alt key spawns new spheres.

In my first implementation, the application would slow down to 20fps when I added about 75 shapes. I tracked down this slowdown to the creation of the vertex input layout each frame. Once I moved that out of the render loop, I could then have 1000 shapes in the scene and still maintain 30fps. I'm still trying to figure out if I can speed up the rendering even more because without rendering, the PhysX engine was able to handle 2000 shapes and maintain 60fps. I doubt I can speed it up much more though.

Here are some screenshots. Pretty simple, but the debug info helps to illustrate the speeds.






I have decided to share the Visual Studio 2008 project and source code to hopefully provide a nice starting point for others. I'm not using an official license or anything, but I'll state that is it free for whatever use you desire, be it commercial, hobby, or education.

Download the zip file: here

Next, I'm going to work on using static triangle meshes in PhysX to have a displaced sphere making up a planet, as well as using force fields to simulate planetary gravity.

Sunday, April 19, 2009

Boxes, Cylinders, and Spheres (Oh My!)



After deciding to use PhysX in combination with DirectX 11 last week, I thought about how I would go about drawing simple 3D shapes. In the samples and lessons, PhysX uses GLUT with has some shape drawing functions built-in. While DX9 has similar functions, neither DX10 nor XNA do. I believe it is safe to assume that DX11 will not have them either. I can understand why they were removed. They don't really make sense anymore in a programmable pipeline system. What is the vertex format of the shape created?

While most people these days get around it by creating a mesh in a 3D modeling application and then importing it into their game, I prefer to have my simple 3D shapes constructed programatically. This allows me to easily change the detail of the mesh without worrying about exporting/importing an entire new model.

Instead of implementing it in DX10 and C++ first, I decided to implement it in XNA. This allowed me to focus on the algorithms themselves and not have to worry about any C++ issues getting in the way.

My initial implementation was a static class that had static methods in it that built the shapes and returned the vertex buffer and index buffer. This worked well, but I thought it still placed too much burden on the user to remember how many vertices they had just created and how many triangles they were going to draw.

In order to make things simpler, I changed it to be a normal, instantiated class that contained the static methods that created an instance of the class. This allowed me to store the vertex count, triangle count, as well as the buffers in instance properties in the class. I even threw in a Draw method to make it incredibly simple to use the generated shape.

Because this is such a basic, fundamental class that can benefit several people ( have seen various people requesting something like this), I have decided to share it with the public.

You may download the C# file from here:
http://re-creationstudios.com/shared/Shape3D.cs

You can also download the entire test project here:
http://re-creationstudios.com/shared/ShapeTest.zip

To use, simply create a shape using one of the static methods:
Shape3D sphere = Shape3D.CreateSphere(GraphicsDevice, 1, 12, 12);

To draw, in your Effect block, call the Draw method on the shape:
sphere.Draw(GraphicsDevice);

The Create methods are made to follow the same structure as the DX9 shape drawing functions. You can read more about those here:
http://msdn.microsoft.com/en-us/library/bb172976(VS.85).aspx

Sunday, April 12, 2009

Tactical RPG

I've been engrossed with learning about DX11 lately. I've looked at slide presentations, listened to audio recordings of speeches, and read various articles discussing the new features being introduced. I believe it's a great understatement to say that I'm excited about DX11. I've finally come to the conclusion that once I have a DX11 GPU, I'm going to rewrite my procedural planet code using DX11.

In the meantime, I've decided to take about 1 month to implement a prototype for a tactical RPG I've been thinking about. I started about 2 weeks ago, and I plan to finish it by the end of April. One of my main goals is to have it completely mouse driven so that it can be played on a tablet.

I believe it is coming along rather well. I have a really nice 2D camera set up that behaves similar to Google Maps. You can use the mouse to drag around the view and you can zoom in and out using the scroll wheel. I have basic movement and attacking implemented as well. I even have one of my graphic designer friends making up some art for me. Overall, it should shape up to be a pretty decent prototype. Maybe I will even release it to the public, source and all.

PhysX

New content for Banjo-Kazooie: Nuts & Bolts was released last week. As a result, I pulled out the game again and played it some more. I wasted several hours just messing around with the vehicle editor to make various contraptions. I started thinking about how much fun it was to just tinker around like that without really following any goals, and then I started wondering about how hard it would be to implement a similar system myself.

Almost 4 years ago, I had implemented a "domino simulator" using what was then known as the NovodeX physics engine. It is now known as PhysX, is owned by Nvidia, and has hardware acceleration. So, I downloaded the SDK and played around with some of the samples.

First, the good. I was simply astounded by how many samples were provided in the SDK. There are 37 samples and 89 "lessons", all with documentation. It is amazing. Plus, the hardware acceleration really helps speed the physics engine up. One of the samples was getting about 40fps in software mode and 130fps in hardware mode. That was on a 9800M GT.

The bad is more about C++ than PhysX. I decided to create a C++ project from scratch and then add all of the libraries and code necessary to get the first lesson from the SDK working. It was horrific. It took me 3 hours to get everything to compile and run. In the end, here is what was in my project:

5 include directories
3 static libraries
- added to both the project and VS itself
- had to add one directly to solution to get to compile
12 include files (separate from the include directories)
8 cpp files
1 dll

Remember, all of that was to run the FIRST lesson, which is just three shapes on a plane. In C#, it would have been 3-4 DLLs and one CS file. As I said, this is more of a complaint about C++ and not PhysX. I forgot how tedious it was to setup a project for the first time. I do plan to stick with PhysX though, because once I do port my procedural planet code over to C++/DX11, then I will want a nice physics engine to go along with it, and it might was well be the only one with hardware acceleration.

Until next time...