Refactor geometry generation to standardize Blender object coordinates

- Unified the canonical local frame for generated geometries (Plane, Depth Plane, Relief Plane, Cutout, Depth Cutout) to align with Blender's object coordinate system, setting X as horizontal, Z as up, and +Y as depth.
- Removed the `Depth Axis` parameter from `O Image Cutout` and `O Image Depth Cutout`, simplifying the geometry generation process.
- Updated the depth direction defaults to use +Y instead of -Z for `O Image Relief Plane` and Depth Symmetry.
- Adjusted the geometry nodes to ensure thickness, projection, and shell displacements operate along the Y-axis.
- Implemented new capabilities for handling object space normals to align with the new canonical frame.
- Enhanced the Depth Symmetry functionality to mirror across the canonical Y-axis and perform a final rotation to maintain the correct orientation.
- Added tests to validate the new coordinate system and ensure compatibility with existing assets.
This commit is contained in:
2026-09-15 13:33:37 +08:00
parent 591e62085a
commit 4035f5c9e4
47 changed files with 892 additions and 570 deletions

View File

@@ -57,39 +57,39 @@ def _extrude_layers(group, geometry):
node = group.nodes.new("GeometryNodeExtrudeMesh")
node.mode = "FACES"
node.inputs["Individual"].default_value = False
node.inputs["Offset"].default_value = (0.0, 0.0, 1.0)
# Keep distinct front and back vertices before overriding their Z positions.
node.inputs["Offset"].default_value = (0.0, 1.0, 0.0)
# Keep distinct front and back vertices before overriding their Y positions.
node.inputs["Offset Scale"].default_value = 1.0
group.links.new(geometry, node.inputs["Mesh"])
return node
def _offset_geometry_z(group, geometry, z_value):
def _offset_geometry_y(group, geometry, y_value):
nodes = group.nodes
links = group.links
offset = nodes.new("ShaderNodeCombineXYZ")
links.new(z_value, offset.inputs["Z"])
links.new(y_value, offset.inputs["Y"])
set_position = nodes.new("GeometryNodeSetPosition")
links.new(geometry, set_position.inputs["Geometry"])
links.new(offset.outputs["Vector"], set_position.inputs["Offset"])
return set_position.outputs["Geometry"]
def _set_layer_z(group, geometry, extrude, front_z, back_z):
def _set_layer_y(group, geometry, extrude, front_y, back_y):
nodes = group.nodes
links = group.links
choose_z = nodes.new("GeometryNodeSwitch")
choose_z.input_type = "FLOAT"
links.new(extrude.outputs["Top"], choose_z.inputs["Switch"])
links.new(front_z, choose_z.inputs["False"])
links.new(back_z, choose_z.inputs["True"])
choose_y = nodes.new("GeometryNodeSwitch")
choose_y.input_type = "FLOAT"
links.new(extrude.outputs["Top"], choose_y.inputs["Switch"])
links.new(front_y, choose_y.inputs["False"])
links.new(back_y, choose_y.inputs["True"])
position = nodes.new("GeometryNodeInputPosition")
separate = nodes.new("ShaderNodeSeparateXYZ")
links.new(position.outputs["Position"], separate.inputs["Vector"])
combine = nodes.new("ShaderNodeCombineXYZ")
links.new(separate.outputs["X"], combine.inputs["X"])
links.new(separate.outputs["Y"], combine.inputs["Y"])
links.new(choose_z.outputs["Output"], combine.inputs["Z"])
links.new(choose_y.outputs["Output"], combine.inputs["Y"])
links.new(separate.outputs["Z"], combine.inputs["Z"])
set_position = nodes.new("GeometryNodeSetPosition")
links.new(extrude.outputs["Mesh"], set_position.inputs["Geometry"])
links.new(combine.outputs["Vector"], set_position.inputs["Position"])
@@ -100,11 +100,11 @@ def _set_layer_z(group, geometry, extrude, front_z, back_z):
links.new(extrude.outputs["Side"], side.inputs["Selection"])
flip_side = nodes.new("GeometryNodeFlipFaces")
links.new(side.outputs["Selection"], flip_side.inputs["Mesh"])
front = _offset_geometry_z(
group, geometry, front_z
front = _offset_geometry_y(
group, geometry, front_y
)
back = _offset_geometry_z(
group, geometry, back_z
back = _offset_geometry_y(
group, geometry, back_y
)
flip_back = nodes.new("GeometryNodeFlipFaces")
links.new(back, flip_back.inputs["Mesh"])