From f858f9528e57a1362fa4164a3b0391f8965d2a4a Mon Sep 17 00:00:00 2001 From: Thomas Barlow Date: Tue, 18 Apr 2023 23:40:15 +0100 Subject: [PATCH] FBX Import: Fix pre-, post- and geometric rotations The pre-, post- and geometric rotations were using the rotation order of the transform, but it's only the rotation that uses the rotation order of the transform. The post-rotation used in calculating the WorldTransform was being used as-is, this seems to have been an error in the FBX 2011 documentation because since FBX 2012, the documentation has specified that the inverse of post-rotation is used and there is no mention of this change in the FBX 2012 changes. Additionally, given files in FBX 2011 format, the post-rotation works the same as in FBX 2012 and newer. The pre-, post- and geometric rotations have been changed to always use XYZ order. The post-rotation is now inverted when calculating each WorldTransform. Fixes the import of .fbx that have non-zero post-rotation. Fixes the import of .fbx that have pre-/post-/geometric rotation and have non-XYZ rotation order. Cases where the "Use Pre/Post Rotation" option of the FBX Importer had to be disabled to get a working import are likely to now work with the option enabled. Fixes #45176: Incorrect rotation of imported Cameras and Lights --- io_scene_fbx/import_fbx.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/io_scene_fbx/import_fbx.py b/io_scene_fbx/import_fbx.py index 6dcece2f3..b8da2923e 100644 --- a/io_scene_fbx/import_fbx.py +++ b/io_scene_fbx/import_fbx.py @@ -372,7 +372,7 @@ def blen_read_custom_properties(fbx_obj, blen_obj, settings): def blen_read_object_transform_do(transform_data): # This is a nightmare. FBX SDK uses Maya way to compute the transformation matrix of a node - utterly simple: # - # WorldTransform = ParentWorldTransform @ T @ Roff @ Rp @ Rpre @ R @ Rpost @ Rp-1 @ Soff @ Sp @ S @ Sp-1 + # WorldTransform = ParentWorldTransform @ T @ Roff @ Rp @ Rpre @ R @ Rpost-1 @ Rp-1 @ Soff @ Sp @ S @ Sp-1 # # Where all those terms are 4 x 4 matrices that contain: # WorldTransform: Transformation matrix of the node in global space. @@ -382,7 +382,7 @@ def blen_read_object_transform_do(transform_data): # Rp: Rotation pivot # Rpre: Pre-rotation # R: Rotation - # Rpost: Post-rotation + # Rpost-1: Inverse of the post-rotation (FBX 2011 documentation incorrectly specifies this without inversion) # Rp-1: Inverse of the rotation pivot # Soff: Scaling offset # Sp: Scaling pivot @@ -402,14 +402,15 @@ def blen_read_object_transform_do(transform_data): # S: Scaling # OT: Geometric transform translation # OR: Geometric transform rotation - # OS: Geometric transform translation + # OS: Geometric transform scale # # Notes: # Geometric transformations ***are not inherited***: ParentWorldTransform does not contain the OT, OR, OS # of WorldTransform's parent node. + # The R matrix takes into account the rotation order. Other rotation matrices are always 'XYZ' order. # - # Taken from http://download.autodesk.com/us/fbx/20112/FBX_SDK_HELP/ - # index.html?url=WS1a9193826455f5ff1f92379812724681e696651.htm,topicNumber=d0e7429 + # Taken from https://help.autodesk.com/view/FBX/2020/ENU/ + # ?guid=FBX_Developer_Help_nodes_and_scene_graph_fbx_nodes_computing_transformation_matrix_html # translation lcl_translation = Matrix.Translation(transform_data.loc) @@ -418,9 +419,9 @@ def blen_read_object_transform_do(transform_data): # rotation to_rot = lambda rot, rot_ord: Euler(convert_deg_to_rad_iter(rot), rot_ord).to_matrix().to_4x4() lcl_rot = to_rot(transform_data.rot, transform_data.rot_ord) @ transform_data.rot_alt_mat - pre_rot = to_rot(transform_data.pre_rot, transform_data.rot_ord) - pst_rot = to_rot(transform_data.pst_rot, transform_data.rot_ord) - geom_rot = to_rot(transform_data.geom_rot, transform_data.rot_ord) + pre_rot = to_rot(transform_data.pre_rot, 'XYZ') + pst_rot = to_rot(transform_data.pst_rot, 'XYZ') + geom_rot = to_rot(transform_data.geom_rot, 'XYZ') rot_ofs = Matrix.Translation(transform_data.rot_ofs) rot_piv = Matrix.Translation(transform_data.rot_piv) @@ -439,7 +440,7 @@ def blen_read_object_transform_do(transform_data): rot_piv @ pre_rot @ lcl_rot @ - pst_rot @ + pst_rot.inverted_safe() @ rot_piv.inverted_safe() @ sca_ofs @ sca_piv @ -- 2.30.2