FBX IO: Export normals with IndexToDirect reference mode #105020

Merged
Thomas Barlow merged 3 commits from Mysteryem/blender-addons:fbx_normals_IndexToDirect into main 2023-12-02 02:08:21 +01:00
3 changed files with 33 additions and 38 deletions

View File

@ -5,7 +5,7 @@
bl_info = { bl_info = {
"name": "FBX format", "name": "FBX format",
"author": "Campbell Barton, Bastien Montagne, Jens Restemeier, @Mysteryem", "author": "Campbell Barton, Bastien Montagne, Jens Restemeier, @Mysteryem",
"version": (5, 10, 3), "version": (5, 11, 0),
"blender": (4, 1, 0), "blender": (4, 1, 0),
"location": "File > Import-Export", "location": "File > Import-Export",
"description": "FBX IO meshes, UVs, vertex colors, materials, textures, cameras, lamps and actions", "description": "FBX IO meshes, UVs, vertex colors, materials, textures, cameras, lamps and actions",

View File

@ -1155,10 +1155,6 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes):
# Loop normals. # Loop normals.
tspacenumber = 0 tspacenumber = 0
if write_normals: if write_normals:
# NOTE: ByVertice-IndexToDirect is not supported by the importer currently.
# XXX Official docs says normals should use IndexToDirect,
# but this does not seem well supported by apps currently...
normal_bl_dtype = np.single normal_bl_dtype = np.single
normal_fbx_dtype = np.float64 normal_fbx_dtype = np.float64
match me.normals_domain: match me.normals_domain:
@ -1182,12 +1178,12 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes):
t_normal = np.empty(len(normal_source) * 3, dtype=normal_bl_dtype) t_normal = np.empty(len(normal_source) * 3, dtype=normal_bl_dtype)
normal_source.foreach_get("vector", t_normal) normal_source.foreach_get("vector", t_normal)
t_normal = nors_transformed(t_normal, geom_mat_no, normal_fbx_dtype) t_normal = nors_transformed(t_normal, geom_mat_no, normal_fbx_dtype)
if 0:
normal_idx_fbx_dtype = np.int32 normal_idx_fbx_dtype = np.int32
lay_nor = elem_data_single_int32(geom, b"LayerElementNormal", 0) lay_nor = elem_data_single_int32(geom, b"LayerElementNormal", 0)
elem_data_single_int32(lay_nor, b"Version", FBX_GEOMETRY_NORMAL_VERSION) elem_data_single_int32(lay_nor, b"Version", FBX_GEOMETRY_NORMAL_VERSION)
elem_data_single_string(lay_nor, b"Name", b"") elem_data_single_string(lay_nor, b"Name", b"")
elem_data_single_string(lay_nor, b"MappingInformationType", normal_mapping) elem_data_single_string(lay_nor, b"MappingInformationType", normal_mapping)
# FBX SDK documentation says that normals should use IndexToDirect.
elem_data_single_string(lay_nor, b"ReferenceInformationType", b"IndexToDirect") elem_data_single_string(lay_nor, b"ReferenceInformationType", b"IndexToDirect")
# Tuple of unique sorted normals and then the index in the unique sorted normals of each normal in t_normal. # Tuple of unique sorted normals and then the index in the unique sorted normals of each normal in t_normal.
@ -1207,16 +1203,6 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes):
del t_normal_idx del t_normal_idx
# del t_normal_w # del t_normal_w
else:
lay_nor = elem_data_single_int32(geom, b"LayerElementNormal", 0)
elem_data_single_int32(lay_nor, b"Version", FBX_GEOMETRY_NORMAL_VERSION)
elem_data_single_string(lay_nor, b"Name", b"")
elem_data_single_string(lay_nor, b"MappingInformationType", normal_mapping)
elem_data_single_string(lay_nor, b"ReferenceInformationType", b"Direct")
elem_data_single_float64_array(lay_nor, b"Normals", t_normal)
# Normal weights, no idea what it is.
# t_normal = np.zeros(len(me.loops), dtype=np.float64)
# elem_data_single_float64_array(lay_nor, b"NormalsW", t_normal)
del t_normal del t_normal
# tspace # tspace

View File

@ -1398,7 +1398,18 @@ def blen_read_geom_array_mapped_vert(
xform=None, quiet=False, xform=None, quiet=False,
): ):
if fbx_layer_mapping == b'ByVertice': if fbx_layer_mapping == b'ByVertice':
if fbx_layer_ref == b'Direct': if fbx_layer_ref == b'IndexToDirect':
# XXX Looks like we often get no fbx_layer_index in this case, shall not happen but happens...
# We fallback to 'Direct' mapping in this case.
#~ assert(fbx_layer_index is not None)
if fbx_layer_index is None:
blen_read_geom_array_foreach_set_direct(blen_data, blen_attr, blen_dtype, fbx_layer_data, stride,
item_size, descr, xform)
else:
blen_read_geom_array_foreach_set_indexed(blen_data, blen_attr, blen_dtype, fbx_layer_data,
fbx_layer_index, stride, item_size, descr, xform)
return True
elif fbx_layer_ref == b'Direct':
assert(fbx_layer_index is None) assert(fbx_layer_index is None)
blen_read_geom_array_foreach_set_direct(blen_data, blen_attr, blen_dtype, fbx_layer_data, stride, item_size, blen_read_geom_array_foreach_set_direct(blen_data, blen_attr, blen_dtype, fbx_layer_data, stride, item_size,
descr, xform) descr, xform)
@ -1754,8 +1765,6 @@ def blen_read_geom_layer_normal(fbx_obj, mesh, xform=None):
loop_normals = np.repeat(bdata, poly_loop_totals, axis=0) loop_normals = np.repeat(bdata, poly_loop_totals, axis=0)
mesh.attributes["temp_custom_normals"].data.foreach_set("vector", loop_normals.ravel()) mesh.attributes["temp_custom_normals"].data.foreach_set("vector", loop_normals.ravel())
elif blen_data_type == "Vertices": elif blen_data_type == "Vertices":
# Note: Currently unreachable because `blen_read_geom_array_mapped_polyloop` covers all the supported
# import cases covered by `blen_read_geom_array_mapped_vert`.
# We have to copy vnors to lnors! Far from elegant, but simple. # We have to copy vnors to lnors! Far from elegant, but simple.
loop_vertex_indices = MESH_ATTRIBUTE_CORNER_VERT.to_ndarray(mesh.attributes) loop_vertex_indices = MESH_ATTRIBUTE_CORNER_VERT.to_ndarray(mesh.attributes)
mesh.attributes["temp_custom_normals"].data.foreach_set("vector", bdata[loop_vertex_indices].ravel()) mesh.attributes["temp_custom_normals"].data.foreach_set("vector", bdata[loop_vertex_indices].ravel())