[Bf-blender-cvs] [fa57c691f66] master: USD IO CI Tests

Michael Kowalski noreply at git.blender.org
Wed Jan 25 20:52:23 CET 2023


Commit: fa57c691f663bf4b446ccf0f91ce82ed9a2078b2
Author: Michael Kowalski
Date:   Wed Jan 25 14:51:39 2023 -0500
Branches: master
https://developer.blender.org/rBfa57c691f663bf4b446ccf0f91ce82ed9a2078b2

USD IO CI Tests

Various new CI tests for USD Import / Export functionalty:

Import:
 - Added mesh import tests for topology types and multiple UV sets. (Python)

Export:
 - Added a verification tests for mesh topology. (C++)
 - Added a test to make sure UsdPreviewSurface export conversion of materials
is correct. (C++)

Reviewed by: Sybren and Hans.

Differential Revision: https://developer.blender.org/D16274

===================================================================

M	source/blender/blenloader/tests/blendfile_loading_base_test.cc
M	source/blender/io/usd/CMakeLists.txt
M	source/blender/io/usd/intern/usd_capi_export.cc
M	source/blender/io/usd/intern/usd_capi_import.cc
M	source/blender/io/usd/intern/usd_writer_material.cc
M	source/blender/io/usd/intern/usd_writer_material.h
A	source/blender/io/usd/tests/usd_export_test.cc
M	tests/python/bl_usd_import_test.py

===================================================================

diff --git a/source/blender/blenloader/tests/blendfile_loading_base_test.cc b/source/blender/blenloader/tests/blendfile_loading_base_test.cc
index 6f190ce427e..6613c65c42a 100644
--- a/source/blender/blenloader/tests/blendfile_loading_base_test.cc
+++ b/source/blender/blenloader/tests/blendfile_loading_base_test.cc
@@ -103,8 +103,8 @@ void BlendfileLoadingBaseTest::TearDownTestCase()
 void BlendfileLoadingBaseTest::TearDown()
 {
   BKE_mball_cubeTable_free();
-  depsgraph_free();
   blendfile_free();
+  depsgraph_free();
 
   testing::Test::TearDown();
 }
diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt
index ebd292782c0..862bd41c087 100644
--- a/source/blender/io/usd/CMakeLists.txt
+++ b/source/blender/io/usd/CMakeLists.txt
@@ -163,13 +163,18 @@ target_link_libraries(bf_usd INTERFACE ${TBB_LIBRARIES})
 if(WITH_GTESTS)
   set(TEST_SRC
     tests/usd_stage_creation_test.cc
+    tests/usd_export_test.cc
     tests/usd_tests_common.cc
     tests/usd_tests_common.h
+
+    intern/usd_writer_material.h
   )
   if(USD_IMAGING_HEADERS)
     list(APPEND TEST_SRC tests/usd_imaging_test.cc)
   endif()
 
+  include_directories(intern)
+
   set(TEST_INC
   )
   set(TEST_LIB
diff --git a/source/blender/io/usd/intern/usd_capi_export.cc b/source/blender/io/usd/intern/usd_capi_export.cc
index 28da9e388c5..1d33ca3a13c 100644
--- a/source/blender/io/usd/intern/usd_capi_export.cc
+++ b/source/blender/io/usd/intern/usd_capi_export.cc
@@ -66,7 +66,9 @@ static void export_startjob(void *customdata,
   data->start_time = timeit::Clock::now();
 
   G.is_rendering = true;
-  WM_set_locked_interface(data->wm, true);
+  if (data->wm) {
+    WM_set_locked_interface(data->wm, true);
+  }
   G.is_break = false;
 
   /* Construct the depsgraph for exporting. */
@@ -160,7 +162,9 @@ static void export_endjob(void *customdata)
   }
 
   G.is_rendering = false;
-  WM_set_locked_interface(data->wm, false);
+  if (data->wm) {
+    WM_set_locked_interface(data->wm, false);
+  }
   report_job_duration(data);
 }
 
diff --git a/source/blender/io/usd/intern/usd_capi_import.cc b/source/blender/io/usd/intern/usd_capi_import.cc
index 66319a7f04e..fb870eb154c 100644
--- a/source/blender/io/usd/intern/usd_capi_import.cc
+++ b/source/blender/io/usd/intern/usd_capi_import.cc
@@ -207,6 +207,7 @@ static void import_startjob(void *customdata, bool *stop, bool *do_update, float
   if (!stage) {
     WM_reportf(RPT_ERROR, "USD Import: unable to open stage to read %s", data->filepath);
     data->import_ok = false;
+    data->error_code = USD_ARCHIVE_FAIL;
     return;
   }
 
diff --git a/source/blender/io/usd/intern/usd_writer_material.cc b/source/blender/io/usd/intern/usd_writer_material.cc
index 98cd4036fd0..7e744b74f61 100644
--- a/source/blender/io/usd/intern/usd_writer_material.cc
+++ b/source/blender/io/usd/intern/usd_writer_material.cc
@@ -748,4 +748,16 @@ static void export_texture(bNode *node,
   }
 }
 
+const pxr::TfToken token_for_input(const char *input_name)
+{
+  const InputSpecMap &input_map = preview_surface_input_map();
+  const InputSpecMap::const_iterator it = input_map.find(input_name);
+
+  if (it == input_map.end()) {
+    return pxr::TfToken();
+  }
+
+  return it->second.input_name;
+}
+
 }  // namespace blender::io::usd
diff --git a/source/blender/io/usd/intern/usd_writer_material.h b/source/blender/io/usd/intern/usd_writer_material.h
index fdfd13871ff..c6123b3cce2 100644
--- a/source/blender/io/usd/intern/usd_writer_material.h
+++ b/source/blender/io/usd/intern/usd_writer_material.h
@@ -14,6 +14,10 @@ namespace blender::io::usd {
 
 struct USDExporterContext;
 
+/* Returns a USDPreviewSurface token name for a given Blender shader Socket name,
+ * or an empty TfToken if the input name is not found in the map. */
+const pxr::TfToken token_for_input(const char *input_name);
+
 /**
  * Entry point to create an approximate USD Preview Surface network from a Cycles node graph.
  * Due to the limited nodes in the USD Preview Surface specification, only the following nodes
diff --git a/source/blender/io/usd/tests/usd_export_test.cc b/source/blender/io/usd/tests/usd_export_test.cc
new file mode 100644
index 00000000000..c13da695c87
--- /dev/null
+++ b/source/blender/io/usd/tests/usd_export_test.cc
@@ -0,0 +1,314 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "testing/testing.h"
+#include "tests/blendfile_loading_base_test.h"
+
+#include <pxr/base/plug/registry.h>
+#include <pxr/base/tf/stringUtils.h>
+#include <pxr/base/vt/types.h>
+#include <pxr/base/vt/value.h>
+#include <pxr/usd/sdf/types.h>
+#include <pxr/usd/usd/prim.h>
+#include <pxr/usd/usd/stage.h>
+#include <pxr/usd/usdGeom/mesh.h>
+#include <pxr/usd/usdGeom/subset.h>
+#include <pxr/usd/usdGeom/tokens.h>
+
+#include "DNA_image_types.h"
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+
+#include "BKE_context.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_node.h"
+#include "BLI_fileops.h"
+#include "BLI_math.h"
+#include "BLI_path_util.h"
+#include "BLI_math_vector_types.hh"
+#include "BLO_readfile.h"
+
+#include "BKE_node_runtime.hh"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+
+#include "usd.h"
+#include "usd_tests_common.h"
+#include "usd_writer_material.h"
+
+namespace blender::io::usd {
+
+const StringRefNull simple_scene_filename = "usd/usd_simple_scene.blend";
+const StringRefNull materials_filename = "usd/usd_materials_export.blend";
+const StringRefNull output_filename = "output.usd";
+
+
+static const bNode *find_node_for_type_in_graph(const bNodeTree *nodetree,
+                                                const blender::StringRefNull type_idname);
+
+
+class UsdExportTest : public BlendfileLoadingBaseTest {
+ protected:
+  struct bContext *context = nullptr;
+
+ public:
+  bool load_file_and_depsgraph(const StringRefNull &filepath,
+                               const eEvaluationMode eval_mode = DAG_EVAL_VIEWPORT)
+  {
+    if (!blendfile_load(filepath.c_str())) {
+      return false;
+    }
+    depsgraph_create(eval_mode);
+
+    context = CTX_create();
+    CTX_data_main_set(context, bfile->main);
+    CTX_data_scene_set(context, bfile->curscene);
+
+    return true;
+  }
+
+  virtual void SetUp() override
+  {
+    BlendfileLoadingBaseTest::SetUp();
+    std::string usd_plugin_path = register_usd_plugins_for_tests();
+    if (usd_plugin_path.empty()) {
+      FAIL() << "Unable to find the USD Plugins path.";
+    }
+  }
+
+  virtual void TearDown() override
+  {
+    BlendfileLoadingBaseTest::TearDown();
+    CTX_free(context);
+    context = nullptr;
+
+    if (BLI_exists(output_filename.c_str())) {
+      BLI_delete(output_filename.c_str(), false, false);
+    }
+  }
+
+  const pxr::UsdPrim get_first_child_mesh(const pxr::UsdPrim prim)
+  {
+    for (auto child : prim.GetChildren()) {
+      if (child.IsA<pxr::UsdGeomMesh>()) {
+        return child;
+      }
+    }
+    return pxr::UsdPrim();
+  }
+
+  /*
+   * Loop the sockets on the Blender bNode, and fail if any of their values do
+   * not match the equivalent Attribtue values on the UsdPrim.
+   */
+  const void compare_blender_node_to_usd_prim(const bNode *bsdf_node, const pxr::UsdPrim& bsdf_prim) {
+    ASSERT_NE(bsdf_node, nullptr);
+    ASSERT_TRUE(bool(bsdf_prim));
+
+    for (auto socket : bsdf_node->input_sockets()) {
+      const pxr::TfToken attribute_token = blender::io::usd::token_for_input(socket->name);
+      if (attribute_token.IsEmpty()) {
+        /* This socket is not translated between Blender and USD. */
+        continue;
+      }
+
+      const pxr::UsdAttribute bsdf_attribute = bsdf_prim.GetAttribute(attribute_token);
+      pxr::SdfPathVector paths;
+      bsdf_attribute.GetConnections(&paths);
+      if (!paths.empty() || !bsdf_attribute.IsValid()) {
+        /* Skip if the attribute is connected or has an error. */
+        continue;
+      }
+
+      const float socket_value_f = *socket->default_value_typed<float>();
+      const float3 socket_value_3f = *socket->default_value_typed<float3>();
+      float attribute_value_f;
+      pxr::GfVec3f attribute_value_3f;
+
+      switch (socket->type) {
+        case SOCK_FLOAT:
+          bsdf_attribute.Get(&attribute_value_f, 0.0);
+          EXPECT_FLOAT_EQ(socket_value_f, attribute_value_f);
+          break;
+
+        case SOCK_VECTOR:
+          bsdf_attribute.Get(&attribute_value_3f, 0.0);
+          EXPECT_FLOAT_EQ(socket_value_3f[0], attribute_value_3f[0]);
+          EXPECT_FLOAT_EQ(socket_value_3f[1], attribute_value_3f[1]);
+          EXPECT_FLOAT_EQ(socket_value_3f[2], attribute_value_3f[2]);
+          break;
+
+        case SOCK_RGBA:
+          bsdf_attribute.Get(&attribute_value_3f, 0.0);
+          EXPECT_FLOAT_EQ(socket_value_3f[0], attribute_value_3f[0]);
+          EXPECT_FLOAT_EQ(socket_value_3f[1], attribute_value_3f[1]);
+          EXPECT_FLOAT_EQ(socket_value_3f[2], attribute_value_3f[2]);
+          break;
+
+        default:
+          FAIL() << "Socket " << socket->name << " has unsupported type " << socket->type;
+          break;
+      }
+    }
+  }
+
+  const void compare_blender_image_to_usd_image_shader(const bNode *image_node, const pxr::UsdPrim& image_prim) {
+    const Image *image = reinterpret_cast<Image *>(image_node->id);
+
+    const pxr::UsdShadeShader image_shader(image_prim);
+    const pxr::UsdShadeInput file_input = image_shader.GetInput(pxr::TfToken("file"));
+    EXPECT_TRUE(bool(file_input));
+
+    pxr::VtValue file_val;
+    EXPECT_TRUE(file_input.Get(&file_val));
+    EXPECT_TRUE(file_val.IsHolding<pxr::SdfAssetPath>());
+
+    pxr::SdfAssetPath image_prim_asset = file_val.Get<pxr::SdfAssetPath>();
+
+    /* The path is expected to be relative, but that means in Blender the
+     * path will start with //.
+     */
+    EXPECT_EQ(BLI_path_cmp_normalized(image->filepath+2, image_prim_asset.GetAssetPath().c_str()), 0);
+  }
+
+  /*
+   * Determine if a Blender Mesh matches a UsdGeomMesh prim by checking counts
+   * on vertices, faces, face indices, and normals.
+   */
+  const void compare_blender_mesh_to_usd_prim(const Mesh *mesh, const pxr::UsdGeomMesh& mesh_prim) {
+    pxr::VtIntArray face_indices;
+ 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list