- Introduced `frames.py` to manage field complex calculations and their arrangement within node groups. - Added functionality to create and remove field frames based on node arrangements. - Developed `passages.py` to find unobstructed paths for connections around calculation frames. - Implemented `references.py` to route shared results on peripheral tracks, ensuring efficient distribution of outputs. - Created `sections.py` to reserve space for field calculations adjacent to geometry consumers. - Added `sources.py` to position shared calculation sources effectively beside their distribution channels. - Enhanced outline smoothing with `outline_smoothing.py` to adapt camera depth along original outlines.
99 lines
5.3 KiB
Python
99 lines
5.3 KiB
Python
"""Adapt camera depth along the original outline with batched weight updates."""
|
|
|
|
from .boundary_smoothing import boundary_influence, reconstruct_camera_depth
|
|
from .depth_surface import CUT_ATTRIBUTE, _math, ray_distance
|
|
from .nodes import evaluate_field, group_input, read_float_attribute, sample_field
|
|
from .smoothing import edge_boundary_field
|
|
|
|
|
|
def _outline_influence(group, original, geometry):
|
|
"""Identify original outline points and protect split boundary intersections."""
|
|
nodes, links = group.nodes, group.links
|
|
rim = evaluate_field(group, edge_boundary_field(nodes, links), "FLOAT", "POINT")
|
|
nearest = nodes.new("GeometryNodeSampleNearest")
|
|
nearest.domain = "POINT"
|
|
links.new(original, nearest.inputs["Geometry"])
|
|
position = nodes.new("GeometryNodeInputPosition").outputs["Position"]
|
|
links.new(position, nearest.inputs["Sample Position"])
|
|
original_rim = sample_field(group, original, rim, "FLOAT", index=nearest.outputs["Index"])
|
|
original_rim = _math(group, "GREATER_THAN", original_rim, 0)
|
|
cut = _math(group, "GREATER_THAN", read_float_attribute(group, CUT_ATTRIBUTE), 0)
|
|
protected = _math(group, "MULTIPLY", _math(group, "GREATER_THAN", rim, 0),
|
|
_math(group, "MAXIMUM", cut, _math(group, "SUBTRACT", 1, original_rim)))
|
|
# Resolve planar correspondence before replacing positions with camera depth.
|
|
return sample_field(group, geometry, boundary_influence(group, protected), "FLOAT")
|
|
|
|
|
|
def smooth_outline_camera(group, original, geometry, camera, uniform_scale):
|
|
"""Update outline weights and blur ray distance in fixed-weight batches."""
|
|
nodes, links = group.nodes, group.links
|
|
controls = group_input(nodes, {"Outline Depth Fix", "Boundary Smooth"})
|
|
influence = _outline_influence(group, original, geometry)
|
|
depth = ray_distance(group, camera)
|
|
|
|
endpoints = nodes.new("GeometryNodeInputMeshEdgeVertices")
|
|
length = nodes.new("ShaderNodeVectorMath")
|
|
length.operation = "DISTANCE"
|
|
links.new(endpoints.outputs["Position 1"], length.inputs[0])
|
|
links.new(endpoints.outputs["Position 2"], length.inputs[1])
|
|
statistic = nodes.new("GeometryNodeAttributeStatistic")
|
|
statistic.data_type, statistic.domain = "FLOAT", "EDGE"
|
|
links.new(geometry, statistic.inputs["Geometry"])
|
|
links.new(length.outputs["Value"], statistic.inputs["Attribute"])
|
|
scale = _math(group, "DIVIDE", uniform_scale,
|
|
_math(group, "MAXIMUM", statistic.outputs["Median"], 1e-8))
|
|
|
|
seed = nodes.new("ShaderNodeCombineXYZ")
|
|
links.new(depth, seed.inputs["Z"])
|
|
carrier = nodes.new("GeometryNodeSetPosition")
|
|
links.new(geometry, carrier.inputs["Geometry"])
|
|
links.new(seed.outputs[0], carrier.inputs["Position"])
|
|
repeat_output = nodes.new("GeometryNodeRepeatOutput")
|
|
repeat_input = nodes.new("GeometryNodeRepeatInput")
|
|
repeat_input.pair_with_output(repeat_output)
|
|
links.new(carrier.outputs[0], repeat_input.inputs["Geometry"])
|
|
links.new(controls.outputs["Outline Depth Fix"], repeat_input.inputs["Iterations"])
|
|
|
|
position = nodes.new("GeometryNodeInputPosition")
|
|
current = nodes.new("ShaderNodeSeparateXYZ")
|
|
links.new(position.outputs[0], current.inputs[0])
|
|
reference = nodes.new("GeometryNodeBlurAttribute")
|
|
reference.data_type = "FLOAT"
|
|
reference.inputs["Iterations"].default_value = 1
|
|
reference.inputs["Weight"].default_value = 0.5
|
|
links.new(current.outputs["Z"], reference.inputs["Value"])
|
|
residual = _math(group, "ABSOLUTE", _math(group, "SUBTRACT", current.outputs["Z"], reference.outputs[0]))
|
|
ratio = _math(group, "MULTIPLY", residual, scale)
|
|
weight = nodes.new("ShaderNodeMapRange")
|
|
weight.interpolation_type, weight.clamp = "SMOOTHSTEP", True
|
|
weight.inputs["From Min"].default_value = 0.25
|
|
weight.inputs["From Max"].default_value = 0.5
|
|
links.new(ratio, weight.inputs["Value"])
|
|
active = _math(group, "MULTIPLY", influence, _math(group, "GREATER_THAN", depth, 1e-8))
|
|
active = sample_field(group, geometry, active, "FLOAT")
|
|
weighted = _math(group, "MULTIPLY", weight.outputs[0], active)
|
|
# Sampling the round's input prevents the inner Blur from updating its weight.
|
|
frozen = sample_field(group, repeat_input.outputs["Geometry"], weighted, "FLOAT")
|
|
blur = nodes.new("GeometryNodeBlurAttribute")
|
|
blur.data_type = "FLOAT"
|
|
links.new(current.outputs["Z"], blur.inputs["Value"])
|
|
links.new(frozen, blur.inputs["Weight"])
|
|
links.new(controls.outputs["Boundary Smooth"], blur.inputs["Iterations"])
|
|
updated = nodes.new("ShaderNodeCombineXYZ")
|
|
links.new(blur.outputs[0], updated.inputs["Z"])
|
|
move = nodes.new("GeometryNodeSetPosition")
|
|
links.new(repeat_input.outputs["Geometry"], move.inputs["Geometry"])
|
|
links.new(updated.outputs[0], move.inputs["Position"])
|
|
links.new(move.outputs[0], repeat_output.inputs["Geometry"])
|
|
|
|
result = sample_field(group, repeat_output.outputs["Geometry"], current.outputs["Z"], "FLOAT")
|
|
enabled = _math(group, "MULTIPLY", active,
|
|
_math(group, "MULTIPLY", controls.outputs["Outline Depth Fix"],
|
|
controls.outputs["Boundary Smooth"]))
|
|
choose = nodes.new("GeometryNodeSwitch")
|
|
choose.input_type = "FLOAT"
|
|
links.new(enabled, choose.inputs["Switch"])
|
|
links.new(depth, choose.inputs["False"])
|
|
links.new(result, choose.inputs["True"])
|
|
return reconstruct_camera_depth(group, camera, depth, choose.outputs[0])
|