"An item with the same key has already been added" error

Topics: User Forum
Nov 4, 2007 at 9:52 PM
Edited Nov 4, 2007 at 9:54 PM
Hiya everyone

I'm getting a rather odd error:

Error Building content threw ArgumentException: An item with the same key has already been added.
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at Microsoft.Xna.Framework.Content.Pipeline.NamedValueDictionary`1.AddItem(String key, T value)
at Microsoft.Xna.Framework.Content.Pipeline.NamedValueDictionary`1.Add(String key, T value)
at Xclna.Xna.Animation.Content.XModelImporter.ImportAnimationSet()
at Xclna.Xna.Animation.Content.XModelImporter.ImportRoot()
at Xclna.Xna.Animation.Content.XModelImporter.Import(String filename, ContentImporterContext context)
at Microsoft.Xna.Framework.Content.Pipeline.ContentImporter`1.Microsoft.Xna.Framework.Content.Pipeline.IContentImporter.Import(String filename, ContentImporterContext context)
at Microsoft.Xna.Framework.Content.Pipeline.BuildCoordinator.ImportAssetDirectly(BuildItem item, String importerName)
at Microsoft.Xna.Framework.Content.Pipeline.BuildCoordinator.ImportAsset(BuildItem item)
at Microsoft.Xna.Framework.Content.Pipeline.BuildCoordinator.BuildAssetWorker(BuildItem item)
at Microsoft.Xna.Framework.Content.Pipeline.BuildCoordinator.BuildAsset(BuildItem item)
at Microsoft.Xna.Framework.Content.Pipeline.BuildCoordinator.BuildAndLoadAsset(BuildItem item, BuildItem requestingItem)
at Microsoft.Xna.Framework.Content.Pipeline.BuildCoordinator.ImportAssetViaCache(BuildItem item, String importerName)
at Microsoft.Xna.Framework.Content.Pipeline.BuildCoordinator.ImportAsset(BuildItem item)
at Microsoft.Xna.Framework.Content.Pipeline.BuildCoordinator.BuildAssetWorker(BuildItem item)
at Microsoft.Xna.Framework.Content.Pipeline.BuildCoordinator.BuildAsset(BuildItem item)
at Microsoft.Xna.Framework.Content.Pipeline.BuildCoordinator.RunTheBuild()
at Microsoft.Xna.Framework.Content.Pipeline.Tasks.BuildContent.RemoteProxy.RunTheBuild(BuildCoordinatorSettings settings, TimestampCache timestampCache, ITaskItem[] sourceAssets, String[]& outputContent, String[]& rebuiltContent, String[]& intermediates, Dictionary`2& dependencyTimestamps, KeyValuePair`2[]& warnings) Z:\Revv\XNA\Second 3D\Content\Models\Characters\BoxDude\BoxDude.x

I think the gist of it is that when my model is imported, it's being added twice.

This is my first foray into using the Animation Component Library so this is the only model being handled by the library. The file definitely isn't in there twice, and I've rebuilt my solution. It's not the only .x file in the project.

It was exported from Cinema4D with Xport.

Also, when I exported a version from C4D without the animation (by mistake) it drew fine.

What should I do here?
Nov 5, 2007 at 1:06 AM
Edited Nov 5, 2007 at 1:12 AM
You can see from the stack trace in the error that the problem is occurring while importing animation data, which explains why you didn't get the error when it was exported with no anim data.

I'm not as well versed with this library as I'd like, so I can't give a definitive answer without referring to the code, but one guess I would make is that some exporters are not careful about making sure that you don't have two bones/joints with the same name, and if you did have two bones with the same name in your .x file the error above would make sense.

I've used other .x files with this library (with animation data), so I don't think it's a general problem with reading the files. It seems somewhat likely to be a problem with this specific file.

I might recommend placing a breakpoint in the XModelImporter.ImportRoot() method and verifying whether the dictionary that it's adding an object to already contains a similarly named object. As a side benefit, you'll find out the name of the object causing the problem and this can help you track down why there are two such-named objects in your file (perhaps your C4D file also contains two identically-named objects in the character rig?).

Failing that, find a place to put the file up so that others can try to debug the issue, I guess.

Hope that helps at least a little.
Nov 5, 2007 at 4:21 AM
Yup, I'd say you're right. Unfortunately I'm not really experienced enough to go mucking with the guts of the component to find out where the file is doubling up.

Xport has an option to append a unique number to each object, so I've tried toggling that but to no avail. I'll have to learn another 3D program I guess. :)

Thanks!
Nov 5, 2007 at 8:46 AM
Edited Nov 5, 2007 at 8:50 AM
I can't believe it. I got it working. I more or less completely removed everything and remade it, which fixed the "duplicate entry" bug. No idea what happened there really.

Anyway, here's how you get .x animations from Cinema 4D into XNA:

Export from C4D with Xport. The plugin is a bit old, but it works. Make sure you set it up like this:

Check "Add unique number to each entity name"
Check "Export animation"
Uncheck "Only bones"

Now open your .x file and search for this part:

AnimationSet {
Animation {
AnimationKey {

And change it to:

AnimationSet myAnimationName {
Animation {
AnimationKey {

"myAnimationName" is the same as "AnimationSet0" in the XML file.

In XNA I didn't want to let the ModelAnimator draw for me, I wanted to keep my own drawing routines. So I changed:

Matrix[] transforms = new Matrixm.Bones.Count;
myModel.CopyAbsoluteBoneTransformsTo(transforms);

to:

Matrix[] transforms = new MatrixAnimator.BonePoses.Count;
Animator.BonePoses.CopyAbsoluteTransformsTo(transforms);

Animator is the same type of object as DwarfAnimator in the tutorial files. I also made sure to called Animator.Update(gameTime) in my model's update.

I hope this helps someone else! I am stoked it worked!
Nov 5, 2007 at 2:59 PM
Ah, very cool indeed, and that's awesome that you posted the workaround.
Nov 5, 2007 at 3:29 PM
Thanks!

I'm having a little trouble getting weighted skins exporting. I've tried both bones and joints and the transformations are not used.

Is there anything special you need to do on the Animation Component side, or is it all automatic if the file is correct?
Nov 5, 2007 at 11:49 PM
Edited Nov 5, 2007 at 11:51 PM
For the files that I have used, it seems to be basically "automatic", which really just means that the Animation Component has internal code for importing the vertex weights, etc.

That information does have to be explicitly defined in the file, as it's a tremendously difficult problem to calculate good blend weights programmatically. This is why so many modelling programs have "weight painting", for instance.

I haven't used .x files much with XNA Animation Component lib, I usually use .fbx files exported by Mod Tool, but the few that I've used have worked pretty much painlessly. This leads me to believe that it could be a problem with your file, though I'm not familiar with the tools you are using and can't say so for sure.

Does C4D export COLLADA files? One of the things on my todo list is create a COLLADA content processor for Animation Components based on the code at https://collada.org/public_forum/viewtopic.php?p=2366.

That's still a ways down the road since I have little enough free time, so I guess it's not terribly helpful, but it makes me think that perhaps if C4D can export to a format that another program (like Milkshape, which has okay .x support) understands, you could use that second application as a converter to export to .X for use with this library.
Nov 20, 2007 at 7:37 PM
Sadly C4D does not support COLLADA at the moment, although there has been talk about support being added. Frankly I would hope they'd shore up DirectX export support at the same time.

I had a look at Milkshape but I either wasn't able to get it to import correctly, or I couldn't get C4D to export correctly.

I'm trying some other options now such as Blender and eventually I'll probably have to go back to the XSI Modtool and learn how to rig a character in it. Modtool can automatically create a nice bipedal skeleton for you, but it's quite complicated and I reckon weighting the mesh for each bone would be a real mission.

How were you using .fbx? What content processor did you select from the popups under model properties in XNA?
Feb 24, 2008 at 8:26 PM
I experienced the same troubles when importing a mesh, and while debugging i came across a odd piece of the code when calculating the bind pose:

In the file "XModelImporter.cs", at the end of Method "NodeContent Import(string filename, ContentImporterContext context)"

There is code like this (sry, i messed around with it, so it does not exactly match the code in the repository)

// Calculates bind pose as required for compatibility with Xna Content DOM
Dictionary<string, Matrix> absTransformsDict = new Dictionary<string, Matrix>(skinTransforms.Count);
int k = 0;
foreach (SkinTransformContent[] sst in skinTransforms)
{

if (sst != null)
{
absoluteMeshTransform = meshesk.Mesh.AbsoluteTransform;
foreach (SkinTransformContent st in sst)
{
Matrix abs = Matrix.Invert(Matrix.Invert(absoluteMeshTransform) * st.Transform);
// !!! HERE the error happens
absTransformsDict.Add(st.BoneName, abs);
}
}
k++;
}

(sry, i couldn't figure out how to format code)

This was actually the first time i encountered the term bind pose, so i looked it up and found this
http://www.okino.com/conv/skinning.htm
(at the very bottom)

So if this arctile is correct and i understand correctly these are - from a programmers point of view - simply matrices which transform from MESH-space to WORLD-space and from BONE-space to WORLD-space. So meshes have their matrices, and bones also have their matrices - and these things should be seperated.

So I don't understand what the mesh's transform has to do with the bone's transform in "Matrix abs = Matrix.Invert(Matrix.Invert(absoluteMeshTransform) * st.Transform);
" but this doesnt seem right, because in our x files a mesh may be affected by multiple bones:

Mesh
affected by Bone
0:
Back
1:
Wrist_Right
2:
LowerLeg_Right
LowerLeg_Left
3:
Back // Oooops! Mesh #0 was already affected by the Bone "Back", Now mesh #3 cannot be affected by bone "Back" anymore? Huh?

While searching for a solution, i also came accross this thread
http://www.codeplex.com/animationcomponents/Thread/View.aspx?ThreadId=8423
but im not sure how much this relates to my problem.

So is there some fix out there?
One obvious fix would be having our designer to duplicate the bones for each mesh (so instead of Mesh #3 being affecte by bone "Back" it coult be affected by bone "Back2" which undergoes the same transformations/animations as bone "Back").
Hmmm, on the other hand this could probably be done in the importer too.

Well, any ideas?
Feb 25, 2008 at 4:34 AM
So to me the problem seems to be that mesh matrix in the line

Matrix abs = Matrix.Invert(Matrix.Invert(absoluteMeshTransform) * st.Transform);

which causes my troubles.
So i wonder, isn't it possible to transform the meshs' vertices and normals by the absolute transform, so that the absolute transformation becomes the identity, in which case the its doesnt matter which aboluteMeshTransform is taken since they are all identity?

Unfortunately it doesn't work - i am transforming the vertices and normals after mesh.CreateGeometry() is called.
Are there any other things that need to be transformed by the mesh transform?

Or is it just a bug i made? Or is the idea not going to work anyway for whatever reasons?
Help plz :)