- Updated the depth plane node group to load from an asset and simplified the interface. - Created a new build script for depth plane geometry nodes. - Introduced material layer groups for image and depth materials with appropriate sockets. - Added functionality to connect balloon normal scale to the image material. - Enhanced tests to validate the new node groups and their connections. - Ensured that production code does not create node groups directly.
196 lines
8.2 KiB
Python
196 lines
8.2 KiB
Python
"""Build the image material Shader node groups."""
|
|
|
|
import bpy
|
|
|
|
from anyimage.operators.common.mesh_result import (
|
|
DEPTH_MATERIAL_NODE_GROUP_NAME,
|
|
IMAGE_MATERIAL_NODE_GROUP_NAME,
|
|
)
|
|
|
|
|
|
BUMP_BASE_DISTANCE = 0.001
|
|
MATERIAL_DISPLACEMENT_ATTRIBUTE = "o_material_displacement"
|
|
BACKGROUND_DEPTH_ATTRIBUTE = "o_background_depth"
|
|
DEPTH_SCALE_ATTRIBUTE = "o_depth_scale"
|
|
|
|
|
|
def build_material_layer_group(depth_plane=False):
|
|
group_name = (
|
|
DEPTH_MATERIAL_NODE_GROUP_NAME
|
|
if depth_plane
|
|
else 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"),
|
|
]
|
|
normal_group = not depth_plane
|
|
if normal_group:
|
|
input_sockets.insert(2, ("Normal", "NodeSocketColor"))
|
|
input_sockets.insert(3, ("Normal Scale", "NodeSocketFloat"))
|
|
input_sockets.insert(4, ("Object Space", "NodeSocketBool"))
|
|
if depth_plane:
|
|
input_sockets.insert(2, ("Depth", "NodeSocketFloat"))
|
|
for name, socket_type in input_sockets:
|
|
socket = interface.new_socket(
|
|
name=name,
|
|
in_out="INPUT",
|
|
socket_type=socket_type,
|
|
)
|
|
if name == "Alpha":
|
|
socket.default_value = 1.0
|
|
socket.min_value = 0.0
|
|
socket.max_value = 1.0
|
|
socket.subtype = "FACTOR"
|
|
elif name == "Bump Scale":
|
|
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.default_value = 1.0
|
|
socket.min_value = 0.0
|
|
socket.max_value = 10.0
|
|
elif name == "Object Space":
|
|
socket.default_value = False
|
|
output_sockets = [
|
|
("Color", "NodeSocketColor"),
|
|
("Roughness", "NodeSocketFloat"),
|
|
("Alpha", "NodeSocketFloat"),
|
|
("Normal", "NodeSocketVector"),
|
|
]
|
|
if depth_plane:
|
|
output_sockets.append(("Displacement", "NodeSocketVector"))
|
|
for name, socket_type in output_sockets:
|
|
interface.new_socket(
|
|
name=name,
|
|
in_out="OUTPUT",
|
|
socket_type=socket_type,
|
|
)
|
|
|
|
nodes = group.nodes
|
|
links = group.links
|
|
group_input = nodes.new("NodeGroupInput")
|
|
group_input.location = (-500.0, 100.0)
|
|
group_output = nodes.new("NodeGroupOutput")
|
|
group_output.location = (300.0, 100.0)
|
|
roughness_curve = nodes.new("ShaderNodeFloatCurve")
|
|
roughness_curve.mapping.initialize()
|
|
curve_points = roughness_curve.mapping.curves[0].points
|
|
curve_points[0].location = (0.0, 0.5)
|
|
curve_points[-1].location = (1.0, 0.1)
|
|
roughness_curve.mapping.update()
|
|
roughness_curve.location = (-250.0, 350.0)
|
|
bump = nodes.new("ShaderNodeBump")
|
|
bump.location = (100.0, 0.0)
|
|
if normal_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"])
|
|
displacement = None
|
|
|
|
processed_alpha = group_input.outputs["Alpha"]
|
|
bump_depth = group_input.outputs["Color"]
|
|
if depth_plane:
|
|
displacement = nodes.new("ShaderNodeDisplacement")
|
|
displacement.inputs["Midlevel"].default_value = 0.0
|
|
displacement.inputs["Scale"].default_value = 1.0
|
|
group_input.location = (-1200.0, 100.0)
|
|
group_output.location = (1050.0, 100.0)
|
|
roughness_curve.location = (-300.0, 450.0)
|
|
bump.location = (750.0, 50.0)
|
|
displacement.location = (750.0, -300.0)
|
|
background_attribute = nodes.new("ShaderNodeAttribute")
|
|
background_attribute.attribute_type = "GEOMETRY"
|
|
background_attribute.attribute_name = BACKGROUND_DEPTH_ATTRIBUTE
|
|
background_attribute.location = (-950.0, -500.0)
|
|
material_attribute = nodes.new("ShaderNodeAttribute")
|
|
material_attribute.attribute_type = "GEOMETRY"
|
|
material_attribute.attribute_name = MATERIAL_DISPLACEMENT_ATTRIBUTE
|
|
material_attribute.location = (-50.0, -650.0)
|
|
strength_attribute = nodes.new("ShaderNodeAttribute")
|
|
strength_attribute.attribute_type = "GEOMETRY"
|
|
strength_attribute.attribute_name = DEPTH_SCALE_ATTRIBUTE
|
|
strength_attribute.location = (200.0, -650.0)
|
|
foreground_mask = nodes.new("ShaderNodeMath")
|
|
foreground_mask.operation = "GREATER_THAN"
|
|
foreground_mask.inputs[1].default_value = 0.5
|
|
foreground_mask.location = (-950.0, -250.0)
|
|
clamp_foreground = nodes.new("ShaderNodeMath")
|
|
clamp_foreground.operation = "MAXIMUM"
|
|
clamp_foreground.location = (-650.0, -400.0)
|
|
masked_depth = nodes.new("ShaderNodeMix")
|
|
masked_depth.data_type = "FLOAT"
|
|
masked_depth.location = (-350.0, -350.0)
|
|
enabled_depth = nodes.new("ShaderNodeMath")
|
|
enabled_depth.operation = "MULTIPLY"
|
|
enabled_depth.location = (250.0, -350.0)
|
|
scaled_depth = nodes.new("ShaderNodeMath")
|
|
scaled_depth.operation = "MULTIPLY"
|
|
scaled_depth.location = (450.0, -350.0)
|
|
links.new(group_input.outputs["Alpha"], foreground_mask.inputs[0])
|
|
links.new(group_input.outputs["Depth"], clamp_foreground.inputs[0])
|
|
links.new(background_attribute.outputs["Fac"], clamp_foreground.inputs[1])
|
|
links.new(foreground_mask.outputs[0], masked_depth.inputs[0])
|
|
links.new(background_attribute.outputs["Fac"], masked_depth.inputs[2])
|
|
links.new(clamp_foreground.outputs[0], masked_depth.inputs[3])
|
|
links.new(masked_depth.outputs["Result"], enabled_depth.inputs[0])
|
|
links.new(material_attribute.outputs["Fac"], enabled_depth.inputs[1])
|
|
links.new(enabled_depth.outputs[0], scaled_depth.inputs[0])
|
|
links.new(strength_attribute.outputs["Fac"], scaled_depth.inputs[1])
|
|
processed_alpha = foreground_mask.outputs[0]
|
|
processed_depth = scaled_depth.outputs[0]
|
|
|
|
links.new(group_input.outputs["Color"], group_output.inputs["Color"])
|
|
links.new(group_input.outputs["Color"], roughness_curve.inputs["Value"])
|
|
links.new(
|
|
roughness_curve.outputs["Value"],
|
|
group_output.inputs["Roughness"],
|
|
)
|
|
links.new(processed_alpha, group_output.inputs["Alpha"])
|
|
links.new(bump_depth, bump.inputs["Height"])
|
|
bump_distance = nodes.new("ShaderNodeMath")
|
|
bump_distance.operation = "MULTIPLY"
|
|
bump_distance.inputs[1].default_value = BUMP_BASE_DISTANCE
|
|
bump_distance.location = (500.0, 100.0) if depth_plane else (-250.0, 150.0)
|
|
links.new(group_input.outputs["Bump Scale"], bump_distance.inputs[0])
|
|
links.new(bump_distance.outputs[0], bump.inputs["Distance"])
|
|
links.new(bump.outputs["Normal"], group_output.inputs["Normal"])
|
|
if displacement is not None:
|
|
links.new(processed_depth, displacement.inputs["Height"])
|
|
links.new(
|
|
displacement.outputs["Displacement"],
|
|
group_output.inputs["Displacement"],
|
|
)
|
|
group.color_tag = "SHADER"
|
|
group.description = (
|
|
"Prepare image depth material outputs."
|
|
if depth_plane
|
|
else f"Prepare {group_name} material outputs."
|
|
)
|
|
group.use_fake_user = True
|
|
return group
|