7

Blender 2.83

In python I can create all of the features that I want in my world, but when I go to the world, each thing has the same location data. I can click on each and click set origin to geometry, and that fixes it. The info pane says:

bpy.ops.object.origin_set(
    type='ORIGIN_GEOMETRY',
    center='MEDIAN'
)

So I would think I can run, at the end of my script, something like:

for object in bpy.context.scene.objects:
    bpy.ops.object.origin_set(
        type='ORIGIN_GEOMETRY', 
        center='MEDIAN'
    )

but this doesn't seem to do anything. How do I set everything to have origin_geometry, so that they have reasonable position data?

JmathLoy
  • 73
  • 1
  • 7

1 Answers1

13

Low level Origin to geometry

Will have to investigate the difference between calling the set origin operator via code and via the UI

Instead can sum the vert coordinates make that the origin, and shift the matrix back accordingly

import bpy
from mathutils import Matrix, Vector

scene = bpy.context.scene

mesh_obs = [o for o in scene.objects if o.type == 'MESH']

for o in mesh_obs: me = o.data mw = o.matrix_world origin = sum((v.co for v in me.vertices), Vector()) / len(me.vertices)

T = Matrix.Translation(-origin)
me.transform(T)
mw.translation = mw @ origin

Alternatively could change your mesh creation class to not use global coordinates.

Operators run on context

Operators use the context. The origin set will set the origin of all selected mesh objects and can be run once on the selection rather than per object. See Python performance with Blender operators as to why this matters.

Another part of context is the code in question? It is quite possible that changing the origin could be dealt with somewhere else if you are to quote:

In python I can create all of the features that I want

However without any idea of what prior code is, here is a Test script, set origin of all mesh objects in the scene by passing them as overridden context to the operator.

Blender 3.2+

import bpy

C = bpy.context scene = C.scene

mesh_obs = [o for o in scene.objects if o.type == 'MESH'] c = {"object" : mesh_obs[0], "selected_objects" : mesh_obs, "selected_editable_objects" : mesh_obs}

if mesh_obs: with C.temp_override(**c): bpy.ops.object.origin_set()

Blender 2.8+

import bpy

scene = bpy.context.scene

mesh_obs = [o for o in scene.objects if o.type == 'MESH']

if mesh_obs: bpy.ops.object.origin_set( {"object" : mesh_obs[0], "selected_objects" : mesh_obs, "selected_editable_objects" : mesh_obs, } )

p2or
  • 15,860
  • 10
  • 83
  • 143
batFINGER
  • 84,216
  • 10
  • 108
  • 233
  • Hey batFIGNER. Probably it's my own fault in trying to apply your answer, or in poorly explaining what I wanted to do. When I create a bunch of cubes in different locations, and then go and click them, they all have the same location "5.7463,6.9448,1.5576" (despite appearing in different places on the screen). When I right click each of them, and change origin to geometry, they give reasonable coordinates (for example (7.2463,14.445,2.0575)) and are now distant from each other by integer differences like $(m,n,0)\in\Bbb Z^3$ (which is what I want). – JmathLoy Jul 11 '20 at 09:51
  • After running your script, it moves all the blocks to the same location on screen, instead of doing the same thing as right clicking and changing to origin_geometry – JmathLoy Jul 11 '20 at 09:52
  • Possibly I've caused the problem myself by defining my own cube class https://i.imgur.com/WqPl5Qg.png, instead of just using bpy.ops.mesh.primitive_cube_add(size=2, enter_editmode=False, align='WORLD', location=(5.74625, 6.94476, 1.5576)) – JmathLoy Jul 11 '20 at 10:10
  • At some point I'll want to do other geometric figures though, and probably I would modify my above class with the appropriate vertices and faces in those cases, so I'm still interested in the answer for my class – JmathLoy Jul 11 '20 at 10:13
  • Your edit works great, thank you! – JmathLoy Jul 12 '20 at 19:10