"""Build O Image Layer.""" import bpy from anyimage.common.material import IMAGE_MATERIAL_NODE_GROUP_NAME from ..common.shader import build_material_nodes, connect_material_outputs def build_image_layer_group(): group_name = IMAGE_MATERIAL_NODE_GROUP_NAME existing = bpy.data.node_groups.get(group_name) if existing is not None: return existing group = bpy.data.node_groups.new(group_name, 'ShaderNodeTree') interface = group.interface input_sockets = [('Color', 'NodeSocketColor'), ('Alpha', 'NodeSocketFloat'), ('Bump Scale', 'NodeSocketFloat')] input_sockets.insert(2, ('Normal', 'NodeSocketColor')) input_sockets.insert(3, ('Normal Scale', 'NodeSocketFloat')) input_sockets.insert(4, ('Object Space', 'NodeSocketBool')) input_sockets.insert(2, ('Alpha Fix', 'NodeSocketFloat')) options = interface.new_panel(name='Options', default_closed=True) option_names = {'Alpha Fix', 'Normal Scale', 'Object Space'} for name, socket_type in input_sockets: socket = interface.new_socket(name=name, in_out='INPUT', socket_type=socket_type, parent=options if name in option_names else None) if name in {'Alpha', 'Alpha Fix'}: socket.default_value = 1.0 if name == 'Alpha' else 0.0 socket.min_value = 0.0 socket.max_value = 1.0 socket.subtype = 'FACTOR' elif name == 'Bump Scale': socket.description = 'Control bump detail derived from image brightness. Negative values reverse the bumps. Zero disables the effect.' socket.default_value = 0.0 socket.min_value = -10000.0 socket.max_value = 10000.0 elif name == 'Normal': socket.default_value = (0.5, 0.5, 1.0, 1.0) elif name == 'Normal Scale': socket.description = 'Control the strength of surface detail from the normal map.' socket.default_value = 1.0 socket.min_value = 0.0 socket.max_value = 10.0 elif name == 'Object Space': socket.description = 'Interpret the normal map in object space when enabled, or tangent space when disabled.' socket.default_value = False if name == 'Alpha Fix': socket.description = 'Reduce semi-transparent fringes around image edges. Higher values remove more faint edge pixels. Zero keeps the original transparency.' output_sockets = [('Color', 'NodeSocketColor'), ('Roughness', 'NodeSocketFloat'), ('Alpha', 'NodeSocketFloat'), ('Normal', 'NodeSocketVector')] for name, socket_type in output_sockets: interface.new_socket(name=name, in_out='OUTPUT', socket_type=socket_type) nodes, links = group.nodes, group.links group_input, group_output, roughness_curve, bump = build_material_nodes(group) tangent_normal = nodes.new('ShaderNodeNormalMap') tangent_normal.space = 'TANGENT' tangent_normal.location = (-500.0, -100.0) object_normal = nodes.new('ShaderNodeNormalMap') object_normal.space = 'OBJECT' object_normal.location = (-500.0, -350.0) choose_normal = nodes.new('ShaderNodeMix') choose_normal.data_type = 'VECTOR' choose_normal.location = (-150.0, -150.0) for normal_map in (tangent_normal, object_normal): links.new(group_input.outputs['Normal'], normal_map.inputs['Color']) links.new(group_input.outputs['Normal Scale'], normal_map.inputs['Strength']) links.new(group_input.outputs['Object Space'], choose_normal.inputs[0]) links.new(tangent_normal.outputs['Normal'], choose_normal.inputs[4]) links.new(object_normal.outputs['Normal'], choose_normal.inputs[5]) links.new(choose_normal.outputs['Result'], bump.inputs['Normal']) processed_alpha = group_input.outputs['Alpha'] alpha_curve = nodes.new('ShaderNodeFloatCurve') alpha_curve.mapping.initialize() alpha_curve.mapping.extend = 'HORIZONTAL' alpha_curve.mapping.use_clip = True alpha_points = alpha_curve.mapping.curves[0].points alpha_points[0].location = (0.0, 0.0) alpha_points[-1].location = (1.0, 1.0) alpha_points.new(0.8, 0.0) alpha_points.new(0.925, 0.925) for point in alpha_points: point.handle_type = 'AUTO_CLAMPED' alpha_curve.mapping.update() group_input.location = (-750.0, 150.0) group_output.location = (350.0, 450.0) alpha_curve.location = (-350.0, 1100.0) roughness_curve.location = (-350.0, 650.0) links.new(group_input.outputs['Alpha'], alpha_curve.inputs['Value']) links.new(group_input.outputs['Alpha Fix'], alpha_curve.inputs['Factor']) processed_alpha = alpha_curve.outputs['Value'] connect_material_outputs(group, group_input, group_output, roughness_curve, bump, processed_alpha, (-250.0, 150.0)) group.color_tag = 'SHADER' group.description = f'Prepare {group_name} material outputs.' group.use_fake_user = True for node in nodes: for socket in node.outputs: socket.hide = not socket.is_linked return group