[Bf-extensions-cvs] [075a6a5] master: FBX Importer: Bake space transform on import

Bastien Montagne noreply at git.blender.org
Mon Sep 8 15:02:04 CEST 2014


Commit: 075a6a591630733c5e53c24d8d2c53d6ef0ce493
Author: Bastien Montagne
Date:   Mon Sep 8 14:58:26 2014 +0200
Branches: master
https://developer.blender.org/rBA075a6a591630733c5e53c24d8d2c53d6ef0ce493

FBX Importer: Bake space transform on import

Revision: D739

Patch by jrestemeier (Jens Restemeier).

===================================================================

M	io_scene_fbx_experimental/__init__.py
M	io_scene_fbx_experimental/fbx_utils.py
M	io_scene_fbx_experimental/import_fbx.py

===================================================================

diff --git a/io_scene_fbx_experimental/__init__.py b/io_scene_fbx_experimental/__init__.py
index b1e0777..a273e21 100644
--- a/io_scene_fbx_experimental/__init__.py
+++ b/io_scene_fbx_experimental/__init__.py
@@ -101,6 +101,13 @@ class ImportFBX_experimental(bpy.types.Operator, ImportHelper):
             min=0.001, max=1000.0,
             default=1.0,
             )
+    bake_space_transform = BoolProperty(
+            name="Apply Transform",
+            description=("Bake space transform into object data, avoids getting unwanted rotations to objects when "
+                         "target space is not aligned with Blender's space "
+                         "(WARNING! experimental option, might give odd/wrong results)"),
+            default=False,
+            )
 
     use_image_search = BoolProperty(
             name="Image Search",
@@ -180,6 +187,7 @@ class ImportFBX_experimental(bpy.types.Operator, ImportHelper):
         sub.prop(self, "axis_forward")
         sub.prop(self, "axis_up")
         sub.prop(self, "global_scale")
+        layout.prop(self, "bake_space_transform")
 
         layout.prop(self, "use_image_search")
         # layout.prop(self, "use_alpha_decals")
diff --git a/io_scene_fbx_experimental/fbx_utils.py b/io_scene_fbx_experimental/fbx_utils.py
index e065165..f0eeca0 100644
--- a/io_scene_fbx_experimental/fbx_utils.py
+++ b/io_scene_fbx_experimental/fbx_utils.py
@@ -1102,6 +1102,7 @@ FBXExportData = namedtuple("FBXExportData", (
 # Helper container gathering all importer settings.
 FBXImportSettings = namedtuple("FBXImportSettings", (
     "report", "to_axes", "global_matrix", "global_scale",
+    "bake_space_transform", "global_matrix_inv", "global_matrix_inv_transposed",
     "use_cycles", "use_image_search",
     "use_alpha_decals", "decal_offset",
     "use_custom_props", "use_custom_props_enum_as_string",
diff --git a/io_scene_fbx_experimental/import_fbx.py b/io_scene_fbx_experimental/import_fbx.py
index 4bb6443..98edf0c 100644
--- a/io_scene_fbx_experimental/import_fbx.py
+++ b/io_scene_fbx_experimental/import_fbx.py
@@ -624,15 +624,21 @@ def blen_read_geom_array_mapped_vert(
         fbx_layer_data, fbx_layer_index,
         fbx_layer_mapping, fbx_layer_ref,
         stride, item_size, descr,
+        xform=None
         ):
     # TODO, generic mapping apply function
     if fbx_layer_mapping == b'ByVertice':
         if fbx_layer_ref == b'Direct':
             assert(fbx_layer_index is None)
             # TODO, more generic support for mapping types
-            for i, blen_data_item in enumerate(blen_data):
-                setattr(blen_data_item, blend_attr,
-                        fbx_layer_data[(i * stride): (i * stride) + item_size])
+            if xform is None:
+                for i, blen_data_item in enumerate(blen_data):
+                    setattr(blen_data_item, blend_attr,
+                            fbx_layer_data[(i * stride): (i * stride) + item_size])
+            else:
+                for i, blen_data_item in enumerate(blen_data):
+                    setattr(blen_data_item, blend_attr,
+                            xform(fbx_layer_data[(i * stride): (i * stride) + item_size]))
             return True
         else:
             print("warning layer %r ref type unsupported: %r" % (descr, fbx_layer_ref))
@@ -881,7 +887,7 @@ def blen_read_geom_layer_smooth(fbx_obj, mesh):
         return False
 
 
-def blen_read_geom_layer_normal(fbx_obj, mesh):
+def blen_read_geom_layer_normal(fbx_obj, mesh, xform=None):
     fbx_layer = elem_find_first(fbx_obj, b'LayerElementNormal')
 
     if fbx_layer is None:
@@ -902,10 +908,25 @@ def blen_read_geom_layer_normal(fbx_obj, mesh):
         fbx_layer_data, None,
         fbx_layer_mapping, fbx_layer_ref,
         3, 3, layer_id,
+        xform
         )
 
 
 def blen_read_geom(fbx_tmpl, fbx_obj, settings):
+    from mathutils import Matrix, Vector
+    from itertools import chain
+    import array
+
+    # Vertices are in object space, but we are post-multiplying all transforms with the inverse of the
+    # global matrix, so we need to apply the global matrix to the vertices to get the correct result.
+    geom_mat_co = settings.global_matrix if settings.bake_space_transform else None
+    # We need to apply the inverse transpose of the global matrix when transforming normals.
+    geom_mat_no = Matrix(settings.global_matrix_inv_transposed) if settings.bake_space_transform else None
+    if geom_mat_no is not None:
+        # Remove translation & scaling!
+        geom_mat_no.translation = Vector()
+        geom_mat_no.normalize()
+
     # TODO, use 'fbx_tmpl'
     elem_name_utf8 = elem_name_ensure_class(fbx_obj, b'Geometry')
 
@@ -913,6 +934,12 @@ def blen_read_geom(fbx_tmpl, fbx_obj, settings):
     fbx_polys = elem_prop_first(elem_find_first(fbx_obj, b'PolygonVertexIndex'))
     fbx_edges = elem_prop_first(elem_find_first(fbx_obj, b'Edges'))
 
+    if geom_mat_co is not None:
+        def _vcos_transformed_gen(raw_cos, m=None):
+            # Note: we could most likely get much better performances with numpy, but will leave this as TODO for now.
+            return chain(*(m * Vector(v) for v in zip(*(iter(raw_cos),) * 3)))
+        fbx_verts = array.array(fbx_verts.typecode, _vcos_transformed_gen(fbx_verts, geom_mat_co))
+
     if fbx_verts is None:
         fbx_verts = ()
     if fbx_polys is None:
@@ -978,7 +1005,12 @@ def blen_read_geom(fbx_tmpl, fbx_obj, settings):
     # must be after edge, face loading.
     ok_smooth = blen_read_geom_layer_smooth(fbx_obj, mesh)
 
-    ok_normals = blen_read_geom_layer_normal(fbx_obj, mesh)
+    if geom_mat_no is None:
+        ok_normals = blen_read_geom_layer_normal(fbx_obj, mesh)
+    else:
+        def nortrans(v):
+            return geom_mat_no * Vector(v)
+        ok_normals = blen_read_geom_layer_normal(fbx_obj, mesh, nortrans)
 
     mesh.validate()
 
@@ -1274,16 +1306,21 @@ class FbxImportHelperNode:
                 child.ignore = True  # Ignore leaf bone at end of chain
         for child in self.children:
             child.mark_leaf_bones()
-            
-    def find_correction_matrix(self, settings, parent_correction_inv = None):
+
+    def do_bake_transform(self, settings):
+        return (settings.bake_space_transform and self.fbx_type in (b'Mesh', b'Null') and
+                not self.is_armature and not self.is_bone)
+
+    def find_correction_matrix(self, settings, parent_correction_inv=None):
         from bpy_extras.io_utils import axis_conversion
         from mathutils import Matrix, Vector
 
-        if self.parent and self.parent.is_root:
+        if self.parent and (self.parent.is_root or self.parent.do_bake_transform(settings)):
             self.pre_matrix = settings.global_matrix
-        else:
-            self.pre_matrix = parent_correction_inv # if the parent has a correction we need the inverse applied here
-        
+
+        if parent_correction_inv:
+            self.pre_matrix = parent_correction_inv * (self.pre_matrix if self.pre_matrix else Matrix())
+
         correction_matrix = None
 
         if self.is_bone:
@@ -1372,7 +1409,10 @@ class FbxImportHelperNode:
                 correction_matrix = MAT_CONVERT_LAMP
 
         self.post_matrix = correction_matrix
-                    
+
+        if self.do_bake_transform(settings):
+            self.post_matrix = settings.global_matrix_inv * (self.post_matrix if self.post_matrix else Matrix())
+
         # process children
         correction_matrix_inv = correction_matrix.inverted() if correction_matrix else None
         for child in self.children:
@@ -1805,6 +1845,7 @@ def load(operator, context, filepath="",
          axis_forward='-Z',
          axis_up='Y',
          global_scale=1.0,
+         bake_space_transform=False,
          use_cycles=True,
          use_image_search=False,
          use_alpha_decals=False,
@@ -1894,6 +1935,11 @@ def load(operator, context, filepath="",
     global_matrix = (Matrix.Scale(global_scale, 4) *
                      axis_conversion(from_forward=axis_forward, from_up=axis_up).to_4x4())
 
+    # To cancel out unwanted rotation/scale on nodes.
+    global_matrix_inv = global_matrix.inverted()
+    # For transforming mesh normals.
+    global_matrix_inv_transposed = global_matrix_inv.transposed()
+
     # Compute bone correction matrix
     bone_correction_matrix = None  # None means no correction/identity
     if not automatic_bone_orientation:
@@ -1916,6 +1962,7 @@ def load(operator, context, filepath="",
     # store global settings that need to be accessed during conversion
     settings = FBXImportSettings(
         operator.report, (axis_up, axis_forward), global_matrix, global_scale,
+        bake_space_transform, global_matrix_inv, global_matrix_inv_transposed,
         use_cycles, use_image_search,
         use_alpha_decals, decal_offset,
         use_custom_props, use_custom_props_enum_as_string,



More information about the Bf-extensions-cvs mailing list