def ensure_uniform_scale(self): if self.is_bounding_box: return l, r, s = decompose(self.matrix_local) if not np.allclose(s[:1], s[1:], rtol=0, atol=0.001): print(f"[INFO] {self.name} has non-uniform scale") if self.source.type == "MESH": self.vertex_transform = s self.matrix_local = compose(l, r, 1) for child in self.children: child.matrix_local[:3, :3] *= s for child in self.children: child.ensure_uniform_scale()
def correct_rest_positions(self): """Correct the rest pose of the root bone. The rest pose of vanilla assets often feature inconvenient transforms. This is not an issue in-game since you would only ever see actors with their animations applied. When working in Blender however, a sane rest pose will make the lives of artists much easier. This function replaces the root bone's rest matrix with an edited copy of its posed matrix. This edited copy is identical to pose matrix with regards to location and scale, but has had its rotation about all axes aligned to the nearest 90 degree angle. """ if not self.armatures: return root = self.get_armature_node() root_bone = next(self.iter_bones(root)) # calculate corrected transformation matrix l, r, s = decompose(root_bone.matrix_posed) r = nif_utils.snap_rotation(r) corrected_matrix = compose(l, r, s) # only do corrections if they are necessary if np.allclose(root_bone.matrix_world, corrected_matrix, rtol=0, atol=1e-6): return # correct the rest matrix of skinned meshes inverse = la.inv(root_bone.matrix_world) for node in self.get_skinned_meshes(): if root_bone not in node.parents: node.matrix_world = corrected_matrix @ ( inverse @ node.matrix_world) # correct the rest matrix of the root bone root_bone.matrix_world = corrected_matrix
def correct_rest_positions(self): if not self.armatures: return root = self.get(*self.armatures) # __history__ root_bone = next(self.iter_bones(root)) # __history__ # calculate corrected transformation matrix l, r, s = decompose(root_bone.matrix_posed) r = nif_utils.snap_rotation(r) corrected_matrix = compose(l, r, s) # correct the rest matrix of skinned meshes bone_inverse = la.inv(root_bone.matrix_world) for node in self.nodes: skin = getattr(node.source, "skin", None) if skin and (skin.root is root.source) and (root_bone not in node.parents): node.matrix_world = corrected_matrix @ bone_inverse @ node.matrix_world # correct the rest matrix of the root bone root_bone.matrix_world = corrected_matrix
def matrix(self) -> ndarray: return compose(self.translation, self.rotation, self.scale)
def matrix(self): return compose(self.center, self.rotation, self.extents)
def matrix(self) -> ndarray: return compose(self.center, self.axes, self.extents)