/* SPDX-License-Identifier: GPL-2.0-or-later * Copyright 2022 Blender Foundation. */ #include "BKE_cryptomatte.hh" #include "GPU_material.h" #include "eevee_cryptomatte.hh" #include "eevee_instance.hh" #include "eevee_renderbuffers.hh" namespace blender::eevee { void Cryptomatte::begin_sync() { const eViewLayerEEVEEPassType enabled_passes = static_cast( inst_.film.enabled_passes_get() & (EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT | EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET | EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET)); session_.reset(); object_layer_ = nullptr; asset_layer_ = nullptr; material_layer_ = nullptr; if (enabled_passes && !inst_.is_viewport()) { session_.reset(BKE_cryptomatte_init_from_view_layer(inst_.view_layer)); for (const std::string &layer_name : bke::cryptomatte::BKE_cryptomatte_layer_names_get(*session_)) { StringRef layer_name_ref = layer_name; bke::cryptomatte::CryptomatteLayer *layer = bke::cryptomatte::BKE_cryptomatte_layer_get( *session_, layer_name); if (layer_name_ref.endswith(RE_PASSNAME_CRYPTOMATTE_OBJECT)) { object_layer_ = layer; } else if (layer_name_ref.endswith(RE_PASSNAME_CRYPTOMATTE_ASSET)) { asset_layer_ = layer; } else if (layer_name_ref.endswith(RE_PASSNAME_CRYPTOMATTE_MATERIAL)) { material_layer_ = layer; } } } if (!(enabled_passes & (EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT | EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET))) { cryptomatte_object_buf.resize(16); } } void Cryptomatte::sync_object(Object *ob, ResourceHandle res_handle) { const eViewLayerEEVEEPassType enabled_passes = inst_.film.enabled_passes_get(); if (!(enabled_passes & (EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT | EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET))) { return; } uint32_t resource_id = res_handle.resource_index(); float2 object_hashes(0.0f, 0.0f); if (enabled_passes & EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT) { object_hashes[0] = register_id(EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT, ob->id); } if (enabled_passes & EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET) { Object *asset = ob; while (asset->parent) { asset = asset->parent; } object_hashes[1] = register_id(EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET, asset->id); } cryptomatte_object_buf.get_or_resize(resource_id) = object_hashes; } void Cryptomatte::sync_material(const ::Material *material) { /* Material crypto hashes are generated during shader codegen stage. We only need to register * them to store inside the metadata. */ if (material_layer_ && material) { material_layer_->add_ID(material->id); } } void Cryptomatte::end_sync() { cryptomatte_object_buf.push_update(); object_layer_ = nullptr; asset_layer_ = nullptr; material_layer_ = nullptr; } float Cryptomatte::register_id(const eViewLayerEEVEEPassType layer, const ID &id) const { BLI_assert(ELEM(layer, EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT, EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET, EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL)); uint32_t cryptomatte_hash = 0; if (session_) { if (layer == EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT) { BLI_assert(object_layer_); cryptomatte_hash = object_layer_->add_ID(id); } else if (layer == EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET) { BLI_assert(asset_layer_); cryptomatte_hash = asset_layer_->add_ID(id); } else if (layer == EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL) { BLI_assert(material_layer_); cryptomatte_hash = material_layer_->add_ID(id); } } else { const char *name = &id.name[2]; const int name_len = BLI_strnlen(name, MAX_NAME - 2); cryptomatte_hash = BKE_cryptomatte_hash(name, name_len); } return BKE_cryptomatte_hash_to_float(cryptomatte_hash); } void Cryptomatte::store_metadata(RenderResult *render_result) { if (session_) { BKE_cryptomatte_store_metadata(&*session_, render_result, inst_.view_layer); } } } // namespace blender::eevee