1
$\begingroup$

My overall goal is to copy the vertex groups from a mesh object to the new object created with that mesh as a bevel object. I have written some python code to help me accomplish this.

Here is a blend file that you can use to test out the code:

Here is how to follow along with my attempt to do this:

  1. Create a new bezier circle and change the resolution preview to 2. Convert this circle to a mesh and name it "profile"

enter image description here

  1. In Edit mode, add a subset of the vertices to vertex groups. Here I have created 2 vertex group, "inside" and "outside".

enter image description here enter image description here

  1. Return to Object mode

  2. Run the following python code:

import bpy

# find indices of inside and outside vertices on the profile
profile = bpy.data.objects["profile"]
vertices_by_group = {}
profile_vert_count = len(profile.data.vertices)
for v in profile.data.vertices:
    for g in v.groups:
        group_name = profile.vertex_groups[g.group].name
        if group_name not in vertices_by_group:
            vertices_by_group[group_name] = []
        vertices_by_group[group_name].append(v.index)

# create circle object that will be beveled with the profile.
bpy.context.view_layer.objects.active = profile
profile.select_set(True)
bpy.ops.object.convert(target='CURVE')
bpy.ops.curve.primitive_bezier_circle_add(radius=10)
ring = bpy.context.object
ring.name = 'ring'
ring.data.bevel_mode = 'OBJECT'
ring.data.bevel_object = profile
ring.data.resolution_u = 64

# convert to mesh object
bpy.ops.object.convert(target='MESH')

# create new vertex groups on the ring that match those on the profile
mesh_groups = {}
for group_name in vertices_by_group.keys():
    mesh_groups[group_name] = bpy.context.active_object.vertex_groups.new(name=group_name)

# Check if new vert index would have been part of original profile groups
for v in ring.data.vertices:
    for group_name, group in mesh_groups.items():
        if v.index % profile_vert_count in vertices_by_group[group_name]:
            group.add([v.index], 1.0, 'ADD')

Note how the vertex groups created on the beveled curve are off by one relative to the vertex groups in the profile object:

enter image description here

The code works by finding the index of the verts in each group on the profile object. It then converts that profile object to a curve, and uses it as a bevel object on a bezier circle. The beveled circle is then converted to a mesh. Then, every vertex on this new mesh is iterated over. If the vertex index modulo the profile vert count matches the index in the original vertex groups, then that vert is added to a group on the new object.

The general idea is that the verts in the new mesh created via beveling the profile will all be nicely ordered and the vert indexes will match up (modulo the original profile vert count). As you can see this almost works, its just that the vertexes are off by one.

If you edit the last line of code to be group.add([v.index-1], 1.0, 'ADD') then it does appear to work. However this feels somewhat fragile as I am relying on blender's vertex ordering to always follow some rules.

My questions are:

Are there hard and fast rules about the order of verts in objects created this way?

Is it possible to achieve my goal of copying the vertex groups from the profile to the final object in a robust manner?

$\endgroup$
9
  • $\begingroup$ vertex indices are assigned in the order of vertex creation, starting at 0. The tricky bit is what happens when you add a new vertex after you've deleted one or more old ones. $\endgroup$ Oct 29, 2021 at 14:50
  • $\begingroup$ Do you know why the order of vertex creation differs depending on whether the profile object was created as a curve or mesh initially? $\endgroup$
    – jminardi
    Oct 29, 2021 at 21:43
  • $\begingroup$ I don't think they do. When I run your code, it appears to give me the correct results. What specific problem should I look for in the ring? $\endgroup$ Oct 29, 2021 at 21:58
  • $\begingroup$ ah, I think I know the problem: the 'inside' and 'outside' vertex groups appear to be reversed on the torus to you. Is that correct? $\endgroup$ Oct 29, 2021 at 22:07
  • $\begingroup$ The code does work correctly for me if the profile starts out as a mesh circle. However if I create a bezier curve, convert that to a mesh and then set the vertex groups on that mesh the resulting ring object has vertex groups that are off by one. Is it possible for me to send you a blend file somehow? $\endgroup$
    – jminardi
    Oct 29, 2021 at 23:03

1 Answer 1

4
$\begingroup$

The default order of things.

Re first incarnation of question

The code does work correctly for me if the profile starts out as a mesh circle.

ie I read this as, starting with a mesh circle works as expected.

However, if the profile object is first created as a curve, and then converted to a mesh, this procedure does not work. The indices are all off by one.

Will explain a method to add a curve, but re-order as if a mesh was added.

Can investigate the vertex order by enabling the indices overlay

For an 8 vert mesh circle, vertex 0 is at 12 o'clock, subsequent vertices are wound counter-clockise. Viewing from top.

enter image description here

For a bezier circle, converted to an 8 vert mesh, vert 0 is at 9 o'clock and subsequent vertices are ordered clockwise.

enter image description here

Re-order the vert indicess.

How can I order the vertex index?

How can I sort vertex positions sequentially indices in a closed area?

Hence to re-sort the curve produced mesh to match the mesh

import bpy
import bmesh
from mathutils import Vector
from math import pi

ob = bpy.context.object
assert ob.type == "MESH"
me = ob.data

bm = bmesh.new()
bm.from_mesh(me)
up = Vector((0, -1))
verts = bm.verts[:]
verts.sort(key=lambda v: pi - up.angle_signed(v.co.xy))
verts.insert(0, verts.pop())

for i, v in enumerate(verts):
    v.index = i

bm.verts.sort()


bm.to_mesh(me)
me.update()

Note, quick hack, by means of example above using 2D vectors angle signed which ranges in $(-\pi, \pi)$ Probably a far more elegant way to sort.

Data Layers.

Another approach could be to assign a data layer to the verts,

Uniquely addressing vertices in python

Somehat related.

How to create a list containing lists of bm.verts based on their deform layer (vertex group)?

Face edges angle - python

$\endgroup$
1
  • $\begingroup$ Thanks for all the useful information. The vert index overlay option is helpful. However for my use case I don't particularly care what the vert indexes are or their order. What I am wondering about is the rules for vertex ordering on the mesh created from a beveled curve. Why do the verts nicely line up when the profile object is created as a mesh, but do not nicely line up when the profile object is created as a curve but then converted to a mesh? $\endgroup$
    – jminardi
    Nov 1, 2021 at 11:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.