Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force matrix_world to be recalculated in Blender

I'm designing an add-on for blender, that changes the location of certain vertices of an object. Every object in blender has a matrix_world atribute, that holds a matrix that transposes the coordinates of the vertices from the object to the world frame.

print(object.matrix_world) # unit matrix (as expected)
object.location += mathutils.Vector((5,0,0))
object.rotation_quaternion *= mathutils.Quaternion((0.0, 1.0, 0.0), math.radians(45))
print(object.matrix_world) # Also unit matrix!?!

The above snippet shows that after the translation, you still have the same matrix_world. How can I force blender to recalculate the matrix_world?

like image 220
Nallath Avatar asked Dec 12 '12 13:12

Nallath


3 Answers

You should call Scene.update after changing those values, otherwise Blender won't recalculate matrix_world until it's needed [somewhere else]. The reason, according to the "Gotcha's" section in the API docs, is that this re-calc is an expensive operation, so it's not done right away:

Sometimes you want to modify values from python and immediately access the updated values, eg:

Once changing the objects bpy.types.Object.location you may want to access its transformation right after from bpy.types.Object.matrix_world, but this doesn’t work as you might expect.

Consider the calculations that might go into working out the objects final transformation, this includes:

  • animation function curves.
  • drivers and their pythons expressions.
  • constraints
  • parent objects and all of their f-curves, constraints etc.

To avoid expensive recalculations every time a property is modified, Blender defers making the actual calculations until they are needed.

However, while the script runs you may want to access the updated values.

This can be done by calling bpy.types.Scene.update after modifying values which recalculates all data that is tagged to be updated.

like image 158
mgibsonbr Avatar answered Nov 17 '22 20:11

mgibsonbr


Calls to bpy.context.scene.update() can become expensive when called within a loop.

If your objects have no complex constraints (e.g. plain or parented), the following can be used to recompute the world matrix after changing object's .location, .rotation_euler\quaternion, or .scale.

def update_matrices(obj):
    if obj.parent is None:
        obj.matrix_world = obj.matrix_basis

    else:
        obj.matrix_world = obj.parent.matrix_world * \
                           obj.matrix_parent_inverse * \
                           obj.matrix_basis

Some notes:

  • Immediately after setting object location/rotation/scale the object's matrix_basis is updated
  • But matrix_local (when parented) and matrix_world are only updated during scene.update()
  • When matrix_world is manually recomputed (using the code above), matrix_local is recomputed as well
  • If the object is parented, then its world matrix depends on the parent's world matrix as well as the parent's inverse matrix at the time of creation of the parenting relationship.
like image 2
Justas Avatar answered Nov 17 '22 21:11

Justas


I needed to do this too but needed this value to be updated whilst I imported a large scene with tens of thousands of objects. Calling 'scene.update()' became exponentially slower, so I needed to find a way to do this without calling that function. This is what I came up with:

def BuildScaleMatrix(s):
    return Matrix.Scale(s[0],4,(1,0,0)) * Matrix.Scale(s[1],4,(0,1,0)) * Matrix.Scale(s[2],4,(0,0,1))

def BuildRotationMatrixXYZ(r):
    return  Matrix.Rotation(r[2],4,'Z') * Matrix.Rotation(r[1],4,'Y') * Matrix.Rotation(r[0],4,'X')

def BuildMatrix(t,r,s):
    return   Matrix.Translation(t) * BuildRotationMatrixXYZ(r) * BuildScaleMatrix(s)

def UpdateObjectTransform(ob):
    ob.matrix_world = BuildMatrix(ob.location, ob.rotation_euler, ob.scale)

This isn't most efficient way to build a matrix (if you know of a better way in blender, please add) and this only works for XYZ order transforms but this avoids exponential slow downs when dealing with large data sets.

like image 1
Luther Avatar answered Nov 17 '22 20:11

Luther