Users browsing this thread: 1 Guest(s)
NDS model + animation => COLLADA converter
#1
Hi everyone. This is my first post.

I've been working on a program to convert NDS models and animations to COLLADA. It outputs vertex colors, joint trees, and skeletal animations. I've been testing it with the games Kingdom Hearts: 358/2 Days and Ore wa Omae o Mamoru, where I've had pretty good success. I don't know how much interest there still is in ripping DS games, but I wanted to share it here. Hopefully if all the kinks are ironed out it can be used for submitting models  Smile

apicula
GitHub Page
Latest Build, 64-bit, Windows

I wrote a tutorial on how to use it here, but the short version is that you can follow Mystie's NDS Ripping Tutorial up to the end of step 4, then use apicula to convert the NSBMD files by running

apicula.exe convert <PATH TO NSBMD FILES> -o <OUTPUT DIRECTORY>

at the command line. You can also add any NSBCA files with the NSBMD files to add animations to the models.

Examples

[Image: joint_ex.png]

[Image: godot_ex.gif]

Bugs

The success rate for models is fairly good, but there are definitely still known bugs  Shy  I'll be working to fix some of them for a while. If you find any, you can post about them here. If anyone is familiar with the Nitro SDK formats, you can also see the code on GitHub.

If anyone can test importing the COLLADA files into commercial DCC programs like Maya or 3DS Max, that's be nice too!
Reply
#2
So if I read this right, this works for most games that have NSMBD usage. Nice!
I'm an opera-crossover singer undergoing classical voice training and I'm also making Super Smash Bros. Feud.

Discord: kold_virus
Reply
Thanked by:
#3
Oh hell yeah, this is great, I've been wanting something like this for ages now. Thanks dude great work.
Reply
Thanked by:
#4
(01-29-2017, 06:47 PM)Rodo Furedorikku Wrote: So if I read this right, this works for most games that have NSMBD usage. Nice!

That's the intention, right. NSBMD files for models and NSBCA files for skeletal animations. In practice, I don't know how many games this will work for. For example Avalon Code has model files that have the BMD0 stamp, but aren't the format that this can understand.

apicula can also scan a ROM (or any kind of file really) and extract all the models and animations that it understands as long as they aren't compressed or encrypted or anything. The instructions for that are here.
Reply
Thanked by: Kold-Virus
#5
Thank you for the tool, i have still some NDS game models that i would like to obtain, both use nsbmd format, unfortunately those versions were not supported when i tried the last time with the most known tools. The games are Golden Sun: Dark Dawn and Love Plus+, i will test them soon. Otherwise i have to manually convert them or modify the nsbmd viewer, but i'm too lazy XD.
Reply
Thanked by:
#6
You just made my day, thanks so much, I'm still getting some rouge vertices (Love Plus Models), but the fact that I don't have to made the rigging by hand is more than enough.

Also, what's with the "_BLEND#_" bones? they are not part of the original rig.
Reply
Thanked by:
#7
I'm glad it's useful! About the __BLEND##___ bones (those are, for example, the really long bones on Roxas's model above that go outside his body)... I'm also not exactly sure! I can tell you what technical feature in the model file makes them necessary, but the purpose they served to the modeler is a mystery to me. They'll only appear is a model uses vertices that are influenced by multiple bones.

Technical explanation follows:

There isn't really an "original rig" for an NSBMD model. The model file contains an array of named object matrices, but they're not connected together in a skeleton or anything (and one object might occur in many places or not at all in the final skeleton). The file also contains rendering commands, which essentially multiply these object matrices together and store them to GPU variables (for example, it might multiply "Root" -> "Torso" -> "LUpperLeg" -> "LLowerLeg" -> "LFoot" together and put it in GPU slot #3). Then before a group of vertices is drawn, the right matrix will be set from the GPU variables (in the last example, before the tris for the left foot are drawn, the matrix from GPU slot #3 would be loaded).

The skeleton is built by tracking which object matrices make up the matrix in a GPU variable and creating joints that will transform the vertices in the same way that running the rendering commands in the model file would. Simply speaking, every factor in a matrix product becomes a joint.

There's also a separate array of unnamed matrices in the model file I called blend matrices because they're used by a weird rendering command that blends matrices together. Specifically, it puts the sum of terms that look like (scalar weight) * (matrix from GPU slot #XXX) * (blend matrix #YYY) into a GPU slot. So if XXX=3 in the example above, you're looking at a matrix like "Root" -> "Torso" -> "LUpperLeg" -> "LLowerLeg" -> "LFoot" -> (blend matrix #YYY) and we need a joint to represent that final factor, and that's where the "__BLENDYYY__" at the leaf comes from. Why there's a command for this (as opposed to just summing terms like (scalar weight) * (matrix from GPU slot #XXX)), I don't know.

(This feature was kind of a pain btw. It was the last thing I needed to get Roxas to work though, which was something like my original goal Smile)
Reply
Thanked by:
#8
Oh, that makes sense, sort of, it certainly is more complex than what I thought it would be, it makes me be more grateful to you, that's for sure.

If I understand correctly, I may be able to edit the armature to remove those bones and pass the influence to others, at least looks like it can be done.

I'll have to check if I can edit the animations to match the new armature thou.
Reply
Thanked by:
#9
I looked into this more and I finally figured out what those blend matrices are supposed to be used for! The good news is that if they are used for that (they're supposed to be inverse bind matrices), they can be eliminated from the skeleton after all, haha  Sweatdrop  And if they're not, you'll at least get a big warning telling you that something weird is happening. But if it goes well, you should get a nice clean skeleton now. Example before/after

[Image: 6pL6dqJ.png]

I also fixed an unrelated bug that caused some verts to be parented to the wrong joints, which might have been the cause of your rogue vertices.

Change are in the latest version.

If this doesn't fix the problems with your model, Inferry, if you can upload the NSBMD file you're using somewhere, I'll take a look and see if I can get it working.
Reply
Thanked by:
#10
Works wonderful, it even fixes some bone misplacements, I still have to play jigsaw with the models but that's because of the way they are stored(F Konami).

I wonder, is it possible to extract animations only? the models I have are a bunch of different parts that the game puts together(like legos), but the animation files (or what I think are the animation files) don't seem to be matching the models at all, so it always trows an error no matter what I try.

I can get animations from other games, but I also seem to be getting only the first animation when there's obviously more than one, so I don't know if I'm doing anything wrong.

I'm kind of sleepy so that may be part of the problem.
Reply
Thanked by:
#11
Really cool men

I just tryed RE: Deadly Silence models and it works perfect, at first I thought they didn't have an skeleton but it was invisible until i turned the x-ray option in blender. Now i wont have to rig them anymore Smile

[Image: DEGn8CQ.png]

Although didn't work with Iron Man 2 NSBMD's when i run it I got "Found 0 BMDs. Found 0 BCAs." even when i can see the model in Console tool

[Image: jiHen2T.jpg]
Reply
Thanked by:
#12
(04-22-2017, 11:54 PM)Inferry Wrote: I wonder, is it possible to extract animations only? the models I have are a bunch of different parts that the game puts together(like legos), but the animation files (or what I think are the animation files) don't seem to be matching the models at all, so it always trows an error no matter what I try.

It seems... difficult Unsure An animation is basically just a big block of matrices. All the information about which joint to target with which matrix comes from the model files. I tried to extract models from Love Plus and only got some disembodied hands, which only seem to have the part of the skeleton that influences that hand (eg. the hand joint and then all of its ancestors). So if you have more pieces I can imagine how you could fit them together but unless some file has the full skeleton it will be hard to apply a NSBCA animation to it.

Btw, the way you can know if a file is an animation file is provide it without any models to the view command (apicula v file_in_question) and you should see Found 0 models. Found <some positive number> animations.. If you see any errors here, apicula couldn't understand the file at all and wouldn't be able to apply to any model.

(Maybe I should add an info command to make this kind of information more accessible....)

(04-22-2017, 11:54 PM)Inferry Wrote: I can get animations from other games, but I also seem to be getting only the first animation when there's obviously more than one, so I don't know if I'm doing anything wrong.

What program are you importing them with? Blender seems to do this—truncate to the first animation—to all COLLADA files (that's why I showed off the animation in Godot). I've been meaning to write up something about the limitations that Blender has. I was hoping other programs wouldn't have this issue though.

(04-23-2017, 07:19 PM)LGB Wrote: Although didn't work with Iron Man 2 NSBMD's when i run it I got "Found 0 BMDs. Found 0 BCAs." even when i can see the model in Console tool

Thanks for the report!
I pushed some changes that should improve things (but it's still not perfect), including support for NSBTX files, which you'll need to provide on the command line along with the NSBMDs get the textures to work.
Reply
Thanked by:
#13
(04-23-2017, 11:41 PM)scurest Wrote: It seems... difficult
Bugger, well for the way you put it, those files may not be the ones to use with those models.

"You should see Found 0 models. Found <some positive number> animations."

Found 0 models.
Found 0 animations.

So the files I thought where animation files, where not animations, or at least they had no animations in, so now I have to find where they actually are, with some luck they'll fit the models I have, if I happen to find them.

(04-23-2017, 11:41 PM)scurest Wrote: What program are you importing them with? Blender seems to do this...

I'm using Blender  Unimpressed

I imported the file into Unity and the animations(from some other game) are all there.
So I tried to use FBXconverter(since it accepts dae) to turn it into a fbx file to see if I can bring that to blender, but it trows a "not enough parameters" error, there may be a node that lacks a definition, but the file is massive so I can't see if that's the case.

I'll try to find a smaller model to import and see if it's a problem with only that file or a more general thing with the format, in the mean time I'll see if I can download max and maya (trials of course Smug ) to see if they can import the dae properly.

(04-23-2017, 11:41 PM)scurest Wrote: only got some disembodied hands... So if you have more pieces I can imagine how you could fit them together.

That sounds about right, you may have the base hands for one of the girls, the armature is not that hard, you just merge them all, remove the duplicated bone and re-parent those who may need it, is not that much of a big deal really as blender does most of the work.
Having the animations is just a nice bonus on top of it all, which is really great, thank you so much.
Reply
Thanked by:
#14
Oh, good idea about FBX converter Smile ! I didn't know about that. The error it gives was due to a bug in my COLLADA code, which is fixed now. Tell me if you still have problems doing the conversion.

The FBX files do preserve all the animations. Importing them into Blender gives even crazier bone placement than importing the .daes though!
Reply
Thanked by:
#15
So the FBX does indeed break the armature, and sadly due to the way blender handles animations I couldn't find a way to pass them to the armature of the *.dae (the nice one) without screwing the animation itself.

So I ended writing and learning a phyton script that separates each *.dae file into several ones, each containing one of the animations in the original file, I only have to import each file individually and merge the animations into one single library, some require editing due to the extra frame they come with but that's not my fault, that's how they were, to begin with.

Anyway, here's the code for anyone interested, copy and paste it into a text file and change the extension to ".py", you'll need python2.7 for it to work

Code:
import sys
import xml.etree.ElementTree as ET
import copy

ET.register_namespace('', "http://www.collada.org/2005/11/COLLADASchema")

my_file = sys.argv[1]

tree = ET.parse(my_file)
root = tree.getroot()

ns = {'d': 'http://www.collada.org/2005/11/COLLADASchema'}

library_animation_clips = root.find('d:library_animation_clips', ns)
library_animation_clips_copy = copy.deepcopy(library_animation_clips)
library_animations = root.find('d:library_animations', ns)
library_animations_copy = copy.deepcopy(library_animations)

def libraryClear():
    for child in library_animation_clips.findall('d:animation_clip', ns):
        for child in library_animation_clips.findall('d:animation_clip', ns):
            library_animation_clips.remove(child)
        for child in library_animations.findall('d:animation', ns):
            library_animations.remove(child)
    return

libraryClear()

i = 0

for child in library_animation_clips_copy:
    
    library_animation_clips.append(child)
    
    att_id    = child.get('id')
    att_name  = child.get('name')
    file_name = att_name + ".dae"
    
    for joint in child:
        library_animations.append(library_animations_copy[i])
        i = i + 1
    
    tree.write(file_name, encoding="utf-8", xml_declaration=True)# <?xml version="1.0" encoding="utf-8"?>
    libraryClear()

I only tested it with three files, is not optimized and there is probably a better way to do this, but the thing works and is enough for me (although if you think it can be improved let me now to change what's needed).

Use the command line and pass the file as an argument

daesplitter.py <file>

or make a bat with this ("c:\Python27\python.exe" daesplitter.py %1), and drag and drop the file onto the bat.

And I was unable to make a test on Maya or 3Dmax due to the fact that 64 exclusive nowadays.
Reply
Thanked by: scurest


Forum Jump: