Cryptomatte: Flexible Definition of CryptomatteLayers.

Cryptomatte layers in Blender are predefined. Other render engines
might have other naming schemes. This patch will allow creation of
cryptomatte layers with other names. This will be used by D3959 to
load cryptomatte openexr files from other render engines.

EEVEE and Cycles still use our fix naming scheme so no changes are
detectable by users.
This commit is contained in:
Jeroen Bakker 2021-03-01 15:14:55 +01:00
parent 1d9092f632
commit 61b3870981
3 changed files with 86 additions and 78 deletions

View File

@ -39,13 +39,17 @@ struct RenderResult;
struct CryptomatteSession *BKE_cryptomatte_init(void);
void BKE_cryptomatte_free(struct CryptomatteSession *session);
void BKE_cryptomatte_add_layer(struct CryptomatteSession *session, const char *layer_name);
uint32_t BKE_cryptomatte_hash(const char *name, int name_len);
uint32_t BKE_cryptomatte_object_hash(struct CryptomatteSession *session,
const char *layer_name,
const struct Object *object);
uint32_t BKE_cryptomatte_material_hash(struct CryptomatteSession *session,
const char *layer_name,
const struct Material *material);
uint32_t BKE_cryptomatte_asset_hash(struct CryptomatteSession *session,
const char *layer_name,
const struct Object *object);
float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash);
@ -53,11 +57,9 @@ char *BKE_cryptomatte_entries_to_matte_id(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,
void BKE_cryptomatte_store_metadata(const struct CryptomatteSession *session,
struct RenderResult *render_result,
const ViewLayer *view_layer,
eViewLayerCryptomatteFlags cryptomatte_layer,
const char *cryptomatte_layer_name);
const ViewLayer *view_layer);
#ifdef __cplusplus
}

View File

@ -47,13 +47,12 @@
#include <string_view>
struct CryptomatteSession {
blender::bke::cryptomatte::CryptomatteLayer objects;
blender::bke::cryptomatte::CryptomatteLayer assets;
blender::bke::cryptomatte::CryptomatteLayer materials;
blender::Map<std::string, blender::bke::cryptomatte::CryptomatteLayer> layers;
CryptomatteSession();
CryptomatteSession(const Main *bmain);
blender::bke::cryptomatte::CryptomatteLayer &add_layer(std::string layer_name);
std::optional<std::string> operator[](float encoded_hash) const;
#ifdef WITH_CXX_GUARDEDALLOC
@ -67,21 +66,34 @@ CryptomatteSession::CryptomatteSession()
CryptomatteSession::CryptomatteSession(const Main *bmain)
{
LISTBASE_FOREACH (ID *, id, &bmain->objects) {
objects.add_ID(*id);
if (!BLI_listbase_is_empty(&bmain->objects)) {
blender::bke::cryptomatte::CryptomatteLayer &objects = add_layer("CryptoObject");
LISTBASE_FOREACH (ID *, id, &bmain->objects) {
objects.add_ID(*id);
}
}
LISTBASE_FOREACH (ID *, id, &bmain->materials) {
materials.add_ID(*id);
if (!BLI_listbase_is_empty(&bmain->materials)) {
blender::bke::cryptomatte::CryptomatteLayer &materials = add_layer("CryptoMaterial");
LISTBASE_FOREACH (ID *, id, &bmain->materials) {
materials.add_ID(*id);
}
}
}
blender::bke::cryptomatte::CryptomatteLayer &CryptomatteSession::add_layer(std::string layer_name)
{
return layers.lookup_or_add_default(layer_name);
}
std::optional<std::string> CryptomatteSession::operator[](float encoded_hash) const
{
std::optional<std::string> result = objects[encoded_hash];
if (result) {
return result;
for (const blender::bke::cryptomatte::CryptomatteLayer &layer : layers.values()) {
std::optional<std::string> result = layer[encoded_hash];
if (result) {
return result;
}
}
return materials[encoded_hash];
return std::nullopt;
}
CryptomatteSession *BKE_cryptomatte_init(void)
@ -90,6 +102,11 @@ CryptomatteSession *BKE_cryptomatte_init(void)
return session;
}
void BKE_cryptomatte_add_layer(struct CryptomatteSession *session, const char *layer_name)
{
session->add_layer(layer_name);
}
void BKE_cryptomatte_free(CryptomatteSession *session)
{
BLI_assert(session != nullptr);
@ -102,26 +119,36 @@ uint32_t BKE_cryptomatte_hash(const char *name, const int name_len)
return hash.hash;
}
uint32_t BKE_cryptomatte_object_hash(CryptomatteSession *session, const Object *object)
uint32_t BKE_cryptomatte_object_hash(CryptomatteSession *session,
const char *layer_name,
const Object *object)
{
return session->objects.add_ID(object->id);
blender::bke::cryptomatte::CryptomatteLayer *layer = session->layers.lookup_ptr(layer_name);
BLI_assert(layer);
return layer->add_ID(object->id);
}
uint32_t BKE_cryptomatte_material_hash(CryptomatteSession *session, const Material *material)
uint32_t BKE_cryptomatte_material_hash(CryptomatteSession *session,
const char *layer_name,
const Material *material)
{
if (material == nullptr) {
return 0.0f;
}
return session->materials.add_ID(material->id);
blender::bke::cryptomatte::CryptomatteLayer *layer = session->layers.lookup_ptr(layer_name);
BLI_assert(layer);
return layer->add_ID(material->id);
}
uint32_t BKE_cryptomatte_asset_hash(CryptomatteSession *session, const Object *object)
uint32_t BKE_cryptomatte_asset_hash(CryptomatteSession *session,
const char *layer_name,
const Object *object)
{
const Object *asset_object = object;
while (asset_object->parent != nullptr) {
asset_object = asset_object->parent;
}
return session->assets.add_ID(asset_object->id);
return BKE_cryptomatte_object_hash(session, layer_name, asset_object);
}
float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
@ -213,37 +240,23 @@ static void add_render_result_meta_data(RenderResult *render_result,
value.data());
}
void BKE_cryptomatte_store_metadata(struct CryptomatteSession *session,
void BKE_cryptomatte_store_metadata(const struct CryptomatteSession *session,
RenderResult *render_result,
const ViewLayer *view_layer,
eViewLayerCryptomatteFlags cryptomatte_layer,
const char *cryptomatte_layer_name)
const ViewLayer *view_layer)
{
/* Create Manifest. */
blender::bke::cryptomatte::CryptomatteLayer *layer = nullptr;
switch (cryptomatte_layer) {
case VIEW_LAYER_CRYPTOMATTE_OBJECT:
layer = &session->objects;
break;
case VIEW_LAYER_CRYPTOMATTE_MATERIAL:
layer = &session->materials;
break;
case VIEW_LAYER_CRYPTOMATTE_ASSET:
layer = &session->assets;
break;
default:
BLI_assert(!"Incorrect cryptomatte layer");
break;
for (const blender::Map<std::string, blender::bke::cryptomatte::CryptomatteLayer>::Item item :
session->layers.items()) {
const blender::StringRefNull layer_name(item.key);
const blender::bke::cryptomatte::CryptomatteLayer &layer = item.value;
const std::string manifest = layer.manifest();
const std::string name = cryptomatte_determine_name(view_layer, layer_name);
add_render_result_meta_data(render_result, name, "name", name);
add_render_result_meta_data(render_result, name, "hash", "MurmurHash3_32");
add_render_result_meta_data(render_result, name, "conversion", "uint32_to_float32");
add_render_result_meta_data(render_result, name, "manifest", manifest);
}
const std::string manifest = layer->manifest();
const std::string name = cryptomatte_determine_name(view_layer, cryptomatte_layer_name);
/* Store the meta data into the render result. */
add_render_result_meta_data(render_result, name, "name", name);
add_render_result_meta_data(render_result, name, "hash", "MurmurHash3_32");
add_render_result_meta_data(render_result, name, "conversion", "uint32_to_float32");
add_render_result_meta_data(render_result, name, "manifest", manifest);
}
namespace blender::bke::cryptomatte {

View File

@ -124,8 +124,20 @@ void EEVEE_cryptomatte_renderpasses_init(EEVEE_Data *vedata)
if (!DRW_state_is_image_render()) {
return;
}
if (eevee_cryptomatte_active_layers(view_layer) != 0) {
g_data->cryptomatte_session = BKE_cryptomatte_init();
const eViewLayerCryptomatteFlags active_layers = eevee_cryptomatte_active_layers(view_layer);
if (active_layers) {
struct CryptomatteSession *session = BKE_cryptomatte_init();
if ((active_layers & VIEW_LAYER_CRYPTOMATTE_OBJECT) != 0) {
BKE_cryptomatte_add_layer(session, "CryptoObject");
}
if ((active_layers & VIEW_LAYER_CRYPTOMATTE_MATERIAL) != 0) {
BKE_cryptomatte_add_layer(session, "CryptoMaterial");
}
if ((active_layers & VIEW_LAYER_CRYPTOMATTE_ASSET) != 0) {
BKE_cryptomatte_add_layer(session, "CryptoAsset");
}
g_data->cryptomatte_session = session;
g_data->render_passes |= EEVEE_RENDER_PASS_CRYPTOMATTE | EEVEE_RENDER_PASS_VOLUME_LIGHT;
g_data->cryptomatte_accurate_mode = (view_layer->cryptomatte_flag &
VIEW_LAYER_CRYPTOMATTE_ACCURATE) != 0;
@ -208,20 +220,22 @@ static DRWShadingGroup *eevee_cryptomatte_shading_group_create(EEVEE_Data *vedat
EEVEE_PassList *psl = vedata->psl;
int layer_offset = 0;
if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_OBJECT) != 0) {
uint32_t cryptomatte_hash = BKE_cryptomatte_object_hash(g_data->cryptomatte_session, ob);
uint32_t cryptomatte_hash = BKE_cryptomatte_object_hash(
g_data->cryptomatte_session, "CryptoObject", ob);
float cryptomatte_color_value = BKE_cryptomatte_hash_to_float(cryptomatte_hash);
cryptohash[layer_offset] = cryptomatte_color_value;
layer_offset++;
}
if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_MATERIAL) != 0) {
uint32_t cryptomatte_hash = BKE_cryptomatte_material_hash(g_data->cryptomatte_session,
material);
uint32_t cryptomatte_hash = BKE_cryptomatte_material_hash(
g_data->cryptomatte_session, "CryptoMaterial", material);
float cryptomatte_color_value = BKE_cryptomatte_hash_to_float(cryptomatte_hash);
cryptohash[layer_offset] = cryptomatte_color_value;
layer_offset++;
}
if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_ASSET) != 0) {
uint32_t cryptomatte_hash = BKE_cryptomatte_asset_hash(g_data->cryptomatte_session, ob);
uint32_t cryptomatte_hash = BKE_cryptomatte_asset_hash(
g_data->cryptomatte_session, "CryptoAsset", ob);
float cryptomatte_color_value = BKE_cryptomatte_hash_to_float(cryptomatte_hash);
cryptohash[layer_offset] = cryptomatte_color_value;
layer_offset++;
@ -693,30 +707,9 @@ void EEVEE_cryptomatte_store_metadata(EEVEE_Data *vedata, RenderResult *render_r
EEVEE_PrivateData *g_data = vedata->stl->g_data;
const DRWContextState *draw_ctx = DRW_context_state_get();
const ViewLayer *view_layer = draw_ctx->view_layer;
const eViewLayerCryptomatteFlags cryptomatte_layers = view_layer->cryptomatte_flag &
VIEW_LAYER_CRYPTOMATTE_ALL;
BLI_assert(g_data->cryptomatte_session);
if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_OBJECT) != 0) {
BKE_cryptomatte_store_metadata(g_data->cryptomatte_session,
render_result,
view_layer,
VIEW_LAYER_CRYPTOMATTE_OBJECT,
"CryptoObject");
}
if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_MATERIAL) != 0) {
BKE_cryptomatte_store_metadata(g_data->cryptomatte_session,
render_result,
view_layer,
VIEW_LAYER_CRYPTOMATTE_MATERIAL,
"CryptoMaterial");
}
if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_ASSET) != 0) {
BKE_cryptomatte_store_metadata(g_data->cryptomatte_session,
render_result,
view_layer,
VIEW_LAYER_CRYPTOMATTE_ASSET,
"CryptoAsset");
}
BKE_cryptomatte_store_metadata(g_data->cryptomatte_session, render_result, view_layer);
}
/** \} */