My name is Crappy Coding Guy, and I use Texture2D.GetData
In a previous post about texture modification, I mentioned the evils of transferring data from the GPU to the CPU, and then presented an example showing one way to avoid doing it. The post wasn’t really about deformable 2D terrain or collision detection, but was intended to help newer game programmers open up a new way of thinking when it comes to using the GPU to accomplish tasks.
Since that post, and the one showing a video of my WP7 game, I’ve received a couple of questions about how I do the collision detection in Guardian, which would seem to require the use of Texture2D.GetData.
As it turns out, I am evil, and I do use GetData. But, my evilness is optimized based on information from here, here, and here.
- Crater drawing is batched, meaning that rather than draw each one as it’s created, I add them to a list and draw all of them every few frames. This reduces the number of GetData calls – one per batch of craters rather than one per crater.
- After drawing craters to the render target, I wait a few frames before calling GetData to make sure the GPU has processed all of the drawing commands. This minimizes pipeline stalls.
- If I have a pending GetData call to make and more craters come in, the craters will stay batched until the GetData call is complete. In other words, the drawing and getting are synchronized so that a GetData call always happens several frames after drawing a batch of craters, and any new crater draw requests wait until after a pending GetData.
If there are a lot of craters being created the built-in delays can cause some slightly inaccurate collision detection since we may be looking at collision data that’s outdated by several frames. At least in this particular game there are never huge numbers of crater adds going on so this isn’t a problem. If there are more than several crater adds they tend to be bunched close together, so the explosion animation hides any visual oddities.
There is one other optimization that I have available but haven’t needed to use. The collision data doesn’t need to be at the same resolution as the drawing data. Basically have two sets of render targets – one for the visual texture, and a lower resolution set for the collision data. Do the GetData on the collision texture and scale everything appropriately when doing the collision check. You have to draw twice – once for the visual data and once for the collision data – but you’re pulling much less data from the GPU which would possibly offset the extra drawing time (this isn’t something I’ve tested yet). You won’t be pixel perfect, but for this type of game that isn’t necessary. As I write this it seems using multiple render targets would eliminate the “draw twice” issue here, but I’ve never done that so some research would be required.
So there you have it. Is this the best or most efficient way? I don’t know – I’m far from an expert on any of this. To be honest, I never actually tested doing this just on the CPU, so it’s entirely possible that that approach is better if there are collision detection requirements. There are also other considerations, such as whether your game is CPU or GPU bound, which would go into determining which method is better suited to your needs. Ultimately, whatever works in your situation is the right method.
2 thoughts on “My name is Crappy Coding Guy, and I use Texture2D.GetData”
I like your planet and crater example. Very nice. And your asteroid game is also super cool. I have a question for you though. In looking at the planet graphic image and the crater graphic image, they both have the dimension of 256 x 256 pixels. What I can’t figure out is how you are reducing the size of the Crater when it is displayed on the planet. You see when the crater is rendered, it appears to be reduced to about 1/5th of it’s original size. Yet if I look in the C# code I can not see how the image is being reduced. Can you possibly explain why the crater is displayed about 1/5 th of it’s original size?
Thanks for your comments.
The crater texture size is reduced by the call to SpriteBatch.Draw.
I’m specifying the desitinationRectangle parameter with a width and height of 50. SpriteBatch.Draw automatically shrinks (or stretches if needed) the texture to fit the rectangle that you pass.
Comments are closed.