From e40eb73496f6d1dbc13ee7c38b45f1c9e54eb939 Mon Sep 17 00:00:00 2001 From: Julien Duroure Date: Wed, 16 Aug 2023 12:05:03 +0200 Subject: [PATCH] merge channels (metallic/Roughness) : use default value --- ...ltf2_blender_gather_materials_clearcoat.py | 2 ++ ...gltf2_blender_gather_materials_emission.py | 2 +- .../gltf2_blender_gather_materials_sheen.py | 2 ++ ...gltf2_blender_gather_materials_specular.py | 3 +++ ...2_blender_gather_materials_transmission.py | 1 + .../gltf2_blender_gather_materials_volume.py | 1 + .../extensions/gltf2_blender_image.py | 10 +++++++ .../material/gltf2_blender_gather_image.py | 27 ++++++++++++++----- .../gltf2_blender_gather_materials.py | 2 +- ...gather_materials_pbr_metallic_roughness.py | 7 ++++- .../gltf2_blender_gather_materials_unlit.py | 1 + .../material/gltf2_blender_gather_texture.py | 7 ++--- .../gltf2_blender_gather_texture_info.py | 19 ++++++++----- 13 files changed, 65 insertions(+), 19 deletions(-) diff --git a/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_clearcoat.py b/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_clearcoat.py index d14f625f1..33d5cdd00 100644 --- a/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_clearcoat.py +++ b/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_clearcoat.py @@ -65,6 +65,7 @@ def export_clearcoat(blender_material, export_settings): clearcoat_texture, clearcoat_texture_use_active_uvmap, _ = gltf2_blender_gather_texture_info.gather_texture_info( clearcoat_socket, clearcoat_roughness_slots, + (), export_settings, ) clearcoat_extension['clearcoatTexture'] = clearcoat_texture @@ -74,6 +75,7 @@ def export_clearcoat(blender_material, export_settings): clearcoat_roughness_texture, clearcoat_roughness_texture_use_active_uvmap, _ = gltf2_blender_gather_texture_info.gather_texture_info( clearcoat_roughness_socket, clearcoat_roughness_slots, + (), export_settings, ) clearcoat_extension['clearcoatRoughnessTexture'] = clearcoat_roughness_texture diff --git a/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_emission.py b/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_emission.py index 0895a68d4..b93012118 100644 --- a/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_emission.py +++ b/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_emission.py @@ -62,7 +62,7 @@ def export_emission_texture(blender_material, export_settings): emissive = gltf2_blender_get.get_socket(blender_material, "Emissive") if emissive is None: emissive = gltf2_blender_get.get_socket_old(blender_material, "Emissive") - emissive_texture, use_actives_uvmap_emissive, _ = gltf2_blender_gather_texture_info.gather_texture_info(emissive, (emissive,), export_settings) + emissive_texture, use_actives_uvmap_emissive, _ = gltf2_blender_gather_texture_info.gather_texture_info(emissive, (emissive,), (), export_settings) return emissive_texture, ["emissiveTexture"] if use_actives_uvmap_emissive else None def export_emission_strength_extension(emissive_factor, export_settings): diff --git a/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_sheen.py b/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_sheen.py index e44031789..b590087cd 100644 --- a/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_sheen.py +++ b/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_sheen.py @@ -50,6 +50,7 @@ def export_sheen(blender_material, export_settings): original_sheenColor_texture, original_sheenColor_use_active_uvmap, _ = gltf2_blender_gather_texture_info.gather_texture_info( sheenColor_socket, (sheenColor_socket,), + (), export_settings, ) sheen_extension['sheenColorTexture'] = original_sheenColor_texture @@ -74,6 +75,7 @@ def export_sheen(blender_material, export_settings): original_sheenRoughness_texture, original_sheenRoughness_use_active_uvmap, _ = gltf2_blender_gather_texture_info.gather_texture_info( sheenRoughness_socket, (sheenRoughness_socket,), + (), export_settings, ) sheen_extension['sheenRoughnessTexture'] = original_sheenRoughness_texture diff --git a/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_specular.py b/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_specular.py index 98f6d99e0..7c67542d8 100644 --- a/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_specular.py +++ b/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_specular.py @@ -49,6 +49,7 @@ def export_original_specular(blender_material, export_settings): original_specular_texture, original_specular_use_active_uvmap, _ = gltf2_blender_gather_texture_info.gather_texture_info( original_specular_socket, (original_specular_socket,), + (), export_settings, ) specular_extension['specularTexture'] = original_specular_texture @@ -71,6 +72,7 @@ def export_original_specular(blender_material, export_settings): original_specularcolor_texture, original_specularcolor_use_active_uvmap, _ = gltf2_blender_gather_texture_info.gather_texture_info( original_specularcolor_socket, (original_specularcolor_socket,), + (), export_settings, ) specular_extension['specularColorTexture'] = original_specularcolor_texture @@ -162,6 +164,7 @@ def normalize(c): specularColorTexture, use_active_uvmap, specularColorFactor = gltf2_blender_gather_texture_info.gather_texture_info( primary_socket, sockets, + (), export_settings, filter_type='ANY') if specularColorTexture is None: diff --git a/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_transmission.py b/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_transmission.py index 67e681b54..c38014014 100644 --- a/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_transmission.py +++ b/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_transmission.py @@ -48,6 +48,7 @@ def export_transmission(blender_material, export_settings): combined_texture, use_active_uvmap, _ = gltf2_blender_gather_texture_info.gather_texture_info( transmission_socket, transmission_slots, + (), export_settings, ) if has_transmission_texture: diff --git a/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_volume.py b/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_volume.py index b893535d4..a8971c276 100644 --- a/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_volume.py +++ b/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_gather_materials_volume.py @@ -76,6 +76,7 @@ def export_volume(blender_material, export_settings): combined_texture, use_active_uvmap, _ = gltf2_blender_gather_texture_info.gather_texture_info( thicknesss_socket, thickness_slots, + (), export_settings, ) if has_thickness_texture: diff --git a/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_image.py b/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_image.py index 7aa8a7069..b9b926cba 100644 --- a/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_image.py +++ b/addons/io_scene_gltf2/blender/exp/material/extensions/gltf2_blender_image.py @@ -38,6 +38,11 @@ class FillWhite: """Fills a channel with all ones (1.0).""" pass +class FillWith: + """Fills a channel with all same values""" + def __init__(self, value): + self.value = value + class StoreData: def __init__(self, data): """Store numeric data (not an image channel""" @@ -109,6 +114,9 @@ def store_data(self, identifier, data, type='Image'): def fill_white(self, dst_chan: Channel): self.fills[dst_chan] = FillWhite() + def fill_with(self, dst_chan, value): + self.fills[dst_chan] = FillWith(value) + def is_filled(self, chan: Channel) -> bool: return chan in self.fills @@ -193,6 +201,8 @@ def __encode_unhappy(self, export_settings) -> bytes: for dst_chan, fill in self.fills.items(): if isinstance(fill, FillImage) and fill.image == image: out_buf[int(dst_chan)::4] = tmp_buf[int(fill.src_chan)::4] + elif isinstance(fill, FillWith): + out_buf[int(dst_chan)::4] = fill.value tmp_buf = None # GC this diff --git a/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_image.py b/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_image.py index 7ae46adf1..5c90cd16f 100644 --- a/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_image.py +++ b/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_image.py @@ -28,11 +28,12 @@ @cached def gather_image( blender_shader_sockets: typing.Tuple[bpy.types.NodeSocket], + default_sockets: typing.Tuple[bpy.types.NodeSocket], export_settings): if not __filter_image(blender_shader_sockets, export_settings): return None, None - image_data = __get_image_data(blender_shader_sockets, export_settings) + image_data = __get_image_data(blender_shader_sockets, default_sockets, export_settings) if image_data.empty(): # The export image has no data return None, None @@ -184,7 +185,7 @@ def __gather_uri(image_data, mime_type, name, export_settings): return None, None -def __get_image_data(sockets, export_settings) -> ExportImage: +def __get_image_data(sockets, default_sockets, export_settings) -> ExportImage: # For shared resources, such as images, we just store the portion of data that is needed in the glTF property # in a helper class. During generation of the glTF in the exporter these will then be combined to actual binary # resources. @@ -194,14 +195,22 @@ def __get_image_data(sockets, export_settings) -> ExportImage: if any([socket.name == "Specular" and socket.node.type == "BSDF_PRINCIPLED" for socket in sockets]): return __get_image_data_specular(sockets, results, export_settings) else: - return __get_image_data_mapping(sockets, results, export_settings) + return __get_image_data_mapping(sockets, default_sockets, results, export_settings) -def __get_image_data_mapping(sockets, results, export_settings) -> ExportImage: +def __get_image_data_mapping(sockets, default_sockets, results, export_settings) -> ExportImage: """ Simple mapping Will fit for most of exported textures : RoughnessMetallic, Basecolor, normal, ... """ composed_image = ExportImage() + + default_metallic = None + default_roughness = None + if "Metallic" in [s.name for s in default_sockets]: + default_metallic = [s for s in default_sockets if s.name == "Metallic"][0].default_value + if "Roughness" in [s.name for s in default_sockets]: + default_roughness = [s for s in default_sockets if s.name == "Roughness"][0].default_value + for result, socket in zip(results, sockets): # Assume that user know what he does, and that channels/images are already combined correctly for pbr # If not, we are going to keep only the first texture found @@ -252,9 +261,15 @@ def __get_image_data_mapping(sockets, results, export_settings) -> ExportImage: # Since metal/roughness are always used together, make sure # the other channel is filled. if socket.name == 'Metallic' and not composed_image.is_filled(Channel.G): - composed_image.fill_white(Channel.G) + if default_roughness is not None: + composed_image.fill_with(Channel.G, default_roughness) + else: + composed_image.fill_white(Channel.G) elif socket.name == 'Roughness' and not composed_image.is_filled(Channel.B): - composed_image.fill_white(Channel.B) + if default_metallic is not None: + composed_image.fill_with(Channel.B, default_metallic) + else: + composed_image.fill_white(Channel.B) else: # copy full image...eventually following sockets might overwrite things composed_image = ExportImage.from_blender_image(result.shader_node.image) diff --git a/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_materials.py b/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_materials.py index ea0b47eeb..1fdd78903 100644 --- a/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_materials.py +++ b/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_materials.py @@ -340,7 +340,7 @@ def __gather_orm_texture(blender_material, export_settings): return None # Double-check this will past the filter in texture_info - info, info_use_active_uvmap, _ = gltf2_blender_gather_texture_info.gather_texture_info(result[0], result, export_settings) + info, info_use_active_uvmap, _ = gltf2_blender_gather_texture_info.gather_texture_info(result[0], result, (), export_settings) if info is None: return None diff --git a/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_materials_pbr_metallic_roughness.py b/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_materials_pbr_metallic_roughness.py index 3d245c81b..fcb1600a4 100644 --- a/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_materials_pbr_metallic_roughness.py +++ b/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_materials_pbr_metallic_roughness.py @@ -108,7 +108,7 @@ def __gather_base_color_texture(blender_material, export_settings): if not inputs: return None, None, None - return gltf2_blender_gather_texture_info.gather_texture_info(inputs[0], inputs, export_settings) + return gltf2_blender_gather_texture_info.gather_texture_info(inputs[0], inputs, (), export_settings) def __gather_extensions(blender_material, export_settings): @@ -139,6 +139,7 @@ def __gather_metallic_roughness_texture(blender_material, orm_texture, export_se hasMetal = metallic_socket is not None and __has_image_node_from_socket(metallic_socket) hasRough = roughness_socket is not None and __has_image_node_from_socket(roughness_socket) + default_sockets = () if not hasMetal and not hasRough: metallic_roughness = gltf2_blender_get.get_socket_old(blender_material, "MetallicRoughness") if metallic_roughness is None or not __has_image_node_from_socket(metallic_roughness): @@ -146,14 +147,18 @@ def __gather_metallic_roughness_texture(blender_material, orm_texture, export_se texture_input = (metallic_roughness,) elif not hasMetal: texture_input = (roughness_socket,) + default_sockets = (metallic_socket,) elif not hasRough: texture_input = (metallic_socket,) + default_sockets = (roughness_socket,) else: texture_input = (metallic_socket, roughness_socket) + default_sockets = () return gltf2_blender_gather_texture_info.gather_texture_info( texture_input[0], orm_texture or texture_input, + default_sockets, export_settings, ) diff --git a/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_materials_unlit.py b/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_materials_unlit.py index ef9d9b161..325844cba 100644 --- a/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_materials_unlit.py +++ b/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_materials_unlit.py @@ -141,6 +141,7 @@ def gather_base_color_texture(info, export_settings): unlit_texture, unlit_use_active_uvmap, _ = gltf2_blender_gather_texture_info.gather_texture_info( sockets[0], sockets, + (), export_settings, ) return unlit_texture, ["unlitTexture"] if unlit_use_active_uvmap else None diff --git a/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_texture.py b/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_texture.py index b995094ff..033e79306 100644 --- a/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_texture.py +++ b/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_texture.py @@ -25,6 +25,7 @@ @cached def gather_texture( blender_shader_sockets: typing.Tuple[bpy.types.NodeSocket], + default_sockets: typing.Tuple[bpy.types.NodeSocket], export_settings): """ Gather texture sampling information and image channels from a blender shader texture attached to a shader socket. @@ -37,7 +38,7 @@ def gather_texture( if not __filter_texture(blender_shader_sockets, export_settings): return None, None - source, factor = __gather_source(blender_shader_sockets, export_settings) + source, factor = __gather_source(blender_shader_sockets, default_sockets, export_settings) texture = gltf2_io.Texture( extensions=__gather_extensions(blender_shader_sockets, export_settings), @@ -88,8 +89,8 @@ def __gather_sampler(blender_shader_sockets, export_settings): export_settings) -def __gather_source(blender_shader_sockets, export_settings): - return gltf2_blender_gather_image.gather_image(blender_shader_sockets, export_settings) +def __gather_source(blender_shader_sockets, default_sockets, export_settings): + return gltf2_blender_gather_image.gather_image(blender_shader_sockets, default_sockets, export_settings) # Helpers diff --git a/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_texture_info.py b/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_texture_info.py index 2369d4c1b..e3925191b 100644 --- a/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_texture_info.py +++ b/addons/io_scene_gltf2/blender/exp/material/gltf2_blender_gather_texture_info.py @@ -29,20 +29,25 @@ # occlusion the primary_socket would be the occlusion socket, and # blender_shader_sockets would be the (O,R,M) sockets. -def gather_texture_info(primary_socket, blender_shader_sockets, export_settings, filter_type='ALL'): - return __gather_texture_info_helper(primary_socket, blender_shader_sockets, 'DEFAULT', filter_type, export_settings) +# Default socket parameter is used when there is a mapping between channels, and one of the channel is not a texture +# In that case, we will create a texture with one channel from texture, other from default socket value +# Example: MetallicRoughness + +def gather_texture_info(primary_socket, blender_shader_sockets, default_sockets, export_settings, filter_type='ALL'): + return __gather_texture_info_helper(primary_socket, blender_shader_sockets, default_sockets, 'DEFAULT', filter_type, export_settings) def gather_material_normal_texture_info_class(primary_socket, blender_shader_sockets, export_settings, filter_type='ALL'): - return __gather_texture_info_helper(primary_socket, blender_shader_sockets, 'NORMAL', filter_type, export_settings) + return __gather_texture_info_helper(primary_socket, blender_shader_sockets, (), 'NORMAL', filter_type, export_settings) def gather_material_occlusion_texture_info_class(primary_socket, blender_shader_sockets, export_settings, filter_type='ALL'): - return __gather_texture_info_helper(primary_socket, blender_shader_sockets, 'OCCLUSION', filter_type, export_settings) + return __gather_texture_info_helper(primary_socket, blender_shader_sockets, (), 'OCCLUSION', filter_type, export_settings) @cached def __gather_texture_info_helper( primary_socket: bpy.types.NodeSocket, blender_shader_sockets: typing.Tuple[bpy.types.NodeSocket], + default_sockets: typing.Tuple[bpy.types.NodeSocket], kind: str, filter_type: str, export_settings): @@ -51,7 +56,7 @@ def __gather_texture_info_helper( tex_transform, tex_coord, use_active_uvmap = __gather_texture_transform_and_tex_coord(primary_socket, export_settings) - index, factor = __gather_index(blender_shader_sockets, export_settings) + index, factor = __gather_index(blender_shader_sockets, default_sockets, export_settings) fields = { 'extensions': __gather_extensions(tex_transform, export_settings), @@ -146,9 +151,9 @@ def __gather_occlusion_strength(primary_socket, export_settings): return None -def __gather_index(blender_shader_sockets, export_settings): +def __gather_index(blender_shader_sockets, default_sockets, export_settings): # We just put the actual shader into the 'index' member - return gltf2_blender_gather_texture.gather_texture(blender_shader_sockets, export_settings) + return gltf2_blender_gather_texture.gather_texture(blender_shader_sockets, default_sockets, export_settings) def __gather_texture_transform_and_tex_coord(primary_socket, export_settings):