我正在为搅拌机设计一个附加组件,它可以改变对象某些顶点的位置。 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?
答案 0 :(得分:5)
您应该在更改这些值后调用Scene.update
,否则Blender将不会重新计算matrix_world
,直到需要[其他地方]。根据API文档中的"Gotcha's" section,原因是这个重新计算是一项昂贵的操作,因此不会马上完成:
有时你想修改python中的值并立即访问更新的值,例如:
更改对象bpy.types.Object.location后,您可能希望在bpy.types.Object.matrix_world之后立即访问其转换,但这不会像您预期的那样有效。
考虑可能用于计算对象最终转换的计算,其中包括:
- 动画功能曲线。
- 司机和他们的蟒蛇表达。
- 约束
- 父对象及其所有f曲线,约束等。
为避免每次修改属性时进行昂贵的重新计算,Blender推迟进行实际计算,直到需要它们为止。
但是,当脚本运行时,您可能希望访问更新的值。
这可以通过在修改重新计算标记为要更新的所有数据的值后调用bpy.types.Scene.update来完成。
答案 1 :(得分:1)
在循环中调用bpy.context.scene.update()
可能会变得昂贵。
如果您的对象没有复杂的约束(例如普通约束或父约束),则可以在更改对象的.location
,.rotation_euler\quaternion
或.scale
之后,使用以下内容重新计算世界矩阵。 / p>
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
也被重新计算答案 2 :(得分:0)
我也需要这样做但是在我导入一个包含数万个对象的大型场景时需要更新这个值。 调用' 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顺序变换,但这可以避免在处理大数据集时呈指数减速