"""Build the Depth Plane Geometry Nodes group.""" import bpy DEPTH_PLANE_NODE_GROUP_NAME = "O Image Depth Plane" def _interface_socket(group, name, in_out, socket_type): socket = group.interface.new_socket( name=name, in_out=in_out, socket_type=socket_type, ) if in_out == "INPUT" and hasattr(socket, "structure_type"): socket.structure_type = "SINGLE" return socket def _group_input(nodes, location, visible_names): node = nodes.new("NodeGroupInput") node.location = location visible = set(visible_names) for output in node.outputs: output.hide = output.name not in visible return node def build_depth_plane_group(mesh_plane_group): group = bpy.data.node_groups.get(DEPTH_PLANE_NODE_GROUP_NAME) if group is not None: return group group = bpy.data.node_groups.new( DEPTH_PLANE_NODE_GROUP_NAME, "GeometryNodeTree", ) group.is_modifier = True _interface_socket(group, "Geometry", "INPUT", "NodeSocketGeometry") subdivide = _interface_socket(group, "Subdivide", "INPUT", "NodeSocketInt") subdivide.default_value = 7 subdivide.min_value = 0 subdivide.max_value = 10 thickness = _interface_socket(group, "Thickness", "INPUT", "NodeSocketFloat") thickness.default_value = 0.1 thickness.min_value = 0.0 thickness.subtype = "DISTANCE" depth_amount = _interface_socket(group, "Depth Amount", "INPUT", "NodeSocketFloat") depth_amount.default_value = 1.0 depth_amount.min_value = 0.0 reference_depth = _interface_socket( group, "Reference Depth", "INPUT", "NodeSocketFloat" ) reference_depth.hide_in_modifier = True uniform_scale = _interface_socket( group, "Uniform Scale", "INPUT", "NodeSocketFloat" ) uniform_scale.hide_in_modifier = True depth_image = _interface_socket(group, "Depth Image", "INPUT", "NodeSocketImage") depth_image.hide_in_modifier = True material = _interface_socket(group, "Material", "INPUT", "NodeSocketMaterial") material.hide_in_modifier = True _interface_socket(group, "Geometry", "OUTPUT", "NodeSocketGeometry") nodes = group.nodes links = group.links geometry_input = _group_input( nodes, (-1850.0, 450.0), {"Geometry", "Subdivide", "Material"}, ) shape_input = _group_input( nodes, (-1250.0, 850.0), {"Thickness", "Depth Amount"}, ) image_input = _group_input( nodes, (-1050.0, 50.0), {"Depth Image", "Reference Depth", "Uniform Scale"}, ) cleanup_input = _group_input(nodes, (650.0, -200.0), {"Thickness"}) group_output = nodes.new("NodeGroupOutput") group_output.location = (1850.0, 450.0) mesh_plane = nodes.new("GeometryNodeGroup") mesh_plane.node_tree = mesh_plane_group mesh_plane.inputs["Thickness"].default_value = 0.0 mesh_plane.location = (-1550.0, 450.0) links.new(geometry_input.outputs["Geometry"], mesh_plane.inputs["Geometry"]) links.new(geometry_input.outputs["Subdivide"], mesh_plane.inputs["Subdivide"]) links.new(geometry_input.outputs["Material"], mesh_plane.inputs["Material"]) extrude = nodes.new("GeometryNodeExtrudeMesh") extrude.mode = "FACES" extrude.inputs["Offset"].default_value = (0.0, 0.0, -1.0) extrude.inputs["Individual"].default_value = False extrude.location = (-1200.0, 450.0) links.new(mesh_plane.outputs["Geometry"], extrude.inputs["Mesh"]) links.new(shape_input.outputs["Thickness"], extrude.inputs["Offset Scale"]) geometry = extrude.outputs["Mesh"] uv = nodes.new("GeometryNodeInputNamedAttribute") uv.data_type = "FLOAT_VECTOR" uv.inputs["Name"].default_value = "UVMap" uv.location = (-1000.0, 50.0) texture = nodes.new("GeometryNodeImageTexture") texture.location = (-800.0, 50.0) links.new(image_input.outputs["Depth Image"], texture.inputs["Image"]) links.new(uv.outputs["Attribute"], texture.inputs["Vector"]) separate = nodes.new("ShaderNodeSeparateXYZ") separate.location = (-600.0, 50.0) links.new(texture.outputs["Color"], separate.inputs["Vector"]) relative_depth = nodes.new("ShaderNodeMath") relative_depth.operation = "SUBTRACT" relative_depth.location = (-600.0, -150.0) links.new(image_input.outputs["Reference Depth"], relative_depth.inputs[0]) links.new(separate.outputs["X"], relative_depth.inputs[1]) local_depth = nodes.new("ShaderNodeMath") local_depth.operation = "MULTIPLY" local_depth.location = (-350.0, -150.0) links.new(relative_depth.outputs[0], local_depth.inputs[0]) links.new(image_input.outputs["Uniform Scale"], local_depth.inputs[1]) raw_depth = nodes.new("ShaderNodeMath") raw_depth.operation = "MULTIPLY" raw_depth.location = (-100.0, 150.0) links.new(local_depth.outputs[0], raw_depth.inputs[0]) links.new(shape_input.outputs["Depth Amount"], raw_depth.inputs[1]) inward_limit = nodes.new("ShaderNodeMath") inward_limit.operation = "MULTIPLY" inward_limit.inputs[1].default_value = -0.98 inward_limit.location = (-100.0, -50.0) links.new(shape_input.outputs["Thickness"], inward_limit.inputs[0]) clamp = nodes.new("ShaderNodeMath") clamp.operation = "MAXIMUM" clamp.location = (150.0, 50.0) links.new(raw_depth.outputs[0], clamp.inputs[0]) links.new(inward_limit.outputs[0], clamp.inputs[1]) has_thickness = nodes.new("ShaderNodeMath") has_thickness.operation = "GREATER_THAN" has_thickness.inputs[1].default_value = 1e-6 has_thickness.location = (-100.0, -350.0) links.new(shape_input.outputs["Thickness"], has_thickness.inputs[0]) choose_depth = nodes.new("GeometryNodeSwitch") choose_depth.input_type = "FLOAT" choose_depth.location = (400.0, 50.0) links.new(has_thickness.outputs[0], choose_depth.inputs["Switch"]) links.new(raw_depth.outputs[0], choose_depth.inputs["False"]) links.new(clamp.outputs[0], choose_depth.inputs["True"]) combine = nodes.new("ShaderNodeCombineXYZ") combine.location = (600.0, 50.0) links.new(choose_depth.outputs["Output"], combine.inputs["Z"]) front = nodes.new("FunctionNodeBooleanMath") front.operation = "NOT" front.location = (400.0, 300.0) links.new(extrude.outputs["Top"], front.inputs[0]) set_position = nodes.new("GeometryNodeSetPosition") set_position.location = (800.0, 450.0) links.new(geometry, set_position.inputs["Geometry"]) links.new(front.outputs[0], set_position.inputs["Selection"]) links.new(combine.outputs["Vector"], set_position.inputs["Offset"]) geometry = set_position.outputs["Geometry"] zero_thickness = nodes.new("ShaderNodeMath") zero_thickness.operation = "LESS_THAN" zero_thickness.inputs[1].default_value = 1e-6 zero_thickness.location = (1000.0, -150.0) links.new(cleanup_input.outputs["Thickness"], zero_thickness.inputs[0]) back_or_side = nodes.new("FunctionNodeBooleanMath") back_or_side.operation = "OR" back_or_side.location = (1000.0, 150.0) links.new(extrude.outputs["Top"], back_or_side.inputs[0]) links.new(extrude.outputs["Side"], back_or_side.inputs[1]) delete_selection = nodes.new("FunctionNodeBooleanMath") delete_selection.operation = "AND" delete_selection.location = (1200.0, 50.0) links.new(zero_thickness.outputs[0], delete_selection.inputs[0]) links.new(back_or_side.outputs[0], delete_selection.inputs[1]) delete_geometry = nodes.new("GeometryNodeDeleteGeometry") delete_geometry.domain = "FACE" delete_geometry.location = (1350.0, 450.0) links.new(geometry, delete_geometry.inputs["Geometry"]) links.new(delete_selection.outputs[0], delete_geometry.inputs["Selection"]) shade_smooth = nodes.new("GeometryNodeSetShadeSmooth") shade_smooth.domain = "FACE" shade_smooth.inputs["Shade Smooth"].default_value = True shade_smooth.location = (1600.0, 450.0) links.new(delete_geometry.outputs["Geometry"], shade_smooth.inputs["Geometry"]) links.new(shade_smooth.outputs["Geometry"], group_output.inputs["Geometry"]) group.use_fake_user = True return group