feat: Implement weight cutout boundary smoothing for image depth cutout
- Added a new proposal for boundary smoothing in the weight cutout process, differentiating between Split edges and Outline smoothing requirements. - Introduced a new capability `cutout-boundary-smoothing` to control smoothing strength and default values. - Updated specifications to define the behavior of boundary-specific smoothing strength and default settings. - Created tasks to verify the implementation of boundary behavior and asset updates. - Developed comprehensive tests for depth symmetry and normal scaling to ensure expected behavior and performance. - Introduced new attributes for normal mapping to facilitate persistent face attributes sharing between depth symmetry and image materials. - Built a new node group for O Image Depth Symmetry, integrating the new smoothing capabilities and ensuring compatibility with existing workflows.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"""Exercise automatic arrangement without changing geometry or publishing assets."""
|
||||
"""Exercise automatic arrangement while preserving node programs and geometry."""
|
||||
|
||||
import bpy
|
||||
import numpy as np
|
||||
@@ -6,12 +6,12 @@ import pytest
|
||||
|
||||
|
||||
from tools.nodes.build import build_node_groups
|
||||
from tools.nodes.check import GEOMETRY_NAMES
|
||||
from tools.nodes.check import ASSET_PATH, GEOMETRY_NAMES, SHADER_NAMES
|
||||
from tools.nodes.arrangement.arrange import arrange_nodes
|
||||
from tools.nodes.arrangement.dimensions import estimate_node_dimensions
|
||||
|
||||
|
||||
@pytest.fixture(params=sorted(GEOMETRY_NAMES))
|
||||
@pytest.fixture(params=sorted(GEOMETRY_NAMES | SHADER_NAMES))
|
||||
def node_group(request):
|
||||
bpy.ops.wm.read_factory_settings(use_empty=True)
|
||||
return next(group for group in build_node_groups() if group.name == request.param)
|
||||
@@ -40,9 +40,18 @@ def _program(node_group):
|
||||
settings = {
|
||||
name: _value(getattr(node, name))
|
||||
for name in ("operation", "data_type", "input_type", "domain", "mode", "clamp",
|
||||
"interpolation", "interpolation_type", "extension", "pattern_mode")
|
||||
"interpolation", "interpolation_type", "extension", "pattern_mode",
|
||||
"space", "uv_map", "attribute_type", "attribute_name", "rotation_type",
|
||||
"invert", "blend_type", "clamp_factor", "clamp_result", "distribution")
|
||||
if hasattr(node, name)
|
||||
}
|
||||
if hasattr(node, "mapping"):
|
||||
mapping = node.mapping
|
||||
settings["mapping"] = (
|
||||
mapping.extend, mapping.use_clip,
|
||||
tuple((tuple(point.location), point.handle_type)
|
||||
for curve in mapping.curves for point in curve.points),
|
||||
)
|
||||
inputs = [
|
||||
(socket.identifier, _value(socket.default_value) if hasattr(socket, "default_value") else None,
|
||||
[_source(link.from_socket) for link in sorted(
|
||||
@@ -88,7 +97,7 @@ def _surface(node_group):
|
||||
pixels[..., 2] = 2 + xx * 0.02
|
||||
image.pixels.foreach_set(pixels.ravel())
|
||||
values = {"Subdivide": 1, "Thickness": 0.2, "Depth Image": image,
|
||||
"Uniform Scale": 1.0, "Reference Depth": 2.0, "Depth Scale": 0.8,
|
||||
"Uniform Scale": 1.0, "Reference Depth": 2.5, "Depth Scale": 0.8,
|
||||
"Smooth": 1, "Normal Smooth": 2, "Depth Split": 0.25}
|
||||
mode = None
|
||||
for item in node_group.interface.items_tree:
|
||||
@@ -119,9 +128,9 @@ def _surface(node_group):
|
||||
return evaluate
|
||||
|
||||
|
||||
def test_arrangement_preserves_program_and_geometry(node_group):
|
||||
def test_arrangement_preserves_program_and_evaluation(node_group):
|
||||
program = _program(node_group)
|
||||
evaluate = _surface(node_group)
|
||||
evaluate = _surface(node_group) if node_group.bl_idname == "GeometryNodeTree" else list
|
||||
geometry = evaluate()
|
||||
arrange_nodes(node_group)
|
||||
assert _program(node_group) == program
|
||||
@@ -142,3 +151,13 @@ def test_arrangement_preserves_program_and_geometry(node_group):
|
||||
arrange_nodes(node_group)
|
||||
assert _program(node_group) == program
|
||||
assert sum(node.bl_idname == "NodeGroupInput" for node in node_group.nodes) == input_count
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", sorted(SHADER_NAMES))
|
||||
def test_shader_asset_preserves_definition(name):
|
||||
bpy.ops.wm.read_factory_settings(use_empty=True)
|
||||
definition = next(group for group in build_node_groups() if group.name == name)
|
||||
expected = _program(definition)
|
||||
with bpy.data.libraries.load(str(ASSET_PATH)) as (_, target):
|
||||
target.node_groups = [name]
|
||||
assert _program(target.node_groups[0]) == expected
|
||||
|
||||
Reference in New Issue
Block a user