Placez les objets au centre du plan du sol et maintenez la structure via un script python

Sep 22 2020

J'essaye de faire ce qui est plus ou moins décrit dans ce fil Comment placer des objets au centre du plan de sol via python? la solution acceptée semble fonctionner correctement si vous n'avez qu'un seul objet dans la scène. Cependant, dans mon cas, ma scène est structurée à partir d'objets individuels, ce qui conduit au résultat que tous les objets doivent être brouillés ensemble au centre du plan comme vous pouvez le voir ci-dessous:

Au départ, ma scène est comme ça:

En utilisant l'interface graphique, j'ai pu centrer tous les objets et maintenir la structure du maillage en suivant ces https://blender.stackexchange.com/a/26452 instructions.

Ainsi, j'aimerais savoir comment je peux y parvenir dans un script python.

Merci.

Réponses

1 lemon Sep 22 2020 at 17:26

Une façon de le faire:

  • Boucle sur les maillages sélectionnés pour obtenir chaque centre individuel en coordonnées mondiales
  • Puis calcule le centre global
  • Boucle à nouveau sur eux pour déplacer leurs sommets en tenant compte du centre global

Le scénario:

import bpy
from mathutils import Vector

# Choose the axis you want to center on
center_x = True
center_y = True
center_z = False

# Get objects
objects = bpy.context.selected_objects

centers = []

# Loop over meshes to get their centers
for obj in [o for o in objects if o.type == 'MESH']:
    world_matrix = obj.matrix_world
    vertices = obj.data.vertices
    # Get object center in world coordinates
    center = sum([world_matrix @ Vector(v.co) for v in vertices], Vector()) / len(vertices)
    centers.append(center)

# Calculate overall center
center = sum([c for c in centers], Vector()) / len(centers)

# Keep axis you want
center.x = center.x if center_x else 0
center.y = center.y if center_y else 0
center.z = center.z if center_z else 0

# Loop over meshes to shift them
for obj in [o for o in objects if o.type == 'MESH']:
    vertices = obj.data.vertices
    world_matrix_inv = obj.matrix_world.inverted()
    # Calculate the shift in object coordinates
    delta = world_matrix_inv @ center
    # Shift vertices
    for v in obj.data.vertices:
        v.co = v.co - delta

1 batFINGER Sep 22 2020 at 17:50

Créer et déplacer une boîte liée globale

Résultat de l'importation, origine aux limites, exécuter le script

Calculez les coordonnées de la boîte englobante globale de chaque objet maillé de la sélection. À partir de là, récupérez la médiane x et y, puis traduisez globalement tous les objets sélectionnés sans parent.

Un cadre englobant est l'étendue alignée sur l'axe d'un objet.

import bpy
from mathutils import Vector
from bpy import context
import numpy as np

obs = [o for o in context.selected_objects
        if o.type == 'MESH']
        
coords = []
for o in obs:
    coords.extend(o.matrix_world @ Vector(b) for b in o.bound_box) 

x, y, z = np.array(coords).reshape((-1, 3)).T

global_xy_trans = Vector(
    (
        (x.min() + x.max()) / 2 , 
        (y.min() + y.max()) / 2
        )
    )


for o in obs:
    
    if o.parent in obs:
        continue
    o.matrix_world.translation.xy -= global_xy_trans

Avant ou après un appel pour définir l'opérateur d'origine. Cet opérateur est disponible via l'interface utilisateurObject > Set Origin > Origin to Geometry > Bounds

bpy.ops.object.origin_set(center='BOUNDS') 

donnera à chaque partie une origine plus sensible. Il peut être exécuté sur tous les objets sélectionnés et les laisse en place, il déplace simplement le point d'origine. Voir Changer l'origine d'un objet en un point arbitraire sans origin_set ()?

L'application de la traduction donnera à chaque objet une origine au niveau global (0, 0, 0)