Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keep original bone structure. #29

Closed
MediaMoots opened this issue Aug 21, 2021 · 42 comments
Closed

Keep original bone structure. #29

MediaMoots opened this issue Aug 21, 2021 · 42 comments

Comments

@MediaMoots
Copy link
Collaborator

As you may have noticed, the current workflow (PMX and CATS) completely nukes the original bone structure, making retargeting animations taken from Koikatsu very time consuming.

One workflow I used was to, use the PMX model, not fix the bones through CATS and manually delete all the extra bones (while comparing the bone structure to GME's fbx export)

This works well but takes an awfully long time.

Since GMEs armature has issues with scale, we also can't use the exported fbx.

Any ideas?
Thanks.

@FlailingFog
Copy link
Owner

FlailingFog commented Aug 21, 2021

Looking back, I kind of forgot what is gained by using CATS to fix the model... I've always it used as part of the process because it nicely connects the main bones together but like you said, using it at all wrecks the bone structure. The plugin code expects the bone changes CATS makes, so currently you're forced to use CATS if you want to use the plugin.

It'd probably be easy to copy their code to do just the bone connections, and if that were done then I think CATS could be dropped and the armature could be preserved to match the one in koikatsu. Though, now that this plugin advertises CATS export compatibility + Unity compatibility, I'd have to check what exactly CATS does so nothing is broken by not using it.

(Also, I'm looking into using the fbx files now, even with the scaling issues. I was originally going to make the fbx files match the pmx files then send it through CATS, but maybe this could be a good opportunity to move away from CATS instead...)

@MediaMoots
Copy link
Collaborator Author

It'd probably be easy to copy their code to do just the bone connections, and if that were done then I think CATS could be dropped and the armature could be preserved to match the one in koikatsu. Though, now that this plugin advertises CATS export compatibility + Unity compatibility, I'd have to check what exactly CATS does so nothing is broken by not using it.

What sort of bone connection/correction does it (CATS) do?

One idea I had for a scripted workflow is this:

  1. Import the PMX model
  2. Import and get a list of bones from GME's FBX
  3. Rename some bones manually (scripted) in the PMX model to match GME (Such as 上半身 -> cf_j_spine01)
  4. Get the list from earlier and iterate through PMX's bones, deleting the ones not in the list.
  5. Profit (I think, haha)

This workflow would remove the need for CATS aside from importing and exporting (which works flawlessly with the workflow from my original comment).

Is there anything else that CATS is necessary for?
image
Even disabling all the options here, renames all bones and structure.

@MediaMoots
Copy link
Collaborator Author

More info.

GME root bone vs KK animation root bone

GME:
image

KK:
image

Note the extra BodyTop bone and the different naming of the p_cf_body_bone

@MediaMoots
Copy link
Collaborator Author

MediaMoots commented Aug 22, 2021

Conversion list.
(It should all be correct, if not please let me know)

Source:

全ての親
センター
上半身
上半身2
左AH1
左AH2
右AH1
右AH2
左肩
左腕
左ひじ
左手首
左人指1
左人指2
左人指3
左小指1
左小指2
左小指3
左中指1
左中指2
左中指3
左薬指1
左薬指2
左薬指3
左親指0
左親指1
左親指2
右肩
右腕
右ひじ
右手首
右人指1
右人指2
右人指3
右小指1
右小指2
右小指3
右中指1
右中指2
右中指3
右薬指1
右薬指2
右薬指3
右親指0
右親指1
右親指2
首
頭
両目x
_dummy_左目x
_dummy_右目x
左目x
右目x
_shadow_左目x
_shadow_右目x
胸親
左胸操作
右胸操作
下半身
左足
左ひざ
左足首
左つま先
右足
右ひざ
右足首
右つま先
左足IK
左つま先IK
右足IK
右つま先IK

Converted:

X
X
cf_j_spine01
cf_j_spine02
cf_j_bust02_L
X
cf_j_bust02_R
X
cf_d_shoulder02_L
cf_j_arm00_L
cf_j_forearm01_L
cf_j_hand_L
cf_j_index01_L
cf_j_index02_L
cf_j_index03_L
cf_j_little01_L
cf_j_little02_L
cf_j_little03_L
cf_j_middle01_L
cf_j_middle02_L
cf_j_middle03_L
cf_j_ring01_L
cf_j_ring02_L
cf_j_ring03_L
cf_j_thumb01_L
cf_j_thumb02_L
cf_j_thumb03_L
cf_d_shoulder02_R
cf_j_arm00_R
cf_j_forearm01_R
cf_j_hand_R
cf_j_index01_R
cf_j_index02_R
cf_j_index03_R
cf_j_little01_R
cf_j_little02_R
cf_j_little03_R
cf_j_middle01_R
cf_j_middle02_R
cf_j_middle03_R
cf_j_ring01_R
cf_j_ring02_R
cf_j_ring03_R
cf_j_thumb01_R
cf_j_thumb02_R
cf_j_thumb03_R
cf_j_neck
cf_j_head
X
X
X
cf_J_hitomi_tx_L
cf_J_hitomi_tx_R
X
X
X
X
X
cf_j_waist01
cf_j_thigh00_L
cf_j_leg01_L
cf_j_foot_L
X
cf_j_thigh00_R
cf_j_leg01_R
cf_j_foot_R
X
X
X
X
X

A useful tool https://wtools.io/convert-list-to-json-array
(X means: Can be removed)

Both of the cf_j_foot_(L/R) bones need to be reparented to cf_j_leg03_(L/R)

@MediaMoots
Copy link
Collaborator Author

Here's a script that does all the above.

All you need to do is:

  1. Import the PMX model through CATS with the following settings
    image

  2. Import the FBX model from GME

  3. Run the script

  4. Profit

import re
import bpy
import fnmatch

pmx = bpy.data.objects['Model_arm']
gme = bpy.data.objects['Armature']

pmxCJKBoneNames = ["全ての親","センター","上半身","上半身2","左AH1","左AH2","右AH1","右AH2","左肩","左腕","左ひじ","左手首","左人指1","左人指2","左人指3","左小指1","左小指2","左小指3","左中指1","左中指2","左中指3","左薬指1","左薬指2","左薬指3","左親指0","左親指1","左親指2","右肩","右腕","右ひじ","右手首","右人指1","右人指2","右人指3","右小指1","右小指2","右小指3","右中指1","右中指2","右中指3","右薬指1","右薬指2","右薬指3","右親指0","右親指1","右親指2","首","頭","両目x","_dummy_左目x","_dummy_右目x","左目x","右目x","_shadow_左目x","_shadow_右目x","胸親","左胸操作","右胸操作","下半身","左足","左ひざ","左足首","左つま先","右足","右ひざ","右足首","右つま先","左足IK","左つま先IK","右足IK","右つま先IK"]
gmeCJKBoneNames = ["X","X","cf_j_spine01","cf_j_spine02","cf_j_bust02_L","X","cf_j_bust02_R","X","cf_d_shoulder02_L","cf_j_arm00_L","cf_j_forearm01_L","cf_j_hand_L","cf_j_index01_L","cf_j_index02_L","cf_j_index03_L","cf_j_little01_L","cf_j_little02_L","cf_j_little03_L","cf_j_middle01_L","cf_j_middle02_L","cf_j_middle03_L","cf_j_ring01_L","cf_j_ring02_L","cf_j_ring03_L","cf_j_thumb01_L","cf_j_thumb02_L","cf_j_thumb03_L","cf_d_shoulder02_R","cf_j_arm00_R","cf_j_forearm01_R","cf_j_hand_R","cf_j_index01_R","cf_j_index02_R","cf_j_index03_R","cf_j_little01_R","cf_j_little02_R","cf_j_little03_R","cf_j_middle01_R","cf_j_middle02_R","cf_j_middle03_R","cf_j_ring01_R","cf_j_ring02_R","cf_j_ring03_R","cf_j_thumb01_R","cf_j_thumb02_R","cf_j_thumb03_R","cf_j_neck","cf_j_head","X","X","X","cf_J_hitomi_tx_L","cf_J_hitomi_tx_R","X","X","X","X","X","cf_j_waist01","cf_j_thigh00_L","cf_j_leg01_L","cf_j_foot_L","X","cf_j_thigh00_R","cf_j_leg01_R","cf_j_foot_R","X","X","X","X","X"]

gmeBoneList = []

# Rename the root bone from p_cf_body_bone to p_cf_body_00
fixModelForKK = True

# First remove all constraints from PMX
for poseBone in pmx.pose.bones:
    for c in poseBone.constraints:
        poseBone.constraints.remove(c)
   
# Then rename PMX bones
for pmxBone in pmx.data.bones:
    if pmxBone.name in pmxCJKBoneNames:
        for idx, pmxBoneName in enumerate(pmxCJKBoneNames):
            if fnmatch.fnmatchcase(pmxBone.name, pmxBoneName):
                if not gmeCJKBoneNames[idx] == 'X':
                    pmxBone.name = gmeCJKBoneNames[idx]
                    break
                
# Prepare a list of bones from GME
for bone in gme.data.bones:
    gmeBoneList.append(bone.name)

# Ensure PMX is selected then enable Edit Mode
pmx.select = True
bpy.ops.object.mode_set(mode='EDIT')

# Remove bones that GME doesn't have from PMX
for editBone in pmx.data.edit_bones:
    if not editBone.name in gmeBoneList:
        pmx.data.edit_bones.remove(editBone)

# Reparent feet bones
pmx.data.edit_bones['cf_j_foot_L'].parent = pmx.data.edit_bones['cf_j_leg03_L']
pmx.data.edit_bones['cf_j_foot_R'].parent = pmx.data.edit_bones['cf_j_leg03_R']

# Renames the root bone to be compatible with KK animations
if fixModelForKK:
    pmx.data.bones['p_cf_body_bone'].name = 'p_cf_body_00'
    pmx.data.edit_bones.remove(pmx.data.edit_bones['BodyTop'])

# Disable Edit Mode for PMX
bpy.ops.object.mode_set(mode='OBJECT')

@FlailingFog
Copy link
Owner

Thanks for this info! I took a slightly different route: https://github.com/FlailingFog/KK-Blender-Shader-Pack/blob/V5-merger/importing/finalizepmx.py
If you import the pmx file using the "Import Model" button in CATS (not the hamburger menu) then run this script, it'll...

  • Rename the bones to match the fbx armature
  • Rotate the finger bones to match the fbx file
  • Reset the leg / foot bone orientation to match the fbx file
  • Set the bone roll to match a dump from a reference fbx file (the animations didn't seem to work until I did this)
    • The finger rolls still need corrections
  • Rename the bones a second time to match the output of CATS's fix model button
  • Set the bone order to be cf_n_height > cf_j_hips (skipped the other bones since they don't seem to contain animation data)
  • Reparents the foot
  • Delete some of the useless bones. You can't delete all of the bones because some accessories have pmx armature bones that don't appear on the fbx armature (these are the accessories that have the scaling issue).

Then I imported the fbx animation, selected the pmx armature, then shift selected the fbx animation armature and ran this: https://github.com/FlailingFog/KK-Blender-Shader-Pack/blob/V5-merger/extras/importanimation.py
This one...

  • Renames the bones in the fbx animation armature to match the names of the CATS output
  • Makes the bone order edits to match the edits in the previous script
  • Copies the animation from the active object (animation armature) to the selected object (pmx armature)

I forgot I make additional armature edits during the bonedrivers.py script, so that's another thing that could break this

What sort of bone connection/correction does it (CATS) do?

It visually connects bones together like fingers and skirt bones. And turns out it's accessible through an ops command: bpy.ops.cats_manual.connect_bones()
Unfortunately it breaks something with the animations, so I left it out.

@MediaMoots
Copy link
Collaborator Author

MediaMoots commented Aug 23, 2021

Quite good, there may be one issue with the above workflow though.

How would it deal with many animations?

With the workflow I posted, you could retarget quickly using the rokoko plugin or even in engine (Unity/UE4) since all the names would match, thus removing the need to process KK animations in blender.
This is a big time saver, because there are hundreds of animations that can be exported from KK.

Rename the bones a second time to match the output of CATS's fix model button
I guess this keeps compatibility?

Set the bone order to be cf_n_height > cf_j_hips (skipped the other bones since they don't seem to contain animation data)
Simply curious, why does this need to be done, is it somehow separated, all my models have them connected correctly (PMX/GME)
Original PMX bones:
image

Delete some of the useless bones. You can't delete all of the bones because some accessories have pmx armature bones that don't appear on the fbx armature (these are the accessories that have the scaling issue).
Good catch, which bones are they?

@MediaMoots
Copy link
Collaborator Author

MediaMoots commented Aug 23, 2021

Here's V2 of my script.

Now it should keep all accessory bones that are in use, and instead of directly deleting the bones, it selects them and then you manually use CATS to merge them to parents.

import re
import bpy
import fnmatch

############################################################### CONFIG


# Rename the root bone from p_cf_body_bone to p_cf_body_00 and deletes extra roots
# NOTE: WIP, only enable this if you have merged the bones already.
fixModelForKK = False


############################################################### PRIVATE


pmx = bpy.data.objects['Model_arm']
pmxBody = bpy.data.objects['Model_mesh']
gme = bpy.data.objects['ArmatureGMESchool']

pmxCJKBoneNames = ["全ての親","センター","上半身","上半身2","左AH1","左AH2","右AH1","右AH2","左肩","左腕","左ひじ","左手首","左人指1","左人指2","左人指3","左小指1","左小指2","左小指3","左中指1","左中指2","左中指3","左薬指1","左薬指2","左薬指3","左親指0","左親指1","左親指2","右肩","右腕","右ひじ","右手首","右人指1","右人指2","右人指3","右小指1","右小指2","右小指3","右中指1","右中指2","右中指3","右薬指1","右薬指2","右薬指3","右親指0","右親指1","右親指2","首","頭","両目x","_dummy_左目x","_dummy_右目x","左目x","右目x","_shadow_左目x","_shadow_右目x","胸親","左胸操作","右胸操作","下半身","左足","左ひざ","左足首","左つま先","右足","右ひざ","右足首","右つま先","左足IK","左つま先IK","右足IK","右つま先IK"]
gmeCJKBoneNames = ["X","X","cf_j_spine01","cf_j_spine02","cf_j_bust02_L","X","cf_j_bust02_R","X","cf_d_shoulder02_L","cf_j_arm00_L","cf_j_forearm01_L","cf_j_hand_L","cf_j_index01_L","cf_j_index02_L","cf_j_index03_L","cf_j_little01_L","cf_j_little02_L","cf_j_little03_L","cf_j_middle01_L","cf_j_middle02_L","cf_j_middle03_L","cf_j_ring01_L","cf_j_ring02_L","cf_j_ring03_L","cf_j_thumb01_L","cf_j_thumb02_L","cf_j_thumb03_L","cf_d_shoulder02_R","cf_j_arm00_R","cf_j_forearm01_R","cf_j_hand_R","cf_j_index01_R","cf_j_index02_R","cf_j_index03_R","cf_j_little01_R","cf_j_little02_R","cf_j_little03_R","cf_j_middle01_R","cf_j_middle02_R","cf_j_middle03_R","cf_j_ring01_R","cf_j_ring02_R","cf_j_ring03_R","cf_j_thumb01_R","cf_j_thumb02_R","cf_j_thumb03_R","cf_j_neck","cf_j_head","X","X","X","cf_J_hitomi_tx_L","cf_J_hitomi_tx_R","X","X","X","X","X","cf_j_waist01","cf_j_thigh00_L","cf_j_leg01_L","cf_j_foot_L","X","cf_j_thigh00_R","cf_j_leg01_R","cf_j_foot_R","X","X","X","X","X"]



############################################################### RENAME & CLEAN


# Rename PMX bones
for pmxBone in pmx.data.bones:
    if pmxBone.name in pmxCJKBoneNames:
        for idx, pmxBoneName in enumerate(pmxCJKBoneNames):
            if fnmatch.fnmatchcase(pmxBone.name, pmxBoneName):
                if not gmeCJKBoneNames[idx] == 'X':
                    pmxBone.name = gmeCJKBoneNames[idx]
                    break

# Remove all constraints from PMX
for poseBone in pmx.pose.bones:
    for c in poseBone.constraints:
        poseBone.constraints.remove(c)


############################################################### DATA COLLECTION


### Function to check for empty vertex groups
def survey(obj):
    maxWeight = {}
    for i in obj.vertex_groups:
        maxWeight[i.index] = 0

    for v in obj.data.vertices:
        for g in v.groups:
            gn = g.group
            w = obj.vertex_groups[g.group].weight(v.index)
            if (maxWeight.get(gn) is None or w>maxWeight[gn]):
                maxWeight[gn] = w
    return maxWeight

# Find empty vertex groups
vertexWeightMap = survey(pmxBody)
vertexIndexes = []
vertexIndexes.extend(vertexWeightMap.keys())
vertexIndexes.sort(key=lambda gn: -gn)

# Prepare a list of vertex group names
vertexGroupNames = []
for vg in pmxBody.vertex_groups:
    vertexGroupNames.append(vg.name)
    

# Prepare a list of bones from GME
gmeBoneList = []
for bone in gme.data.bones:
    gmeBoneList.append(bone.name)


############################################################### SELECT BONES


# Ensure that only the PMX is selected then enable Edit Mode
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.select_all(action='DESELECT')
pmx.select = True
bpy.ops.object.mode_set(mode='EDIT')



# First, delete the bones that are not in vertex groups (For some reason CATS does not remove them when merging weights)
for editBone in pmx.data.edit_bones:
    if not editBone.name in vertexGroupNames:
        pmx.data.edit_bones.remove(editBone)

# Then, select the bones that have empty vertex groups and are not in GME
for idx in vertexIndexes:  
    vg = pmxBody.vertex_groups[idx]
    if vertexWeightMap[idx]<=0 and vg.name not in gmeBoneList:
        print(vg.name)
        pmx.data.edit_bones[vg.name].select = True

##### Finally, manually use CATS to merge weights to parents


############################################################### FINAL CLEANUP


# Reparent feet bones
pmx.data.edit_bones['cf_j_foot_L'].parent = pmx.data.edit_bones['cf_j_leg03_L']
pmx.data.edit_bones['cf_j_foot_R'].parent = pmx.data.edit_bones['cf_j_leg03_R']

# Changes the root bone to be compatible with KK animations (Needs to be run after CATS)
if fixModelForKK:
    pmx.data.bones['p_cf_body_bone'].name = 'p_cf_body_00'
    pmx.data.edit_bones.remove(pmx.data.edit_bones['BodyTop'])
    pmx.data.edit_bones.remove(pmx.data.edit_bones['全ての親'])

@FlailingFog
Copy link
Owner

FlailingFog commented Aug 25, 2021

Here's V2 of my script.

That could work!

I guess this keeps compatibility?

I have no idea. I just assumed CATS renames the bones so they can be automatically detected in Unity. I haven't tried importing the model without the renamed bones to see what it does. I also think bone names like 'Hips' rather than 'cf_j_hips' are easier to identify

Simply curious, why does this need to be done

They're connected correctly on mine too, and it doesn't need to be done. I just think it makes for a slightly cleaner armature, even if it deviates from the KK armature structure (one center bone instead of multiple).

Good catch, which bones are they?

The ca_slot bones

With the workflow I posted, you could retarget quickly using the rokoko plugin or even in engine (Unity/UE4) since all the names would match, thus removing the need to process KK animations in blender.

Interesting! I didn't know that was possible. Though, I want a specific setup for use inside of blender and the animations would still need to be edited with that specific setup. I want a way to add IKs to the arms to use for non-premade animations and the only way I've found to do it is to connect the tail of the arm bone to the head of the hand bone. This reorients the bone, so the animations for those bones have to be reoriented as well. I guess I consider this another reason to not worry about changing the armature structure, since this setup would require code to get the animations to work anyway.
I was able to reorient the animations in line 105 of the script from earlier to make the fbx animations compatible with this change. Not sure how the rokoko plugin handles the reoriented bone issue, but if it does it automagically then that might be easier.

Another thought: What if there were two configurations you could choose from?

  • One for the original armature that kept the original bone names/structure and didn't have IKs, but was fully compatible with the fbx animations inside and outside of blender
  • One with the slightly modified armature that did have IKs and friendlier bone names, but you'd have to run the piece of code to use fbx animations inside of blender, and could run another piece of code to swap back to the original armature at any time and regain that compatibility

@MediaMoots
Copy link
Collaborator Author

What if there were two configurations you could choose from?

That would be perfect, haha

@FlailingFog
Copy link
Owner

Okay, will do then

@MediaMoots
Copy link
Collaborator Author

image

@MediaMoots
Copy link
Collaborator Author

MediaMoots commented Sep 2, 2021

So, made a script to batch retarget all Armature animations (using the Rokoko addon) in the Source collection to the Armature in the Target collection.
I'm not sure if this fits in this addon, but just wanted to share.

import bpy

targetCollection = bpy.data.collections['Target']
targetArmature = targetCollection.objects['Armature']

sourceCollection = bpy.data.collections['Source']
sourceArmatures = sourceCollection.objects

for src in sourceArmatures:
    try:
        if src.type == 'ARMATURE':
            bpy.data.scenes["Scene"].rsl_retargeting_armature_target = targetArmature
            bpy.data.scenes["Scene"].rsl_retargeting_armature_source = src
            bpy.ops.rsl.build_bone_list()
            bpy.ops.rsl.retarget_animation()
    except:
        print('Error')
        pass

@FlailingFog
Copy link
Owner

I don't see why it couldn't be added. I can put it in as a toggle.

@FlailingFog
Copy link
Owner

Most of this is in the latest commit, so you can try it if you want.

  • Use the big import button in CATS to import the pmx file
  • open the KKBP sidebar
  • expand the Import options (fbx and pmx) panel
  • Uncheck the "Use modified armature" toggle
  • click 1a) FInalize pmx button
  • expand the Extras panel
  • click the Import ripped fbx button and choose the ripped fbx file (make sure it's the cf_body_00 type or the "center" bone won't move)

I haven't installed the rokoko plugin yet so I don't know if the toggle works

Haven't put in the "survey" code for removing the useless pmx bones yet, right now it just removes the k_f_ bones and the cf_hit bones that the pmx armature comes with. There's a dictionary with the fbx bone names in finalizepmx.py so I think I'm going to use that instead of importing the fbx armature to generate the bone list.

If you load another animation in it'll overwrite the current one
Switching armature types (stock vs modified) after loading an animation currently breaks the animation

You can switch between the two armature types, but going from modified to stock will just mute the IK/joint drivers and stow the extra (modified) bones created during bonedrivers.py under the pv_root_bone. Do those extra bones matter when retargeting animations with other software (rokoko/unity/unreal)? If it doesn't, then I'll probably keep that behaviour because it makes it easier to switch

@MediaMoots
Copy link
Collaborator Author

click the Import ripped fbx button and choose the ripped fbx file (make sure it's the cf_body_00 type or the "center" bone won't move)

GME's fbx?

If you load another animation in it'll overwrite the current one

Hmm, I'm not sure using KKBP to import animations is really that useful (For me anyway, since I need to convert many animations)
All KKBP needs to do (imo) is to preserve the stock skeleton perfectly so that it can be retargeted easily.

What do you think?

@FlailingFog
Copy link
Owner

GME's fbx?

The ripped fbx animations from \Koikatsu\abdata\action\animator\

All KKBP needs to do (imo) is to preserve the stock skeleton perfectly so that it can be retargeted easily.

That's fair, and if you uncheck the modify armature toggle then it'll preserve everything.
I just made it such that the Import fbx button will import the fbx animation file (without processing it) and send it through the rokoko code you put above, but maybe I misunderstood the usage.

@MediaMoots MediaMoots changed the title Support easy animation retargeting. Keep original bone structure. Sep 13, 2021
@MediaMoots
Copy link
Collaborator Author

I think the way it works now is good.

If you had included the "survey" code to remove unused bones, the naming scheme of separate characters (after export) would be different.

As it is now (I think, needs testing) every character that goes through KKBP will have the same bone structure, and that, I feel, is a good thing, because it makes creating multiple characters in Unity/UE4 easier, e.g. no need to code for separate skeletons.

@MediaMoots
Copy link
Collaborator Author

MediaMoots commented Sep 15, 2021

On an unrelated note, would you know how to solve this sort of issue?
image
The hair not being in the right place.
This is the card:
Koikatu_F_20210824140538769_Tempest_Rimiru_ROHss

Thanks.

@FlailingFog
Copy link
Owner

I think the way it works now is good.

Okay I'll leave it as is then. If needed later it can be added as a toggle

@MediaMoots
Copy link
Collaborator Author

MediaMoots commented Oct 2, 2021

These bones are different from the KK base skeleton.

image

image

@MediaMoots
Copy link
Collaborator Author

MediaMoots commented Oct 2, 2021

If you want, I could make the new KKBP_Exporter plugin not add these extra bones and change bone names.
So, no more Japanese bone names/extra bones (AH, etc...) in the pmx.
Would that be helpful?

@MediaMoots
Copy link
Collaborator Author

All right, I made changes to the plugin, now it exports the rig 1 to 1 (no extra physics/ik/renamed bones)
Feel free to test it.
If you end up using it then I'll include the plugin (With the bone export edit) in PR #43

KKBP_Exporter_dev.zip

@MediaMoots
Copy link
Collaborator Author

MediaMoots commented Oct 2, 2021

Bug fix
KKBP_Exporter_dev.zip

@MediaMoots
Copy link
Collaborator Author

MediaMoots commented Oct 2, 2021

As it is now (I think, needs testing) every character that goes through KKBP will have the same bone structure, and that, I feel, is a good thing, because it makes creating multiple characters in Unity/UE4 easier, e.g. no need to code for separate skeletons.

After more testing, i found that this is incorrect.
There's no benefit in keeping the unused bones for retargeting in UE4.

So maybe it would be good to either use the survey code to delete unused bones during finalize pmx or have the survey/unused bones removal script as a button in the extras section.

Edit: it might still cause issues if we remove unused bones during finalize, I think having a button in Extras is better.

@FlailingFog
Copy link
Owner

Having the original bone structure would help, I'd just have to redo some parts during the finalize step.
The unused / intermediate bones are stored on armature layer 11, so if you select the bones on that layer and use the merge weights thing in CATS it should work the same.

@MediaMoots
Copy link
Collaborator Author

@FlailingFog
Ok so, after messing around with the skeleton, I found out that these bones are useful for IK
image

So would it be possible to keep them?
Thanks!

@MediaMoots
Copy link
Collaborator Author

MediaMoots commented Oct 11, 2021

Also found a bug with the hair select
image

It seems that subtracting 1 from the len causes the script to not select the last material in the list, thus giving this result:
image

Using this:
image

Produces the correct result:
image

@MediaMoots
Copy link
Collaborator Author

There is also an issue when NOT using Modified armature to Finalize PMX:

finalizepmx.py", line 665, in execute
    bpy.ops.object.select_all(action='DESELECT')
RuntimeError: Operator bpy.ops.object.select_all.poll() failed, context is incorrect

Changing that line to this solves the issue

for obj in bpy.context.selected_objects:
    obj.select_set(False)

But reintroduces the issue to bonedrivers.py Line 852

Also changing that line to this solves the issue

for obj in bpy.context.selected_objects:
    obj.select_set(False)

I'm not sure why this happens though.

@FlailingFog
Copy link
Owner

Thanks for finding these. The hit/kf bones are on armature layers 12 and 13 now

@MediaMoots
Copy link
Collaborator Author

Great thanks

i found a bug with this shape key
image

I think the teeth are supposed to be closed.

@FlailingFog
Copy link
Owner

It shouldn't do that anymore.

And semi-related to this, sometimes the original pmx exporter creates a model with broken tongue and lower teeth shapekeys (kuti_sita and kuti_ha). This bug carried over into your new version as well. It only happens on certain cards (like that megumin card from a while back) and I haven't noticed a trend for what causes it. Since you have the source, do you happen to know what could cause it to break only those shapekeys like that?

@MediaMoots
Copy link
Collaborator Author

It shouldn't do that anymore.

Thanks!

Since you have the source, do you happen to know what could cause it to break only those shapekeys like that?

Sure!
Here's a plugin changed to "hopefully" fix the issue, please try it.
I just removed part of the code that the original plugin used to manually modify shape keys, now it should have only the original keys from KK.

KKBP_Exporter.zip

If it works, please let me know and ill add it to the project.

@FlailingFog
Copy link
Owner

FlailingFog commented Oct 14, 2021

I just removed part of the code that the original plugin used to manually modify shape keys, now it should have only the original keys from KK.

Are the shapekey names supposed to change with this too? I'm still seeing the original ones (and seeing the same behavior too)

@MediaMoots
Copy link
Collaborator Author

MediaMoots commented Oct 17, 2021

Ah, pity, I'll investigate this issue more.
The megumin card has this issue right?

@FlailingFog
Copy link
Owner

Yeah it happens on that one. I've tracked it down to a specific accessory on the card that's causing the tongue shapekeys to become corrupted called "Tiny ahoge no movement".

I also had one more question for armature stuff, do you care if the accessory bone names are renamed in the original armature structure? Some characters have duplicate accessory bone names and that's causing the following issue:
When you have accessories that use the same bone and vertex group names, for example two separate hair pieces that use a dynamic bone name of "joint2", the bones will show as "joint2" and "joint2.001" when imported into blender. The vertex group for "joint2 will contain both the joint2 and joint2.001 bone weights and the joint2.001 vertex group will be empty. I'm assuming this happens during the pmx file import, and the importer screws up because it tries to import the same bone / vertex group names twice but instead just merges them. I'm thinking I could modify the finalizepmx.py script to fix this automatically but it would involve renaming the bones and vertex groups.

@MediaMoots
Copy link
Collaborator Author

Yeah it happens on that one. I've tracked it down to a specific accessory on the card that's causing the tongue shapekeys to become corrupted called "Tiny ahoge no movement".

Cool, thank you, I'll see if I can fix it in the dll plugin

I also had one more question for armature stuff, do you care if the accessory bone names are renamed in the original armature structure?

Yeah, I think as long as the base skeleton is unchanged the acc bones can be renamed.

@FlailingFog
Copy link
Owner

FlailingFog commented Nov 6, 2021

I've been trying to work the duplicate vertex group issue I noted above, and after looking into it a little further I think the KK pmx exporter is the one causing the vertex groups to merge, not Blender's pmx importer. When I take the pmx file into another program (PMXEditor) it's showing that the vertex groups are already merged.

I feel like this would resolve itself if the KKBP exporter didn't merge all the objects into one like it usually does, and instead kept everything in separate objects, similar to how Grey's mesh exporter does it. Is this an easy thing to do? I'm guessing the pmx exporter merges the meshes at some point, so would it be as simple as deleting that chunk of code?

I'll continue trying to get it to work with the code I have now, but so far the trick I'm using isn't completely cutting it for dense groups of accessories (like when people make hair completely out of accessories).

@MediaMoots
Copy link
Collaborator Author

Ok, yeah, I think I found a bug in the plugin, I'll try and fix it.

@MediaMoots
Copy link
Collaborator Author

image
: )

@MediaMoots
Copy link
Collaborator Author

image : )

PR #61

@MediaMoots
Copy link
Collaborator Author

V5 is great, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants