0
$\begingroup$

I'm trying to write a quick script that will work on all selected objects:

  1. Start in object mode
  2. Go into edit mode
  3. Set the 3d cursor location to the selected vertices
  4. Go back to object mode
  5. Set the origin of the object to the 3d cursor.

I can't seem to get the cursor to selected part to work properly :/ (step 3)

UPDATE

got this script to work if anyone has any improvements, please suggest: https://pastebin.com/krmzC8Kh

import bpy
import mathutils

# Store the active object and mode
active_object = bpy.context.active_object
active_mode = bpy.context.mode

# Iterate through selected objects
for obj in bpy.context.selected_objects:
    # Select the object and make it active
    bpy.context.view_layer.objects.active = obj
    obj.select_set(True)

# Switch to object mode
bpy.ops.object.mode_set(mode='OBJECT')

# Set the object as the active object
bpy.context.view_layer.objects.active = obj

# Switch to edit mode
bpy.ops.object.mode_set(mode='EDIT')

# Get the selected vertices
selected_verts = []
mesh = obj.data
for vertex in mesh.vertices:
    if vertex.select:
        selected_verts.append(vertex.co)

# Check if there are any selected vertices
if selected_verts:
    # Calculate the average position of selected vertices
    avg_position = [sum(v[i] for v in selected_verts) / len(selected_verts) for i in range(3)]

    # Transform the average position from local space to global space
    global_position = obj.matrix_world @ mathutils.Vector(avg_position)

    # Set the 3D cursor location to the calculated global position
    bpy.context.scene.cursor.location = global_position

# Switch back to object mode
bpy.ops.object.mode_set(mode='OBJECT')

# Set the origin of the object to the 3D cursor location
bpy.ops.object.origin_set(type='ORIGIN_CURSOR')

# Deselect the object
obj.select_set(False)

# Restore the active object and mode
bpy.context.view_layer.objects.active = active_object
bpy.ops.object.mode_set(mode=active_mode)
$\endgroup$
7
  • $\begingroup$ do you need to set the origin on a single vertex or on an average set of vertices? your question shows you need to set on a single vertex but the script you attached does that for an average set of selected vertices. $\endgroup$ Commented May 26, 2023 at 9:33
  • $\begingroup$ check my answer for single vertex setting $\endgroup$ Commented May 26, 2023 at 9:33
  • $\begingroup$ my bad, I meant for all selected vertices.. same as cursor to selected - so can be used for single or many $\endgroup$
    – Ebi
    Commented May 26, 2023 at 9:36
  • $\begingroup$ now I modified it so it works for a bunch of selected verts $\endgroup$ Commented May 26, 2023 at 9:44
  • $\begingroup$ nice but it is not working on multiple objects $\endgroup$
    – Ebi
    Commented May 26, 2023 at 9:48

4 Answers 4

1
$\begingroup$

Select your desired vertices and run the script:

import bpy
from mathutils import Vector
import numpy as np
bpy.ops.object.mode_set(mode = 'OBJECT')
objects = bpy.context.selected_objects
bpy.ops.object.select_all(action='DESELECT')
for obj in objects:
    verts_co = [v.co for v in obj.data.vertices if v.select]
    if len(verts_co) == 0:
        continue
    avg_loc = np.sum(verts_co, axis=0) / len(verts_co)
    global_co = obj.matrix_world @ Vector(avg_loc)
    bpy.context.scene.cursor.location = global_co
    obj.select_set(True)
    bpy.context.view_layer.objects.active = obj
    bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
    obj.select_set(False)
$\endgroup$
1
$\begingroup$
import bpy
from mathutils import Vector, Matrix


def object_origin(object: bpy.types.Object, origin: Vector=Vector((1, 1, 1))):
    '''
    Change object origin location.

    object (bpy.types.Object) - The object to change origin of.
    origin (3D Vector) - The location to change the origin to.
    '''
    local_origin = object.matrix_world.inverted() @ origin
    object.data.transform(Matrix.Translation(-local_origin))
    object.matrix_world.translation += (origin - object.matrix_world.translation)
    
    
object_origin(object=bpy.context.object)
$\endgroup$
0
$\begingroup$

since you know everything already, you can set the 3d cursor like this:

import bpy

bpy.context.scene.cursor.location.xyz = (1,1,1)
bpy.ops.object.origin_set(type='ORIGIN_CURSOR')

of course you have to replace the (1,1,1) with the selected vertex location

$\endgroup$
0
$\begingroup$
import bpy
import mathutils

# Store the active object and mode
active_object = bpy.context.active_object
active_mode = bpy.context.mode

# Iterate through selected objects
for obj in bpy.context.selected_objects:
    # Select the object and make it active
    bpy.context.view_layer.objects.active = obj
    obj.select_set(True)

# Switch to object mode
bpy.ops.object.mode_set(mode='OBJECT')

# Set the object as the active object
bpy.context.view_layer.objects.active = obj

# Switch to edit mode
bpy.ops.object.mode_set(mode='EDIT')

# Get the selected vertices
selected_verts = []
mesh = obj.data
for vertex in mesh.vertices:
    if vertex.select:
        selected_verts.append(vertex.co)

# Check if there are any selected vertices
if selected_verts:
    # Calculate the average position of selected vertices
    avg_position = [sum(v[i] for v in selected_verts) / len(selected_verts) for i in range(3)]

    # Transform the average position from local space to global space
    global_position = obj.matrix_world @ mathutils.Vector(avg_position)

    # Set the 3D cursor location to the calculated global position
    bpy.context.scene.cursor.location = global_position

# Switch back to object mode
bpy.ops.object.mode_set(mode='OBJECT')

# Set the origin of the object to the 3D cursor location
bpy.ops.object.origin_set(type='ORIGIN_CURSOR')

# Deselect the object
obj.select_set(False)

# Restore the active object and mode
bpy.context.view_layer.objects.active = active_object
bpy.ops.object.mode_set(mode=active_mode)
$\endgroup$
5
  • $\begingroup$ it does much unneeded works $\endgroup$ Commented May 26, 2023 at 10:09
  • $\begingroup$ can you explain please $\endgroup$
    – Ebi
    Commented May 26, 2023 at 10:12
  • $\begingroup$ and indentation is not right so it sets a single origin for all objects $\endgroup$ Commented May 26, 2023 at 10:13
  • 1
    $\begingroup$ 1) going back to editmode is not needed since blender updates its selection arrays after exiting edit mode and selection is accessible in objectmode. 2) the summation here is slower than that of numpy. 3) since it doesn't deselect all objects first, it sets the origin of all selected objects in each loop and then deselects a single one so it works functionally but does much unneeded. it will be a burden in large selections $\endgroup$ Commented May 26, 2023 at 10:18
  • $\begingroup$ Thank you :) .. $\endgroup$
    – Ebi
    Commented May 26, 2023 at 10:19

You must log in to answer this question.

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