feat: Add restore cutout depth extension with edge depth correction
- Introduced a new extension for restoring cutout depth with edge correction. - Implemented edge depth extension algorithm in `edge_depth.py` to enhance depth accuracy near cutout edges. - Updated `generate_moge_artifacts` to include an option for extending depth edges during depth generation. - Modified cutout job processing to enable edge depth extension based on depth request. - Added comprehensive tests for edge depth functionality, ensuring correct behavior under various scenarios. - Updated existing node loading functions to remove asset revision dependencies, simplifying the loading process. - Created new design and proposal documentation outlining the goals and decisions for the extension.
This commit is contained in:
@@ -53,6 +53,7 @@
|
||||
"GeometryNodeRepeatOutput": 3,
|
||||
"GeometryNodeSampleIndex": 3,
|
||||
"GeometryNodeSampleNearest": 1,
|
||||
"GeometryNodeSampleNearestSurface": 1,
|
||||
"GeometryNodeSeparateGeometry": 1,
|
||||
"GeometryNodeSetMaterialIndex": 0,
|
||||
"GeometryNodeSetPosition": 0,
|
||||
@@ -72,6 +73,7 @@
|
||||
"ShaderNodeMath": 2,
|
||||
"ShaderNodeMix": 3,
|
||||
"ShaderNodeSeparateXYZ": 0,
|
||||
"ShaderNodeValue": 1,
|
||||
"ShaderNodeVectorMath": 1
|
||||
}
|
||||
}
|
||||
|
||||
78
tools/nodes/common/cutout_center.py
Normal file
78
tools/nodes/common/cutout_center.py
Normal file
@@ -0,0 +1,78 @@
|
||||
"""Build a shared center on the original Cutout mesh."""
|
||||
|
||||
|
||||
from .nodes import evaluate_field, group_input, sample_field
|
||||
|
||||
|
||||
def vector(group, operation, first, second=None):
|
||||
node = group.nodes.new("ShaderNodeVectorMath")
|
||||
node.operation = operation
|
||||
for value, socket in ((first, node.inputs[0]), (second, node.inputs[3 if operation == "SCALE" else 1])):
|
||||
if value is None:
|
||||
continue
|
||||
if hasattr(value, "node"):
|
||||
group.links.new(value, socket)
|
||||
else:
|
||||
socket.default_value = value
|
||||
return node.outputs[0]
|
||||
|
||||
|
||||
def axes(group, value):
|
||||
node = group.nodes.new("ShaderNodeSeparateXYZ")
|
||||
group.links.new(value, node.inputs[0])
|
||||
return node.outputs
|
||||
|
||||
|
||||
def combine(group, x, y, z=0):
|
||||
node = group.nodes.new("ShaderNodeCombineXYZ")
|
||||
for value, socket in zip((x, y, z), node.inputs):
|
||||
if hasattr(value, "node"):
|
||||
group.links.new(value, socket)
|
||||
else:
|
||||
socket.default_value = value
|
||||
return node.outputs[0]
|
||||
|
||||
|
||||
def set_position(group, geometry, position):
|
||||
node = group.nodes.new("GeometryNodeSetPosition")
|
||||
group.links.new(geometry, node.inputs["Geometry"])
|
||||
group.links.new(position, node.inputs["Position"])
|
||||
return node.outputs[0]
|
||||
|
||||
|
||||
def sample_surface(group, geometry, value, data_type, domain_position, query):
|
||||
"""Keep point indices on points before the face interpolation adapts domains."""
|
||||
field = evaluate_field(group, sample_field(group, geometry, value, data_type), data_type, "POINT")
|
||||
flat = set_position(group, geometry, domain_position)
|
||||
sample = group.nodes.new("GeometryNodeSampleNearestSurface")
|
||||
sample.data_type = data_type
|
||||
group.links.new(flat, sample.inputs["Mesh"])
|
||||
group.links.new(field, sample.inputs["Value"])
|
||||
group.links.new(query, sample.inputs["Sample Position"])
|
||||
return sample.outputs[0]
|
||||
|
||||
|
||||
def build_center_surface(group, unsplit):
|
||||
"""Smooth the unsplit displaced surface without moving its XY coordinates."""
|
||||
nodes, links = group.nodes, group.links
|
||||
controls = group_input(nodes, {"Center Smooth"})
|
||||
position = nodes.new("GeometryNodeInputPosition").outputs[0]
|
||||
components = axes(group, position)
|
||||
uv = nodes.new("GeometryNodeInputNamedAttribute")
|
||||
uv.data_type = "FLOAT_VECTOR"
|
||||
uv.inputs["Name"].default_value = "UVMap"
|
||||
coordinates = uv.outputs["Attribute"]
|
||||
blur = nodes.new("GeometryNodeBlurAttribute")
|
||||
blur.data_type = "FLOAT"
|
||||
links.new(components["Z"], blur.inputs["Value"])
|
||||
links.new(controls.outputs["Center Smooth"], blur.inputs["Iterations"])
|
||||
support = set_position(group, unsplit, combine(group, components["X"], components["Y"], blur.outputs[0]))
|
||||
height = sample_surface(group, support, components["Z"], "FLOAT", coordinates, coordinates)
|
||||
normal = nodes.new("GeometryNodeInputNormal").outputs[0]
|
||||
normal_blur = nodes.new("GeometryNodeBlurAttribute")
|
||||
normal_blur.data_type = "FLOAT_VECTOR"
|
||||
links.new(evaluate_field(group, normal, "FLOAT_VECTOR", "POINT"), normal_blur.inputs["Value"])
|
||||
links.new(controls.outputs["Center Smooth"], normal_blur.inputs["Iterations"])
|
||||
normal = normal_blur.outputs[0]
|
||||
normal = vector(group, "NORMALIZE", sample_surface(group, support, normal, "FLOAT_VECTOR", coordinates, coordinates))
|
||||
return {"geometry": support, "preview": support, "height": height, "normal": normal}
|
||||
@@ -155,7 +155,6 @@ def build_image_cutout_group():
|
||||
group = bpy.data.node_groups.new(name, 'GeometryNodeTree')
|
||||
group.is_modifier, group.use_fake_user = (True, True)
|
||||
group.color_tag = 'GEOMETRY'
|
||||
group['anyimage_asset_revision'] = 13
|
||||
interface_socket(group, 'Geometry', 'INPUT', 'NodeSocketGeometry')
|
||||
interface_socket(group, 'Mode', 'INPUT', 'NodeSocketMenu')
|
||||
float_input(group, 'Thickness', 1.0).description = 'Control how much the surface bulges in Balloon mode. Zero removes the bulge.'
|
||||
|
||||
@@ -107,7 +107,6 @@ def build_image_depth_balloon_group():
|
||||
group = bpy.data.node_groups.new(name, 'GeometryNodeTree')
|
||||
group.is_modifier, group.use_fake_user = (True, True)
|
||||
group.color_tag = 'GEOMETRY'
|
||||
group['anyimage_asset_revision'] = 14
|
||||
interface_socket(group, 'Geometry', 'INPUT', 'NodeSocketGeometry')
|
||||
float_input(group, 'Thickness', 1.0).description = 'Control how much the surface bulges. Zero removes the bulge.'
|
||||
float_input(group, 'Depth Scale', 1.0)
|
||||
|
||||
@@ -39,7 +39,6 @@ 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"] = 15
|
||||
interface_socket(group, "Geometry", "INPUT", "NodeSocketGeometry")
|
||||
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."
|
||||
|
||||
@@ -25,7 +25,6 @@ def build_image_depth_plane_group(image_plane_group):
|
||||
"GeometryNodeTree",
|
||||
)
|
||||
group.is_modifier = True
|
||||
group["anyimage_asset_revision"] = 16
|
||||
geometry = _interface_socket(group, "Geometry", "INPUT", "NodeSocketGeometry")
|
||||
geometry.structure_type = "SINGLE"
|
||||
subdivide = _interface_socket(group, "Subdivide", "INPUT", "NodeSocketInt")
|
||||
|
||||
Reference in New Issue
Block a user