Add tests and implement boundary smoothing and cutout functionality
- Introduced tests for boundary smoothing in `test_boundary_smoothing.py`, verifying that smoothing reduces stair-step artifacts while preserving boundary integrity. - Added tests for cutout boundary behavior in `test_cutout_boundary.py`, ensuring proper handling of boundary triangles and normal blending. - Created `test_temporary_attributes.py` to check the cleanup of temporary attributes across depth modifier branches, ensuring no warnings are raised. - Implemented point culling functionality in `test_validity.py`, confirming that invalid points are removed without affecting adjacent geometry. - Developed boundary smoothing logic in `boundary_smoothing.py`, allowing for depth smoothing while maintaining edge integrity. - Added cutout boundary management in `cutout_boundary.py`, including functions for removing boundary triangles and tapering thickness profiles. - Implemented validity checks in `validity.py` to ensure proper deletion of invalid vertices and associated wire edges.
This commit is contained in:
@@ -4,12 +4,15 @@ import math
|
||||
|
||||
import bpy
|
||||
|
||||
from ..common.validity import delete_invalid_points
|
||||
|
||||
from ..common.depth_surface import (
|
||||
_math, split_depth_surface, build_surface_camera,
|
||||
_math, split_depth_surface, build_surface_camera, CUT_ATTRIBUTE,
|
||||
)
|
||||
from ..common.nodes import float_input, group_input, interface_socket, prepare_node_group, evaluate_field
|
||||
from ..common.nodes import float_input, group_input, interface_socket, prepare_node_group, evaluate_field, remove_attributes
|
||||
from ..common.material import inherit_material_slots
|
||||
from ..common.smoothing import expand_smooth
|
||||
from ..common.boundary_smoothing import smooth_boundary_depth, smooth_cut_boundary
|
||||
|
||||
|
||||
def _quad_sphere(group, segments):
|
||||
@@ -36,6 +39,7 @@ def _quad_sphere(group, segments):
|
||||
def build_image_depth_panorama_group():
|
||||
group = bpy.data.node_groups.new("O Image Depth Panorama", "GeometryNodeTree")
|
||||
group.is_modifier = group.use_fake_user = True
|
||||
group["anyimage_asset_revision"] = 14
|
||||
interface_socket(group, "Geometry", "INPUT", "NodeSocketGeometry")
|
||||
subdivide = interface_socket(group, "Subdivide", "INPUT", "NodeSocketInt")
|
||||
subdivide.default_value, subdivide.min_value, subdivide.max_value = 7, 0, 8
|
||||
@@ -45,6 +49,9 @@ def build_image_depth_panorama_group():
|
||||
smooth.default_value, smooth.min_value, smooth.max_value = 0, 0, 20
|
||||
interface_socket(group, "Valid Only", "INPUT", "NodeSocketBool").default_value = True
|
||||
options = group.interface.new_panel("Options", default_closed=True)
|
||||
boundary_smooth = interface_socket(group, "Boundary Smooth", "INPUT", "NodeSocketInt", options)
|
||||
boundary_smooth.default_value, boundary_smooth.min_value, boundary_smooth.max_value = 5, 0, 20
|
||||
boundary_smooth.description = "Smooth boundary distance and cut-edge geometry on the sphere"
|
||||
float_input(group, "Smooth Weight", 1, maximum=1, subtype="FACTOR", parent=options)
|
||||
float_input(group, "Validity Threshold", 0.9, maximum=1, subtype="FACTOR", parent=options)
|
||||
float_input(group, "Invalid Distance", 100, minimum=1e-5, subtype="DISTANCE", parent=options)
|
||||
@@ -133,18 +140,20 @@ def build_image_depth_panorama_group():
|
||||
any_invalid = _math(group, "GREATER_THAN", face_invalid, 0)
|
||||
mixed = _math(group, "MULTIPLY", any_invalid,
|
||||
_math(group, "LESS_THAN", face_invalid, 1))
|
||||
selection = nodes.new("GeometryNodeSwitch")
|
||||
selection.input_type = "BOOLEAN"
|
||||
links.new(group_input(nodes, {"Valid Only"}).outputs["Valid Only"], selection.inputs["Switch"])
|
||||
links.new(mixed, selection.inputs["False"])
|
||||
links.new(any_invalid, selection.inputs["True"])
|
||||
protected = uv_map.outputs["Geometry"]
|
||||
culled = delete_invalid_points(group, protected, any_invalid)
|
||||
delete = nodes.new("GeometryNodeDeleteGeometry")
|
||||
delete.domain, delete.mode = "FACE", "ALL"
|
||||
links.new(uv_map.outputs["Geometry"], delete.inputs["Geometry"])
|
||||
links.new(selection.outputs[0], delete.inputs["Selection"])
|
||||
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, {"Valid Only"}).outputs["Valid Only"], selection.inputs["Switch"])
|
||||
links.new(delete.outputs[0], selection.inputs["False"])
|
||||
links.new(culled, selection.inputs["True"])
|
||||
controls = group_input(nodes, {"Split Threshold", "Reference Distance"})
|
||||
strength = controls.outputs["Split Threshold"]
|
||||
geometry, corner_camera, cut_vertex = split_depth_surface(group, delete.outputs[0], depth(combine(face_u, face_v))[0], strength,
|
||||
geometry, corner_camera, cut_vertex = split_depth_surface(group, selection.outputs[0], depth(combine(face_u, face_v))[0], strength,
|
||||
_math(group, "DIVIDE", 1, controls.outputs["Reference Distance"]),
|
||||
face_center=face.outputs["Value"])
|
||||
distance = build_surface_camera(group, pixel, corner_camera, cut_vertex, strength)
|
||||
@@ -153,7 +162,7 @@ def build_image_depth_panorama_group():
|
||||
distance = nodes.new("GeometryNodeSwitch")
|
||||
distance.input_type = "FLOAT"
|
||||
links.new(face_invalid, distance.inputs["Switch"])
|
||||
links.new(axes.outputs["X"], distance.inputs["False"])
|
||||
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"])
|
||||
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)))
|
||||
@@ -164,7 +173,12 @@ def build_image_depth_panorama_group():
|
||||
deform = nodes.new("GeometryNodeSetPosition")
|
||||
links.new(geometry, deform.inputs["Geometry"])
|
||||
links.new(radial.outputs[0], deform.inputs["Position"])
|
||||
geometry = expand_smooth(group, deform.outputs[0], iterations_name="Smooth", weight_name="Smooth Weight")
|
||||
geometry = remove_attributes(
|
||||
group, deform.outputs[0], CUT_ATTRIBUTE,
|
||||
enabled=_math(group, "GREATER_THAN", strength, 0.0),
|
||||
)
|
||||
geometry = smooth_cut_boundary(group, geometry)
|
||||
geometry = expand_smooth(group, geometry, iterations_name="Smooth", weight_name="Smooth Weight")
|
||||
flip = nodes.new("GeometryNodeFlipFaces")
|
||||
links.new(geometry, flip.inputs["Mesh"])
|
||||
smooth = nodes.new("GeometryNodeSetShadeSmooth")
|
||||
|
||||
Reference in New Issue
Block a user