Update SnapForm to version 0.10.10 and add technical documentation
- Bump SnapForm version in uv.lock from 0.9.30 to 0.10.10. - Introduce comprehensive technical documentation for SnapForm, detailing features, usage instructions, and development guidelines.
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import importlib.util
|
||||
import inspect
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
@@ -60,6 +59,22 @@ class ImageDepthTest(unittest.TestCase):
|
||||
np.array(((1.0, 2.0), (3.0, 4.0)), dtype=np.float32),
|
||||
)
|
||||
|
||||
def test_extract_depth_arrays_returns_every_frame(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
npz_path = Path(directory) / "results.npz"
|
||||
np.savez_compressed(
|
||||
npz_path,
|
||||
depth=np.arange(12, dtype=np.float32).reshape(3, 2, 2),
|
||||
)
|
||||
|
||||
depth_frames = self.image_depth.extract_depth_arrays(npz_path)
|
||||
|
||||
self.assertEqual(len(depth_frames), 3)
|
||||
np.testing.assert_array_equal(
|
||||
depth_frames[1],
|
||||
np.array(((4.0, 5.0), (6.0, 7.0)), dtype=np.float32),
|
||||
)
|
||||
|
||||
def test_accepts_depths_key_with_single_channel(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
npz_path = Path(directory) / "results.npz"
|
||||
@@ -72,6 +87,261 @@ class ImageDepthTest(unittest.TestCase):
|
||||
|
||||
self.assertEqual(depth.shape, (2, 3))
|
||||
|
||||
def test_is_animated_image_accepts_movie_and_sequence(self):
|
||||
self.assertTrue(
|
||||
self.image_depth.is_animated_image(
|
||||
SimpleNamespace(source="MOVIE")
|
||||
)
|
||||
)
|
||||
self.assertTrue(
|
||||
self.image_depth.is_animated_image(
|
||||
SimpleNamespace(source="SEQUENCE")
|
||||
)
|
||||
)
|
||||
self.assertFalse(
|
||||
self.image_depth.is_animated_image(
|
||||
SimpleNamespace(source="FILE")
|
||||
)
|
||||
)
|
||||
|
||||
def test_video_total_frames_reads_movie_duration(self):
|
||||
image = SimpleNamespace(source="MOVIE", frame_duration=97)
|
||||
|
||||
self.assertEqual(self.image_depth.video_total_frames(image), 97)
|
||||
|
||||
def test_video_total_frames_counts_sequence_files(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
(root / "foreground-0001.png").touch()
|
||||
(root / "foreground-0002.png").touch()
|
||||
image = SimpleNamespace(
|
||||
source="SEQUENCE",
|
||||
filepath=str(root / "foreground-0001.png"),
|
||||
)
|
||||
|
||||
self.assertEqual(self.image_depth.video_total_frames(image), 2)
|
||||
|
||||
def test_video_total_frames_returns_one_for_still_image(self):
|
||||
image = SimpleNamespace(source="FILE", frame_duration=1)
|
||||
|
||||
self.assertEqual(self.image_depth.video_total_frames(image), 1)
|
||||
|
||||
def test_default_extract_frames_uses_empty_image_frames(self):
|
||||
source_object = SimpleNamespace(
|
||||
data=SimpleNamespace(source="MOVIE", frame_duration=97),
|
||||
image_user=SimpleNamespace(frame_duration=24),
|
||||
)
|
||||
|
||||
self.assertEqual(self.image_depth.default_extract_frames(source_object), 24)
|
||||
|
||||
def test_default_extract_frames_caps_at_video_total(self):
|
||||
source_object = SimpleNamespace(
|
||||
data=SimpleNamespace(source="MOVIE", frame_duration=97),
|
||||
image_user=SimpleNamespace(frame_duration=200),
|
||||
)
|
||||
|
||||
self.assertEqual(self.image_depth.default_extract_frames(source_object), 97)
|
||||
|
||||
def test_default_extract_frames_falls_back_to_video_total(self):
|
||||
source_object = SimpleNamespace(
|
||||
data=SimpleNamespace(source="MOVIE", frame_duration=97),
|
||||
)
|
||||
|
||||
self.assertEqual(self.image_depth.default_extract_frames(source_object), 97)
|
||||
|
||||
def test_extract_frame_range_honors_offset_within_clip(self):
|
||||
source_object = SimpleNamespace(
|
||||
data=SimpleNamespace(source="MOVIE", frame_duration=97),
|
||||
image_user=SimpleNamespace(
|
||||
frame_start=4,
|
||||
frame_offset=70,
|
||||
frame_duration=24,
|
||||
),
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.image_depth.extract_frame_range(source_object),
|
||||
(71, 24),
|
||||
)
|
||||
|
||||
def test_extract_frame_range_clamps_large_offset_to_clip_tail(self):
|
||||
source_object = SimpleNamespace(
|
||||
data=SimpleNamespace(source="MOVIE", frame_duration=97),
|
||||
image_user=SimpleNamespace(
|
||||
frame_start=1,
|
||||
frame_offset=90,
|
||||
frame_duration=24,
|
||||
),
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.image_depth.extract_frame_range(source_object),
|
||||
(74, 24),
|
||||
)
|
||||
|
||||
def test_extract_frame_range_clamps_negative_offset_to_start(self):
|
||||
source_object = SimpleNamespace(
|
||||
data=SimpleNamespace(source="MOVIE", frame_duration=97),
|
||||
image_user=SimpleNamespace(
|
||||
frame_start=1,
|
||||
frame_offset=-5,
|
||||
frame_duration=24,
|
||||
),
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.image_depth.extract_frame_range(source_object),
|
||||
(1, 24),
|
||||
)
|
||||
|
||||
def test_extract_frame_range_returns_full_clip_for_still(self):
|
||||
source_object = SimpleNamespace(
|
||||
data=SimpleNamespace(source="FILE", frame_duration=1),
|
||||
image_user=SimpleNamespace(
|
||||
frame_start=1,
|
||||
frame_offset=50,
|
||||
frame_duration=24,
|
||||
),
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.image_depth.extract_frame_range(source_object),
|
||||
(1, 1),
|
||||
)
|
||||
|
||||
def test_configure_image_user_preserves_cyclic_setting(self):
|
||||
image_user = SimpleNamespace(
|
||||
frame_start=0,
|
||||
frame_offset=5,
|
||||
use_auto_refresh=False,
|
||||
use_cyclic=False,
|
||||
frame_duration=1,
|
||||
)
|
||||
|
||||
self.image_depth.configure_image_user(
|
||||
image_user,
|
||||
97,
|
||||
frame_start=4,
|
||||
frame_offset=70,
|
||||
)
|
||||
|
||||
self.assertFalse(image_user.use_cyclic)
|
||||
self.assertTrue(image_user.use_auto_refresh)
|
||||
self.assertEqual(image_user.frame_start, 4)
|
||||
self.assertEqual(image_user.frame_offset, 70)
|
||||
self.assertEqual(image_user.frame_duration, 97)
|
||||
self.image_depth.configure_image_user(
|
||||
image_user,
|
||||
use_cyclic=True,
|
||||
)
|
||||
self.assertTrue(image_user.use_cyclic)
|
||||
|
||||
def test_image_user_settings_reads_empty_values(self):
|
||||
source_object = SimpleNamespace(
|
||||
image_user=SimpleNamespace(
|
||||
frame_start=4,
|
||||
frame_offset=70,
|
||||
frame_duration=12,
|
||||
)
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.image_depth.image_user_settings(source_object),
|
||||
(4, 70, 12, False),
|
||||
)
|
||||
|
||||
source_object.image_user.use_cyclic = True
|
||||
self.assertEqual(
|
||||
self.image_depth.image_user_settings(source_object),
|
||||
(4, 70, 12, True),
|
||||
)
|
||||
|
||||
def test_image_user_settings_defaults_without_user(self):
|
||||
self.assertEqual(
|
||||
self.image_depth.image_user_settings(
|
||||
SimpleNamespace(image_user=None)
|
||||
),
|
||||
(1, 0, 0, False),
|
||||
)
|
||||
|
||||
def test_image_base_name_strips_video_extension(self):
|
||||
image = SimpleNamespace(name="微信视频2026-07-23_192756_414.mp4")
|
||||
|
||||
self.assertEqual(
|
||||
self.image_depth.image_base_name(image),
|
||||
"微信视频2026-07-23_192756_414",
|
||||
)
|
||||
|
||||
def test_removed_background_name_strips_video_extension(self):
|
||||
source_object = SimpleNamespace(data=SimpleNamespace(name="clip.mp4"))
|
||||
|
||||
self.assertEqual(
|
||||
self.image_depth.removed_background_data_name(source_object),
|
||||
"clip.foreground",
|
||||
)
|
||||
|
||||
def test_force_sequence_source_keeps_loaded_sequence(self):
|
||||
image = SimpleNamespace(source="SEQUENCE")
|
||||
|
||||
result = self.image_depth.force_sequence_source(image)
|
||||
|
||||
self.assertIs(result, image)
|
||||
self.assertEqual(image.source, "SEQUENCE")
|
||||
|
||||
def test_force_sequence_source_switches_single_image(self):
|
||||
image = SimpleNamespace(source="FILE")
|
||||
|
||||
result = self.image_depth.force_sequence_source(image)
|
||||
|
||||
self.assertIs(result, image)
|
||||
self.assertEqual(image.source, "SEQUENCE")
|
||||
|
||||
def test_force_sequence_source_reports_unloadable_sequence(self):
|
||||
class BlockedImage:
|
||||
@property
|
||||
def source(self):
|
||||
return "FILE"
|
||||
|
||||
@source.setter
|
||||
def source(self, value):
|
||||
raise RuntimeError("blocked")
|
||||
|
||||
with self.assertRaisesRegex(RuntimeError, "cannot load"):
|
||||
self.image_depth.force_sequence_source(BlockedImage())
|
||||
|
||||
def test_collect_sequence_frames_returns_numbered_files_in_order(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
(root / "frame-0001.jpg").touch()
|
||||
(root / "frame-0002.jpg").touch()
|
||||
(root / "frame-0003.jpg").touch()
|
||||
(root / "notes.txt").touch()
|
||||
image = SimpleNamespace(
|
||||
source="SEQUENCE",
|
||||
filepath=str(root / "frame-0002.jpg"),
|
||||
)
|
||||
|
||||
frames = self.image_depth.collect_sequence_frames(image)
|
||||
|
||||
self.assertEqual(
|
||||
[path.name for path in frames],
|
||||
["frame-0001.jpg", "frame-0002.jpg", "frame-0003.jpg"],
|
||||
)
|
||||
|
||||
def test_sorted_frame_paths_uses_numeric_frame_order(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
(root / "frame-2.jpg").touch()
|
||||
(root / "frame-10.jpg").touch()
|
||||
(root / "frame-1.jpg").touch()
|
||||
|
||||
frames = self.image_depth.sorted_frame_paths(root)
|
||||
|
||||
self.assertEqual(
|
||||
[path.name for path in frames],
|
||||
["frame-1.jpg", "frame-2.jpg", "frame-10.jpg"],
|
||||
)
|
||||
|
||||
def test_accepts_single_depth_map_with_channel_axis(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
npz_path = Path(directory) / "results.npz"
|
||||
@@ -205,16 +475,6 @@ class ImageDepthTest(unittest.TestCase):
|
||||
(12, 8),
|
||||
)
|
||||
|
||||
def test_modifiers_use_native_names_and_fixed_levels(self):
|
||||
source = inspect.getsource(self.image_depth.build_depth_plane)
|
||||
|
||||
self.assertIn('modifiers.new("Subdivision", "SUBSURF")', source)
|
||||
self.assertIn('modifiers.new("Displace", "DISPLACE")', source)
|
||||
self.assertNotIn("DA3 Subdivision", source)
|
||||
self.assertNotIn("DA3 Displace", source)
|
||||
self.assertIn("subdivision.levels = 1", source)
|
||||
self.assertIn("subdivision.render_levels = 2", source)
|
||||
|
||||
def test_plane_fit_transform_matches_source_size_and_offset(self):
|
||||
source = SimpleNamespace(
|
||||
data=SimpleNamespace(size=(800, 400)),
|
||||
@@ -233,37 +493,6 @@ class ImageDepthTest(unittest.TestCase):
|
||||
):
|
||||
self.assertAlmostEqual(value, expected)
|
||||
|
||||
def test_source_empty_is_only_removed_when_requested(self):
|
||||
source = inspect.getsource(self.image_depth.finish_depth_plane)
|
||||
|
||||
self.assertIn("source_name = source_object.name", source)
|
||||
self.assertIn("if delete_source:", source)
|
||||
self.assertIn(
|
||||
"bpy.data.objects.remove(source_object, do_unlink=True)",
|
||||
source,
|
||||
)
|
||||
self.assertNotIn("source_object.name =", source)
|
||||
self.assertIn(
|
||||
"bpy.data.objects.remove(source_object, do_unlink=True)\n"
|
||||
" plane_object.name = source_name",
|
||||
source,
|
||||
)
|
||||
|
||||
def test_original_depth_mode_uses_uv_and_zero_midlevel(self):
|
||||
source = inspect.getsource(self.image_depth.build_image_depth_plane)
|
||||
|
||||
self.assertIn("texture.image = source_object.data", source)
|
||||
self.assertIn('modifiers.new("Displace", "DISPLACE")', source)
|
||||
self.assertIn("displace.texture = texture", source)
|
||||
self.assertIn('displace.texture_coords = "UV"', source)
|
||||
self.assertNotIn("displace.direction", source)
|
||||
self.assertNotIn("displace.strength", source)
|
||||
self.assertIn(
|
||||
"displace.mid_level = ORIGINAL_DISPLACEMENT_MIDLEVEL",
|
||||
source,
|
||||
)
|
||||
self.assertIn("plane_object.matrix_world =", source)
|
||||
|
||||
def test_process_resolution_scales_the_image_long_edge(self):
|
||||
image = SimpleNamespace(size=(1080, 1920))
|
||||
|
||||
@@ -272,11 +501,6 @@ class ImageDepthTest(unittest.TestCase):
|
||||
960,
|
||||
)
|
||||
|
||||
def test_mesh_uses_source_object_name(self):
|
||||
source = inspect.getsource(self.image_depth.create_plane_mesh)
|
||||
|
||||
self.assertIn("bpy.data.meshes.new(source_object.name)", source)
|
||||
|
||||
def test_depth_data_uses_source_image_name(self):
|
||||
source_object = SimpleNamespace(
|
||||
name="obj_img",
|
||||
@@ -292,17 +516,20 @@ class ImageDepthTest(unittest.TestCase):
|
||||
self.image_depth.depth_data_name(source_object),
|
||||
"img.001.depth",
|
||||
)
|
||||
estimate_source = inspect.getsource(
|
||||
self.image_depth.build_depth_plane
|
||||
)
|
||||
original_source = inspect.getsource(
|
||||
self.image_depth.build_image_depth_plane
|
||||
)
|
||||
self.assertIn(
|
||||
"depth_name = depth_name or depth_data_name(source_object)",
|
||||
estimate_source,
|
||||
)
|
||||
self.assertIn("depth_data_name(source_object)", original_source)
|
||||
|
||||
def test_copy_depth_image_renames_still_source(self):
|
||||
class FakeImage:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def copy(self):
|
||||
return FakeImage("img.png.001")
|
||||
|
||||
source_object = SimpleNamespace(data=FakeImage("img.png"))
|
||||
|
||||
depth_image = self.image_depth.copy_depth_image(source_object)
|
||||
|
||||
self.assertEqual(depth_image.name, "img.depth")
|
||||
|
||||
def test_removed_background_name_uses_source_image_base_name(self):
|
||||
source_object = SimpleNamespace(
|
||||
@@ -311,213 +538,14 @@ class ImageDepthTest(unittest.TestCase):
|
||||
|
||||
self.assertEqual(
|
||||
self.image_depth.removed_background_data_name(source_object),
|
||||
"img.rb",
|
||||
"img.foreground",
|
||||
)
|
||||
source_object.data.name = "img.png.001"
|
||||
self.assertEqual(
|
||||
self.image_depth.removed_background_data_name(source_object),
|
||||
"img.001.rb",
|
||||
"img.001.foreground",
|
||||
)
|
||||
|
||||
def test_depth_name_override_keeps_original_base_name(self):
|
||||
source = inspect.getsource(self.image_depth.build_depth_plane)
|
||||
|
||||
self.assertIn(
|
||||
"depth_name = depth_name or depth_data_name(source_object)",
|
||||
source,
|
||||
)
|
||||
self.assertIn(
|
||||
"color_image if color_image is not None else source_object.data",
|
||||
source,
|
||||
)
|
||||
|
||||
def test_original_depth_background_only_changes_material_color(self):
|
||||
source = inspect.getsource(self.image_depth.build_image_depth_plane)
|
||||
|
||||
self.assertIn("texture.image = source_object.data", source)
|
||||
self.assertIn(
|
||||
"source_object.data if displacement_via == \"MATERIAL\" else None",
|
||||
source,
|
||||
)
|
||||
self.assertIn(
|
||||
"color_image if color_image is not None else source_object.data",
|
||||
source,
|
||||
)
|
||||
|
||||
def test_material_uses_source_object_name(self):
|
||||
da3_source = inspect.getsource(self.image_depth.build_depth_plane)
|
||||
image_source = inspect.getsource(
|
||||
self.image_depth.build_image_depth_plane
|
||||
)
|
||||
|
||||
self.assertIn(
|
||||
"create_material(\n source_name,",
|
||||
da3_source,
|
||||
)
|
||||
self.assertIn("create_material(\n source_name,", image_source)
|
||||
self.assertNotIn("DA3DepthMaterial", da3_source)
|
||||
|
||||
def test_displace_texture_uses_extend(self):
|
||||
source = inspect.getsource(
|
||||
self.image_depth.build_depth_plane
|
||||
)
|
||||
|
||||
self.assertIn(
|
||||
"depth_name = depth_name or depth_data_name(source_object)",
|
||||
source,
|
||||
)
|
||||
self.assertIn("create_depth_image(\n depth_name,", source)
|
||||
self.assertIn("bpy.data.textures.new(\n depth_name,", source)
|
||||
self.assertIn('texture.extension = "EXTEND"', source)
|
||||
|
||||
def test_material_supports_bump_and_optional_displacement(self):
|
||||
source = inspect.getsource(self.image_depth.create_material)
|
||||
|
||||
self.assertIn('nodes.new("ShaderNodeBump")', source)
|
||||
self.assertIn(
|
||||
'color_texture.outputs["Color"], bump.inputs["Height"]',
|
||||
source,
|
||||
)
|
||||
self.assertIn(
|
||||
'bump.outputs["Normal"], shader.inputs["Normal"]',
|
||||
source,
|
||||
)
|
||||
self.assertIn(
|
||||
'bump.inputs["Distance"].default_value = '
|
||||
"BUMP_BASE_DISTANCE * depth_scale",
|
||||
source,
|
||||
)
|
||||
self.assertIn('nodes.new("ShaderNodeFloatCurve")', source)
|
||||
self.assertIn(
|
||||
'roughness_curve.inputs["Value"]',
|
||||
source,
|
||||
)
|
||||
self.assertIn(
|
||||
'shader.inputs["Roughness"]',
|
||||
source,
|
||||
)
|
||||
self.assertIn(
|
||||
'curve_points[0].location = (0.0, 0.5)',
|
||||
source,
|
||||
)
|
||||
self.assertIn(
|
||||
'curve_points[-1].location = (1.0, 0.1)',
|
||||
source,
|
||||
)
|
||||
self.assertNotIn('shader.inputs["IOR"]', source)
|
||||
self.assertIn(
|
||||
'roughness_curve.location = (-300.0, 320.0)',
|
||||
source,
|
||||
)
|
||||
self.assertIn('bump.location = (-300.0, -80.0)', source)
|
||||
self.assertIn('nodes.new("ShaderNodeDisplacement")', source)
|
||||
self.assertIn(
|
||||
'depth_texture.outputs["Color"],\n'
|
||||
' displacement.inputs["Height"]',
|
||||
source,
|
||||
)
|
||||
self.assertIn(
|
||||
'displacement.outputs["Displacement"],\n'
|
||||
' output.inputs["Displacement"]',
|
||||
source,
|
||||
)
|
||||
self.assertIn(
|
||||
'displacement.inputs["Midlevel"].default_value',
|
||||
source,
|
||||
)
|
||||
self.assertIn(
|
||||
'displacement.inputs["Scale"].default_value',
|
||||
source,
|
||||
)
|
||||
self.assertIn("set_displacement_only(material)", source)
|
||||
|
||||
def test_unshaded_material_uses_alpha_mixed_emission(self):
|
||||
source = inspect.getsource(self.image_depth.create_material)
|
||||
|
||||
unshaded_start = source.index("if unshaded:")
|
||||
shaded_start = source.index("else:", unshaded_start)
|
||||
displacement_start = source.index(
|
||||
"if displacement_image is not None:",
|
||||
shaded_start,
|
||||
)
|
||||
unshaded_source = source[unshaded_start:shaded_start]
|
||||
shaded_source = source[shaded_start:displacement_start]
|
||||
|
||||
self.assertIn('nodes.new("ShaderNodeEmission")', unshaded_source)
|
||||
self.assertIn(
|
||||
'nodes.new("ShaderNodeBsdfTransparent")',
|
||||
unshaded_source,
|
||||
)
|
||||
self.assertIn('nodes.new("ShaderNodeMixShader")', unshaded_source)
|
||||
self.assertIn(
|
||||
'color_texture.outputs["Color"]',
|
||||
unshaded_source,
|
||||
)
|
||||
self.assertIn('emission.inputs["Color"]', unshaded_source)
|
||||
self.assertIn('color_texture.outputs["Alpha"]', unshaded_source)
|
||||
self.assertIn('mix_shader.inputs["Fac"]', unshaded_source)
|
||||
self.assertIn('transparent.outputs["BSDF"]', unshaded_source)
|
||||
self.assertIn('mix_shader.inputs[1]', unshaded_source)
|
||||
self.assertIn('emission.outputs["Emission"]', unshaded_source)
|
||||
self.assertIn('mix_shader.inputs[2]', unshaded_source)
|
||||
self.assertIn('mix_shader.outputs["Shader"]', unshaded_source)
|
||||
self.assertNotIn("ShaderNodeBsdfPrincipled", unshaded_source)
|
||||
self.assertNotIn("ShaderNodeBump", unshaded_source)
|
||||
self.assertNotIn("ShaderNodeFloatCurve", unshaded_source)
|
||||
self.assertIn("ShaderNodeBsdfPrincipled", shaded_source)
|
||||
self.assertGreater(displacement_start, unshaded_start)
|
||||
|
||||
def test_displacement_values_follow_depth_source(self):
|
||||
estimate_source = inspect.getsource(
|
||||
self.image_depth.build_depth_plane
|
||||
)
|
||||
original_source = inspect.getsource(
|
||||
self.image_depth.build_image_depth_plane
|
||||
)
|
||||
|
||||
self.assertIn(
|
||||
"displacement_midlevel=DISPLACEMENT_MIDLEVEL",
|
||||
estimate_source,
|
||||
)
|
||||
self.assertIn(
|
||||
"displacement_scale=DISPLACEMENT_STRENGTH",
|
||||
estimate_source,
|
||||
)
|
||||
self.assertIn(
|
||||
"displacement_midlevel=ORIGINAL_DISPLACEMENT_MIDLEVEL",
|
||||
original_source,
|
||||
)
|
||||
self.assertIn(
|
||||
"displacement_scale=ORIGINAL_DISPLACEMENT_STRENGTH",
|
||||
original_source,
|
||||
)
|
||||
self.assertEqual(self.image_depth.DISPLACEMENT_MIDLEVEL, 1.0)
|
||||
self.assertEqual(self.image_depth.DISPLACEMENT_STRENGTH, -1.0)
|
||||
self.assertEqual(
|
||||
self.image_depth.ORIGINAL_DISPLACEMENT_MIDLEVEL,
|
||||
0.0,
|
||||
)
|
||||
self.assertEqual(
|
||||
self.image_depth.ORIGINAL_DISPLACEMENT_STRENGTH,
|
||||
1.0,
|
||||
)
|
||||
|
||||
def test_material_displacement_mode_skips_displace_modifier(self):
|
||||
estimate_source = inspect.getsource(
|
||||
self.image_depth.build_depth_plane
|
||||
)
|
||||
original_source = inspect.getsource(
|
||||
self.image_depth.build_image_depth_plane
|
||||
)
|
||||
|
||||
for source in (estimate_source, original_source):
|
||||
self.assertIn('if displacement_via == "MODIFIER":', source)
|
||||
self.assertIn(
|
||||
'if displacement_via == "MATERIAL" else None',
|
||||
source,
|
||||
)
|
||||
self.assertIn("unshaded=unshaded", source)
|
||||
|
||||
def test_surface_displacement_is_set_to_displacement_only(self):
|
||||
class Material:
|
||||
surface_displacement_method = "BUMP"
|
||||
@@ -530,12 +558,6 @@ class ImageDepthTest(unittest.TestCase):
|
||||
"DISPLACEMENT",
|
||||
)
|
||||
|
||||
def test_plane_transform_scales_depth_axis(self):
|
||||
source = inspect.getsource(self.image_depth.apply_plane_transform)
|
||||
|
||||
self.assertIn("(0.0, 0.0, scale_z, 0.0)", source)
|
||||
self.assertIn("plane_object.scale.z", source)
|
||||
|
||||
def test_plane_bounds_keep_image_aspect_and_empty_offset(self):
|
||||
source = SimpleNamespace(
|
||||
data=SimpleNamespace(size=(800, 400)),
|
||||
|
||||
Reference in New Issue
Block a user