November 9th, 2007 Greg
On the whole, D3DX does a great job of making our lives easier, us Direct3D 9 programmers. But one topic that has generated a lot of confusion yet very little documentation is the correct usage of the BLENDINDICES shader semantic.
If you’re having trouble getting your CPU and GPU to communicate blend-indices correctly, the first thing to do is make sure that your source data is valid. If you’re using a custom mesh-loading routine then you’re on your own, but certainly under D3DXLoadMeshHierarchyFromX you can save yourself a lot of potential grief by prototyping with a reliable X-file. Support for X-file exporting is very shaky for most 3D modelling suites, but the SDK’s tiny.x sample is as close as you’ll get to a standard model. Once Tiny is happily running around in her fighter-pilot’s uniform you can start thinking about trying out your own models.
Nobody seems to be sure just what went wrong when the late ARB drafted up the usage semantics of blending parameters, but many current video cards lack hardware support for the UBYTE data type needed to store the indices. For this reason, developers have found themselves hammering unsigned-byte-quadruplets into the shape of D3DCOLORs, lying about the data content and praying that the vertex pipeline will have magically transformed the output into something that can be jimmied back into a tuple of UBYTEs. As far as I can see, this is the mother of all DirectX hacks, but it also seems to be the universal standard. That’s the only reason I’ll sleep at night after posting this.
After successfully calling ID3DXSkinInfo::ConvertToIndexBlendedMesh, the blend-index data is all present and correct. The challenge is to pipe it to the shader without misinterpretation. For that, I found it necessary to set all index data in the vertex declaration to be passed as D3DCOLOR data (DWORDS in disguise). By the way, if you are still using FVFs for something as finicky as GPU skinning then you don’t deserve any help: bite the bullet and write out those overly verbose, but oh-so-flexible vertex declarations.
// Fix UBYTE4 Support
D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
skinned_mesh->GetDeclaration(decl);
{
int i = 0;
while (decl[i].Method != 0xFF)
{
if (decl[i].Usage == D3DDECLUSAGE_BLENDINDICES)
{
decl[i].Type = D3DDECLTYPE_D3DCOLOR;
break;
}
++i;
}
}
skinned_mesh->UpdateSemantics(decl);
This takes care of the program code. All that remains is to interpret the data accordingly in the shader. For this, Microsoft generously provided us with the D3DCOLORtoUBYTE4 macro. HLSL (as of SM3) doesn’t have true integer support, let alone unsigned byte support, so we use their emulated int4 vector.
VS_OUTPUT VS_SkeletalBlend
(float3 pos : POSITION0,
float1 blend_weight : BLENDWEIGHT0,
float4 blend_indices : BLENDINDICES0,
float3 normal : NORMAL0,
float2 tex_coord : TEXCOORD0)
{
int4 indices = D3DCOLORtoUBYTE4(blend_indices);
float weight0 = blend_weight;
float weight1 = 1 - weight0;
int ind0 = indices.x;
int ind1 = indices.y;
// ...
}
Notice that the semantic here is BLENDINDICES, even though the vertex declaration says D3DCOLOR. Note further that the type becomes, somewhat wastefully, a float4 as all colour values are passed as such. The sample here is for a two-weights-per-vertex animation, but it’s easy enough to scale this up to four. If you need more than four weights then you need to have a word/fight with your artist, but the idea is the same, only you pass another parameter just like the first. Now I’m not certain that this is the best configuration - it certainly looks like a horrid mess - but it’s the only combination I know to work, after hours and hours of painful Googling. Suggestions for improvement are welcome.
Posted in Game Programming | No Comments »
November 5th, 2007 Greg
DLL Hell, SxS libraries, manifest files, ‘The application configuration is incorrect’.
Oh my!
It seems that every C++ blogger and his dog is talking about the side-by-side hell that Microsoft have cooked up, but after having a hard enough time finding answers myself, I figured that it’s best to be part of the solution. If you’ve stumbled upon this post from a Google search, it’s likely that you’re one of the many poor souls who has no idea why their program refuses to run on any computer other than the one it was compiled on.
![[Side-by-side error message]](/images/sxs.png)
The necessity for all of this incompatibility is clear when you consider how many different versions of the Windows kernel interfaces are floating around, but it’s still a pain for those of us who just want to compile a program for personal use. The most correct way to address the situation is to package your application with the MSVC++ runtime library. This way, the executable can’t be used without running an installer that ensures all the appropriate DLLs are present. But for most of us this is unnecessary bloat, and VC++EE doesn’t even offer a means of producing such a setup package.
There is a lot of talk about determining the dependencies with a PE-viewer or the dependency-walker, copying the appropriate SxS DLLs from Windows/WinSxS/ to a carefully-crafted directory hierarchy, and manually editing an XML manifest file to tell the OS how to find them. This is error-prone, beginner-unfriendly and seems to be causing more confusion than good.
But the solution that Microsoft have kept quiet is somewhat cleaner. If you configure the Visual C++ IDE to statically link against the multithreaded libraries (Project | Properties | Configuration Properties | C++ | Code Generation | Runtime Library := Multithreaded [Debug]) then the program will never have any such unpredictable external dependencies and so avoids the problem altogether. This will of course mean that you have an extra 150kB of PE to carry around, which may be undesirable for widely-distributed DLLs, but for small-time projects it’s a worthwhile trade.
Posted in Game Programming | No Comments »