0
$\begingroup$

I've created a humanoid model that I'm exporting as an FBX for use in Unity. The model is composed of many sub-meshes, because I want the model to "explode" in the game, and send the individual pieces flying. So, for example, I have individual "Hand", "LowerArm", "UpperArm", etc objects in my model. Currently each object has an unapplied Mirror modifier to keep the model symmetrical.

The issue is that when exporting this model as an FBX, the "Hands" object contains both the left and right hands as a single object, as opposed to being separate objects.

A very manual way to address this is to apply all of my Mirror modifiers, then manually separate the vertices on one half of the model to a new object. The obvious downside to that is that it's destructive, and I can't easily edit the model anymore after doing that.

I was hoping there might exist a "separation" modifier, which could intelligently separate a mesh into two pieces depending on whether the vertices are on one side of the model or another. That way, the modifier would be applied on export, but I wouldn't need to apply my Mirror modifiers in Blender.

So, in short: Is there a way to export an FBX of my model that separates my current "Hand" object into "LeftHand" and "RightHand", without having to manually apply the Mirror modifiers, and manually separate the vertices?

Thanks,

-Dan

$\endgroup$

1 Answer 1

4
$\begingroup$

I suggest you name your mesh with the suffix .l since it is the left side which is modelled (even if there is a subdivision modifier).

Here are some manual steps.

  1. Duplicate objects. ⇧ ShiftD
  2. With the duplicates selected, mirror them ⎈ CtrlM, X.
  3. Export as fbx but deselect apply modifiers.

Or use a short python script. (Paste this in Blender's text editor and click Run Script with the objects selected. The script will automatically remove the modifiers and create a duplicated mirror, even if the mirror axis isn't x.

If you're using a different naming scheme than .l/.r, change this line new_obj.name = re.sub(r'\.l\.\d\d\d', '.r', new_obj.name).

new_obj.name = re.sub('left', 'right', obj .name) would replace left with right. (You would name everything with the left prefix beforehand (e.g. "leftHand".)

import bpy
import mathutils


for obj in bpy.context.selected_objects:
    # Check if a mirror modifier exists.
    for mod in obj.modifiers:
        if mod.type != "MIRROR":
            continue

        mirror_name = obj.name.replace("Left", "Right")
        if mirror_name == obj.name:
            mirror_name = obj.name + "_mirrored"

        # Reference the mirrored object. Create it if it doesn't exist.
        mirror_obj = bpy.data.objects.get(mirror_name)
        if mirror_obj == None:
            mirror_obj = bpy.data.objects.new(mirror_name, obj.data.copy())
            mirror_obj.name = mirror_name
            bpy.context.scene.objects.link(mirror_obj)
        else:
            mirror_obj.data = obj.data.copy()

        axes = [mod.use_x, mod.use_y, mod.use_z]
        dir = [(1,0,0), (0,1,0), (0,0,1)]
        for axis, direction in zip(axes, dir):
            if axis:
                mirror_obj.data.transform(mathutils.Matrix.Scale(-1, 4, direction))
                mirror_obj.data.flip_normals()

        mod.show_render = mod.show_viewport = False
        break

To remove the duplicates created by the script and re-show the mirror modifier simply undo the actions of the script with a single undo step. ⎈ CtrlZ

For 2.8x, this script can be changed to:

import bpy
import re
import mathutils

scn = bpy.context.scene
objs = bpy.context.selected_objects


for obj in objs:
    new_obj = obj.copy ()
    new_obj.data = obj.data.copy ()
    if len(obj.users_collection):
        obj.users_collection[0].objects.link(new_obj)
    else:
        scn.collection.objects.link(new_obj)
    new_obj.name = re.sub(r'\.l\.\d\d\d', '.r', new_obj.name)

    for m, n in zip (new_obj.modifiers, obj.modifiers):
        if m.type == "MIRROR":
            axes = [m.use_axis[0], m.use_axis[1], m.use_axis[2]]
            dir = [(1,0,0), (0,1,0), (0,0,1)]
            for axis, direction in zip (axes, dir):
                if axis:
                    new_obj.data.transform (mathutils.Matrix.Scale (-1, 4, direction))
                    new_obj.data.flip_normals ()
            obj.modifiers.remove (n)
            new_obj.modifiers.remove (m)
  • scene.objects is change to collections system
  • mirror modifier used axis are now accessible as a vector
$\endgroup$
4
  • $\begingroup$ @lemon I am seeing some additional spaces at r'\.l\.\d\d\d'. Was that intential and/or does it have a benefit? $\endgroup$
    – Leander
    Commented Feb 29, 2020 at 10:21
  • $\begingroup$ Nothing, I previously took the code from blender.stackexchange.com/questions/168413/… and did not pay attention to these spaces $\endgroup$
    – lemon
    Commented Feb 29, 2020 at 10:26
  • $\begingroup$ Additionally, was wondering: shouldn't the code test if a mirror exists before duplicating? $\endgroup$
    – lemon
    Commented Feb 29, 2020 at 10:28
  • $\begingroup$ Probably, I have updated the 2.7 script. You could add some of those changes to the 2.8 version. However, the seemingly trivial task of adding the object the collection can introduce problems, when the object exists in bpy.data.objects but not in the current collection. $\endgroup$
    – Leander
    Commented Feb 29, 2020 at 10:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .