glTF exporter: Texture: Use default value when merging channels
[blender-addons.git] / io_scene_gltf2 / blender / exp / material / gltf2_blender_gather_materials_unlit.py
blobf90882c65f5107c03ef08f4cf86f53672e4af1de
1 # SPDX-FileCopyrightText: 2018-2022 The glTF-Blender-IO authors
3 # SPDX-License-Identifier: Apache-2.0
5 from ....io.com.gltf2_io_extensions import Extension
6 from ...exp import gltf2_blender_get
7 from . import gltf2_blender_gather_texture_info
9 def detect_shadeless_material(blender_material, export_settings):
10 """Detect if this material is "shadeless" ie. should be exported
11 with KHR_materials_unlit. Returns None if not. Otherwise, returns
12 a dict with info from parsing the node tree.
13 """
14 if not blender_material.use_nodes: return None
16 # Old Background node detection (unlikely to happen)
17 bg_socket = gltf2_blender_get.get_socket(blender_material, "Background")
18 if bg_socket is not None:
19 return {'rgb_socket': bg_socket}
21 # Look for
22 # * any color socket, connected to...
23 # * optionally, the lightpath trick, connected to...
24 # * optionally, a mix-with-transparent (for alpha), connected to...
25 # * the output node
27 info = {}
29 for node in blender_material.node_tree.nodes:
30 if node.type == 'OUTPUT_MATERIAL' and node.is_active_output:
31 socket = node.inputs[0]
32 break
33 else:
34 return None
36 # Be careful not to misidentify a lightpath trick as mix-alpha.
37 result = __detect_lightpath_trick(socket)
38 if result is not None:
39 socket = result['next_socket']
40 else:
41 result = __detect_mix_alpha(socket)
42 if result is not None:
43 socket = result['next_socket']
44 info['alpha_socket'] = result['alpha_socket']
46 result = __detect_lightpath_trick(socket)
47 if result is not None:
48 socket = result['next_socket']
50 # Check if a color socket, or connected to a color socket
51 if socket.type != 'RGBA':
52 from_socket = gltf2_blender_get.previous_socket(socket)
53 if from_socket is None: return None
54 if from_socket.type != 'RGBA': return None
56 info['rgb_socket'] = socket
57 return info
60 def __detect_mix_alpha(socket):
61 # Detects this (used for an alpha hookup)
63 # [ Mix ]
64 # alpha_socket => [Factor ] => socket
65 # [Transparent] => [Shader ]
66 # next_socket => [Shader ]
68 # Returns None if not detected. Otherwise, a dict containing alpha_socket
69 # and next_socket.
70 prev = gltf2_blender_get.previous_node(socket)
71 if prev is None or prev.type != 'MIX_SHADER': return None
72 in1 = gltf2_blender_get.previous_node(prev.inputs[1])
73 if in1 is None or in1.type != 'BSDF_TRANSPARENT': return None
74 return {
75 'alpha_socket': prev.inputs[0],
76 'next_socket': prev.inputs[2],
80 def __detect_lightpath_trick(socket):
81 # Detects this (used to prevent casting light on other objects) See ex.
82 # https://blender.stackexchange.com/a/21535/88681
84 # [ Lightpath ] [ Mix ]
85 # [ Is Camera Ray] => [Factor ] => socket
86 # (don't care) => [Shader ]
87 # next_socket => [ Emission ] => [Shader ]
89 # The Emission node can be omitted.
90 # Returns None if not detected. Otherwise, a dict containing
91 # next_socket.
92 prev = gltf2_blender_get.previous_node(socket)
93 if prev is None or prev.type != 'MIX_SHADER': return None
94 in0 = gltf2_blender_get.previous_socket(prev.inputs[0])
95 if in0 is None or in0.node.type != 'LIGHT_PATH': return None
96 if in0.name != 'Is Camera Ray': return None
97 next_socket = prev.inputs[2]
99 # Detect emission
100 prev = gltf2_blender_get.previous_node(next_socket)
101 if prev is not None and prev.type == 'EMISSION':
102 next_socket = prev.inputs[0]
104 return {'next_socket': next_socket}
107 def gather_base_color_factor(info, export_settings):
108 rgb, alpha = None, None
110 if 'rgb_socket' in info:
111 rgb = gltf2_blender_get.get_factor_from_socket(info['rgb_socket'], kind='RGB')
112 if 'alpha_socket' in info:
113 alpha = gltf2_blender_get.get_factor_from_socket(info['alpha_socket'], kind='VALUE')
115 if rgb is None: rgb = [1.0, 1.0, 1.0]
116 if alpha is None: alpha = 1.0
118 rgba = [*rgb, alpha]
119 if rgba == [1, 1, 1, 1]: return None
120 return rgba
123 def gather_base_color_texture(info, export_settings):
124 sockets = (info.get('rgb_socket'), info.get('alpha_socket'))
125 sockets = tuple(s for s in sockets if s is not None)
126 if sockets:
127 # NOTE: separate RGB and Alpha textures will not get combined
128 # because gather_image determines how to pack images based on the
129 # names of sockets, and the names are hard-coded to a Principled
130 # style graph.
131 unlit_texture, unlit_use_active_uvmap, _ = gltf2_blender_gather_texture_info.gather_texture_info(
132 sockets[0],
133 sockets,
135 export_settings,
137 return unlit_texture, ["unlitTexture"] if unlit_use_active_uvmap else None
138 return None, None