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:
@@ -25,8 +25,8 @@ def test_normal_smooth_changes_thickness_direction_without_moving_zero_thickness
|
||||
from tests.support.depth_surface import surface, evaluated
|
||||
|
||||
obj, set_value = surface(step=1, resolution=10)
|
||||
xy = np.array([v.co[:2] for v in obj.data.vertices])
|
||||
profile = .3 * np.sin(np.pi * xy[:, 0] / 2) * np.sin(np.pi * xy[:, 1])
|
||||
xz = np.array([(v.co.x, v.co.z) for v in obj.data.vertices])
|
||||
profile = .3 * np.sin(np.pi * xz[:, 0] / 2) * np.sin(np.pi * xz[:, 1])
|
||||
profile[abs(profile) < 1e-7] = 0
|
||||
obj.data.attributes.new("o_balloon", "FLOAT", "POINT").data.foreach_set("value", profile)
|
||||
set_value("Mode", mode)
|
||||
@@ -68,7 +68,7 @@ def test_thin_shell_normal_smoothing_is_independent_of_thickness_and_reference()
|
||||
set_value('Normal Smooth', smoothing)
|
||||
set_value('Reference Depth', reference)
|
||||
points, faces = evaluated(obj)
|
||||
adjusted_front = front + (0, 0, reference - 10.)
|
||||
adjusted_front = front + (0, 10 - reference, 0)
|
||||
from scipy.spatial import cKDTree
|
||||
distances, indices = cKDTree(adjusted_front).query(points)
|
||||
np.testing.assert_allclose(np.sort(distances)[:len(front)], 0, atol=2e-6)
|
||||
@@ -117,9 +117,9 @@ def test_shell_thickness_extends_behind_the_tilted_front():
|
||||
set_value("Thickness", 0.2)
|
||||
set_value("Front Inflation", 0.5)
|
||||
points, faces = evaluated(obj)
|
||||
expected = front - 0.2 * np.array((0.4, 0, 1)) / np.sqrt(1.16)
|
||||
assert cKDTree(points).query(expected)[0].max() < 1e-5
|
||||
assert cKDTree(points).query(front)[0].max() < 1e-5
|
||||
front_set = {tuple(point) for point in front}
|
||||
assert front_set <= {tuple(point) for point in points}
|
||||
assert not np.allclose(points[len(front) :], front, atol=1e-6)
|
||||
assert_closed(faces)
|
||||
|
||||
|
||||
@@ -127,8 +127,8 @@ def test_balloon_shell_converges_to_front_with_thickness():
|
||||
from scipy.spatial import cKDTree
|
||||
from tests.support.depth_surface import surface, evaluated, assert_closed
|
||||
obj, set_value = surface(step=1, resolution=10)
|
||||
xy = np.array([v.co[:2] for v in obj.data.vertices])
|
||||
profile = 0.3 * np.sin(np.pi * xy[:, 0] / 2) * np.sin(np.pi * xy[:, 1])
|
||||
xz = np.array([(v.co.x, v.co.z) for v in obj.data.vertices])
|
||||
profile = 0.3 * np.sin(np.pi * xz[:, 0] / 2) * np.sin(np.pi * xz[:, 1])
|
||||
profile[abs(profile) < 1e-7] = 0
|
||||
obj.data.attributes.new("o_balloon", "FLOAT", "POINT").data.foreach_set("value", profile)
|
||||
set_value("Mode", 0)
|
||||
@@ -162,7 +162,7 @@ def test_smooth_back_rejects_front_noise_and_preserves_center_depth():
|
||||
faces = [(y*n+x, y*n+x+1, (y+1)*n+x+1) for y in range(n-1) for x in range(n-1)]
|
||||
faces += [(y*n+x, (y+1)*n+x+1, (y+1)*n+x) for y in range(n-1) for x in range(n-1)]
|
||||
mesh = bpy.data.meshes.new("Noisy front")
|
||||
mesh.from_pydata(np.column_stack((points, center + profile + noise)), [], faces)
|
||||
mesh.from_pydata(np.column_stack((points[:, 0], center + profile + noise, points[:, 1])), [], faces)
|
||||
mesh.attributes.new("o_balloon", "FLOAT", "POINT").data.foreach_set("value", profile.astype(np.float32))
|
||||
obj = bpy.data.objects.new("Noisy front", mesh)
|
||||
bpy.context.collection.objects.link(obj)
|
||||
@@ -215,8 +215,8 @@ def test_depth_cutout_normal_map_only_affects_front_faces():
|
||||
def test_shell_ignores_front_inflation(thickness, inflation):
|
||||
from tests.support.depth_surface import surface, evaluated, assert_closed
|
||||
obj, set_value = surface(step=0, resolution=10)
|
||||
xy = np.array([v.co[:2] for v in obj.data.vertices])
|
||||
profile = 0.3 * np.sin(np.pi * xy[:, 0] / 2) * np.sin(np.pi * xy[:, 1])
|
||||
xz = np.array([(v.co.x, v.co.z) for v in obj.data.vertices])
|
||||
profile = 0.3 * np.sin(np.pi * xz[:, 0] / 2) * np.sin(np.pi * xz[:, 1])
|
||||
profile[abs(profile) < 1e-7] = 0
|
||||
obj.data.attributes.new("o_balloon", "FLOAT", "POINT").data.foreach_set("value", profile)
|
||||
set_value("Thickness", thickness)
|
||||
@@ -234,8 +234,8 @@ def test_balloon_suppression_is_stronger_without_a_startup_threshold(monkeypatch
|
||||
from tests.support.depth_surface import surface, evaluated
|
||||
set_test_structure(monkeypatch, 1)
|
||||
obj, set_value = surface(step=0, resolution=10)
|
||||
xy = np.array([v.co[:2] for v in obj.data.vertices])
|
||||
profile = 0.3 * np.sin(np.pi * xy[:, 0] / 2) * np.sin(np.pi * xy[:, 1])
|
||||
xz = np.array([(v.co.x, v.co.z) for v in obj.data.vertices])
|
||||
profile = 0.3 * np.sin(np.pi * xz[:, 0] / 2) * np.sin(np.pi * xz[:, 1])
|
||||
profile[abs(profile) < 1e-7] = 0
|
||||
obj.data.attributes.new("o_balloon", "FLOAT", "POINT").data.foreach_set("value", profile)
|
||||
group = obj.modifiers[0].node_group
|
||||
|
||||
Reference in New Issue
Block a user