def detect_manual_uv_wrapping(blender_shader_node): # Detects UV wrapping done using math nodes. This is for emulating wrap # modes Blender doesn't support. It looks like # # next_socket => [Sep XYZ] => [Wrap S] => [Comb XYZ] => blender_shader_node # => [Wrap T] => # # The [Wrap _] blocks are either math nodes (eg. PINGPONG for mirrored # repeat), or can be omitted. # # Returns None if not detected. Otherwise a dict containing the wrap # mode in each direction (or None), and next_socket. result = {} comb = previous_node(blender_shader_node.inputs['Vector']) if comb is None or comb.type != 'COMBXYZ': return None for soc in ['X', 'Y']: node = previous_node(comb.inputs[soc]) if node is None: return None if node.type == 'SEPXYZ': # Passed through without change wrap = None prev_socket = previous_socket(comb.inputs[soc]) elif node.type == 'MATH': # Math node applies a manual wrap if (node.operation == 'PINGPONG' and get_const_from_socket( node.inputs[1], kind='VALUE') == 1.0): # scale = 1 wrap = TextureWrap.MirroredRepeat elif (node.operation == 'WRAP' and get_const_from_socket( node.inputs[1], kind='VALUE') == 0.0 and # min = 0 get_const_from_socket(node.inputs[2], kind='VALUE') == 1.0): # max = 1 wrap = TextureWrap.Repeat else: return None prev_socket = previous_socket(node.inputs[0]) else: return None if prev_socket is None: return None prev_node = prev_socket.node if prev_node.type != 'SEPXYZ': return None # Make sure X goes to X, etc. if prev_socket.name != soc: return None # Make sure both attach to the same SeparateXYZ node if soc == 'X': sep = prev_node else: if sep != prev_node: return None result['wrap_s' if soc == 'X' else 'wrap_t'] = wrap result['next_socket'] = sep.inputs[0] return result
def __gather_occlusion_strength(primary_socket, export_settings): # Look for a MixRGB node that mixes with pure white in front of # primary_socket. The mix factor gives the occlusion strength. node = gltf2_blender_get.previous_node(primary_socket) if node and node.type == 'MIX_RGB' and node.blend_type == 'MIX': fac = gltf2_blender_get.get_const_from_socket(node.inputs['Fac'], kind='VALUE') col1 = gltf2_blender_get.get_const_from_socket(node.inputs['Color1'], kind='RGB') col2 = gltf2_blender_get.get_const_from_socket(node.inputs['Color2'], kind='RGB') if fac is not None: if col1 == [1, 1, 1] and col2 is None: return fac if col1 is None and col2 == [1, 1, 1]: return 1.0 - fac # reversed for reversed inputs return None
def __gather_emissive_factor(blender_material, export_settings): emissive_socket = gltf2_blender_get.get_socket(blender_material, "Emissive") if emissive_socket is None: emissive_socket = gltf2_blender_get.get_socket_old( blender_material, "EmissiveFactor") if isinstance(emissive_socket, bpy.types.NodeSocket): if export_settings['gltf_image_format'] != "NONE": factor = gltf2_blender_get.get_factor_from_socket(emissive_socket, kind='RGB') else: factor = gltf2_blender_get.get_const_from_default_value_socket( emissive_socket, kind='RGB') if factor is None and emissive_socket.is_linked: # In glTF, the default emissiveFactor is all zeros, so if an emission texture is connected, # we have to manually set it to all ones. factor = [1.0, 1.0, 1.0] if factor is None: factor = [0.0, 0.0, 0.0] # Handle Emission Strength strength_socket = None if emissive_socket.node.type == 'EMISSION': strength_socket = emissive_socket.node.inputs['Strength'] elif 'Emission Strength' in emissive_socket.node.inputs: strength_socket = emissive_socket.node.inputs['Emission Strength'] strength = (gltf2_blender_get.get_const_from_socket(strength_socket, kind='VALUE') if strength_socket is not None else None) if strength is not None: factor = [f * strength for f in factor] # Clamp to range [0,1] factor = [min(1.0, f) for f in factor] if factor == [0, 0, 0]: factor = None return factor return None