One part I wasn’t quite satisfied with in the original pixel perfect collision sample was the need to render the image in order to extract its data. Shawn Hargreaves suggested that I skip the middle man (at least for a few common formats), copy the data directly from the texture and perform CPU-side conversion to eliminate the render step and avoid spinning up the GPU rendering pipeline. I thought that was an excellent idea, so that’s what I’ve done. (Shawn just provided the idea; if the code has problems, that’s my fault!)
The new DX::GetTexture2DCollisionDataNoRender function operates on a texture with one of the following formats: DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R32G32B32A8_FLOAT, DXGI_FORMAT_BC1_UNORM (Dxt 1 in old terminology), or DXGI_FORMAT_BC3_UNORM (Dxt 5). Other formats may be added as time allows, though you can easily enough add your own formats if you need them. I should note that this function will produce minor discrepancies (up to 2/255ths difference in my testing) in color and alpha channels for formats where conversion beyond mere swizzling is required. The data from this function should be more accurate since it does not rely on any vagaries of driver implementations. (In my testing of the BC1 and BC3 formats, I observed that CPU-side conversions perfectly matched the color values that could be found by opening up the BC1/3 DDS texture files in Visual Studio 2012’s image editor and using its eye dropper tool to inspect individual pixel’s color values. The original rendering method produced different variations depending on the target hardware (e.g. my Surface RT vs. my developer laptop with an Intel CPU and AMD GPU) and the specifics of the texture data). So if you are relying on this data for more than simple transparent/opaque checks, you should prefer this function to the original DX::GetTexture2DCollisionData since you should get more consistent results with this new function.
I also fixed a few bugs in the original. Key among them was that the memcpy_s function call in DX::GetTexture2DCollisionData was improperly using the row pitch for destination offsets rather than the texture width * 4 (bytes in a B8G8R8A8 pixel). It happened that the row pitch for a B8G8R8A8 texture was the same as the byte width which is why no erroneous results were produced. But this is an implementation detail in D3D drivers, one which could change any time and which might not even be true for some graphics cards/drivers.
Lastly I moved most of the function definitions (i.e. the bodies of them) from CollisionDetection2D.h to a new file, CollisionDetection2D.cpp. This was done both to keep the header file clean and easy to understand and also to speed compilation times when a change needed to be made in one of the collision detection functions.
The link from the original post will now grab the updated project. For reference, here it is again: PerPixelCollisionDetection.zip . I plan to move on from collision detection now. What’ll come next? We’ll see!