tl;dr: I just want to create some curve guides along those middle points of vertex groups but with a script.

I am new to Python in Blender and I can't seem to find how to do this.

So far, I managed to get X, Y and Z coordinates of each vertex, stored in arrays in a variable named like each vertex group. My goal would be to find the middle point, something like a bounding box for each vertex group.

I did find topics about matrix for bpy.types.MeshVertex but what I have is lists of vertices which do not seem to work with those examples.

Edit2:**Thanks for two different answers on how to do it, have a sub-question, if there is a way to create effectors like path, that **start from those points *(Have their starting point there), and I guess prefferably to get them to go outward away from these vertex group locations.


GL = {g.index: g.name for g in ob.vertex_groups}
verts = {name: [] for name in GL.values()}
vertsloc = {name: [] for name in GL.values()}
verts2 = {name: [] for name in GL.values()}

for v in ob.data.vertices:
 for g in v.groups:
  • $\begingroup$ Hello and welcome. It is probably easier to help you for anyone who knows if you post the code for what you already have. $\endgroup$ – Duarte Farrajota Ramos May 3 '19 at 17:01
  • $\begingroup$ Do you want to find a bounding box of every vertex group with the box center? Or the center point(location) you tried to find should consider the weight so it can be calculate by weighted average position? $\endgroup$ – HikariTW May 4 '19 at 12:34

Copy Location Constraint.

enter image description here

Can leverage the existing behaviour of the copy location constraint, targeted to a mesh, subtargeted to a vertex group.

Test script, run in object mode with mesh object selected. Will add an empty for each vertex group at the location of each vertex group.

import bpy

context = bpy.context

ob = context.object
me = ob.data

for name in ob.vertex_groups.keys():
    bpy.ops.object.empty_add(location=(0, 0, 0))
    mt = context.object
    mt.name = f"{ob.name}_{name}"
    cl = mt.constraints.new('COPY_LOCATION')
    cl.target = ob
    cl.subtarget = name

The bonus here is the empties will dynamically follow the vertex group as it deforms via modifiers. It involves no dicking around with vertices.

To go to any next step that requires the empties to be at the constrained locations throw in a scene update to ensure matrices etc are up to date.

For 2.7x


For 2.0x

dg = context.evaluated_depsgraph_get()

To set the locations statically for the frame the script is run on set the empties matrix world and remove the constraint

for mt in empties:
    mt.matrix_world = mt.matrix_world.copy()

or simply get the locations from the empties before removing them

for mt in empties:
    mt.matrix_world.translation # global location of emtpy
    # remove the mt

A quick note if going the route of finding vg verts and calculating bbox etc recommend defaultdict from the collections module. Can be given a type as default, list for example.

Eg add verts to a dictionary keyed by their vertex group name.

import bpy
from collections import defaultdict
context = bpy.context

vgs = defaultdict(list)
ob = context.object
me = ob.data
for v in me.vertices:
    for g in v.groups:

for name, vg in vgs.items():
    print(name, vg)
  • $\begingroup$ Marked this as 'solution' even though both answers are right, as this one is shorter-easier, I updated main post, have a sub-question, maybe could have made new thread not sure. $\endgroup$ – st mm May 4 '19 at 22:49

I will just assume that you're not gonna to consider weight averaging.

The following script show how you could get those coordinates and deal with them, with some comment for very beginner.

import bpy
import numpy as np

# This line select and get the active object from context

# Create a Python structure: dict(), with key = vertex_group.name
# and value = vertex_group.index
GL = {g.index: g.name for g in ob.vertex_groups}
verts = {name: [] for name in GL.values()}

for v in ob.data.vertices:
    for g in v.groups:
# All the location(co) and index can be found in "verts[name]" list by its attribute using '.'
# eg. verts[G_name][314].co == Vector((1,2,3)) #True
# The "verts" dict's list store the references list point to the data (which is object) they linked

vertex_group_info = {}
for key, value in verts.items():
    # Using numpy array for convenience
    temp = np.array([(v.co[0],v.co[1],v.co[2]) for v in value])
    max = np.max(temp,axis=0) #calculate the max
    min = np.min(temp,axis=0) #calculate the min
    # Average the cooridinates by add them and divide by number of vertices
    center = np.sum(temp, axis=0) / temp.shape[0]
    vertex_group_info[key] = {"max": max,
                               "min": min,
                               "center": center}

What is weighted version?

Let say we got 3 points assign to a group with 1.0, 0.02, 0.01 weight. You might want to calculate the weighted average, which is very closed to the 1st point since 2nd and 3rd show little to no influence to the group. The script above still treat these vertices as same weight if the weight value is not equal to 0 (not assigned).

In the weighted case, you will need to multiply the coordinates by the vertex weight and sum all these weighted coordinates. Than divided it by the sum of vertex weight.

  • $\begingroup$ Thanks for answering! Weighted version, would that be to locate position in a vertex group but towards where weight is higher? $\endgroup$ – st mm May 4 '19 at 22:19
  • $\begingroup$ @stmm Yes it is, I just edit my post. Since weight plays a major role in the vertex group. You will want to consider the weight in common situation. $\endgroup$ – HikariTW May 5 '19 at 2:47

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.