[Bf-blender-cvs] [87ace468276] master: Cryptomatte: Manifest Parsing.

Jeroen Bakker noreply at git.blender.org
Fri Feb 26 14:19:21 CET 2021


Commit: 87ace4682761bdeaa8f18ae12a186dbfb83d4e04
Author: Jeroen Bakker
Date:   Fri Feb 26 14:13:15 2021 +0100
Branches: master
https://developer.blender.org/rB87ace4682761bdeaa8f18ae12a186dbfb83d4e04

Cryptomatte: Manifest Parsing.

This patch adds manifest parsing to Cryptomatte. Normally when loading
cryptomatte layer from an OpenEXR file the manifest contains data to
convert a hash to its original name of the object/material. In the
future we want to use this to support lookup of cryptomatte
hashes and show it to the user.

Currently this logic isn't available to users (for now), but is required
by D3959 where a new cryptomatte workflow is implemented.

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

M	source/blender/blenkernel/BKE_cryptomatte.h
M	source/blender/blenkernel/BKE_cryptomatte.hh
M	source/blender/blenkernel/intern/cryptomatte.cc
M	source/blender/blenkernel/intern/cryptomatte_test.cc
M	source/blender/blenloader/intern/versioning_290.c
M	source/blender/compositor/intern/COM_MetaData.cpp
M	source/blender/compositor/operations/COM_OutputFileOperation.cpp
M	source/blender/compositor/operations/COM_RenderLayersProg.cpp
M	source/blender/makesrna/intern/rna_nodetree.c

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

diff --git a/source/blender/blenkernel/BKE_cryptomatte.h b/source/blender/blenkernel/BKE_cryptomatte.h
index 4b62c795a5a..1b1c4deeb8a 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.h
+++ b/source/blender/blenkernel/BKE_cryptomatte.h
@@ -50,8 +50,7 @@ uint32_t BKE_cryptomatte_asset_hash(struct CryptomatteSession *session,
 float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash);
 
 char *BKE_cryptomatte_entries_to_matte_id(struct NodeCryptomatte *node_storage);
-void BKE_cryptomatte_matte_id_to_entries(const struct Main *bmain,
-                                         struct NodeCryptomatte *node_storage,
+void BKE_cryptomatte_matte_id_to_entries(struct NodeCryptomatte *node_storage,
                                          const char *matte_id);
 
 void BKE_cryptomatte_store_metadata(struct CryptomatteSession *session,
diff --git a/source/blender/blenkernel/BKE_cryptomatte.hh b/source/blender/blenkernel/BKE_cryptomatte.hh
index 4631bb2616e..c1da0339359 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.hh
+++ b/source/blender/blenkernel/BKE_cryptomatte.hh
@@ -23,11 +23,15 @@
 
 #pragma once
 
+#include <optional>
 #include <string>
 
+#include "BLI_map.hh"
 #include "BLI_string_ref.hh"
 
-namespace blender {
+struct ID;
+
+namespace blender::bke::cryptomatte {
 
 /* Format to a cryptomatte meta data key.
  *
@@ -56,4 +60,30 @@ std::string BKE_cryptomatte_meta_data_key(const StringRef layer_name,
  */
 StringRef BKE_cryptomatte_extract_layer_name(const StringRef render_pass_name);
 
-}  // namespace blender
+struct CryptomatteHash {
+  uint32_t hash;
+
+  CryptomatteHash(uint32_t hash);
+  CryptomatteHash(const char *name, const int name_len);
+  static CryptomatteHash from_hex_encoded(blender::StringRef hex_encoded);
+
+  std::string hex_encoded() const;
+  float float_encoded() const;
+};
+
+struct CryptomatteLayer {
+  blender::Map<std::string, CryptomatteHash> hashes;
+
+#ifdef WITH_CXX_GUARDEDALLOC
+  MEM_CXX_CLASS_ALLOC_FUNCS("cryptomatte:CryptomatteLayer")
+#endif
+
+  static std::unique_ptr<CryptomatteLayer> read_from_manifest(blender::StringRefNull manifest);
+  uint32_t add_ID(const struct ID &id);
+  void add_hash(blender::StringRef name, CryptomatteHash cryptomatte_hash);
+  std::string manifest();
+
+  std::optional<std::string> operator[](float encoded_hash) const;
+};
+
+}  // namespace blender::bke::cryptomatte
diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc
index 628c8c6e86a..89db7a93501 100644
--- a/source/blender/blenkernel/intern/cryptomatte.cc
+++ b/source/blender/blenkernel/intern/cryptomatte.cc
@@ -35,7 +35,6 @@
 #include "BLI_dynstr.h"
 #include "BLI_hash_mm3.h"
 #include "BLI_listbase.h"
-#include "BLI_map.hh"
 #include "BLI_string.h"
 
 #include "MEM_guardedalloc.h"
@@ -47,60 +46,43 @@
 #include <string>
 #include <string_view>
 
-struct CryptomatteLayer {
-  blender::Map<std::string, std::string> hashes;
+struct CryptomatteSession {
+  blender::bke::cryptomatte::CryptomatteLayer objects;
+  blender::bke::cryptomatte::CryptomatteLayer assets;
+  blender::bke::cryptomatte::CryptomatteLayer materials;
+
+  CryptomatteSession();
+  CryptomatteSession(const Main *bmain);
+
+  std::optional<std::string> operator[](float encoded_hash) const;
 
 #ifdef WITH_CXX_GUARDEDALLOC
-  MEM_CXX_CLASS_ALLOC_FUNCS("cryptomatte:CryptomatteLayer")
+  MEM_CXX_CLASS_ALLOC_FUNCS("cryptomatte:CryptomatteSession")
 #endif
-  std::string encode_hash(uint32_t cryptomatte_hash)
-  {
-    std::stringstream encoded;
-    encoded << std::setfill('0') << std::setw(sizeof(uint32_t) * 2) << std::hex
-            << cryptomatte_hash;
-    return encoded.str();
-  }
+};
 
-  void add_hash(blender::StringRef name, uint32_t cryptomatte_hash)
-  {
-    add_encoded_hash(name, encode_hash(cryptomatte_hash));
-  }
+CryptomatteSession::CryptomatteSession()
+{
+}
 
-  void add_encoded_hash(blender::StringRef name, blender::StringRefNull cryptomatte_encoded_hash)
-  {
-    hashes.add_overwrite(name, cryptomatte_encoded_hash);
+CryptomatteSession::CryptomatteSession(const Main *bmain)
+{
+  LISTBASE_FOREACH (ID *, id, &bmain->objects) {
+    objects.add_ID(*id);
   }
-
-  std::string manifest()
-  {
-    std::stringstream manifest;
-
-    bool is_first = true;
-    const blender::Map<std::string, std::string> &const_map = hashes;
-    manifest << "{";
-    for (blender::Map<std::string, std::string>::Item item : const_map.items()) {
-      if (is_first) {
-        is_first = false;
-      }
-      else {
-        manifest << ",";
-      }
-      manifest << quoted(item.key) << ":\"" << item.value << "\"";
-    }
-    manifest << "}";
-    return manifest.str();
+  LISTBASE_FOREACH (ID *, id, &bmain->materials) {
+    materials.add_ID(*id);
   }
-};
-
-struct CryptomatteSession {
-  CryptomatteLayer objects;
-  CryptomatteLayer assets;
-  CryptomatteLayer materials;
+}
 
-#ifdef WITH_CXX_GUARDEDALLOC
-  MEM_CXX_CLASS_ALLOC_FUNCS("cryptomatte:CryptomatteSession")
-#endif
-};
+std::optional<std::string> CryptomatteSession::operator[](float encoded_hash) const
+{
+  std::optional<std::string> result = objects[encoded_hash];
+  if (result) {
+    return result;
+  }
+  return materials[encoded_hash];
+}
 
 CryptomatteSession *BKE_cryptomatte_init(void)
 {
@@ -116,26 +98,13 @@ void BKE_cryptomatte_free(CryptomatteSession *session)
 
 uint32_t BKE_cryptomatte_hash(const char *name, const int name_len)
 {
-  uint32_t cryptohash_int = BLI_hash_mm3((const unsigned char *)name, name_len, 0);
-  return cryptohash_int;
-}
-
-static uint32_t cryptomatte_hash(CryptomatteLayer *layer, const ID *id)
-{
-  const char *name = &id->name[2];
-  const int name_len = BLI_strnlen(name, MAX_NAME - 2);
-  uint32_t cryptohash_int = BKE_cryptomatte_hash(name, name_len);
-
-  if (layer != nullptr) {
-    layer->add_hash(blender::StringRef(name, name_len), cryptohash_int);
-  }
-
-  return cryptohash_int;
+  blender::bke::cryptomatte::CryptomatteHash hash(name, name_len);
+  return hash.hash;
 }
 
 uint32_t BKE_cryptomatte_object_hash(CryptomatteSession *session, const Object *object)
 {
-  return cryptomatte_hash(&session->objects, &object->id);
+  return session->objects.add_ID(object->id);
 }
 
 uint32_t BKE_cryptomatte_material_hash(CryptomatteSession *session, const Material *material)
@@ -143,7 +112,7 @@ uint32_t BKE_cryptomatte_material_hash(CryptomatteSession *session, const Materi
   if (material == nullptr) {
     return 0.0f;
   }
-  return cryptomatte_hash(&session->materials, &material->id);
+  return session->materials.add_ID(material->id);
 }
 
 uint32_t BKE_cryptomatte_asset_hash(CryptomatteSession *session, const Object *object)
@@ -152,54 +121,12 @@ uint32_t BKE_cryptomatte_asset_hash(CryptomatteSession *session, const Object *o
   while (asset_object->parent != nullptr) {
     asset_object = asset_object->parent;
   }
-  return cryptomatte_hash(&session->assets, &asset_object->id);
+  return session->assets.add_ID(asset_object->id);
 }
 
-/* Convert a cryptomatte hash to a float.
- *
- * Cryptomatte hashes are stored in float textures and images. The conversion is taken from the
- * cryptomatte specification. See Floating point conversion section in
- * https://github.com/Psyop/Cryptomatte/blob/master/specification/cryptomatte_specification.pdf.
- *
- * The conversion uses as many 32 bit floating point values as possible to minimize hash
- * collisions. Unfortunately not all 32 bits can be used as NaN and Inf can be problematic.
- *
- * Note that this conversion assumes to be running on a L-endian system. */
 float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
 {
-  uint32_t mantissa = cryptomatte_hash & ((1 << 23) - 1);
-  uint32_t exponent = (cryptomatte_hash >> 23) & ((1 << 8) - 1);
-  exponent = MAX2(exponent, (uint32_t)1);
-  exponent = MIN2(exponent, (uint32_t)254);
-  exponent = exponent << 23;
-  uint32_t sign = (cryptomatte_hash >> 31);
-  sign = sign << 31;
-  uint32_t float_bits = sign | exponent | mantissa;
-  float f;
-  memcpy(&f, &float_bits, sizeof(uint32_t));
-  return f;
-}
-
-static ID *cryptomatte_find_id(const ListBase *ids, const float encoded_hash)
-{
-  LISTBASE_FOREACH (ID *, id, ids) {
-    uint32_t hash = BKE_cryptomatte_hash((id->name + 2), BLI_strnlen(id->name + 2, MAX_NAME));
-    if (BKE_cryptomatte_hash_to_float(hash) == encoded_hash) {
-      return id;
-    }
-  }
-  return nullptr;
-}
-
-/* Find an ID in the given main that matches the given encoded float. */
-static struct ID *BKE_cryptomatte_find_id(const Main *bmain, const float encoded_hash)
-{
-  ID *result;
-  result = cryptomatte_find_id(&bmain->objects, encoded_hash);
-  if (result == nullptr) {
-    result = cryptomatte_find_id(&bmain->materials, encoded_hash);
-  }
-  return result;
+  return blender::bke::cryptomatte::CryptomatteHash(cryptomatte_hash).float_encoded();
 }
 
 char *BKE_cryptomatte_entries_to_matte_id(NodeCryptomatte *node_storage)
@@ -223,11 +150,10 @@ char *BKE_cryptomatte_entries_to_matte_id(NodeCryptomatte *node_storage)
   return result;
 }
 
-void BKE_cryptomatte_matte_id_to_entries(const Main *bmain,
-                                         NodeCryptomatte *node_storage,
-                                         const char *matte_id)
+void BKE_cryptomatte_matte_id_to_entries(NodeCryptomatte *node_storage, const char *matte_id)
 {
   BLI_freelistN(&node_storage->entries);
+  std::optional<CryptomatteSession> session = std::nullopt;
 
   std::istringstream ss(matte_id);
   while (ss.good()) {
@@ -246,18 +172,12 @@ void BKE_cryptomatte_matte_id_to_entries(const Main *bmain,
         float encoded_hash = atof(token.substr(1, token.length() - 2).c_str());
         entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntry), __func__);
         entry->encoded_hash = encoded_hash;
-        if (bmain) {
-          ID *id = BKE_cryptomatte_find_id(bmain, encoded_hash);
-          if (id != nullptr) {
-            BLI_strncpy(entry->name, id->name + 2, sizeof(entry->name));
-          }
-        }
       }
       else {
         const char *name = token.c_str();
         int name_len = token.length();
         entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntr

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list