Refactor comparison operations in geometry nodes
- Introduced a new `compare_node` function to streamline comparison operations across various geometry nodes. - Replaced instances of mathematical comparison nodes with the new `compare_node` function in multiple files, enhancing code readability and maintainability. - Updated related logic in cutout, depth surface, and image processing groups to utilize the new comparison method. - Ensured consistent handling of boolean logic through the introduction of a `boolean_node` function for combining boolean inputs.
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
"""Build O Image Cutout."""
|
||||
import bpy
|
||||
from anyimage.operators.cutout_tool.shape import NORMAL_REDUCTION_ATTRIBUTE_NAME
|
||||
from ..common.nodes import interface_socket, group_input, math_node, float_input, menu_switch, read_float_attribute, store_float_attribute, prepare_node_group
|
||||
from ..common.nodes import (
|
||||
interface_socket, group_input, compare_node, math_node, float_input,
|
||||
menu_switch, read_float_attribute, store_float_attribute, prepare_node_group,
|
||||
)
|
||||
from ..common.cutout import _extrude_layers, _offset_geometry_y, _set_layer_y, _shade_output
|
||||
|
||||
|
||||
@@ -24,15 +27,12 @@ def _set_segmented_layer_y(
|
||||
links.new(edge_vertices.outputs["Position 1"], edge_length.inputs[0])
|
||||
links.new(edge_vertices.outputs["Position 2"], edge_length.inputs[1])
|
||||
edge_neighbors = nodes.new("GeometryNodeInputMeshEdgeNeighbors")
|
||||
boundary = math_node(nodes, "COMPARE")
|
||||
boundary.inputs[1].default_value = 1.0
|
||||
boundary.inputs[2].default_value = 0.1
|
||||
links.new(edge_neighbors.outputs["Face Count"], boundary.inputs[0])
|
||||
boundary = compare_node(group, "EQUAL", edge_neighbors.outputs["Face Count"], 1, data_type="INT")
|
||||
statistics = nodes.new("GeometryNodeAttributeStatistic")
|
||||
statistics.data_type = "FLOAT"
|
||||
statistics.domain = "EDGE"
|
||||
links.new(geometry, statistics.inputs["Geometry"])
|
||||
links.new(boundary.outputs[0], statistics.inputs["Selection"])
|
||||
links.new(boundary, statistics.inputs["Selection"])
|
||||
links.new(edge_length.outputs["Value"], statistics.inputs["Attribute"])
|
||||
safe_edge = math_node(nodes, "MAXIMUM")
|
||||
safe_edge.inputs[1].default_value = 1e-6
|
||||
@@ -108,12 +108,10 @@ def _set_segmented_layer_y(
|
||||
def _build_shell(group, geometry, thickness):
|
||||
nodes = group.nodes
|
||||
links = group.links
|
||||
zero = math_node(nodes, "LESS_THAN")
|
||||
zero.inputs[1].default_value = 1e-6
|
||||
links.new(thickness, zero.inputs[0])
|
||||
zero = compare_node(group, "LESS_THAN", thickness, 1e-6)
|
||||
choose = nodes.new("GeometryNodeSwitch")
|
||||
choose.input_type = "GEOMETRY"
|
||||
links.new(zero.outputs[0], choose.inputs["Switch"])
|
||||
links.new(zero, choose.inputs["Switch"])
|
||||
links.new(geometry, choose.inputs["True"])
|
||||
front = math_node(nodes, "MULTIPLY")
|
||||
front.inputs[1].default_value = 0.0
|
||||
@@ -135,12 +133,10 @@ def _build_shell(group, geometry, thickness):
|
||||
def _build_balloon(group, geometry, thickness):
|
||||
nodes = group.nodes
|
||||
links = group.links
|
||||
zero = math_node(nodes, "LESS_THAN")
|
||||
zero.inputs[1].default_value = 1e-6
|
||||
links.new(thickness, zero.inputs[0])
|
||||
zero = compare_node(group, "LESS_THAN", thickness, 1e-6)
|
||||
choose = nodes.new("GeometryNodeSwitch")
|
||||
choose.input_type = "GEOMETRY"
|
||||
links.new(zero.outputs[0], choose.inputs["Switch"])
|
||||
links.new(zero, choose.inputs["Switch"])
|
||||
links.new(geometry, choose.inputs["True"])
|
||||
profile = read_float_attribute(group, 'o_balloon')
|
||||
front_scale = math_node(nodes, "MULTIPLY")
|
||||
@@ -183,13 +179,11 @@ def build_image_cutout_group():
|
||||
geometry = choose.outputs[0]
|
||||
profile = read_float_attribute(group, 'o_balloon')
|
||||
amount = group_input(group.nodes, {'Thickness'})
|
||||
enabled = math_node(group.nodes, 'GREATER_THAN')
|
||||
enabled.inputs[1].default_value = 1e-06
|
||||
group.links.new(amount.outputs['Thickness'], enabled.inputs[0])
|
||||
enabled = compare_node(group, 'GREATER_THAN', amount.outputs['Thickness'], 1e-6)
|
||||
inflated = group.nodes.new('GeometryNodeSwitch')
|
||||
inflated.input_type = 'FLOAT'
|
||||
inflated.inputs['False'].default_value = 1
|
||||
group.links.new(enabled.outputs[0], inflated.inputs['Switch'])
|
||||
group.links.new(enabled, inflated.inputs['Switch'])
|
||||
group.links.new(profile, inflated.inputs['True'])
|
||||
mode = menu_switch(group, 'Mode', ('Balloon', 'Shell'), 'FLOAT')
|
||||
mode.inputs['Shell'].default_value = 1
|
||||
|
||||
@@ -6,7 +6,8 @@ from anyimage.operators.cutout_tool.shape import NORMAL_REDUCTION_ATTRIBUTE_NAME
|
||||
|
||||
from ..common.nodes import (
|
||||
interface_socket, group_input, float_input, bool_input, vector_input,
|
||||
evaluate_field, store_float_attribute, read_float_attribute, prepare_node_group,
|
||||
compare_node, evaluate_field, store_float_attribute, read_float_attribute,
|
||||
prepare_node_group,
|
||||
)
|
||||
from ..common.depth_surface import _math
|
||||
from ..common.normal_map import ROTATION_ATTRIBUTE, FACE_ATTRIBUTE, AXIS_ATTRIBUTE
|
||||
@@ -67,7 +68,7 @@ def _align_front(group, geometry, controls):
|
||||
def _boundary_edge_field(group):
|
||||
"""Report one on edges that carry a single face."""
|
||||
neighbors = group.nodes.new('GeometryNodeInputMeshEdgeNeighbors')
|
||||
return _math(group, 'COMPARE', neighbors.outputs['Face Count'], 1)
|
||||
return compare_node(group, 'EQUAL', neighbors.outputs['Face Count'], 1, data_type='INT')
|
||||
|
||||
|
||||
def _fold_to_plane(group, geometry, tolerance):
|
||||
@@ -76,7 +77,7 @@ def _fold_to_plane(group, geometry, tolerance):
|
||||
position = nodes.new('GeometryNodeInputPosition')
|
||||
components = nodes.new('ShaderNodeSeparateXYZ')
|
||||
links.new(position.outputs[0], components.inputs[0])
|
||||
beyond = _math(group, 'GREATER_THAN', components.outputs['Y'], tolerance)
|
||||
beyond = compare_node(group, 'GREATER_THAN', components.outputs['Y'], tolerance)
|
||||
target = nodes.new('ShaderNodeCombineXYZ')
|
||||
links.new(components.outputs['X'], target.inputs['X'])
|
||||
links.new(components.outputs['Z'], target.inputs['Z'])
|
||||
@@ -91,8 +92,8 @@ def _fold_to_plane(group, geometry, tolerance):
|
||||
links.new(normal.outputs[0], normal_axes.inputs[0])
|
||||
flat = nodes.new('FunctionNodeBooleanMath')
|
||||
flat.operation = 'AND'
|
||||
links.new(_math(group, 'LESS_THAN', center, tolerance), flat.inputs[0])
|
||||
links.new(_math(group, 'GREATER_THAN', _math(group, 'ABSOLUTE', normal_axes.outputs['Y']), 1 - 1e-3), flat.inputs[1])
|
||||
links.new(compare_node(group, 'LESS_THAN', center, tolerance), flat.inputs[0])
|
||||
links.new(compare_node(group, 'GREATER_THAN', _math(group, 'ABSOLUTE', normal_axes.outputs['Y']), 1 - 1e-3), flat.inputs[1])
|
||||
delete = nodes.new('GeometryNodeDeleteGeometry')
|
||||
delete.domain, delete.mode = 'FACE', 'ALL'
|
||||
links.new(place.outputs[0], delete.inputs['Geometry'])
|
||||
@@ -106,10 +107,10 @@ def _clean_crease(group, geometry, tolerance):
|
||||
heights = _edge_abs_y(group)
|
||||
edge_plane = nodes.new('FunctionNodeBooleanMath')
|
||||
edge_plane.operation = 'AND'
|
||||
links.new(_math(group, 'LESS_THAN', heights[0], tolerance), edge_plane.inputs[0])
|
||||
links.new(_math(group, 'LESS_THAN', heights[1], tolerance), edge_plane.inputs[1])
|
||||
links.new(compare_node(group, 'LESS_THAN', heights[0], tolerance), edge_plane.inputs[0])
|
||||
links.new(compare_node(group, 'LESS_THAN', heights[1], tolerance), edge_plane.inputs[1])
|
||||
neighbors = nodes.new('GeometryNodeInputMeshEdgeNeighbors')
|
||||
interior = _math(group, 'COMPARE', neighbors.outputs['Face Count'], 2)
|
||||
interior = compare_node(group, 'EQUAL', neighbors.outputs['Face Count'], 2, data_type='INT')
|
||||
fold = nodes.new('FunctionNodeBooleanMath')
|
||||
fold.operation = 'AND'
|
||||
links.new(edge_plane.outputs[0], fold.inputs[0])
|
||||
@@ -147,7 +148,7 @@ def _clean_crease(group, geometry, tolerance):
|
||||
def _off_plane_edge_field(group, tolerance):
|
||||
"""Report one on edges that keep an endpoint off the symmetry plane."""
|
||||
heights = _edge_abs_y(group)
|
||||
return _math(group, 'GREATER_THAN', _math(group, 'MAXIMUM', heights[0], heights[1]), tolerance)
|
||||
return compare_node(group, 'GREATER_THAN', _math(group, 'MAXIMUM', heights[0], heights[1]), tolerance)
|
||||
|
||||
|
||||
def _edge_abs_y(group):
|
||||
@@ -179,14 +180,9 @@ def _boundary_fields(group, tolerance):
|
||||
links.new(position.outputs[0], components.inputs[0])
|
||||
seam = nodes.new('FunctionNodeBooleanMath')
|
||||
seam.operation = 'AND'
|
||||
links.new(_math(group, 'GREATER_THAN', boundary, 0), seam.inputs[0])
|
||||
links.new(compare_node(group, 'GREATER_THAN', boundary, 0), seam.inputs[0])
|
||||
links.new(
|
||||
_math(
|
||||
group,
|
||||
'LESS_THAN',
|
||||
_math(group, 'ABSOLUTE', components.outputs['Y']),
|
||||
tolerance,
|
||||
),
|
||||
compare_node(group, 'LESS_THAN', _math(group, 'ABSOLUTE', components.outputs['Y']), tolerance),
|
||||
seam.inputs[1],
|
||||
)
|
||||
return boundary, seam.outputs[0]
|
||||
@@ -306,12 +302,16 @@ def build_image_cutout_symmetry_group():
|
||||
links.new(is_boundary, boundary.inputs[0])
|
||||
# The seam sits on the plane and welds through the merge, so only off-plane edges need walls.
|
||||
links.new(_off_plane_edge_field(group, snap_tolerance), boundary.inputs[1])
|
||||
fill_smooth = _math(group, 'MULTIPLY', inputs['Fill Smooth'], inputs['Fill Sides'])
|
||||
front = _relax_fill(group, front, boundary_field, fill_smooth)
|
||||
fill_smooth = nodes.new('GeometryNodeSwitch')
|
||||
fill_smooth.input_type = 'INT'
|
||||
fill_smooth.inputs['False'].default_value = 0
|
||||
links.new(inputs['Fill Sides'], fill_smooth.inputs['Switch'])
|
||||
links.new(inputs['Fill Smooth'], fill_smooth.inputs['True'])
|
||||
front = _relax_fill(group, front, boundary_field, fill_smooth.outputs[0])
|
||||
walled = _build_wall(group, front, boundary.outputs[0])
|
||||
wall_shade = nodes.new('GeometryNodeSetShadeSmooth')
|
||||
wall_shade.domain = 'FACE'
|
||||
links.new(_math(group, 'COMPARE', read_float_attribute(group, FACE_ATTRIBUTE), 3), wall_shade.inputs['Selection'])
|
||||
links.new(compare_node(group, 'EQUAL', read_float_attribute(group, FACE_ATTRIBUTE), 3), wall_shade.inputs['Selection'])
|
||||
links.new(walled, wall_shade.inputs['Geometry'])
|
||||
body = nodes.new('GeometryNodeSwitch')
|
||||
body.input_type = 'GEOMETRY'
|
||||
@@ -323,14 +323,14 @@ def build_image_cutout_symmetry_group():
|
||||
mark_back.inputs['Name'].default_value = FACE_ATTRIBUTE
|
||||
mark_back.inputs['Value'].default_value = 2
|
||||
links.new(_mirror(group, body.outputs[0]), mark_back.inputs['Geometry'])
|
||||
links.new(_math(group, 'COMPARE', read_float_attribute(group, FACE_ATTRIBUTE), 1), mark_back.inputs['Selection'])
|
||||
links.new(compare_node(group, 'EQUAL', read_float_attribute(group, FACE_ATTRIBUTE), 1), mark_back.inputs['Selection'])
|
||||
join = nodes.new('GeometryNodeJoinGeometry')
|
||||
for geometry in (body.outputs[0], mark_back.outputs['Geometry']):
|
||||
links.new(geometry, join.inputs[0])
|
||||
position = nodes.new('GeometryNodeInputPosition')
|
||||
axis = nodes.new('ShaderNodeSeparateXYZ')
|
||||
links.new(position.outputs[0], axis.inputs[0])
|
||||
on_axis = _math(group, 'LESS_THAN', _math(group, 'ABSOLUTE', axis.outputs['Y']), snap_tolerance)
|
||||
on_axis = compare_node(group, 'LESS_THAN', _math(group, 'ABSOLUTE', axis.outputs['Y']), snap_tolerance)
|
||||
merge = nodes.new('GeometryNodeMergeByDistance')
|
||||
merge.inputs['Distance'].default_value = 0.01
|
||||
links.new(join.outputs[0], merge.inputs['Geometry'])
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
"""Build O Image Depth Cutout."""
|
||||
import bpy
|
||||
from anyimage.operators.cutout_tool.shape import NORMAL_REDUCTION_ATTRIBUTE_NAME
|
||||
from ..common.nodes import interface_socket, group_input, float_input, read_float_attribute, store_float_attribute, prepare_node_group, sample_field, evaluate_field
|
||||
from ..common.nodes import (
|
||||
interface_socket, group_input, float_input, read_float_attribute,
|
||||
store_float_attribute, prepare_node_group, sample_field, evaluate_field,
|
||||
compare_node,
|
||||
)
|
||||
from ..common.boundary_smoothing import smooth_cut_boundary
|
||||
from ..common.cutout import _position_field, _shade_output
|
||||
from ..common.depth_surface import _math, project_depth_surface, build_surface_camera, split_depth_surface, sample_face_camera, thicken_depth_surface
|
||||
@@ -314,7 +318,7 @@ def _build_depth_surface(group, geometry, controls):
|
||||
links.new(is_shell, selected_thickness.inputs["Switch"])
|
||||
links.new(controls.outputs["Thickness"], selected_thickness.inputs["False"])
|
||||
links.new(controls.outputs["Shell Thickness"], selected_thickness.inputs["True"])
|
||||
has_thickness = _math(group, "GREATER_THAN", selected_thickness.outputs[0], 1e-6)
|
||||
has_thickness = compare_node(group, "GREATER_THAN", selected_thickness.outputs[0], 1e-6)
|
||||
zero_shell = group.nodes.new("GeometryNodeSwitch")
|
||||
zero_shell.input_type = "GEOMETRY"
|
||||
links.new(has_thickness, zero_shell.inputs["Switch"])
|
||||
|
||||
@@ -9,7 +9,10 @@ from ..common.validity import delete_invalid_faces
|
||||
from ..common.depth_surface import (
|
||||
_math, split_depth_surface, build_surface_camera,
|
||||
)
|
||||
from ..common.nodes import float_input, group_input, interface_socket, prepare_node_group, evaluate_field, remove_attribute_pattern
|
||||
from ..common.nodes import (
|
||||
compare_node, float_input, group_input, interface_socket,
|
||||
prepare_node_group, evaluate_field, remove_attribute_pattern,
|
||||
)
|
||||
from ..common.material_slots import inherit_material_slots
|
||||
from ..common.boundary_smoothing import smooth_boundary_depth, smooth_cut_boundary
|
||||
|
||||
@@ -42,6 +45,8 @@ def build_image_depth_panorama_group():
|
||||
subdivide = interface_socket(group, "Subdivide", "INPUT", "NodeSocketInt")
|
||||
subdivide.description = "Increase mesh density to represent finer shapes. Higher levels create more vertices and require more processing time."
|
||||
subdivide.default_value, subdivide.min_value, subdivide.max_value = 8, 0, 8
|
||||
dome = float_input(group, "Dome Radius", 50, minimum=1, maximum=100, subtype="DISTANCE")
|
||||
dome.description = "Radius of the sphere kept at Depth Scale 0, and where mask areas below Mask Threshold land."
|
||||
float_input(group, "Depth Scale", 1, maximum=1, subtype="FACTOR").description = "Blend between a sphere at zero and the estimated depth surface at one."
|
||||
float_input(group, "Depth Split", 0.1, maximum=1, subtype="FACTOR").description = "Split the mesh where depth changes abruptly. Higher values detect smaller depth jumps. Zero disables splitting."
|
||||
valid_only = interface_socket(group, "Depth Mask", "INPUT", "NodeSocketBool")
|
||||
@@ -51,8 +56,7 @@ def build_image_depth_panorama_group():
|
||||
boundary_smooth = interface_socket(group, "Boundary Smooth", "INPUT", "NodeSocketInt", options)
|
||||
boundary_smooth.default_value, boundary_smooth.min_value, boundary_smooth.max_value = 2, 0, 16
|
||||
boundary_smooth.description = "Smooth depth and geometry near cut edges on the panorama surface. Zero disables boundary smoothing."
|
||||
float_input(group, "Mask Threshold", 0.9, maximum=1, subtype="FACTOR", parent=options).description = "Set the minimum depth mask value treated as valid. Higher values exclude more partially valid boundary areas."
|
||||
float_input(group, "Invalid Distance", 100, minimum=1e-5, subtype="DISTANCE", parent=options).description = "Set the fallback distance from the panorama center for invalid depth areas kept when Depth Mask is disabled."
|
||||
float_input(group, "Mask Threshold", 0.9, maximum=0.99, subtype="FACTOR", parent=options).description = "Set the minimum depth mask value treated as valid. Higher values exclude more partially valid boundary areas."
|
||||
data = group.interface.new_panel("Data", default_closed=True)
|
||||
interface_socket(group, "Depth Image", "INPUT", "NodeSocketImage", data).hide_in_modifier = True
|
||||
interface_socket(group, "Geometry", "OUTPUT", "NodeSocketGeometry")
|
||||
@@ -99,8 +103,8 @@ def build_image_depth_panorama_group():
|
||||
alphas.append(separate.outputs["Alpha"])
|
||||
choose = nodes.new("GeometryNodeSwitch")
|
||||
choose.input_type = "RGBA"
|
||||
links.new(_math(group, "LESS_THAN", alphas[0],
|
||||
_math(group, "SUBTRACT", alphas[1], 1e-6)), choose.inputs["Switch"])
|
||||
links.new(compare_node(group, "LESS_THAN", alphas[0],
|
||||
_math(group, "SUBTRACT", alphas[1], 1e-6)), choose.inputs["Switch"])
|
||||
links.new(linear, choose.inputs["False"])
|
||||
links.new(nearest, choose.inputs["True"])
|
||||
return choose.outputs[0], alphas[1]
|
||||
@@ -117,7 +121,7 @@ def build_image_depth_panorama_group():
|
||||
correction = _math(group, "ROUND", _math(group, "SUBTRACT", face_u, longitude))
|
||||
choose = nodes.new("GeometryNodeSwitch")
|
||||
choose.input_type = "FLOAT"
|
||||
links.new(_math(group, "GREATER_THAN", _math(group, "ABSOLUTE", z), 0.999999), choose.inputs["Switch"])
|
||||
links.new(compare_node(group, "GREATER_THAN", _math(group, "ABSOLUTE", z), 0.999999), choose.inputs["Switch"])
|
||||
links.new(_math(group, "ADD", longitude, correction), choose.inputs["False"])
|
||||
links.new(face_u, choose.inputs["True"])
|
||||
uv_map = nodes.new("GeometryNodeStoreNamedAttribute")
|
||||
@@ -127,46 +131,43 @@ def build_image_depth_panorama_group():
|
||||
links.new(combine(choose.outputs[0], latitude), uv_map.inputs["Value"])
|
||||
pixel, _ = depth(coordinates)
|
||||
pixel = evaluate_field(group, pixel, "FLOAT_VECTOR", "POINT")
|
||||
nearest = nodes.new("FunctionNodeSeparateColor")
|
||||
links.new(texture(coordinates, "Closest"), nearest.inputs["Color"])
|
||||
controls = group_input(nodes, {"Mask Threshold"})
|
||||
invalid = _math(group, "MAXIMUM",
|
||||
_math(group, "LESS_THAN", nearest.outputs["Alpha"], controls.outputs["Mask Threshold"]),
|
||||
_math(group, "LESS_THAN", nearest.outputs["Red"], 1e-5))
|
||||
face_invalid = evaluate_field(group, invalid, "FLOAT", "POINT")
|
||||
any_invalid = _math(group, "GREATER_THAN", face_invalid, 0)
|
||||
mixed = _math(group, "MULTIPLY", any_invalid,
|
||||
_math(group, "LESS_THAN", face_invalid, 1))
|
||||
# Both the mask and the depth of a face are read at its centre, like Depth Plane.
|
||||
face_camera, face_alpha = depth(combine(face_u, face_v))
|
||||
face_alpha = evaluate_field(group, face_alpha, "FLOAT", "FACE")
|
||||
threshold_input = group_input(nodes, {"Mask Threshold"})
|
||||
invalid = compare_node(group, "LESS_THAN", face_alpha, threshold_input.outputs["Mask Threshold"])
|
||||
protected = uv_map.outputs["Geometry"]
|
||||
culled = delete_invalid_faces(group, protected, any_invalid)
|
||||
delete = nodes.new("GeometryNodeDeleteGeometry")
|
||||
delete.domain, delete.mode = "FACE", "ALL"
|
||||
links.new(protected, delete.inputs["Geometry"])
|
||||
links.new(mixed, delete.inputs["Selection"])
|
||||
selection = nodes.new("GeometryNodeSwitch")
|
||||
selection.input_type = "GEOMETRY"
|
||||
links.new(group_input(nodes, {"Depth Mask"}).outputs["Depth Mask"], selection.inputs["Switch"])
|
||||
links.new(delete.outputs[0], selection.inputs["False"])
|
||||
links.new(culled, selection.inputs["True"])
|
||||
culled = delete_invalid_faces(group, protected, invalid)
|
||||
cull_controls = group_input(nodes, {"Depth Mask"})
|
||||
cull = nodes.new("GeometryNodeSwitch")
|
||||
cull.input_type = "GEOMETRY"
|
||||
links.new(cull_controls.outputs["Depth Mask"], cull.inputs["Switch"])
|
||||
links.new(culled, cull.inputs["True"])
|
||||
links.new(protected, cull.inputs["False"])
|
||||
controls = group_input(nodes, {"Depth Split"})
|
||||
strength = controls.outputs["Depth Split"]
|
||||
face_camera = depth(combine(face_u, face_v))[0]
|
||||
radial = nodes.new("ShaderNodeSeparateXYZ")
|
||||
links.new(face_camera, radial.inputs[0])
|
||||
geometry, corner_camera, cut_vertex = split_depth_surface(
|
||||
group, selection.outputs[0], face_camera, strength, 1.0,
|
||||
group, cull.outputs["Output"], face_camera, strength, 1.0,
|
||||
face_distance=radial.outputs["X"], face_center=face.outputs["Value"],
|
||||
)
|
||||
distance = build_surface_camera(group, pixel, corner_camera, cut_vertex, strength)
|
||||
axes = nodes.new("ShaderNodeSeparateXYZ")
|
||||
links.new(distance, axes.inputs[0])
|
||||
distance = nodes.new("GeometryNodeSwitch")
|
||||
distance.input_type = "FLOAT"
|
||||
links.new(face_invalid, distance.inputs["Switch"])
|
||||
links.new(smooth_boundary_depth(group, axes.outputs["X"], face_invalid), distance.inputs["False"])
|
||||
links.new(group_input(nodes, {"Invalid Distance"}).outputs["Invalid Distance"], distance.inputs["True"])
|
||||
distance = smooth_boundary_depth(group, axes.outputs["X"])
|
||||
dome_radius = group_input(nodes, {"Dome Radius"}).outputs["Dome Radius"]
|
||||
fallback = nodes.new("GeometryNodeSwitch")
|
||||
fallback.input_type = "FLOAT"
|
||||
links.new(invalid, fallback.inputs["Switch"])
|
||||
links.new(distance, fallback.inputs["False"])
|
||||
links.new(dome_radius, fallback.inputs["True"])
|
||||
controls = group_input(nodes, {"Depth Scale"})
|
||||
radius = _math(group, "ADD", 1, _math(group, "MULTIPLY", controls.outputs["Depth Scale"], _math(group, "SUBTRACT", distance.outputs[0], 1)))
|
||||
radius = _math(
|
||||
group, "ADD", dome_radius,
|
||||
_math(group, "MULTIPLY", controls.outputs["Depth Scale"],
|
||||
_math(group, "SUBTRACT", fallback.outputs[0], dome_radius)),
|
||||
)
|
||||
radial = nodes.new("ShaderNodeVectorMath")
|
||||
radial.operation = "SCALE"
|
||||
links.new(position, radial.inputs[0])
|
||||
|
||||
@@ -5,7 +5,7 @@ import bpy
|
||||
from ..common.validity import delete_invalid_faces
|
||||
|
||||
from ..common.nodes import group_input as _group_input, interface_socket as _interface_socket
|
||||
from ..common.nodes import prepare_node_group, float_input, evaluate_field
|
||||
from ..common.nodes import compare_node, prepare_node_group, float_input, evaluate_field
|
||||
from ..common.boundary_smoothing import smooth_boundary_camera, smooth_cut_boundary
|
||||
from ..common.depth_surface import (
|
||||
_math, project_depth_surface, thicken_depth_surface,
|
||||
@@ -51,7 +51,7 @@ def build_image_depth_plane_group(image_plane_group):
|
||||
validity_threshold = _interface_socket(group, "Mask Threshold", "INPUT", "NodeSocketFloat", parent=options)
|
||||
validity_threshold.description = "Set the minimum depth mask value treated as valid. Higher values exclude more partially valid boundary areas."
|
||||
validity_threshold.default_value = 0.9
|
||||
validity_threshold.min_value, validity_threshold.max_value = 0.0, 1.0
|
||||
validity_threshold.min_value, validity_threshold.max_value = 0.0, 0.99
|
||||
validity_threshold.subtype = "FACTOR"
|
||||
float_input(group, "Reference Depth", 1.0, subtype="DISTANCE", parent=options)
|
||||
data = group.interface.new_panel(name="Data", default_closed=True)
|
||||
@@ -97,15 +97,15 @@ def build_image_depth_plane_group(image_plane_group):
|
||||
links.new(texture.outputs["Color"], channels.inputs["Color"])
|
||||
invalid = nodes.new("FunctionNodeCompare")
|
||||
invalid.data_type, invalid.operation = "FLOAT", "LESS_THAN"
|
||||
links.new(threshold_input.outputs["Mask Threshold"], invalid.inputs["B"])
|
||||
links.new(channels.outputs["Alpha"], invalid.inputs["A"])
|
||||
links.new(threshold_input.outputs["Mask Threshold"], invalid.inputs["B"])
|
||||
# Image Plane's normalized UV rectangle retains its original outline after cuts.
|
||||
uv_axes = nodes.new("ShaderNodeSeparateXYZ")
|
||||
links.new(uv.outputs["Attribute"], uv_axes.inputs[0])
|
||||
u, v = uv_axes.outputs["X"], uv_axes.outputs["Y"]
|
||||
margin = _math(group, "MINIMUM", _math(group, "MINIMUM", u, v),
|
||||
_math(group, "MINIMUM", _math(group, "SUBTRACT", 1, u), _math(group, "SUBTRACT", 1, v)))
|
||||
original_boundary = evaluate_field(group, _math(group, "LESS_THAN", margin, 1e-6), "BOOLEAN", "POINT")
|
||||
original_boundary = evaluate_field(group, compare_node(group, "LESS_THAN", margin, 1e-6), "BOOLEAN", "POINT")
|
||||
protected = plane.outputs["Geometry"]
|
||||
culled = delete_invalid_faces(group, protected, invalid.outputs["Result"])
|
||||
cull_controls = _group_input(nodes, {"Depth Mask"})
|
||||
@@ -139,13 +139,10 @@ def build_image_depth_plane_group(image_plane_group):
|
||||
group, surface, shell_input.outputs["Thickness"],
|
||||
normal_smooth=100,
|
||||
)
|
||||
positive = nodes.new("ShaderNodeMath")
|
||||
positive.operation = "GREATER_THAN"
|
||||
links.new(shell_input.outputs["Thickness"], positive.inputs[0])
|
||||
positive.inputs[1].default_value = 0
|
||||
positive = compare_node(group, "GREATER_THAN", shell_input.outputs["Thickness"], 0)
|
||||
choose = nodes.new("GeometryNodeSwitch")
|
||||
choose.input_type = "GEOMETRY"
|
||||
links.new(positive.outputs[0], choose.inputs["Switch"])
|
||||
links.new(positive, choose.inputs["Switch"])
|
||||
links.new(surface, choose.inputs["False"])
|
||||
links.new(shell["geometry"], choose.inputs["True"])
|
||||
smooth = nodes.new("GeometryNodeSetShadeSmooth")
|
||||
|
||||
@@ -5,7 +5,7 @@ import bpy
|
||||
from anyimage.operators.cutout_tool.shape import NORMAL_REDUCTION_ATTRIBUTE_NAME
|
||||
from ..common.nodes import group_input as _group_input, interface_socket as _interface_socket
|
||||
from ..common.nodes import store_float_attribute
|
||||
from ..common.nodes import prepare_node_group, float_input, vector_input
|
||||
from ..common.nodes import compare_node, prepare_node_group, float_input, vector_input
|
||||
from ..common.reference_plane import reference_plane_depth
|
||||
from ..common.boundary_smoothing import boundary_influence
|
||||
|
||||
@@ -58,7 +58,7 @@ def build_image_relief_plane_group(image_plane_group):
|
||||
validity_threshold = _interface_socket(group, "Mask Threshold", "INPUT", "NodeSocketFloat", options)
|
||||
validity_threshold.description = "Set the minimum depth mask value treated as valid."
|
||||
validity_threshold.default_value = 0.9
|
||||
validity_threshold.min_value, validity_threshold.max_value = 0.0, 1.0
|
||||
validity_threshold.min_value, validity_threshold.max_value = 0.0, 0.99
|
||||
validity_threshold.subtype = "FACTOR"
|
||||
base_plane_depth = _interface_socket(
|
||||
group,
|
||||
@@ -136,10 +136,10 @@ def build_image_relief_plane_group(image_plane_group):
|
||||
links.new(texture.outputs["Alpha"], invalid.inputs["A"])
|
||||
links.new(image_input.outputs["Mask Threshold"], invalid.inputs["B"])
|
||||
mask_enabled = image_input.outputs["Depth Mask"]
|
||||
valid_mask = nodes.new("ShaderNodeMath")
|
||||
valid_mask.operation = "SUBTRACT"
|
||||
valid_mask.inputs[0].default_value = 1.0
|
||||
links.new(invalid.outputs["Result"], valid_mask.inputs[1])
|
||||
valid_mask = nodes.new("GeometryNodeSwitch")
|
||||
valid_mask.input_type = "FLOAT"
|
||||
valid_mask.inputs["False"].default_value = 1.0
|
||||
links.new(invalid.outputs["Result"], valid_mask.inputs["Switch"])
|
||||
mask_switch = nodes.new("GeometryNodeSwitch")
|
||||
mask_switch.input_type = "FLOAT"
|
||||
mask_switch.inputs["False"].default_value = 1.0
|
||||
@@ -165,9 +165,7 @@ def build_image_relief_plane_group(image_plane_group):
|
||||
links.new(full_offset.outputs[0], masked_full_offset.inputs[0])
|
||||
links.new(mask_switch.outputs[0], masked_full_offset.inputs[1])
|
||||
|
||||
has_thickness = _math(nodes, "GREATER_THAN")
|
||||
has_thickness.inputs[1].default_value = 1e-6
|
||||
links.new(shape_input.outputs["Thickness"], has_thickness.inputs[0])
|
||||
has_thickness = compare_node(group, "GREATER_THAN", shape_input.outputs["Thickness"], 1e-6)
|
||||
safe_offset = _math(nodes, "MINIMUM")
|
||||
safe_offset.inputs[1].default_value = 0.0
|
||||
links.new(masked_full_offset.outputs[0], safe_offset.inputs[0])
|
||||
@@ -201,7 +199,7 @@ def build_image_relief_plane_group(image_plane_group):
|
||||
layer_weight = nodes.new("GeometryNodeSwitch")
|
||||
layer_weight.input_type = "FLOAT"
|
||||
layer_weight.inputs["False"].default_value = 1.0
|
||||
links.new(has_thickness.outputs[0], layer_weight.inputs["Switch"])
|
||||
links.new(has_thickness, layer_weight.inputs["Switch"])
|
||||
links.new(one_minus_ratio.outputs[0], layer_weight.inputs["True"])
|
||||
|
||||
weighted_offset = _math(nodes, "MULTIPLY")
|
||||
|
||||
Reference in New Issue
Block a user