[Bf-extensions-cvs] [f1dd37b8] master: Add optional subdivision surface support to the FBX exporter

Samuli Raivio noreply at git.blender.org
Thu Aug 29 12:17:17 CEST 2019


Commit: f1dd37b8ac8f2db93f56002bae24e70b2cbf986f
Author: Samuli Raivio
Date:   Thu Aug 29 12:01:39 2019 +0200
Branches: master
https://developer.blender.org/rBAf1dd37b8ac8f2db93f56002bae24e70b2cbf986f

Add optional subdivision surface support to the FBX exporter

Add option 'Export Subdivision Surface' to the FBX exporter (disabled by default).
When enabled the exporter will write the **last active Catmull-Clark subdivision surface modifier**
as FBX properties instead of applying it.

Edge crease data is also written to the FBX file if 'Use Creases' is enabled in the subsurf modifier.

Reviewers: mont29

Tags: #add-ons

Differential Revision: https://developer.blender.org/D4982

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

M	io_scene_fbx/__init__.py
M	io_scene_fbx/export_fbx_bin.py
M	io_scene_fbx/fbx_utils.py
M	io_scene_fbx/import_fbx.py

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

diff --git a/io_scene_fbx/__init__.py b/io_scene_fbx/__init__.py
index bb9528af..ebbf2a19 100644
--- a/io_scene_fbx/__init__.py
+++ b/io_scene_fbx/__init__.py
@@ -21,7 +21,7 @@
 bl_info = {
     "name": "FBX format",
     "author": "Campbell Barton, Bastien Montagne, Jens Restemeier",
-    "version": (4, 14, 15),
+    "version": (4, 15, 0),
     "blender": (2, 80, 0),
     "location": "File > Import-Export",
     "description": "FBX IO meshes, UV's, vertex colors, materials, textures, cameras, lamps and actions",
@@ -131,6 +131,12 @@ class ImportFBX(bpy.types.Operator, ImportHelper):
             default=1.0,
             )
 
+    use_subsurf: BoolProperty(
+            name="Import Subdivision Surface",
+            description="Import FBX subdivision information as subdivision surface modifiers",
+            default=False,
+            )
+
     use_custom_props: BoolProperty(
             name="Import User Properties",
             description="Import user properties as custom properties",
@@ -205,6 +211,8 @@ class ImportFBX(bpy.types.Operator, ImportHelper):
             layout.prop(self, "use_anim")
             layout.prop(self, "anim_offset")
 
+            layout.prop(self, "use_subsurf")
+
             layout.prop(self, "use_custom_props")
             sub = layout.row()
             sub.enabled = self.use_custom_props
@@ -334,6 +342,12 @@ class ExportFBX(bpy.types.Operator, ExportHelper):
                         "(prefer 'Normals Only' option if your target importer understand split normals)",
             default='OFF',
             )
+    use_subsurf: BoolProperty(
+            name="Export Subdivision Surface",
+            description="Export the last Catmull-Rom subidivion modifier as FBX subdivision "
+                        "(Does not apply the modifier even if 'Apply Modifiers' is enabled)",
+            default=False,
+            )
     use_mesh_edges: BoolProperty(
             name="Loose Edges",
             description="Export loose edges (as two-vertices polygons)",
@@ -507,6 +521,7 @@ class ExportFBX(bpy.types.Operator, ExportHelper):
             sub.enabled = self.use_mesh_modifiers and False  # disabled in 2.8...
             sub.prop(self, "use_mesh_modifiers_render")
             layout.prop(self, "mesh_smooth_type")
+            layout.prop(self, "use_subsurf")
             layout.prop(self, "use_mesh_edges")
             sub = layout.row()
             #~ sub.enabled = self.mesh_smooth_type in {'OFF'}
diff --git a/io_scene_fbx/export_fbx_bin.py b/io_scene_fbx/export_fbx_bin.py
index 9292d656..5cba16e6 100644
--- a/io_scene_fbx/export_fbx_bin.py
+++ b/io_scene_fbx/export_fbx_bin.py
@@ -49,7 +49,7 @@ from .fbx_utils import (
     FBX_VERSION, FBX_HEADER_VERSION, FBX_SCENEINFO_VERSION, FBX_TEMPLATES_VERSION,
     FBX_MODELS_VERSION,
     FBX_GEOMETRY_VERSION, FBX_GEOMETRY_NORMAL_VERSION, FBX_GEOMETRY_BINORMAL_VERSION, FBX_GEOMETRY_TANGENT_VERSION,
-    FBX_GEOMETRY_SMOOTHING_VERSION, FBX_GEOMETRY_VCOLOR_VERSION, FBX_GEOMETRY_UV_VERSION,
+    FBX_GEOMETRY_SMOOTHING_VERSION, FBX_GEOMETRY_CREASE_VERSION, FBX_GEOMETRY_VCOLOR_VERSION, FBX_GEOMETRY_UV_VERSION,
     FBX_GEOMETRY_MATERIAL_VERSION, FBX_GEOMETRY_LAYER_VERSION,
     FBX_GEOMETRY_SHAPE_VERSION, FBX_DEFORMER_SHAPE_VERSION, FBX_DEFORMER_SHAPECHANNEL_VERSION,
     FBX_POSE_BIND_VERSION, FBX_DEFORMER_SKIN_VERSION, FBX_DEFORMER_CLUSTER_VERSION,
@@ -865,6 +865,30 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes):
     if scene_data.settings.use_custom_props:
         fbx_data_element_custom_properties(props, me)
 
+    # Subdivision levels. Take them from the first found subsurf modifier from the
+    # first object that has the mesh. Write crease information if the object has
+    # and subsurf modifier.
+    write_crease = False
+    if scene_data.settings.use_subsurf:
+        last_subsurf = None
+        for mod in me_obj.bdata.modifiers:
+            if not (mod.show_render or mod.show_viewport):
+                continue
+            if mod.type == 'SUBSURF' and mod.subdivision_type == 'CATMULL_CLARK':
+                last_subsurf = mod
+
+        if last_subsurf:
+            elem_data_single_int32(geom, b"Smoothness", 2) # Display control mesh and smoothed
+            elem_data_single_int32(geom, b"BoundaryRule", 2) # Round edges like Blender
+            elem_data_single_int32(geom, b"PreviewDivisionLevels", last_subsurf.levels)
+            elem_data_single_int32(geom, b"RenderDivisionLevels", last_subsurf.render_levels)
+
+            elem_data_single_int32(geom, b"PreserveBorders", 0)
+            elem_data_single_int32(geom, b"PreserveHardEdges", 0)
+            elem_data_single_int32(geom, b"PropagateEdgeHardness", 0)
+
+            write_crease = mod.use_creases
+
     elem_data_single_int32(geom, b"GeometryVersion", FBX_GEOMETRY_VERSION)
 
     # Vertex cos.
@@ -980,7 +1004,21 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes):
         elem_data_single_int32_array(lay_smooth, b"Smoothing", t_ps)  # Sight, int32 for bool...
         del t_ps
 
-    # TODO: Edge crease (LayerElementCrease).
+    # Edge crease for subdivision
+    if write_crease:
+        t_ec = array.array(data_types.ARRAY_FLOAT64, (0.0,)) * edges_nbr
+        for e in me.edges:
+            if e.key not in edges_map:
+                continue  # Only loose edges, in theory!
+            t_ec[edges_map[e.key]] = e.crease
+
+        lay_crease = elem_data_single_int32(geom, b"LayerElementEdgeCrease", 0)
+        elem_data_single_int32(lay_crease, b"Version", FBX_GEOMETRY_CREASE_VERSION)
+        elem_data_single_string(lay_crease, b"Name", b"")
+        elem_data_single_string(lay_crease, b"MappingInformationType", b"ByEdge")
+        elem_data_single_string(lay_crease, b"ReferenceInformationType", b"Direct")
+        elem_data_single_float64_array(lay_crease, b"EdgeCrease", t_ec)
+        del t_ec
 
     # And we are done with edges!
     del edges_map
@@ -1193,6 +1231,10 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes):
         lay_smooth = elem_empty(layer, b"LayerElement")
         elem_data_single_string(lay_smooth, b"Type", b"LayerElementSmoothing")
         elem_data_single_int32(lay_smooth, b"TypedIndex", 0)
+    if write_crease:
+        lay_smooth = elem_empty(layer, b"LayerElement")
+        elem_data_single_string(lay_smooth, b"Type", b"LayerElementEdgeCrease")
+        elem_data_single_int32(lay_smooth, b"TypedIndex", 0)
     if vcolnumber:
         lay_vcol = elem_empty(layer, b"LayerElement")
         elem_data_single_string(lay_vcol, b"Type", b"LayerElementColor")
@@ -2217,8 +2259,10 @@ def fbx_data_from_scene(scene, depsgraph, settings):
             # We cannot use default mesh in that case, or material would not be the right ones...
             use_org_data = not (is_ob_material or ob.type in BLENDER_OTHER_OBJECT_TYPES)
             backup_pose_positions = []
+            tmp_mods = []
             if use_org_data and ob.type == 'MESH':
                 # No need to create a new mesh in this case, if no modifier is active!
+                last_subsurf = None
                 for mod in ob.modifiers:
                     # For meshes, when armature export is enabled, disable Armature modifiers here!
                     # XXX Temp hacks here since currently we only have access to a viewport depsgraph...
@@ -2232,10 +2276,24 @@ def fbx_data_from_scene(scene, depsgraph, settings):
                             backup_pose_positions.append((armature, armature.pose_position))
                             armature.pose_position = 'REST'
                     elif mod.show_render or mod.show_viewport:
-                        use_org_data = False
+                        # If exporting with subsurf collect the last Catmull-Clark subsurf modifier
+                        # and disable it. We can use the original data as long as this is the first
+                        # found applicable subsurf modifier.
+                        if settings.use_subsurf and mod.type == 'SUBSURF' and mod.subdivision_type == 'CATMULL_CLARK':
+                            if last_subsurf:
+                                use_org_data = False
+                            last_subsurf = mod
+                        else:
+                            use_org_data = False
+                if settings.use_subsurf and last_subsurf:
+                    # XXX: When exporting with subsurf information temporarily disable
+                    # the last subsurf modifier.
+                    tmp_mods.append((last_subsurf, last_subsurf.show_render, last_subsurf.show_viewport))
+                    last_subsurf.show_render = False
+                    last_subsurf.show_viewport = False
             if not use_org_data:
                 # If modifiers has been altered need to update dependency graph.
-                if backup_pose_positions:
+                if backup_pose_positions or tmp_mods:
                     depsgraph.update()
                 ob_to_convert = ob.evaluated_get(depsgraph) if settings.use_mesh_modifiers else ob
                 # NOTE: The dependency graph might be re-evaluating multiple times, which could
@@ -2249,6 +2307,11 @@ def fbx_data_from_scene(scene, depsgraph, settings):
                 print((armature, pose_position))
                 armature.pose_position = pose_position
                 # Update now, so we don't leave modified state after last object was exported.
+            # Re-enable temporary disabled modifiers.
+            for mod, show_render, show_viewport in tmp_mods:
+                mod.show_render = show_render
+                mod.show_viewport = show_viewport
+            if backup_pose_positions or tmp_mods:
                 depsgraph.update()
         if use_org_data:
             data_meshes[ob_obj] = (get_blenderID_key(ob.data), ob.data, False)
@@ -2913,6 +2976,7 @@ def save_single(operator, scene, depsgraph, filepath="",
                 use_mesh_modifiers=True,
                 use_mesh_modifiers_render=True,
                 mesh_smooth_type='FACE',
+                use_subsurf=False,
                 use_armature_deform_only=False,
                 bake_anim=True,
                 bak

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list