3
$\begingroup$

So i need to need to replicate translate, rotate & scale with 3d cursor as pivot point action using Matrix or bmesh in a script.

i read Rotate objects around their origin along a global axis (scripted) without bpy.ops and after changing the matrix order the object was rotating around 0,0,0 but i was unable to change this pivot position.(mainly cause I'm blindly copy pasting code without understanding it).

What is the correct way to set a custom pivot point ?(example: (1,2,0))

I found a way to perform this using bmesh+matrix but the results are transformed in edit mode so the origins stay at the same place. Since the object I'll be rotating has many child objects, i would like to perform the rotation in Object mode and avoid having to merge everything into one object.

Here's the function which is used to rotate or scale with 3d cursor as pivot in edit mode For blender 2.83

import bpy
import bmesh
from mathutils import Matrix
from math import radians

# Rotate or scale with pivot point

def rotate_or_scale(tr_mode, obj, value,axis_value):
    bpy.ops.object.select_all(action='DESELECT')
    obj.select_set(True)
    bpy.context.view_layer.objects.active = obj
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='SELECT')
    context = bpy.context
    scene = context.scene
    pivot_point = bpy.context.scene.cursor.location

    ob = context.edit_object
    mesh_dat = ob.data
    bm = bmesh.from_edit_mesh(mesh_dat)
    S = ob.matrix_world.copy()
    S.translation -= pivot_point

     if tr_mode == 'rotate':
        translation_matrix = Matrix.Rotation(radians(value), 3, axis_or_value)
    elif tr_mode == 'scale':
        translation_matrix = Matrix.Diagonal(axis_or_value)
    else:
        bpy.ops.object.mode_set(mode='OBJECT')
        return
        
    bmesh.ops.rotate(bm, 
            matrix=translation_matrix, 
            verts=[v for v in bm.verts if v.select],
            space=S)

    bmesh.update_edit_mesh(mesh_dat)
    bpy.ops.object.mode_set(mode='OBJECT')
    
rotate_or_scale('scale',bpy.context.selected_objects[0],0,(1,1,1.1)) #scale z by 1.1
rotate_or_scale('rotate',bpy.context.selected_objects[0],45,(0,0,1)) #rotate 45deg on zaxis
$\endgroup$

1 Answer 1

8
$\begingroup$

Object mode global rotation / scale around global axis thru scene cursor.

To rotate or scale about a non origin pivot point we need to change the space of our object such that its origin is the pivot point.

Can do both the scale and the rotation in one fell swoop. To just rotate set scale_factor to 1, or to just scale set the angle to zero, for either case the matrix becomes Identity.

Notice the way M is made in the reverse order, ie translates by negative pivot point to move pivot point to origin, then rotates, scales (its uniform scale), then moves the pivot point back.

import bpy
from mathutils import Matrix
from math import radians

context = bpy.context
scale_factor = 1.1
angle = radians(45) 
axis = (0, 0, 1)

scene = context.scene
pivot = scene.cursor.location

for ob in context.selected_objects:
    M = (
        Matrix.Translation(pivot) @
        Matrix.Diagonal((scale_factor,) * 3).to_4x4() @
        Matrix.Rotation(angle, 4, axis) @       
        Matrix.Translation(-pivot)
        )
    ob.matrix_world = M @ ob.matrix_world
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .