You are a Super Space Ranger with an awesome space buggy. Fortunately you’ve landed on a really sweet planet with deformable terrain (Wait… what?). You can catch some sweet air or dig around through the ground. You can do whatever you want because you are a Super Space Ranger. Who could stop you anyway?
This isn’t really a game per-se, so the controls are a bit of a mashup:
- Drive the car using the buttons.
- Drag the car around with your finger.
- Pull up or down on the terrain to change it.
This is a Chipmunk Pro autogeometry demo project that is built on top of Cocos2D 2.0. The focus for this demo is to show how to mix Chipmunk Pro’s autogeometry to implement very large scale, real-time deformable terrain with Cocos2D 2.0. Unlike the Cloud Bomber example, which deformed the terrain bitmap on the GPU and paid a high syncronization cost to read it back, Space Patrol deforms the bitmap using a CGBitmapContext and then uploads only the changed pixels back to the GPU.
The terrain density texture is 2048×512 (You could go as high as 2048×2048 though). When rendering, this is upscaled by 32x (64x on retina) giving you a fully deformable world that is over 130 screen widths wide. That is a huge world to explore from a measely 12kb PNG density image! Rendering the world is performed by a shader that renders all of the following in a single pass:
- A textured sky (Currently somewhat wased on a simple gradient)
- A parallax background
- A textured terrain layer
- A layer of crust along the terrain’s contour
Because this all happens in a single draw pass without blending to the framebuffer, it’s very fast and can even run at 60fps on an iPhone 4. Another benefit of rendering the entire terrain using a fragment shader is that the terrain can be smoothly morphed without having chunky geometry changes. You can see the effect of this in the video above. It basically looks awesome. :D
Chipmunk Pro allows you to trace images (or procedural functions) to turn them into geometry. For Objective-C, it comes with a few handy wrapper classes that make this easy to do. One of them, ChipmunkCGContextSampler, links the autogeometry to a CGBitmapContext. In this way you can perform high-quality, CPU side rendering of the terrain deformations.
Then the ChipmunkCGContextSampler is linked up with a tile cache that breaks the world up into tiles. The geometry for a tile only needs to be regenerated if it is onscreen (or some other rect you specify) and its pixels have been modified. This means you don’t need to waste CPU time or memory to process geometry that isn’t onscreen.
After drawing terrain deformations into the CGBitmapContext, it marks the drawn areas as dirty rects in the tile cache. It also uploads those dirty rects to the terrain density texture at this point too. This is unfortunately a little slow, making the framerate a little jump when constantly deforming the terrain, but I don’t think there is much that can be done about that.
The terrain shader uses the value from the terrain density texture as a threshold to decide whether to draw terrain or the parallax background. If the density was used directly as the alpha, this would look terrible as it is somewhat blurry and upscaled by a huge amount. I used a lookup texture to get a nice threshold for the terrain as well as the thickness of the crust on top. The threshold is perturbed by a second texture to make the crust look more interesting.
There are a few things that could be enhanced in the demo, but I didn’t want to waste too much time on it. Maybe I’ll come back around and do them later…
- Because the terrain is drawn using a single gigantic quad, the precision of the texture samplers is a little shaky. Despite centering the texture coords around (0,0) there are some filtering artifacts. It could be fixed easily enough by splitting the quad into multiple pieces though.
- The quality of the anti-aliasing of the crust layer could be improved using a higher resolution mixing texture and/or using derivatives in the fragment shader (I left the latter commented out in the shader). The iPhone 4 doesn’t have enough GPU horsepower to handle this though. You’d want to enable these only if the user has an iPhone 4s/iPad 2 or better.
- Particle effects: Kick up dust and throw dirt from the wheels.
- Motor noises or other sounds.
- It’s currently using the SD textures but double scaling them on the iPad using a custom projection. I used to have a hack to force it to load the retina assets, but it tends to break with every Cocos version.