1
$\begingroup$

I'm trying to set the size of an object without it's modifiers. So, in a script, I turn off the visible modifiers, then set the scale, then turn them back on. Why doesn't it work?

It does shrink the room and set correctly if I comment out the last:

show_modifiers_master_room(True)

But, when I turn the modifiers back on, the object's scale includes the modifier dimensions (I have a simple Solidify modifier on the object "Master Room"). It appears as if Blender is applying the dimensions after the modifiers are turned back on.

def show_modifiers_master_room(p_bool):
    ob = bpy.data.objects['Master Room']
    for mod in getattr(ob, "modifiers", []):
        mod.show_viewport = p_bool
    print ("show mods: " + str(p_bool))

def room_dim_changed_v(self, context):
    show_modifiers_master_room(False)
    bpy.data.objects['Master Room'].dimensions = (4.0,2.0,2.0)
    show_modifiers_master_room(True)
$\endgroup$
3

1 Answer 1

2
$\begingroup$

Setting dimension requires a view layer update

As outlined in Exporting data: looping through objects gets wrong data for very last object call view_layer.update() after using dimensions, to set the scale.

Get the dimensions from the mesh

Borrowing from both

How to get the base dimensions of an object (ignoring all of it's modifiers)?

How do I get the bounding box of all objects in a scene

can get the unmodified global sized bounding box of a mesh

import bpy
import numpy as np
from bpy.props import FloatVectorProperty

def np_matmul_coords(coords, matrix, space=None):
    M = (space @ matrix @ space.inverted()
         if space else matrix).transposed()
    ones = np.ones((coords.shape[0], 1))
    coords4d = np.hstack((coords, ones))
    
    return np.dot(coords4d, M)[:,:-1]


def get_mesh_dims(self):
    if self.type != 'MESH':
        return None
    me = self.data
    coords = np.empty(3 * len(me.vertices))
    
    me.vertices.foreach_get("co", coords)

    x, y, z = np_matmul_coords(coords.reshape(-1, 3), self.matrix_world).T

    return (
            x.max() - x.min(),
            y.max() - y.min(),
            z.max() - z.min()
            )

bpy.types.Object.mesh_dimensions = FloatVectorProperty(
        name="Mesh Dimensions",
        get=get_mesh_dims,
        subtype='XYZ',
        unit='LENGTH',
        )

Now having run script above every object has a mesh dimension property. Here is a test run on default cube with default subdivision surface.

>>> C.object.mesh_dimensions
Vector((2.0, 2.0, 2.0))

>>> C.object
bpy.data.objects['Cube']

>>> C.object.dimensions
Vector((1.6790125370025635, 1.6790125370025635, 1.6790125370025635))

>>> C.object.mesh_dimensions
Vector((2.0, 2.0, 2.0))

>>> d = C.object.mesh_dimensions
>>> C.object.scale = 4 / d.x, 4 / d.y, 4 / d.z
>>> C.object.scale
Vector((2.0, 2.0, 2.0))
$\endgroup$

You must log in to answer this question.

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