6

我正在为搅拌机设计一个附加组件,它可以改变对象某些顶点的位置。Blender 中的每个对象都有一个 matrix_world 属性,该属性包含一个矩阵,该矩阵将顶点坐标从对象转置到世界框架。

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!?!

上面的代码片段显示,在翻译之后,你仍然拥有相同的 matrix_world。如何强制搅拌机重新计算 matrix_world?

4

4 回答 4

8

您应该在更改这些值后调用,否则 Blender在需要 [其他地方] 之前Scene.update不会重新计算。matrix_world根据 API 文档中的“Gotcha's”部分,原因是重新计算是一项昂贵的操作,因此不会立即完成:

有时您想从 python 修改值并立即访问更新的值,例如:

更改对象bpy.types.Object.location后,您可能希望立即从bpy.types.Object.matrix_world访问其转换,但这并不像您预期​​的那样工作。

考虑可能用于计算对象最终转换的计算,这包括:

  • 动画功能曲线。
  • 司机和他们的蟒蛇表达式。
  • 约束
  • 父对象及其所有的 f 曲线、约束等。

为了避免每次修改属性时进行昂贵的重新计算,Blender 将实际计算推迟到需要时进行。

但是,当脚本运行时,您可能希望访问更新的值。

这可以通过在修改值后调用bpy.types.Scene.update来完成,该值会重新计算所有标记为要更新的数据。

于 2012-12-16T06:57:28.373 回答
2

在循环中调用时调用bpy.context.scene.update()会变得昂贵

如果您的对象没有复杂的约束(例如普通约束或父对象),则可以在更改对象的 、 或 后使用以下方法重新计算.location世界.rotation_euler\quaternion矩阵.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

一些注意事项:

  • 设置对象位置/旋转/缩放后立即matrix_basis更新对象
  • 但是matrix_local(当父母)并且matrix_world仅在期间更新scene.update()
  • 何时matrix_world手动重新计算(使用上面的代码),matrix_local也重新计算
  • 如果对象是父对象,则其世界矩阵取决于父对象的世界矩阵以及父对象在创建父对象关系时的逆矩阵。
于 2019-08-13T21:40:08.863 回答
1

我也需要这样做,但需要在导入包含数万个对象的大型场景时更新此值。调用 'scene.update()' 变得指数级地变慢,所以我需要找到一种方法来做到这一点,而无需调用该函数。这就是我想出的:

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)

这不是构建矩阵的最有效方法(如果您知道搅拌机中的更好方法,请添加),并且仅适用于 XYZ 顺序转换,但这避免了在处理大型数据集时出现指数级减速。

于 2018-04-30T14:00:25.733 回答
0

访问 Object.matrix_world 会导致它“冻结”,即使你没有对它做任何事情,例如:

m = C.active_object.matrix_world

导致矩阵卡住。每当您想访问矩阵时,请使用

Object.matrix_world.copy()

仅当您想编写矩阵时,才使用

C.active_object.matrix_world = m
于 2021-10-06T09:28:38.073 回答