powroupi / blender_mmd_tools

mmd_tools is a blender addon for importing Models and Motions of MikuMikuDance.
GNU General Public License v3.0
1.82k stars 277 forks source link

A better way to approximate SDEF interpolation using blender armatures #162

Open Takuyax opened 6 years ago

Takuyax commented 6 years ago

Hi! This issue is mainly intended as a discussion that might lead to some enhancements in mmd tools, or to myself understanding how to do this manually.

My main usage scenario is to use MMD tools as an importer to render models directly in Blender. Models get imported, converted to quads, and I do a bunch of blender-specific manual adjustments (separate mesh objects, creases, lattice deformed spherical eyes, etc.)

To get nice pointy elbows and knees, I manually add a second armature modifier, set it to “Preserve Volume” (which activates quaternion interpolation) and “Multi Modifier”, then add a vertex group “volume”, which controls the influence of the quaternion armature modifier. I then pose the model and weight paint the “volume” vertex group until I get a nice shape.

This manual approach works great, however every time I see that a model has SDEF shape keys, I wonder if it wouldn’t be possible to convert this to something that blender could use, even if that would be a simplified approximation.

For starters, is there any good documentation about how the c, r0 and r1 coordinates work? I suppose c stands for center and r for radius, so it would seem like it’s possible to calculate some basic per-vertex volume data from these. Why are are two radiuses though?

nagadomi commented 6 years ago

suwatoh's pmx exporter for blender(exp_pmx-1.5.2.zip) supports automatically setting of SDEF parameters from the distribution of vertex positions and the bones position. It is licensed under NSYL (it is similar to CC0). The relevant lines of code: (recommend refer to the original code)

sdef_key = (bi1, bi2)
sdef_data = sdef_map.get(sdef_key)
if sdef_data is None:
    pos1 = bone_specs[bi2]["position"]
    pos2 = bone_specs[bi1]["position"]
    vec1 = (pos2 - pos1).normalized()
    vec2 = co - pos1
    dist_pos1_pi = vec1.dot(vec2)
    sdef_c = pos1 + (vec1 * dist_pos1_pi)
    sdef_map[sdef_key] = [[index], pos1, vec1, dist_pos1_pi, dist_pos1_pi]
else:                                                                      
    sdef_data[0].append(index)
    pos1 = sdef_data[1]
    vec1 = sdef_data[2]
    vec2 = co - pos1
    dist_pos1_pi = vec1.dot(vec2)
    sdef_c = pos1 + (vec1 * dist_pos1_pi)
    sdef_data[3] = max(sdef_data[3], dist_pos1_pi)
    sdef_data[4] = min(sdef_data[4], dist_pos1_pi)
vert_spec["deform"] = 3  # SDEF              
vert_spec["bone1"] = bi1
vert_spec["bone2"] = bi2
vert_spec["weight1"] = weight1 / weight_sum
vert_spec["weight2"] = sdef_c  # C           
vert_spec["weight3"] = ZERO_VECTOR  # R0     
vert_spec["weight4"] = ZERO_VECTOR  # R1     

R0, R1 will be recalculated later.

for sdef_data in sdef_map.values():                        
    for index in sdef_data[0]:
        vert_spec = vertices[index]
        if vert_spec["deform"] != 3:
            continue
        pos = sdef_data[1]
        nvec = sdef_data[2]
        vert_spec["weight3"] = pos + (nvec * sdef_data[3]) # R0
        vert_spec["weight4"] = pos + (nvec * sdef_data[4]) # R1
Takuyax commented 6 years ago

@nathanvasil Okay, I did some research about what the anchor editor actually does. The way I use it is probably a bit unusual, because I only use it to add SDEF to knees and elbows if models don't have it yet. So I shape the anchors to form a wedge that only affects the area I want to change. They cover almost exactly the same space. If there is space that only one of them covers, it turns everything in that non-overlapping space into BDEF1 weights. Here are some examples using Tsukuan's Wasabi model (https://bowlroll.net/file/153807) anchor_editor anchor_editor2 You can see that using a wedge shape in the anchor editor makes her knees pointier than using the BDEF to SDEF conversion. When you import the resulting pmx models into Blender, you can see that the BDEF to SDEF conversion sets C to the closest point on the bone line and R0+R1 to some other point on the bone line, while the anchor editor limits the C, R0, R1 positions to be inside wedge shape. Apparently this is the reason it produces more volume during deformation. Actually in the past I got weird results when trying to not include the bone joint within both anchor boxes. It probably couldn't place C, R0, R1 correctly. Here are some example anchor files for pmx editor: wasabi20171209_anchors.zip You can open the Wasabi model, press F10 to open the anchor editor and load the psk files from the file menu. The psk file format is extremely simple, but only seems to contain the vertex coordinates of the anchors, so there is probably nothing interesting to be found in them.

nathanvasil commented 6 years ago

Thanks @Takuyax, I'll check that out! Don't have a bowlroll account which I'd need to download that model, but maybe I'll register, or just try playing with anchors and see if I can figure it out (I like using simple test cases, cubes and such, to figure out how tools like that work.)

Hogarth-MMD commented 6 years ago

You can log into bowlroll.net with a twitter, facebook, or github account.