USD: Add more thorough testing of various material setups
Newly validates the following: - Image mapping transforms on import and export - Typical normal map setups on import and export - Alpha-clip node setups on import (was already tested for export) Pull Request: https://projects.blender.org/blender/blender/pulls/126776
This commit is contained in:
committed by
Jesse Yurkovich
parent
6bd515e0d2
commit
b265161aea
@@ -264,9 +264,9 @@ TEST_F(UsdExportTest, usd_export_material)
|
||||
}
|
||||
|
||||
/* File sanity checks. */
|
||||
EXPECT_EQ(BLI_listbase_count(&bfile->main->objects), 3);
|
||||
/* There are 4 materials because of the Dots Stroke. */
|
||||
EXPECT_EQ(BLI_listbase_count(&bfile->main->materials), 4);
|
||||
EXPECT_EQ(BLI_listbase_count(&bfile->main->objects), 6);
|
||||
/* There is 1 additional material because of the "Dots Stroke". */
|
||||
EXPECT_EQ(BLI_listbase_count(&bfile->main->materials), 7);
|
||||
|
||||
Material *material = reinterpret_cast<Material *>(
|
||||
BKE_libblock_find_name(bfile->main, ID_MA, "Material"));
|
||||
@@ -279,6 +279,8 @@ TEST_F(UsdExportTest, usd_export_material)
|
||||
params.export_textures = false;
|
||||
params.export_uvmaps = true;
|
||||
params.generate_preview_surface = true;
|
||||
params.generate_materialx_network = false;
|
||||
params.convert_world_material = false;
|
||||
params.relative_paths = false;
|
||||
|
||||
const bool result = USD_export(context, output_filename.c_str(), ¶ms, false, nullptr);
|
||||
|
||||
@@ -96,6 +96,7 @@ TEST_F(UsdUsdzExportTest, usdz_export)
|
||||
|
||||
USDExportParams params;
|
||||
params.export_materials = false;
|
||||
params.convert_world_material = false;
|
||||
params.visible_objects_only = false;
|
||||
|
||||
bool result = USD_export(context, output_filepath, ¶ms, false, nullptr);
|
||||
|
||||
Submodule tests/data updated: 528aadad4b...a77ff59342
@@ -132,18 +132,68 @@ class USDExportTest(AbstractUSDTest):
|
||||
Gf.Vec3d(extent[1]), Gf.Vec3d(0.7515701, 0.5500924, 0.9027928)
|
||||
)
|
||||
|
||||
def test_opacity_threshold(self):
|
||||
# Note that the scene file used here is shared with a different test.
|
||||
# Here we assume that it has a Principled BSDF material with
|
||||
# a texture connected to its Base Color input.
|
||||
bpy.ops.wm.open_mainfile(filepath=str(self.testdir / "usd_materials_export.blend"))
|
||||
def test_material_transforms(self):
|
||||
"""Validate correct export of image mapping parameters to the UsdTransform2d shader def"""
|
||||
|
||||
export_path = self.tempdir / "opaque_material.usda"
|
||||
res = bpy.ops.wm.usd_export(
|
||||
filepath=str(export_path),
|
||||
export_materials=True,
|
||||
evaluation_mode="RENDER",
|
||||
)
|
||||
# Use the common materials .blend file
|
||||
bpy.ops.wm.open_mainfile(filepath=str(self.testdir / "usd_materials_export.blend"))
|
||||
export_path = self.tempdir / "material_transforms.usda"
|
||||
res = bpy.ops.wm.usd_export(filepath=str(export_path), export_materials=True)
|
||||
self.assertEqual({'FINISHED'}, res, f"Unable to export to {export_path}")
|
||||
|
||||
# Inspect the UsdTransform2d prim on the "Transforms" material
|
||||
stage = Usd.Stage.Open(str(export_path))
|
||||
shader_prim = stage.GetPrimAtPath("/root/_materials/Transforms/Mapping")
|
||||
shader = UsdShade.Shader(shader_prim)
|
||||
self.assertEqual(shader.GetIdAttr().Get(), "UsdTransform2d")
|
||||
input_trans = shader.GetInput('translation')
|
||||
input_rot = shader.GetInput('rotation')
|
||||
input_scale = shader.GetInput('scale')
|
||||
self.assertEqual(input_trans.Get(), [0.75, 0.75])
|
||||
self.assertEqual(input_rot.Get(), 180)
|
||||
self.assertEqual(input_scale.Get(), [0.5, 0.5])
|
||||
|
||||
def test_material_normal_maps(self):
|
||||
"""Validate correct export of typical normal map setups to the UsdUVTexture shader def.
|
||||
Namely validate that scale, bias, and ColorSpace settings are correct"""
|
||||
|
||||
# Use the common materials .blend file
|
||||
bpy.ops.wm.open_mainfile(filepath=str(self.testdir / "usd_materials_export.blend"))
|
||||
export_path = self.tempdir / "material_normalmaps.usda"
|
||||
res = bpy.ops.wm.usd_export(filepath=str(export_path), export_materials=True)
|
||||
self.assertEqual({'FINISHED'}, res, f"Unable to export to {export_path}")
|
||||
|
||||
# Inspect the UsdUVTexture prim on the "typical" "NormalMap" material
|
||||
stage = Usd.Stage.Open(str(export_path))
|
||||
shader_prim = stage.GetPrimAtPath("/root/_materials/NormalMap/Image_Texture")
|
||||
shader = UsdShade.Shader(shader_prim)
|
||||
self.assertEqual(shader.GetIdAttr().Get(), "UsdUVTexture")
|
||||
input_scale = shader.GetInput('scale')
|
||||
input_bias = shader.GetInput('bias')
|
||||
input_colorspace = shader.GetInput('sourceColorSpace')
|
||||
self.assertEqual(input_scale.Get(), [2, 2, 2, 2])
|
||||
self.assertEqual(input_bias.Get(), [-1, -1, -1, -1])
|
||||
self.assertEqual(input_colorspace.Get(), 'raw')
|
||||
|
||||
# Inspect the UsdUVTexture prim on the "inverted" "NormalMap_Scale_Bias" material
|
||||
stage = Usd.Stage.Open(str(export_path))
|
||||
shader_prim = stage.GetPrimAtPath("/root/_materials/NormalMap_Scale_Bias/Image_Texture")
|
||||
shader = UsdShade.Shader(shader_prim)
|
||||
self.assertEqual(shader.GetIdAttr().Get(), "UsdUVTexture")
|
||||
input_scale = shader.GetInput('scale')
|
||||
input_bias = shader.GetInput('bias')
|
||||
input_colorspace = shader.GetInput('sourceColorSpace')
|
||||
self.assertEqual(input_scale.Get(), [2, -2, 2, 1])
|
||||
self.assertEqual(input_bias.Get(), [-1, 1, -1, 0])
|
||||
self.assertEqual(input_colorspace.Get(), 'raw')
|
||||
|
||||
def test_material_opacity_threshold(self):
|
||||
"""Validate correct export of opacity and opacity_threshold parameters to the UsdPreviewSurface shader def"""
|
||||
|
||||
# Use the common materials .blend file
|
||||
bpy.ops.wm.open_mainfile(filepath=str(self.testdir / "usd_materials_export.blend"))
|
||||
export_path = self.tempdir / "material_opacities.usda"
|
||||
res = bpy.ops.wm.usd_export(filepath=str(export_path), export_materials=True)
|
||||
self.assertEqual({'FINISHED'}, res, f"Unable to export to {export_path}")
|
||||
|
||||
# Inspect and validate the exported USD for the opaque blend case.
|
||||
|
||||
@@ -33,7 +33,6 @@ class AbstractUSDTest(unittest.TestCase):
|
||||
|
||||
|
||||
class USDImportTest(AbstractUSDTest):
|
||||
|
||||
def test_import_operator(self):
|
||||
"""Test running the import operator on valid and invalid files."""
|
||||
|
||||
@@ -203,6 +202,65 @@ class USDImportTest(AbstractUSDTest):
|
||||
self.assertAlmostEqual(2.281, test_cam.shift_x, 3)
|
||||
self.assertAlmostEqual(0.496, test_cam.shift_y, 3)
|
||||
|
||||
def test_import_materials(self):
|
||||
"""Validate UsdPreviewSurface shader graphs."""
|
||||
|
||||
# Use the existing materials test file to create the USD file
|
||||
# for import. It is validated as part of the bl_usd_export test.
|
||||
bpy.ops.wm.open_mainfile(filepath=str(self.testdir / "usd_materials_export.blend"))
|
||||
testfile = str(self.tempdir / "temp_materials.usda")
|
||||
res = bpy.ops.wm.usd_export(filepath=str(testfile), export_materials=True)
|
||||
self.assertEqual({'FINISHED'}, res, f"Unable to export to {testfile}")
|
||||
|
||||
# Reload the empty file and import back in
|
||||
bpy.ops.wm.open_mainfile(filepath=str(self.testdir / "empty.blend"))
|
||||
res = bpy.ops.wm.usd_import(filepath=testfile)
|
||||
self.assertEqual({'FINISHED'}, res, f"Unable to import USD file {testfile}")
|
||||
|
||||
# Most shader graph validation should occur through the Hydra render test suite. Here we
|
||||
# will only check some high-level criteria for each expected node graph.
|
||||
|
||||
def assert_all_nodes_present(mat, node_list):
|
||||
nodes = mat.node_tree.nodes
|
||||
self.assertEqual(len(nodes), len(node_list))
|
||||
for node in node_list:
|
||||
self.assertTrue(nodes.find(node) >= 0, f"Could not find node '{node}' in material '{mat.name}'")
|
||||
|
||||
def round_vector(vector):
|
||||
return [round(c, 5) + 0 for c in vector]
|
||||
|
||||
mat = bpy.data.materials["Material"]
|
||||
assert_all_nodes_present(mat, ["Principled BSDF", "Image Texture", "UV Map", "Material Output"])
|
||||
|
||||
mat = bpy.data.materials["Clip_With_LessThanInvert"]
|
||||
assert_all_nodes_present(
|
||||
mat, ["Principled BSDF", "Image Texture", "UV Map", "Math", "Math.001", "Material Output"])
|
||||
node = [n for n in mat.node_tree.nodes if n.type == 'MATH' and n.operation == "LESS_THAN"][0]
|
||||
self.assertAlmostEqual(node.inputs[1].default_value, 0.2, 3)
|
||||
|
||||
mat = bpy.data.materials["Clip_With_Round"]
|
||||
assert_all_nodes_present(
|
||||
mat, ["Principled BSDF", "Image Texture", "UV Map", "Math", "Math.001", "Material Output"])
|
||||
node = [n for n in mat.node_tree.nodes if n.type == 'MATH' and n.operation == "LESS_THAN"][0]
|
||||
self.assertAlmostEqual(node.inputs[1].default_value, 0.5, 3)
|
||||
|
||||
mat = bpy.data.materials["Transforms"]
|
||||
assert_all_nodes_present(mat, ["Principled BSDF", "Image Texture", "UV Map", "Mapping", "Material Output"])
|
||||
node = mat.node_tree.nodes["Mapping"]
|
||||
self.assertEqual(round_vector(node.inputs[1].default_value), [0.75, 0.75, 0])
|
||||
self.assertEqual(round_vector(node.inputs[2].default_value), [0, 0, 3.14159])
|
||||
self.assertEqual(round_vector(node.inputs[3].default_value), [0.5, 0.5, 1])
|
||||
|
||||
mat = bpy.data.materials["NormalMap"]
|
||||
assert_all_nodes_present(mat, ["Principled BSDF", "Image Texture", "UV Map", "Normal Map", "Material Output"])
|
||||
|
||||
mat = bpy.data.materials["NormalMap_Scale_Bias"]
|
||||
assert_all_nodes_present(mat, ["Principled BSDF", "Image Texture", "UV Map",
|
||||
"Normal Map", "Vector Math", "Vector Math.001", "Material Output"])
|
||||
node = mat.node_tree.nodes["Vector Math"]
|
||||
self.assertEqual(round_vector(node.inputs[1].default_value), [2, -2, 2])
|
||||
self.assertEqual(round_vector(node.inputs[2].default_value), [-1, 1, -1])
|
||||
|
||||
def test_import_shader_varname_with_connection(self):
|
||||
"""Test importing USD shader where uv primvar is a connection"""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user