Hello, I'm back again.
I have been making some wonderful progress on my C# Mesh Viewer but have been suddenly halted. I use the SkinnedMesh and MView C++ source as a guide, keeping the general idea of the work flow but obviously writing in C# using Direct3D. However, there seems to be a difference I can not find since my test mesh (the 3DSMax Panda exporter dragon sample) loads fine in MView, but not in my program.
I have managed to get my mesh, including the bones, to load. The bones are clearly animating as I can see my fully rendered and textured mesh move. The vertices, however, are all over the place; clearly not where they should be. I am fairly certain my offset matrix and bone frame matrices are lined up properly and setup in the world palette correctly. I think my problem might be in ConvertToIndexedBlendedMesh(...). I seems as if it isn't applying the proper verts to the proper bones for some reason, not defining the proper attribute table. As far as I know, I have little control over that when using Indexed Skinning. And no, I don't want to use a different skinning method, I would like to fix this one that clearly CAN work.
Here's some source snippets.
In my custom CreateMeshContainer(...) function, this is how I build my skinned mesh.
if(skinInfo != null)
{
int maxFaceInfluence;
Direct3D.BoneCombination[] boneCombination;
meshContainer.PaletteSize = 12;
meshContainer.SkinnedMesh = skinInfo.ConvertToIndexedBlendedMesh(
meshContainer.MeshData.Mesh,
Direct3D.MeshFlags.Managed | Direct3D.MeshFlags.OptimizeVertexCache,
meshContainer.GetAdjacencyStream(),
meshContainer.PaletteSize,
out maxFaceInfluence,
out boneCombination);
meshContainer.BoneCombination = boneCombination;
meshContainer.MaxFaceInfluence = maxFaceInfluence;
}
I recurse through the frame tree, when I find a mesh container I setup the bone matrix pointers. In C++ you would add a reference to the bone offset matrix to the MeshContainer. In C# you can't do that without using unsafe code, so instead I give the MeshContainer references to the bone frames which influence it. With that it can easily get the combination matrix at render time.
public void SetupBoneMatrixPointers(Direct3D.MeshContainer meshContainer)
{
if(meshContainer.SkinInformation != null)
{
ExtendedMeshContainer extendedMeshContainer = (ExtendedMeshContainer)meshContainer;
int numberBones = extendedMeshContainer.SkinInformation.NumberBones;
extendedMeshContainer.BoneFramePointers = new ExtendedFrame[numberBones];
extendedMeshContainer.BoneOffsetMatrices = new DirectX.Matrix[numberBones];
for(int bone = 0; bone < numberBones; ++bone)
{
ExtendedFrame frame = (ExtendedFrame)Direct3D.Frame.Find(_rootFrame, extendedMeshContainer.SkinInformation.GetBoneName(bone));
extendedMeshContainer.BoneFramePointers[bone] = frame;
extendedMeshContainer.BoneOffsetMatrices[bone] = extendedMeshContainer.SkinInformation.GetBoneOffsetMatrix(bone);
}
}
}
And lastly, here is the mesh rendering function. A bone combination is the same as an attribute group except it includes the skin information bone ID.
private void RenderMeshContainer(Direct3D.MeshContainer meshContainer, Direct3D.Frame frame)
{
ExtendedMeshContainer extendedMeshContainer = (ExtendedMeshContainer)meshContainer;
ExtendedFrame extendedFrame = (ExtendedFrame)frame;
_d3dDevice.SetRenderState(Direct3D.RenderStates.VertexBlend, extendedMeshContainer.MaxFaceInfluence - 1);
if((extendedMeshContainer.MaxFaceInfluence - 1) > 0)
_d3dDevice.SetRenderState(Direct3D.RenderStates.IndexedVertexBlendEnable, true);
for(int counter = 0; counter < extendedMeshContainer.BoneCombination.Length; ++counter)
{
for(int paletteItem = 0; paletteItem < extendedMeshContainer.PaletteSize; ++paletteItem)
{
int boneMatrixIndex = extendedMeshContainer.BoneCombination[counter].BoneId[paletteItem];
if(boneMatrixIndex != -1)
{
DirectX.Matrix tempMatrix = extendedMeshContainer.BoneFramePointers[boneMatrixIndex].CombinedTransformationMatrix * extendedMeshContainer.BoneOffsetMatrices[boneMatrixIndex];
_d3dDevice.Transform.SetWorldMatrixByIndex(paletteItem, tempMatrix);
}
}
_d3dDevice.Material = extendedMeshContainer.Materials[extendedMeshContainer.BoneCombination[counter].AttributeId];
_d3dDevice.SetTexture(0, extendedMeshContainer.Textures[extendedMeshContainer.BoneCombination[counter].AttributeId]);
extendedMeshContainer.SkinnedMesh.DrawSubset(counter);
}
_d3dDevice.SetRenderState(Direct3D.RenderStates.IndexedVertexBlendEnable, false);
_d3dDevice.SetRenderState(Direct3D.RenderStates.VertexBlend, 0);
}
And just so you have an idea of what I'm talking about, here's two screen shots.
MView Dragon:
My Dragon:
If anyone has any ideas I'd love to hear it. Next thing I plan to do is go over all the SkinnedMesh sample device settings to see if I'm missing something there.
Thanks,
[Edited by - GeekSharp on June 19, 2005 1:29:36 AM]
---------------------------------------------------------------"The problem with computers is they do what you tell them.""Computer programmers know how to use their hardware."- Geek#