Add "Triangulate Faces" option to FBX export

I noticed the FBX export was missing a triangulation option seen in other software and other Blender exporters such as .obj.

This feature is rather useful for example for ensuring consistent normal map baking in third party software, where tangent space gets easily messed up with tools using mikktspace that depends on triangulation choices.

This patch adds a "Triangulate Faces" option in the export options similarly to what the Wavefront OBJ exporter has. Diff-wise it's rather simple by reusing the temporary mesh creation from "Apply Modifiers".

Reviewed By: mont29

Differential Revision: https://developer.blender.org/D14352
This commit is contained in:
Samuli Raivio 2022-03-28 09:36:27 +02:00 committed by Bastien Montagne
parent 0f6165054b
commit d700a6888e
3 changed files with 22 additions and 4 deletions

View File

@ -5,7 +5,7 @@
bl_info = {
"name": "FBX format",
"author": "Campbell Barton, Bastien Montagne, Jens Restemeier",
"version": (4, 34, 2),
"version": (4, 35, 0),
"blender": (3, 2, 0),
"location": "File > Import-Export",
"description": "FBX IO meshes, UV's, vertex colors, materials, textures, cameras, lamps and actions",
@ -477,6 +477,11 @@ class ExportFBX(bpy.types.Operator, ExportHelper):
"(will only work correctly with tris/quads only meshes!)",
default=False,
)
use_triangles: BoolProperty(
name="Triangulate Faces",
description="Convert all faces to triangles",
default=False,
)
use_custom_props: BoolProperty(
name="Custom Properties",
description="Export custom properties",
@ -754,6 +759,7 @@ class FBX_PT_export_geometry(bpy.types.Panel):
#sub.enabled = operator.use_mesh_modifiers and False # disabled in 2.8...
#sub.prop(operator, "use_mesh_modifiers_render")
layout.prop(operator, "use_mesh_edges")
layout.prop(operator, "use_triangles")
sub = layout.row()
#~ sub.enabled = operator.mesh_smooth_type in {'OFF'}
sub.prop(operator, "use_tspace")

View File

@ -2266,12 +2266,14 @@ def fbx_data_from_scene(scene, depsgraph, settings):
is_ob_material = any(ms.link == 'OBJECT' for ms in ob.material_slots)
if settings.use_mesh_modifiers or ob.type in BLENDER_OTHER_OBJECT_TYPES or is_ob_material:
if settings.use_mesh_modifiers or settings.use_triangles or ob.type in BLENDER_OTHER_OBJECT_TYPES or is_ob_material:
# 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':
if settings.use_triangles:
use_org_data = False
# No need to create a new mesh in this case, if no modifier is active!
last_subsurf = None
for mod in ob.modifiers:
@ -2316,6 +2318,14 @@ def fbx_data_from_scene(scene, depsgraph, settings):
# free them afterwards. Not ideal but ensures correct ownerwhip.
tmp_me = bpy.data.meshes.new_from_object(
ob_to_convert, preserve_all_data_layers=True, depsgraph=depsgraph)
# Triangulate the mesh if requested
if settings.use_triangles:
import bmesh
bm = bmesh.new()
bm.from_mesh(tmp_me)
bmesh.ops.triangulate(bm, faces=bm.faces)
bm.to_mesh(tmp_me)
bm.free()
data_meshes[ob_obj] = (get_blenderID_key(tmp_me), tmp_me, True)
# Change armatures back.
for armature, pose_position in backup_pose_positions:
@ -3008,6 +3018,7 @@ def save_single(operator, scene, depsgraph, filepath="",
path_mode='AUTO',
use_mesh_edges=True,
use_tspace=True,
use_triangles=False,
embed_textures=False,
use_custom_props=False,
bake_space_transform=False,
@ -3074,7 +3085,7 @@ def save_single(operator, scene, depsgraph, filepath="",
operator.report, (axis_up, axis_forward), global_matrix, global_scale, apply_unit_scale, unit_scale,
bake_space_transform, global_matrix_inv, global_matrix_inv_transposed,
context_objects, object_types, use_mesh_modifiers, use_mesh_modifiers_render,
mesh_smooth_type, use_subsurf, use_mesh_edges, use_tspace,
mesh_smooth_type, use_subsurf, use_mesh_edges, use_tspace, use_triangles,
armature_nodetype, use_armature_deform_only,
add_leaf_bones, bone_correction_matrix, bone_correction_matrix_inv,
bake_anim, bake_anim_use_all_bones, bake_anim_use_nla_strips, bake_anim_use_all_actions,
@ -3148,6 +3159,7 @@ def defaults_unity3d():
"mesh_smooth_type": 'FACE',
"use_subsurf": False,
"use_tspace": False, # XXX Why? Unity is expected to support tspace import...
"use_triangles": False,
"use_armature_deform_only": True,

View File

@ -1210,7 +1210,7 @@ FBXExportSettings = namedtuple("FBXExportSettings", (
"report", "to_axes", "global_matrix", "global_scale", "apply_unit_scale", "unit_scale",
"bake_space_transform", "global_matrix_inv", "global_matrix_inv_transposed",
"context_objects", "object_types", "use_mesh_modifiers", "use_mesh_modifiers_render",
"mesh_smooth_type", "use_subsurf", "use_mesh_edges", "use_tspace",
"mesh_smooth_type", "use_subsurf", "use_mesh_edges", "use_tspace", "use_triangles",
"armature_nodetype", "use_armature_deform_only", "add_leaf_bones",
"bone_correction_matrix", "bone_correction_matrix_inv",
"bake_anim", "bake_anim_use_all_bones", "bake_anim_use_nla_strips", "bake_anim_use_all_actions",