Wow! I can't really believe it's been 7 months (exactly!) since I last posted an entry here. I wish I had something to show, but sadly I do not. To be honest, I have been all over the place with my development. I experimented with a number of different things, but nothing for an extended period of time. I'm hoping to change that soon though. More on that later, first a list of the things I was working on:
Shadow Mapping
I had actually never done any shadow mapping programming before, so it was more of a learning experience in understanding the concept and what is required. I implemented a simple demo in SlimDX/DirectX 11 and posted a video of it on YouTube, but it really is nothing exciting. Standard, run of the mill, shadow mapping. No fancy tricks in the implementation.
Parallel City Generation
I pulled out the old procedural city generator code I blogged about before and updated and refactored the road generator to be able to run in parallel. This allowed me to draw the roads as they were being created. I thought it was pretty cool looking. My goal was to parallelize it to the point where I could implement it as a compute shader, but I couldn't seem to get it to that point. So, I kind of gave up on it.
Bullet Physics
I decided to go back and start messing around with physics again, and I used XNA and BulletSharp this time. I was working on an idea that I've had brewing in the back of my brain for quite awhile. I made some decent progress and was quite happy. However, I started thinking about how I was essentially writing my own game engine (terrain, lighting, shadowing, physics integration). Plus, looking at the target platforms for XNA (Xbox 360, Windows Desktop, Windows Phone), I started wondering if that was best for me. So, that led me to the next item.
Unity
For several months Unity had been looking appealing to me. Two of the biggest pulls for me were C# scripting (via the Mono Framework) and PhysX integration. The wide array of supported platforms was also a huge plus (Mac, Windows, iPhone, iPad, Web). When they announced support for Android as well, I was "sold" in a manner of speaking (as I have an Android phone myself). So, I installed the free version of Unity and tried to see if I could implement the functionality I had already implemented via BulletSharp and XNA inside of Unity scripting itself. One weekend later, I had accomplished that and more!
I'll be honest, Unity is far from the perfect engine. It severely limits you due to the wide range of hardware specs that it runs on. Don't expect to be doing any tessellation or compute shaders here. Heck, it doesn't even support geometry shaders! However, it does seem to be a very well organized engine with good documentation on their webpage and a component based system that I love. I like it enough to at least fiddle around with it some more over the next couple of months.
An added bonus is that my prototypes can be deployed to my server which means you (the reader) can run them in your browser without installing the them. Expect to see a Perlin Noise example soon. :-) That really has become my "Hello World" program for testing different graphics APIs.
A final note I'd like to leave here is regarding some other "big" game engines. I was slightly surprised last week to hear not just one, but two game engines have essentially "imploded". Both Torque and Gamebryo are closing up shop and looking for buyers. That leaves Unity looking even stronger.
Until next time!
Following my adventures in various graphics projects. These mainly consist of procedural development, image processing, and physics.
Showing posts with label Bullet. Show all posts
Showing posts with label Bullet. Show all posts
Monday, November 15, 2010
Thursday, April 15, 2010
Spherical Terrain Physics
For quite a long while I have been trying to figure out how exactly to do collision detection on my procedurally generated, tessellated, spherical terrain.
The problem lies with the fact that terrain itself doesn't really exist until the GPU. I generate a simple spherical mesh on the CPU and then send it to the GPU to draw. Once there it is tessellated based upon the distance to the camera and then it is displaced via a summation of Perlin Noise.
Obviously this makes it very hard to do collision detection on the CPU side. Many physics engines support a special heightmap object for terrain, but they all assume the terrain is on a plane (usually the XZ) with one axis being the displacement axis (usually the Y). Of course that wouldn't work for spherical terrain. Most physics engines also have a generic triangle mesh object. However these are usually meant to be static meshes and therefore are hard to tessellate. It would require destroying and recreating a mesh on the fly, which would be rather slow and wasteful.
What I really needed was the ability to create a collision shape that was defined by an equation (the Perlin sum in my case). In the past I have always used PhysX, but since it is closed source I decided to try this out in another physics engine. I hopped onto the Bullet forums and posed the question. I was told that it should be possible if I created a new shape object that inherited from the base concave object and overrode its ProcessAllTriangles() method to use the equation.
So, I went and did exactly that. Lo and behold it worked!
First, I created a shape called btSphericalTerrainShape which inherits from btConcaveShape. It takes 3 parameters to setup: The center point of the terrain, the radius of the terrain (including the maximum offset of the terrain) which is used for the bounding box, and a function pointer that points to a function that defines the terrain's equation.
The function pointer passes along 2 parameters: the current point being evaluated (usually one of the corners of the other object's bounding box), and the center point of the terrain. This allows the terrain to be defined by practically any method desired.
For example, if you wanted to define the terrain as a simple sphere with a radius of 50, you would use the following method:
If you wanted to define the terrain as a sphere with a radius of 50 that was offset by 8 octaves of Perlin Noise, you would use this method:
Now, for the details on the ProcessAllTriangles() method. It takes an axis aligned bounding box (AABB) for the other shape being tested and a callback that is called for each triangle that collides with that bounding box.
These are the steps done in the method:
1) Calculate the 8 corners of the AABB
2) Calculate the midpoint of each of the 6 sides of the AABB
3) Calculate the position of the vertex on the terrain by calling the calculateTerrainVertex function pointer
4) Determine which of the corners of the AABB are colliding with the terrain by checking if the bounding box corners are closer to the center point than the respective terrain vertices
5) Find which 3 sides of the AABB are closest to the terrain in order to prevent extraneous triangle processing
6) Use the callback to process each triangle that collides
For the actual implementation details, be sure to download the source code for the btSphericalTerrainShape.
btSphericalTerrainShape.h
btSphericalTerrainShape.cpp
The problem lies with the fact that terrain itself doesn't really exist until the GPU. I generate a simple spherical mesh on the CPU and then send it to the GPU to draw. Once there it is tessellated based upon the distance to the camera and then it is displaced via a summation of Perlin Noise.
Obviously this makes it very hard to do collision detection on the CPU side. Many physics engines support a special heightmap object for terrain, but they all assume the terrain is on a plane (usually the XZ) with one axis being the displacement axis (usually the Y). Of course that wouldn't work for spherical terrain. Most physics engines also have a generic triangle mesh object. However these are usually meant to be static meshes and therefore are hard to tessellate. It would require destroying and recreating a mesh on the fly, which would be rather slow and wasteful.
What I really needed was the ability to create a collision shape that was defined by an equation (the Perlin sum in my case). In the past I have always used PhysX, but since it is closed source I decided to try this out in another physics engine. I hopped onto the Bullet forums and posed the question. I was told that it should be possible if I created a new shape object that inherited from the base concave object and overrode its ProcessAllTriangles() method to use the equation.
So, I went and did exactly that. Lo and behold it worked!
First, I created a shape called btSphericalTerrainShape which inherits from btConcaveShape. It takes 3 parameters to setup: The center point of the terrain, the radius of the terrain (including the maximum offset of the terrain) which is used for the bounding box, and a function pointer that points to a function that defines the terrain's equation.
btSphericalTerrainShape(const btVector3& center, btScalar radius, btVector3 (*calcVertex)(const btVector3& position, const btVector3& center));
The function pointer passes along 2 parameters: the current point being evaluated (usually one of the corners of the other object's bounding box), and the center point of the terrain. This allows the terrain to be defined by practically any method desired.
For example, if you wanted to define the terrain as a simple sphere with a radius of 50, you would use the following method:
btVector3 calculateTerrainVertex(const btVector3& position, const btVector3& center)
{ return (position - center).normalized() * 50.0f;}
If you wanted to define the terrain as a sphere with a radius of 50 that was offset by 8 octaves of Perlin Noise, you would use this method:
btVector3 calculateTerrainVertex(const btVector3& position, const btVector3& center)
{btVector3 normalized = (position - center).normalized();
double result = PerlinNoise::fBm(normalized.x(), normalized.y(), normalized.z(), 8); return normalized * btScalar(50.0f + result * 10.0);}
Now, for the details on the ProcessAllTriangles() method. It takes an axis aligned bounding box (AABB) for the other shape being tested and a callback that is called for each triangle that collides with that bounding box.
These are the steps done in the method:
1) Calculate the 8 corners of the AABB
2) Calculate the midpoint of each of the 6 sides of the AABB
3) Calculate the position of the vertex on the terrain by calling the calculateTerrainVertex function pointer
4) Determine which of the corners of the AABB are colliding with the terrain by checking if the bounding box corners are closer to the center point than the respective terrain vertices
5) Find which 3 sides of the AABB are closest to the terrain in order to prevent extraneous triangle processing
6) Use the callback to process each triangle that collides
For the actual implementation details, be sure to download the source code for the btSphericalTerrainShape.
btSphericalTerrainShape.h
btSphericalTerrainShape.cpp
Subscribe to:
Posts (Atom)