Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #1956 merge channels (metallic/Roughness) : use default value #1968

Merged
merged 6 commits into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def export_original_specular(blender_material, export_settings):
original_specular_texture, original_specular_use_active_uvmap, _ = gather_texture_info(
original_specular_socket,
(original_specular_socket,),
(),
export_settings,
)
specular_extension['specularTexture'] = original_specular_texture
Expand All @@ -72,6 +73,7 @@ def export_original_specular(blender_material, export_settings):
original_specularcolor_texture, original_specularcolor_use_active_uvmap, _ = gather_texture_info(
original_specularcolor_socket,
(original_specularcolor_socket,),
(),
export_settings,
)
specular_extension['specularColorTexture'] = original_specularcolor_texture
Expand Down Expand Up @@ -162,6 +164,7 @@ def normalize(c):
specularColorTexture, use_active_uvmap, specularColorFactor = gather_texture_info(
primary_socket,
sockets,
(),
export_settings,
filter_type='ANY')
if specularColorTexture is None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"""
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ def gather_material(blender_material, active_uvmap_index, export_settings):
export_user_extensions('gather_material_hook', export_settings, mat_unlit, blender_material)
return mat_unlit

orm_texture = __gather_orm_texture(blender_material, export_settings)
orm_texture, default_sockets = __gather_orm_texture(blender_material, export_settings)

emissive_factor = __gather_emissive_factor(blender_material, export_settings)
emissive_texture, uvmap_actives_emissive_texture = __gather_emissive_texture(blender_material, export_settings)
extensions, uvmap_actives_extensions = __gather_extensions(blender_material, emissive_factor, export_settings)
normal_texture, uvmap_actives_normal_texture = __gather_normal_texture(blender_material, export_settings)
occlusion_texture, uvmap_actives_occlusion_texture = __gather_occlusion_texture(blender_material, orm_texture, export_settings)
occlusion_texture, uvmap_actives_occlusion_texture = __gather_occlusion_texture(blender_material, orm_texture, default_sockets, export_settings)
pbr_metallic_roughness, uvmap_actives_pbr_metallic_roughness = __gather_pbr_metallic_roughness(blender_material, orm_texture, export_settings)

if any([i>1.0 for i in emissive_factor or []]) is True:
Expand Down Expand Up @@ -313,46 +313,51 @@ def __gather_orm_texture(blender_material, export_settings):
if occlusion is None or not gltf2_blender_get.has_image_node_from_socket(occlusion):
occlusion = gltf2_blender_get.get_socket_old(blender_material, "Occlusion")
if occlusion is None or not gltf2_blender_get.has_image_node_from_socket(occlusion):
return None
return None, None

metallic_socket = gltf2_blender_get.get_socket(blender_material, "Metallic")
roughness_socket = gltf2_blender_get.get_socket(blender_material, "Roughness")

hasMetal = metallic_socket is not None and gltf2_blender_get.has_image_node_from_socket(metallic_socket)
hasRough = roughness_socket is not None and gltf2_blender_get.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 gltf2_blender_get.has_image_node_from_socket(metallic_roughness):
return None
return None, default_sockets
result = (occlusion, metallic_roughness)
elif not hasMetal:
result = (occlusion, roughness_socket)
default_sockets = (metallic_socket,)
elif not hasRough:
result = (occlusion, metallic_socket)
default_sockets = (roughness_socket,)
else:
result = (occlusion, roughness_socket, metallic_socket)
default_sockets = ()

if not gltf2_blender_gather_texture_info.check_same_size_images(result):
print_console("INFO",
"Occlusion and metal-roughness texture will be exported separately "
"(use same-sized images if you want them combined)")
return None
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, default_sockets, export_settings)
if info is None:
return None
return None, ()

return result
return result, default_sockets

def __gather_occlusion_texture(blender_material, orm_texture, export_settings):
def __gather_occlusion_texture(blender_material, orm_texture, default_sockets, export_settings):
occlusion = gltf2_blender_get.get_socket(blender_material, "Occlusion")
if occlusion is None:
occlusion = gltf2_blender_get.get_socket_old(blender_material, "Occlusion")
occlusion_texture, use_active_uvmap_occlusion, _ = gltf2_blender_gather_texture_info.gather_material_occlusion_texture_info_class(
occlusion,
orm_texture or (occlusion,),
default_sockets,
export_settings)
return occlusion_texture, ["occlusionTexture"] if use_active_uvmap_occlusion else None

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def __gather_base_color_texture(blender_material, export_settings):
if not inputs:
return None, None, None

return gather_texture_info(inputs[0], inputs, export_settings)
return gather_texture_info(inputs[0], inputs, (), export_settings)


def __gather_extensions(blender_material, export_settings):
Expand Down Expand Up @@ -139,21 +139,26 @@ def __gather_metallic_roughness_texture(blender_material, orm_texture, export_se
hasMetal = metallic_socket is not None and image_tex_is_valid_from_socket(metallic_socket)
hasRough = roughness_socket is not None and image_tex_is_valid_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 image_tex_is_valid_from_socket(metallic_roughness):
return None, None, None
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 gather_texture_info(
texture_input[0],
orm_texture or texture_input,
default_sockets,
export_settings,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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),
Expand Down Expand Up @@ -88,5 +89,5 @@ 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)
Original file line number Diff line number Diff line change
Expand Up @@ -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)
def gather_material_occlusion_texture_info_class(primary_socket, blender_shader_sockets, default_sockets, export_settings, filter_type='ALL'):
return __gather_texture_info_helper(primary_socket, blender_shader_sockets, default_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):
Expand All @@ -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),
Expand Down Expand Up @@ -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):
Expand Down
Binary file added tests/scenes/08_tiny-box-__b_roughness_0.2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/scenes/08_tiny-box-_g_metallic_0.1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/scenes/08_tiny-box-r_b_roughness_0.2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/scenes/08_tiny-box-rg_metallic_0.1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading