Blended Mesh Container Drawing (Help? Source included)

Started by
8 comments, last by ramy 18 years, 10 months ago
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#
Advertisement
im having the same problem with my demo as well.

it gets drawn very weirdly, and i load it the exact same way as the directx sample SkinningMesh does. but im doing it under native c++.

but if u solved the problem plz do tell me.

and i suspect the device microsoft does in those samples has afew extra things setup that we dont know about, cause all animation demos and codes i came accross, use the Deivce microsoft provides in the sample (the thing in common folder).
i fixed the problem maybe the solution will solve urs too:

it turned out that when i move the frame, i needed to pass the world matrix that had his center negated from it.

ramy
Hey,

If you mean you you had to start with the world matrix and pass that down your hierarchy then I've already done that. But maybe I'm missing the idea of your actual fix?
---------------------------------------------------------------"The problem with computers is they do what you tell them.""Computer programmers know how to use their hardware."- Geek#
no i didnt pass the world matrix down, i passed a matrix that has translation for the negative center of that model.

for example, if center was (1,1,1), then translateMatrix(-1,-1,-1);

and pass that translateMatrix down the hierarchy in FrameMove.
Ok,

I'm pretty certain that adding those negatives only moves the start position. The skin mesh sample just wanted it moved off centre. And since my start position is 0,0,0. Then negating it doesn't do much anyway. If that fixed yours, that's very weird.

Anyway, I did find my problem. Understandably it does matter what order you multiply matrices in. I switched the order of the multiplication of the BoneOffset and the CombinedTransformation in my render function and it's coming out perfectly, on my computer, now.

However, I sent the executable and resources to a friend of mine and when he runs the demo many of the joints are "disconnected" but they still animate along with the body. But it works perfectly when I run the same thing. Any ideas?

This might be worthy of a new thread...

Here's a screenshot.


[Edited by - GeekSharp on June 20, 2005 11:26:34 PM]
---------------------------------------------------------------"The problem with computers is they do what you tell them.""Computer programmers know how to use their hardware."- Geek#
Well that problem was easy to solve.

His card doesn't support indexed pre-vertex skinning. It's a ChainTech GeForce 6600 GT, so that's supprising. My generally inferior ATI RADEON 9600 supports a palette size of 38. I guess it's an Nvidia thing?

So I'll probably work on Shader skinning now, and non-indexed. Software seems almost useless to me. The dragon alone runs at 60 fps. Throw in a few more and a world and you're finished!
---------------------------------------------------------------"The problem with computers is they do what you tell them.""Computer programmers know how to use their hardware."- Geek#
well to say the truth i didnt do mine with indexing. i did it without indeing, i am taking bit by bit, and building it slowly.
i have xfx geforce 6600 gt and it supports indexing, cause the Mesh Viewer from DirectX sdk works fine :S yeah the softawre indexing is quite slow compared to fixed function indexing and shader indexing.

its a weird problem. something is wrong.

and btw: my object that i loaded wasnt in the center, it was abit off, that depends on the modeller that modeled it in 3D max or something.

[Edited by - ramy on June 21, 2005 10:15:59 AM]
You should look at your caps with the Direct3D Caps Viewer to see if it supports hardware indexed matrices (a MaxVertexBlendMatrixIndex of 0 means it isn't supported, > 0 is good). Your reasoning about the Mesh Viewer is flawed.

The Mesh viewer tests this cap and if you don't support it then it uses system memory and stores the matricies there instead and you end up doing software vertex processing even though it doesn't TELL you that you are.

Instead of placing the matrix palette into managed GPU cache it gets stored in the system ram. Everything else about indexed processing remains the same, so it's not nearly as slow as full software blending but it's not quite as fast as real hardware indexing.

But as long as you support shader blending then your good GeForce cards will work great. Indexed and non-indexed will handle older cards. Software... not worth the trouble.
---------------------------------------------------------------"The problem with computers is they do what you tell them.""Computer programmers know how to use their hardware."- Geek#
you are right, MaxVertexBlendMatrixIndex is 0.

i didnt pay attention to that before. thx for pointing out.

This topic is closed to new replies.

Advertisement