Refactor geometry node groups for image depth processing

- Introduced new utility functions in common nodes for evaluating fields and capturing attributes.
- Simplified volume field calculations in image depth cutout and panorama groups by utilizing new utility functions.
- Enhanced readability and maintainability of the image depth cutout and panorama node groups by removing redundant code and improving function usage.
- Adjusted default values for thickness and depth scale in image relief plane group for better user experience.
- Improved handling of geometry attributes and connections in image depth plane group to streamline processing.
This commit is contained in:
2026-09-10 16:46:19 +08:00
parent 489003c2cc
commit 8ae3c1d5b7
20 changed files with 553 additions and 473 deletions

View File

@@ -5,9 +5,9 @@ import math
import bpy
from ..common.depth_surface import (
_math, remove_surface_attributes, split_depth_surface, store_surface_camera,
_math, split_depth_surface, build_surface_camera,
)
from ..common.nodes import float_input, group_input, interface_socket, prepare_node_group
from ..common.nodes import float_input, group_input, interface_socket, prepare_node_group, evaluate_field
from ..common.material import inherit_material_slots
from ..common.smoothing import expand_smooth
@@ -54,20 +54,6 @@ def build_image_depth_panorama_group():
interface_socket(group, "Geometry", "OUTPUT", "NodeSocketGeometry")
nodes, links = group.nodes, group.links
def read(name):
node = nodes.new("GeometryNodeInputNamedAttribute")
node.data_type = "FLOAT_VECTOR"
node.inputs["Name"].default_value = name
return node.outputs["Attribute"]
def store(geometry, name, value, domain):
node = nodes.new("GeometryNodeStoreNamedAttribute")
node.data_type, node.domain = ("FLOAT2" if name == "UVMap" else "FLOAT_VECTOR"), domain
node.inputs["Name"].default_value = name
links.new(geometry, node.inputs["Geometry"])
links.new(value, node.inputs["Value"])
return node.outputs["Geometry"]
def uv(direction):
normalize = nodes.new("ShaderNodeVectorMath")
normalize.operation = "NORMALIZE"
@@ -118,12 +104,11 @@ def build_image_depth_panorama_group():
inputs = group_input(nodes, {"Subdivide"})
sphere = _quad_sphere(group, _math(group, "ADD", _math(group, "POWER", 2, inputs.outputs["Subdivide"]), 1))
position = nodes.new("GeometryNodeInputPosition").outputs[0]
geometry = store(sphere, "o_panorama_direction", position, "POINT")
longitude, latitude, z = uv(read("o_panorama_direction"))
geometry = store(geometry, "o_panorama_uv", combine(longitude, latitude), "POINT")
longitude, latitude, z = uv(position)
coordinates = evaluate_field(group, combine(longitude, latitude), "FLOAT_VECTOR", "POINT")
face = nodes.new("GeometryNodeFieldOnDomain")
face.data_type, face.domain = "FLOAT_VECTOR", "FACE"
links.new(read("o_panorama_direction"), face.inputs["Value"])
links.new(position, face.inputs["Value"])
face_u, face_v, _ = uv(face.outputs["Value"])
correction = _math(group, "ROUND", _math(group, "SUBTRACT", face_u, longitude))
choose = nodes.new("GeometryNodeSwitch")
@@ -131,17 +116,20 @@ def build_image_depth_panorama_group():
links.new(_math(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"])
geometry = store(geometry, "UVMap", combine(choose.outputs[0], latitude), "CORNER")
pixel, _ = depth(read("o_panorama_uv"))
geometry = store(geometry, "o_panorama_distance", pixel, "POINT")
uv_map = nodes.new("GeometryNodeStoreNamedAttribute")
uv_map.data_type, uv_map.domain = "FLOAT2", "CORNER"
uv_map.inputs["Name"].default_value = "UVMap"
links.new(sphere, uv_map.inputs["Geometry"])
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(read("o_panorama_uv"), "Closest"), nearest.inputs["Color"])
links.new(texture(coordinates, "Closest"), nearest.inputs["Color"])
controls = group_input(nodes, {"Validity Threshold"})
invalid = _math(group, "MAXIMUM",
_math(group, "LESS_THAN", nearest.outputs["Alpha"], controls.outputs["Validity Threshold"]),
_math(group, "LESS_THAN", nearest.outputs["Red"], 1e-5))
geometry = store(geometry, "o_panorama_invalid", invalid, "POINT")
face_invalid = read("o_panorama_invalid")
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))
@@ -152,36 +140,31 @@ def build_image_depth_panorama_group():
links.new(any_invalid, selection.inputs["True"])
delete = nodes.new("GeometryNodeDeleteGeometry")
delete.domain, delete.mode = "FACE", "ALL"
links.new(geometry, delete.inputs["Geometry"])
links.new(uv_map.outputs["Geometry"], delete.inputs["Geometry"])
links.new(selection.outputs[0], delete.inputs["Selection"])
controls = group_input(nodes, {"Split Threshold", "Reference Distance"})
strength = controls.outputs["Split Threshold"]
geometry = split_depth_surface(group, delete.outputs[0], depth(combine(face_u, face_v))[0], strength,
geometry, corner_camera, cut_vertex = split_depth_surface(group, delete.outputs[0], depth(combine(face_u, face_v))[0], strength,
_math(group, "DIVIDE", 1, controls.outputs["Reference Distance"]),
face_center=face.outputs["Value"])
geometry, distance = store_surface_camera(group, geometry, read("o_panorama_distance"), strength)
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(read("o_panorama_invalid"), distance.inputs["Switch"])
links.new(face_invalid, distance.inputs["Switch"])
links.new(axes.outputs["X"], 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)))
radial = nodes.new("ShaderNodeVectorMath")
radial.operation = "SCALE"
links.new(read("o_panorama_direction"), radial.inputs[0])
links.new(position, radial.inputs[0])
links.new(radius, radial.inputs[3])
deform = nodes.new("GeometryNodeSetPosition")
links.new(geometry, deform.inputs["Geometry"])
links.new(radial.outputs[0], deform.inputs["Position"])
geometry = remove_surface_attributes(group, deform.outputs[0])
remove = nodes.new("GeometryNodeRemoveAttribute")
remove.pattern_mode = "WILDCARD"
remove.inputs["Name"].default_value = "o_panorama_*"
links.new(geometry, remove.inputs["Geometry"])
geometry = expand_smooth(group, remove.outputs[0], iterations_name="Smooth", weight_name="Smooth Weight")
geometry = expand_smooth(group, deform.outputs[0], iterations_name="Smooth", weight_name="Smooth Weight")
flip = nodes.new("GeometryNodeFlipFaces")
links.new(geometry, flip.inputs["Mesh"])
smooth = nodes.new("GeometryNodeSetShadeSmooth")