Blender: Scale a group of vertices using python I have a mesh made of 94 groups of 4 vertices:


I need to scale each group of vertices by a decreasing factor (from 100% to 0%).

I tried two different ways to do that, the first is based on the same function called when using the "scale command" via user interface:

bpy.ops.transform.resize(
value=(0.2, 0.2, 0.2), 
constraint_axis=(False, False, False), 
constraint_orientation='GLOBAL', 
mirror=False, 
proportional='DISABLED', 
proportional_edit_falloff='SMOOTH', 
proportional_size=1)


to begin, I tried to scale the first four vertices:

import bpy

obj = bpy.context.active_object
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action="DESELECT")

verts = obj.data.vertices
obj.data.vertices[0].select=True
obj.data.vertices[1].select=True
obj.data.vertices[2].select=True
obj.data.vertices[3].select=True


bpy.ops.transform.resize(
    value=(0.2, 0.2, 0.2), 
    constraint_axis=(False, False, False), 
    constraint_orientation='GLOBAL', 
    mirror=False, 
    proportional='DISABLED', 
    proportional_edit_falloff='SMOOTH', 
    proportional_size=1)


running the code in object mode with my mesh selected, just switches the enviroment to edit mode and nothing else, however if I manually select four vertices and run this script, it scales the four selected vertices correctly.
so.. why is obj.data.vertices[i].select=True completely useless? and how can I correctly select the vertices in order to get bpy.ops.transform.resize() correctly work on them?

I also tried to use bmesh library as it was recommended in most of the forums and guides I visited.

import bpy
import bmesh
import math
import mathutils

# Get the active mesh
obj = bpy.context.edit_object
me = obj.data


# Get a BMesh representation
bm = bmesh.from_edit_mesh(me)
face = bm.faces.active

vertices=[bm.verts[0],bm.verts[1],bm.verts[2],bm.verts[3]]

# Scale
scale = mathutils.Vector((0.2,0.2,0.2))
bmesh.ops.scale(
            bm,
            vec=scale,
            verts=vertices
            )

# Show the updates in the viewport
bmesh.update_edit_mesh(me, True)


this script actually does something: it scales the coordinates of the first four vertices. this means that for each vertex I pass to that function, its position is scaled respect to the origin of the scene ( the point (0,0,0) ).
But I want it to be scaled respect to the center of the four vertices, as it would be if I manually select the vertices and apply the bpy.ops.transform.resize() function.

So, in the first case, how can I tell to "Blender" to select vertices in order to apply the bpy.ops.transform.resize() function? 

And in the latter case, how can I make it to scale respect to the center of the four vertices instead of the center of the image?
I prefer a more low level solution. This particular approach requires the object to be in Object Mode, but a small change using Bmesh would let you do it in edit mode. This will give you some insight I hope.



import bpy
from mathutils import Vector

# replace this with reference to your object.
obj = bpy.data.objects['BezierCurve']

def get_average(vert_range):
    med = Vector()
    for vert in vert_range:
        vec = vert.co
        med = med + vec
    return med / len(vert_range)

verts = obj.data.vertices
num_verts = len(verts)
scale = 1 / (num_verts / 4)
j = 0
for i in range(0, num_verts, 4):
    mid = get_average(verts[i:i+4])
    for k in range(i, i+4):
        verts[k].co = verts[k].co.lerp(mid, 1-(j*scale))
    j += 1




For every 4 verts, it finds their average, and scales those verts towards that average by an increasing value every 4 verts. I may have reversed the direction so instead of 1-(j*scale) you might want (j*scale)



for completeness A Bmesh solution, this works in edit mode

import bpy
import bmesh
from mathutils import Vector

def get_average(vert_range):
    med = Vector()
    for vert in vert_range:
        vec = vert.co
        med = med + vec
    return med / len(vert_range)

# Get the active mesh
obj = bpy.context.edit_object
me = obj.data

# Get a BMesh representation
bm = bmesh.from_edit_mesh(me)

verts = bm.verts
num_verts = len(verts)
scale = 1 / (num_verts / 4)
j = 0
for i in range(0, num_verts, 4):
    mid = get_average(verts[i:i+4])
    for k in range(i, i+4):
        verts[k].co = verts[k].co.lerp(mid, 1-(j*scale))
    j += 1

bmesh.update_edit_mesh(me, True)


As you can see you were going in the right direction.