Skip to main content
added 1642 characters in body
Source Link
batFINGER
  • 85.2k
  • 10
  • 114
  • 244

Using copy on both the object and the mesh brings along all data.

Alternatively, instead of copying a new mesh each time, copy the bmesh and write to a new mesh. Once again will have to deal with materials, using all faces left after delete operator, to check which materials are assigned to faces of a particular vertex group.

See Delete all materials that aren't assigned to a face?

If the material is data (mesh) linked, can append to the Mesh.materials collection instead of using the slot operators.

import bpy
from collections import defaultdict
import bmesh

context = bpy.context

ob = context.object
me = ob.data
vgs = ob.vertex_groups[:]
col = context.collection
rg = defaultdict(set)

for v in me.vertices:
    for g in v.groups:
        rg[vgs[g.group]].add(v.index)

bm = bmesh.new()
all_verts = set(range(len(me.vertices)))
bm.from_mesh(me)
for vg, verts in rg.items():
    if not verts:
        continue #  no empty vg mesh
    oc = ob.copy()
    oc.name = vg.name
    oc.data = bpy.data.meshes.new(vg.name)
    bmc = bm.copy()
    bmc.verts.ensure_lookup_table()
    bmesh.ops.delete(bmc,
        geom=list(bmc.verts[i] for i in (all_verts - verts)),
        context='VERTS',
        )
    bmc.to_mesh(oc.data)
    bmc.free()
    for g in oc.vertex_groups:
        if g.name != vg.name:
            oc.vertex_groups.remove(g)       
    col.objects.link(oc)

Using copy on both the object and the mesh brings along all data.

Alternatively, instead of copying a new mesh each time, copy the bmesh and write to a new mesh. Once again will have to deal with materials, using all faces left after delete operator, to check which materials are assigned to faces of a particular vertex group.

See Delete all materials that aren't assigned to a face?

If the material is data (mesh) linked, can append to the Mesh.materials collection instead of using the slot operators.

import bpy
from collections import defaultdict
import bmesh

context = bpy.context

ob = context.object
me = ob.data
vgs = ob.vertex_groups[:]
col = context.collection
rg = defaultdict(set)

for v in me.vertices:
    for g in v.groups:
        rg[vgs[g.group]].add(v.index)

bm = bmesh.new()
all_verts = set(range(len(me.vertices)))
bm.from_mesh(me)
for vg, verts in rg.items():
    if not verts:
        continue #  no empty vg mesh
    oc = ob.copy()
    oc.name = vg.name
    oc.data = bpy.data.meshes.new(vg.name)
    bmc = bm.copy()
    bmc.verts.ensure_lookup_table()
    bmesh.ops.delete(bmc,
        geom=list(bmc.verts[i] for i in (all_verts - verts)),
        context='VERTS',
        )
    bmc.to_mesh(oc.data)
    bmc.free()
    for g in oc.vertex_groups:
        if g.name != vg.name:
            oc.vertex_groups.remove(g)       
    col.objects.link(oc)
added 12 characters in body
Source Link
batFINGER
  • 85.2k
  • 10
  • 114
  • 244

Dupe n Delete

Similarly to another answer re materials and "normalizing" material slots (removing unused), can use a default dictionary with a list of the vertices of each vertex group, then remove others from from a dupe for each group.

Ultimately this would be better if could split using bmesh, but as of now cannot set a split target to another mesh or bmesh instance.

Note this will split based on vertex group. Vertices that are members of more than one group will be in each split off object. Vertices not assigned to any group will not be split off into new object.

import bpy
from collections import defaultdict
import bmesh

context = bpy.context

ob = context.object
me = ob.data
vgs = ob.vertex_groups[:]
col = context.collection
rg = defaultdict(set)

for v in me.vertices:
    for g in v.groups:
        rg[vgs[g.group]].add(v.index)

bm = bmesh.new()
all_verts = set(range(len(me.vertices)))

for vg, verts in rg.items():
    if not verts:
        continue #  no empty vg mesh
    oc = ob.copy()
    oc.name = vg.name
    me = oc.data = oc.data.copy()
    bm.from_mesh(me)
    bm.verts.ensure_lookup_table()
    bmesh.ops.delete(bm,
        geom=list(bm.verts[i] for i in (all_verts - verts)),
        context='VERTS',
        )
    bm.to_mesh(me)
    bm.clear()
    for g in oc.vertex_groups:
        if g.name != vg.name:
            oc.vertex_groups.remove(g)       
    col.objects.link(oc)

Note I haven't bothered to remove materials, as mentioned this is similar to a previous script used in one of your answers, to test what materials are on a face and remove.

Dupe n Delete

Similarly to another answer re materials and "normalizing" material slots (removing unused), can use a default dictionary with a list of the vertices of each vertex group, then remove others from from a dupe for each group.

Ultimately this would be better if could split using bmesh, but as of now cannot set a split target to another mesh or bmesh instance.

Note this will split based on vertex group. Vertices that are members of more than one group will be in each split off object. Vertices not assigned to any group will not be split off into new object.

import bpy
from collections import defaultdict
import bmesh

context = bpy.context

ob = context.object
me = ob.data
vgs = ob.vertex_groups[:]
col = context.collection
rg = defaultdict(set)

for v in me.vertices:
    for g in v.groups:
        rg[vgs[g.group]].add(v.index)

bm = bmesh.new()
all_verts = set(range(len(me.vertices)))

for vg, verts in rg.items():
    oc = ob.copy()
    oc.name = vg.name
    me = oc.data = oc.data.copy()
    bm.from_mesh(me)
    bm.verts.ensure_lookup_table()
    bmesh.ops.delete(bm,
        geom=list(bm.verts[i] for i in (all_verts - verts)),
        context='VERTS',
        )
    bm.to_mesh(me)
    bm.clear()
    for g in oc.vertex_groups:
        if g.name != vg.name:
            oc.vertex_groups.remove(g)       
    col.objects.link(oc)

Note I haven't bothered to remove materials, as mentioned this is similar to a previous script used in one of your answers, to test what materials are on a face and remove.

Dupe n Delete

Similarly to another answer re materials and "normalizing" material slots (removing unused), can use a default dictionary with a list of the vertices of each vertex group, then remove others from from a dupe for each group.

Ultimately this would be better if could split using bmesh, but as of now cannot set a split target to another mesh or bmesh instance.

Note this will split based on vertex group. Vertices that are members of more than one group will be in each split off object. Vertices not assigned to any group will not be split off into new object.

import bpy
from collections import defaultdict
import bmesh

context = bpy.context

ob = context.object
me = ob.data
vgs = ob.vertex_groups[:]
col = context.collection
rg = defaultdict(set)

for v in me.vertices:
    for g in v.groups:
        rg[vgs[g.group]].add(v.index)

bm = bmesh.new()
all_verts = set(range(len(me.vertices)))

for vg, verts in rg.items():
    if not verts:
        continue #  no empty vg mesh
    oc = ob.copy()
    oc.name = vg.name
    me = oc.data = oc.data.copy()
    bm.from_mesh(me)
    bm.verts.ensure_lookup_table()
    bmesh.ops.delete(bm,
        geom=list(bm.verts[i] for i in (all_verts - verts)),
        context='VERTS',
        )
    bm.to_mesh(me)
    bm.clear()
    for g in oc.vertex_groups:
        if g.name != vg.name:
            oc.vertex_groups.remove(g)       
    col.objects.link(oc)

Note I haven't bothered to remove materials, as mentioned this is similar to a previous script used in one of your answers, to test what materials are on a face and remove.

added 12 characters in body
Source Link
batFINGER
  • 85.2k
  • 10
  • 114
  • 244

Dupe n Delete

Similarly to another answer re materials and "normalizing" material slots (removing unused), can use a default dictionary with a list of the vertices of each vertex group, then remove others from from a dupe for each group.

Ultimately this would be better if could split using bmesh, but as of now cannot set a split target to another mesh or bmesh instance.

Note this will split based on vertex group. Vertices that are members of amore than one group will be in each split off object. Vertices not assigned to any group will not be split off into new object.

import bpy
from collections import defaultdict
import bmesh

context = bpy.context

ob = context.object
me = ob.data
vgs = ob.vertex_groups[:]
col = context.collection
rg = defaultdict(set)

for v in me.vertices:
    for g in v.groups:
        rg[vgs[g.group]].add(v.index)

bm = bmesh.new()
all_verts = set(range(len(me.vertices)))

for vg, verts in rg.items():
    oc = ob.copy()
    oc.name = vg.name
    me = oc.data = oc.data.copy()
    bm.from_mesh(me)
    bm.verts.ensure_lookup_table()
    bmesh.ops.delete(bm,
        geom=list(bm.verts[i] for i in (all_verts - verts)),
        context='VERTS',
        )
    bm.to_mesh(me)
    bm.clear()
    for g in oc.vertex_groups:
        if g.name != vg.name:
            oc.vertex_groups.remove(g)       
    col.objects.link(oc)

Note I haven't bothered to remove materials, as mentioned this is similar to a previous script used in one of your answers, to test what materials are on a face and remove.

Dupe n Delete

Similarly to another answer re materials and "normalizing" material slots (removing unused), can use a default dictionary with a list of the vertices of each vertex group, then remove others from from a dupe for each group.

Ultimately this would be better if could split using bmesh, but as of now cannot set a split target to another mesh or bmesh instance.

Note this will split based on vertex group. Vertices that are members of a group will be in each split off object. Vertices not assigned to any group will not be split off into new object.

import bpy
from collections import defaultdict
import bmesh

context = bpy.context

ob = context.object
me = ob.data
vgs = ob.vertex_groups[:]
col = context.collection
rg = defaultdict(set)

for v in me.vertices:
    for g in v.groups:
        rg[vgs[g.group]].add(v.index)

bm = bmesh.new()
all_verts = set(range(len(me.vertices)))

for vg, verts in rg.items():
    oc = ob.copy()
    oc.name = vg.name
    me = oc.data = oc.data.copy()
    bm.from_mesh(me)
    bm.verts.ensure_lookup_table()
    bmesh.ops.delete(bm,
        geom=list(bm.verts[i] for i in (all_verts - verts)),
        context='VERTS',
        )
    bm.to_mesh(me)
    bm.clear()
    for g in oc.vertex_groups:
        if g.name != vg.name:
            oc.vertex_groups.remove(g)       
    col.objects.link(oc)

Note I haven't bothered to remove materials, as mentioned this is similar to a previous script used in one of your answers, to test what materials are on a face and remove.

Dupe n Delete

Similarly to another answer re materials and "normalizing" material slots (removing unused), can use a default dictionary with a list of the vertices of each vertex group, then remove others from from a dupe for each group.

Ultimately this would be better if could split using bmesh, but as of now cannot set a split target to another mesh or bmesh instance.

Note this will split based on vertex group. Vertices that are members of more than one group will be in each split off object. Vertices not assigned to any group will not be split off into new object.

import bpy
from collections import defaultdict
import bmesh

context = bpy.context

ob = context.object
me = ob.data
vgs = ob.vertex_groups[:]
col = context.collection
rg = defaultdict(set)

for v in me.vertices:
    for g in v.groups:
        rg[vgs[g.group]].add(v.index)

bm = bmesh.new()
all_verts = set(range(len(me.vertices)))

for vg, verts in rg.items():
    oc = ob.copy()
    oc.name = vg.name
    me = oc.data = oc.data.copy()
    bm.from_mesh(me)
    bm.verts.ensure_lookup_table()
    bmesh.ops.delete(bm,
        geom=list(bm.verts[i] for i in (all_verts - verts)),
        context='VERTS',
        )
    bm.to_mesh(me)
    bm.clear()
    for g in oc.vertex_groups:
        if g.name != vg.name:
            oc.vertex_groups.remove(g)       
    col.objects.link(oc)

Note I haven't bothered to remove materials, as mentioned this is similar to a previous script used in one of your answers, to test what materials are on a face and remove.

deleted 118 characters in body
Source Link
batFINGER
  • 85.2k
  • 10
  • 114
  • 244
Loading
Source Link
batFINGER
  • 85.2k
  • 10
  • 114
  • 244
Loading