sugiany / blender_mmd_tools

mmd_tools is a blender addon for importing Models and Motions of MikuMikuDance.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

English Bone Conversion

vmJoe opened this issue · comments

commented

Couldn't find any support email/forum so I hope using issues is ok for this question?

With PMXEditor I can load a pmx model and then translate/set English bone/material/... names along with the Japanese. When the model is imported into blender however only the Japanese names show up. A work-around is to copy all the English names in PMXEditor and apply them to the Japanese names however this breaks importing VMD files in the MMD app as the correct bone names no longer exist and is extra work when someone provides an MMD with both En/Jp names already setup.

How practical would it be to have mmd_tools optionally create blender nodes using the English names during import instead of Japanese (I think it stores both Japanese and English names during read already?) so that blender displays English names.

commented

As a workaround, I've setup the following script:

import bpy

for item in bpy.data.objects:
    if item.type == "ARMATURE":
        for bone in item.pose.bones[0].children_recursive:
            print("renaming " + bone.name + " to " + bone.mmd_bone.name_e)
            bone.name = bone.mmd_bone.name_e

Whilst a little hacky, this could either run run automatically on import or via a button in the MMD tools menu to toggle back and forth. It might be worth extending this to all nodes that provide _e and _j options.

Maybe this is designed this way because models may not have English data, this could be changed however to using the English name when available otherwise default to Japanese. I will try to implement it.

Update: I've analysed the code and it seems that the Japanese names of the bones are used as reference in many places, therefore changing that behaviour could break the functionality of the addon

commented

I'm not sure if it's the norm, but most models I've seen have only Japanese names so if any change is made it should probably default to using Japanese. Perhaps an import tickbox to create using English names if available and Japanese if not.

I've made a small change to the script I use, there might be other elements that can be changed as well.

import bpy

for item in bpy.data.objects:
    if item.type == "MESH":
        for slot in item.material_slots:
            if hasattr(slot.material, "mmd_material") and slot.material.mmd_material.name_e != "":
                print("Rename material " + slot.material.name + " to " + slot.material.mmd_material.name_e)
                slot.material.name = slot.material.mmd_material.name_e
    if item.type == "ARMATURE":
        for bone in item.pose.bones:
            if hasattr(bone, "mmd_bone") and bone.mmd_bone.name_e != "":
                print("Rename bone " + bone.name + " to " + bone.mmd_bone.name_e)
                bone.name = bone.mmd_bone.name_e

Originally I thought there was a need to change back to JP names in order to import a VMD, but that appears to work fine regardless of names so may be positional based with a margin of error.

@lordscales91 Can you elaborate on what may break? I've not seen any issues with the rig/vmds but then my usage is rather limited so that may be why I've not encountered any of them. My current use is import model, export to UE4, import VMD, adjust and export animations to UE4.

At the present time, if you import and export a .pmx model with mmd_tools, all of the English names are lost(deleted). This should be changed to the opposite of this situation. If you import and export a model which has no English names, the exported model will have all of the English names added into it.

The pymeshio Blender add-on has a file called englishmap.py which it uses as a Japanese-English translation dictionary for bones, bone groups and morphs of .pmd and .pmx models. You would need to create a similar translation dictionary file in mmd_tools to implement this feature. Here is pymeshio's englishmap.py:

https://github.com/ousttrue/pymeshio/blob/master/pymeshio/englishmap.py

In Blender, every bone can have 1 or more custom properties attached to it. But mmd_tools does not use this feature. Instead sugiany has created his own types for Japanese and English bone names. For example, if the armature is the active object, this code will give you the Japanese and English names of the first bone in the armature:

bpy.context.active_object.pose.bones[0].mmd_bone.name_j
bpy.context.active_object.pose.bones[0].mmd_bone.name_e

When a model is imported into Blender, I suggest that a Japanese-English translation dictionary for morph names should be created as a custom property of the mesh object. The keys of the dictionary will be the Japanese names, the values will each be a 2 member list: The English name and 1,2,3 or 4 for the shape key categories (mouth, eyes, brows, other). The English names will preferably be imported from the model itself, unless a model's morph has no English name, in which case the morph name will be created from the mmd_tools translation dictionary file.

@vmJoe Honestly I have no idea of the Blender API, but using my favourite IDE (Eclipse with the PyDev plugin) I performed text-based search to see where the Japanese names are used and they are used to locate the bones later, let me explain:

The Armature Object in Blender has a property called "edit_bones", it seems that is a dictionary of the bones keyed by the bone name, when accessing that dictionary the Japanese name is used, if we change it to English the bone couldn't be located.

If what you want is to see the English names on the bones, it would be possible by using the same trick used for the Rigid Bodies (instead of using the builtin "show bone names" of the armature object), that combined with a button on the MMD Display Panel to toggle between Japanese and English will suffice.

Update: Oh! I didn't read the last part of your comment, you actually are using Blender as a bridge to port MMD models and motions to Unreal Engine, well that's not how MMD Tools should be used, they are designed to import/export MMD data into/from Blender, since your use case is very specific you should stick to your own script.

@Hogarth-MMD I have detected why English names are lost during export, it's a typo on the code, I already fixed that on my local working copy, I'm also fixing other little issues, I will open a pull request after that

bpy.context.active_object['english_name'] = 'smile'

(creates a custom property of the active object whose key is 'english_name' and whose value is 'smile"

Try to create a custom property for a shapekey key_block and you get an error message:

    >>> bpy.context.active_object.data.shape_keys.key_blocks[1]['english_name'] = 'smile'
Traceback (most recent call last):
  File "<blender_console>", line 1, in <module>
TypeError: bpy_struct[key] = val: id properties not supported for this type

There is no id_data for a shapekey key_block:

    >>> bpy.data.shape_keys[0].key_blocks[1].id_data
bpy.data.shape_keys['Key']

Therefore no Japanese name or English name custom properties (or custom attributes) are possible in Blender for shapekey key_blocks (as far as I know). An inconvenience for people who want to import and export MMD models using Blender!

In Blender python, is there not some method by which we can create these 3 attributes(Shape Key English name, Japanese name, and category)?:

bpy.types.ShapeKey(bpy.data.shape_keys[0]).key_blocks[1].name_e
bpy.types.ShapeKey(bpy.data.shape_keys[0]).key_blocks[1].name_j
bpy.types.ShapeKey(bpy.data.shape_keys[0]).key_blocks[1].category

bpy.context.active_object.data.shape_keys.key_blocks[1].name_e
bpy.context.active_object.data.shape_keys.key_blocks[1].name_j
bpy.context.active_object.data.shape_keys.key_blocks[1].category

bpy.data.shape_keys[0].key_blocks[1].name_e
bpy.data.shape_keys[0].key_blocks[1].name_j
bpy.data.shape_keys[0].key_blocks[1].category

@Hogarth-MMD From the API Documentation:

"Custom properties can be added to any subclass of an ID, Bone and PoseBone"

A ShapeKey is a subclass of bpy_struct and not ID, so it's not possible. However we can use any other datablock to store that information, for example on the mmd_root object by using a Collection Property. I tried to do it but due to my lack of knowledge of the API I was not able to do it. I'm reading de documentation right now and I hope I will be able to do it

Is there possibly a technique by which we can give each shapekey key_block its own ID data? What is ID data? To answer this question, I am quoting from the documentation for Python built-in functions:

"id(object)
Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.
CPython implementation detail: This is the address of the object in memory."

In Blender python:

class bpy.types.ID(bpy_struct)
Base type for datablocks, defining a unique name, linking from other libraries and garbage collection

Inherited Properties

bpy_struct.id_data

@Hogarth-MMD Why do you want to store the English names on the ShapeKey itself? I said that this is not possible, but there is a work-around, we can use a collection inside the mmd_root object to wrap that data, each item of the collection could have bl_name (Which will be the ShapeKey name used by Blender), name_e (The English name) and category

Also I would like to say:
@sugiany We are missing you! crying

Come back soon please

"@Hogarth-MMD Why do you want to store the English names on the ShapeKey itself? "

I want the English names and categories to be stored in a way that they will stay correctly connected to the rest of the shape key data and be automatically and correctly updated, if and when the user renames or reorders or edits the shape keys or adds or deletes shape keys. A custom attribute could be more easily and intuitively referenced in code as well.

Here is a simple method of implementing dual names for shape keys and shape key categories:

For example:

bpy.context.active_object.data.shape_keys.key_blocks[1].name = '["笑い", "smile", 2]'

>>> eval(bpy.context.active_object.data.shape_keys.key_blocks[1].name)[0]
'笑い'

>>> eval(bpy.context.active_object.data.shape_keys.key_blocks[1].name)[1]
'smile'

>>> eval(bpy.context.active_object.data.shape_keys.key_blocks[1].name)[2]
2

@Hogarth-MMD If what you want to accomplish is that, it could be possible by providing a custom button on the panel to create a shapekey, as well as controls to edit and reorder shapekeys, that will automatically sync with the shapekeys (via code logic of course). The trick of using a special string to store all the data within the name of the shapekey will force the user to follow that name convention.

Example:

  • user clicks create button
  • a panel pop-up with inputs for specifying the Japanese name, English name and category

Once done the code will:

  • Create a new ShapeKey with the Japanese name specified
  • Then store the metadata of the ShapeKey on the mmd_root
data = MetadataItem('笑い', 'smile', 2)
mmd_root.shapekey_metadata.add(data)

Well, I have successfully created an english_name attribute for shape_key key_blocks, but exactly the same English name is assigned to each and every key_block. :-(

>>> bpy.types.ShapeKey.english_name = bpy.props.StringProperty(name='english_name', description='English name attribute added to shape_keys')

>>> bpy.context.active_object.data.shape_keys.key_blocks[1].english_name
(<built-in function StringProperty>, {'description': 'English name attribute added to shape_keys', 'name': 'english_name'})

>>> bpy.context.active_object.data.shape_keys.key_blocks[1].english_name[1]['name']
'english_name'

>>> bpy.context.active_object.data.shape_keys.key_blocks[1].english_name[1]['name'] = 'smile'
>>> bpy.context.active_object.data.shape_keys.key_blocks[1].english_name[1]['name']
'smile'

@Hogarth-MMD That's because you have added the attribute not the each shapekey but to the Key datablock that contains all the shapekeys. Just don't keep trying to add an attribute directly to the ShapeKey because it's not posible

"that will automatically sync with the shapekeys (via code logic of course)"

Sorry, but this is not clear to me. Are you talking about using the Blender game engine logic for this? If you know a surefire technique of keeping 2 collections of string data synchronized in Blender, I would definitely be interested in learning that technique from you.

Sorry for my late reply.

@vmJoe Thank you for your comment. I had never care about the language of the names on Blender, so it is helpful to me.

Your script probably work well! mmd_tools uses a value of bone.mmd_bone.name_j for importing vmd files, so you can change the bone names. However, shape keys cannot have extra data in Blender. Therefore, mmd_tools uses the shape key name of Blender for importing vmd. For this reason, you should not change shape key names.

Maybe I'll implement the feature for switching the language of bones and materials, but it is lower priority.

@sugiany I'm glad to see you are back, it has been more than a month since your last commit.

I can implement the language switch feature, leave it to me, also I'm working on a "Morph Tools" panel that will let users create, edit, order and delete morphs and sync it with Blender ShapeKeys. I will create a pull request once done

@lordscales91 "also I'm working on a "Morph Tools" panel that will let users create, edit, order and delete morphs and sync it with Blender ShapeKeys." Good luck to you! 👍
Does anyone know if it is possible to create a list box (for shape keys) which has 3 columns instead of 1? I have tried to find this information without any success. It seems to me that a 3 column list box might avoid a lot of programming headaches because you then don't need to do any automated mass renaming of shape keys.

I am very sorry for awaking this sleeping issue but I was wondering if any progress has been done since?
@vmJoe I am trying to use my exported model inside UE4 too but it throws me duplicate bone error and also multiple bones error, have you encountered these and if so how did you solve them?

@ZetaHunter
Hi, if you want the best and fastest help from people who don't use UE4, we need preferably links to Blender import and export add-ons for UE4 models and a link to a free downloadable UE4 model viewer. In pmd and pmx models, each bone is a single point. So in Blender an extra tip bone is added to the tails of some bones. Maybe this is the cause of your problem and a Blender python script which automatically deletes all tip bones would help you.

I found 2 Unreal Engine add-ons which are included with Blender, but when I tried to export a model, Blender hanged on me. Sorry, maybe I jumped in prematurely trying to be helpful, but, unfortunately, I don't know what I'm doing with the Unreal Engine stuff yet. :-(

Hi @ZetaHunter like @sugiany said the renaming of bones and materials to English is a low priority feature, but definitely it will be implemented, I personally will implement it, but first I'm interested on improving other features.

At the moment what we have is a Morph Tools Panel where the metadata of the ShapeKeys (including the English name and category) is stored, among the other Morph types (Material and Bone based morphs).

You can take a look to the commit log to see more details

Actually I finally got it to work, my mistake was exporting the entire blender scene to FBX, when I selected just the MMD ( This one for reference ), also inside UE4 you have to set REF T-POS in fbx importer, there were some texture issues but I fixed that manually ( probably due to me embedding the textures into the fbx in blender ), but yeah, it does work, at least as a model, I need to work on getting the animations to work on the body, since there aren't many useable as game-assets animations (idle, walk, run, crouch, etc,etc, etc) for MMD's, I guess making humanoid skeleton adoptation for my MMD and using the animations that go with UE4 is my best option, thanks for the quick response and sorry for my very late response, also this is just my new weekend hobby, nothing more then that probably, but who knows ^.^

tldr; fixed, works fine no - motions thou.

@ZetaHunter
Is there a standard bone-naming hierarchy for UE4 character models? If so, can you provide the info about that? Do you and other people need an MMD to UE4 automatic bone renaming script?

@lordscales91 I congratulate you on all of your cleverness, hard work and perseverance with your new MMD morph tools panel! 👍 Honestly I was worried that you might get frustrated, give up on python scripting and go off to live in a cave somewhere, but I'm glad that you have persevered. :-) With your morph tools panel, I cannot create or edit a vertex morph. Are there any other features which have not yet been implemented with it?

@Hogarth-MMD I would certainly love to have a script that would automagicly adopt the skeleton to that of UE4, I've made several screenshots of the default skeleton mesh that comes with UE4.
http://i.imgur.com/OGGAZFE.png , http://i.imgur.com/aQFEB85.png and http://i.imgur.com/2RAzMdY.png

I am still in process of importing the Kurumi model back in ( had to remake the project so she wasn't in it anymore, Morph creation takes its time... and I have to head to work in 7 minutes ).
However I did use @vmJoe 's translation script and it worked ( After I worked in PmxEditor translating all bones and morphs ), however it seems it doesn't handle morphs ( previous time I imported morphs they were all japanese still ).

I am not quite sure how you think of making the MMD to UE4 but I'd really love it, it would make it really easy to get more awesome MMD's into our projects :D

@Hogarth-MMD You should be able to create and edit vertex morphs, it's working for me. To create a vertex morph you need to click the plus button that is on the right of the Morphs list, then a dialog should show up asking you for a Morph name (which will be the name of the corresponding ShapeKey that will be created), English name and category. To edit a vertex morph just select it on the list, and you can edit it's properties there, be careful however because changing the name of the morph doesn't properly update the corresponding ShapeKey name. I tried to deal with that issue, but however the API is limited and the update function doesn't give the old value. You can see the details here

@lordscales91 Do you mean that I can go into edit mode with a morph and drag vertices around to create a new shape key? I was not able to do that. And I got a KeyError error message when I tried to add a new morph. When I have time, I'll try to do some more tests with your morph tools panel and send you a proper bug report.

@ZetaHunter If you want someone to make a bone renaming script, you need to get the list of UE4 bones as text, not as image screen capture.

@lordscales91 I click on '+' to add a vertex morph. A popup dialog appears. I click on 'OK' and I get this error message. If the name of the imported model is 'AB5', it says key "AB5_mesh" not found. ( I tested this with 2 different models with the same error, so it does not seem to be specific to a particular model.):

Traceback (most recent call last):
File "C:\Program Files\Blender Foundation\Blender\2.74\scrip
s\operators\morph.py", line 116, in execute
if bpy.data.meshes[obj.name].shape_keys is None:
KeyError: 'bpy_prop_collection[key]: key "AB5_mesh" not found'

@ZetaHunter @vmJoe
If you can get a UE4 character model into Blender which has all the correct, standard UE4 bone names, and then upload the .blend file, I can extract a list of the UE4 bone names from the .blend file.

@Hogarth-MMD You have not installed the add-on correctly, you need to copy the whole mmd_tools directory to "C:\Program Files\Blender Foundation\Blender\2.74\scripts\addons". Also, it seems you are using an outdated version of the add-on, download the latest one and try again

@lordscales91 No, that's not it. I'm still getting the same error. Installed correctly and the latest version.

@Hogarth-MMD Oh! I found it, it's my fault, I assume that you will have selected the model mesh object, so if you have selected something else it fails, because it uses the active object's name to access the corresponding mesh data through the bpy.data but actually that's not necessary since I already have a reference to it. I could submit a quick fix but probably it will take so much time until @sugiany merges it (he is not much active right now, probably he is busy with something else), instead you are better selecting the mesh object before creating a vertex morph. I will submit that fix later along with other fixes and improvements. Also please, for new bugs open a new issue instead of commenting it on an existing issue (this is not a forum)

@ZetaHunter
In object mode, with the armature object selected to be the active object, enter this into the Blender python console:
bpy.context.active_object.data.bones.keys()

That one line of code is all you need and it will spit out a list of all names of bones of the active armature. :-)

How to rename ?

How to rename ?

This repo is not currently maintained. The latest fork with active maintenance is https://github.com/UuuNyaa/blender_mmd_tools/tree/main
You should try that version.