I'm playing around with bmesh and have run into something I can't figure out how to do and can't find any related documentation on.

I have extruded a face directly outward (after subdividing a larger object to create it) and now want to scale it inward after the extrusion. When I try to use bmesh transform and scale operators (code below), it ends up moving the face location, apparently in relation to the global space. It seems like the answer is related to feeding the proper matrix into whatever function I'm calling, but I haven't quite wrapped my head around how it all works yet.

Here is what the result looks like just after the extruding operation:

blender bmesh scale face in place

And here is what I'm trying to achieve:

enter image description here

Basically, what I want is to use the equivalent of:


...inside of bmesh, to scale the face on the X and Z axis in place/relative to the face center.

I've tried performing the operation using the scale operator with different "space" arguments:

face = bm.faces[0]
    vec=(.5, 1, .5),

I've also tried using the transform operator with manually constructed matrices

face = bm.faces[0]
matrix = mathutils.Matrix([ ... ])

I can't figure out how to get the boundaries of the scale transformation space to be confined to the face area.

Thanks for any insight or help!


Scale the distance from face centre to vert.

Propose in this case could simply use the face centre as stationary point, and reposition each vertex coordinate by a scale factor. For a face face with a centre c = face.calc_center_median() having a vertex v the vector v.co - c represents the straight line from vert to c. Can then move the vertex to a new location by a factor along this line v.co = c + scale_factor * (v.co - c)

Example script, run in edit mode with the face you want to scale active.

import bpy
import bmesh

context = bpy.context
ob = context.edit_object
me = ob.data
bm = bmesh.from_edit_mesh(me)
scale_factor = 0.5

face = bm.select_history.active
if isinstance(face, bmesh.types.BMFace):
    c = face.calc_center_median()
    for v in face.verts:
        v.co = c + scale_factor * (v.co - c)


Have assumed the face is co-planar

Using Matrices.

Another way to achieve this is using matrices, v.co = c + scale_factor * (v.co - c) Indicates the operation needs both a transformation and scale. For the transformation can change the space locally such that the point c becomes the origin. (Wont be shifted by any scale).

face = bm.select_history.active
if isinstance(face, bmesh.types.BMFace):
    c = face.calc_center_median()
    T = Matrix.Translation(-c)
    S = Matrix.Scale(scale_factor, 4)
    bmesh.ops.transform(bm, matrix=S, verts=face.verts, space=T)
  • $\begingroup$ Thanks for this - I was just thinking about implementing a similar solution myself and your code will save me a few minutes and hopefully help others in the future. I was hoping for a matrix-based solution vs. operating on each vertex individually, because it's a lot cleaner - this is much easier to understand though! Do you know if it's possible to do it with transformation matrices? $\endgroup$
    – ineedhelp
    Oct 24 '18 at 4:30
  • $\begingroup$ Very cool, thanks for the matrix update - just seeing it now. I've been struggling to wrap my mind around exactly how to use matrices and your explanation and script helped a lot. I don't think I've ever encountered matrices before scripting Blender operations. I was not a very ambitious mathematician in school :P One further question, if you can spare another moment: Would you consider it safe to view the named "space" parameter as synonymous (in this context) with "transformation origin"? If so, is it the same for every function (in Blender) where the "space" argument exists? $\endgroup$
    – ineedhelp
    Dec 18 '18 at 5:54

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.