Compositor: Support viewport in Cryptomatte picker
This patch supports the Cryptomatte picker in the 3D viewport. Instead of picking a color from the viewport GPU texture, we instead sample the scene directly to get the object or material under the cursor, then hash their names to get the Cryptomatte hash value. We do this because the viewport texture have limited precision, so it can't store the Cryptomatte hash values. Additionally, we adjust the Cryptomatte session code to extract the Cryptomatte manifest from the scene directly, as opposed to the RenderResult. This is done to make it work even when no RenderResult exist, as is the case for the viewport compositor, which is needed especially after #123378. Pull Request: https://projects.blender.org/blender/blender/pulls/123815
This commit is contained in:
parent
b724756873
commit
4cd1245396
@ -25,7 +25,11 @@ struct Scene;
|
||||
struct CryptomatteSession *BKE_cryptomatte_init(void);
|
||||
struct CryptomatteSession *BKE_cryptomatte_init_from_render_result(
|
||||
const struct RenderResult *render_result);
|
||||
struct CryptomatteSession *BKE_cryptomatte_init_from_scene(const struct Scene *scene);
|
||||
/* Initializes a cryptomatte session from the view layers of the given scene. If build_meta_data is
|
||||
* true, the object and material IDs in the view layer will be hashed and added to the Cryptomatte
|
||||
* layers, allowing hash-name lookups. */
|
||||
struct CryptomatteSession *BKE_cryptomatte_init_from_scene(const struct Scene *scene,
|
||||
bool build_meta_data);
|
||||
struct CryptomatteSession *BKE_cryptomatte_init_from_view_layer(
|
||||
const struct ViewLayer *view_layer);
|
||||
void BKE_cryptomatte_free(struct CryptomatteSession *session);
|
||||
|
@ -9,7 +9,9 @@
|
||||
#include "BKE_cryptomatte.h"
|
||||
#include "BKE_cryptomatte.hh"
|
||||
#include "BKE_image.h"
|
||||
#include "BKE_layer.hh"
|
||||
#include "BKE_main.hh"
|
||||
#include "BKE_material.h"
|
||||
|
||||
#include "DNA_layer_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
@ -43,8 +45,8 @@ struct CryptomatteSession {
|
||||
CryptomatteSession(const Main *bmain);
|
||||
CryptomatteSession(StampData *stamp_data);
|
||||
CryptomatteSession(const ViewLayer *view_layer);
|
||||
CryptomatteSession(const Scene *scene);
|
||||
void init(const ViewLayer *view_layer);
|
||||
CryptomatteSession(const Scene *scene, bool build_meta_data = false);
|
||||
void init(const ViewLayer *view_layer, bool build_meta_data = false);
|
||||
|
||||
blender::bke::cryptomatte::CryptomatteLayer &add_layer(std::string layer_name);
|
||||
std::optional<std::string> operator[](float encoded_hash) const;
|
||||
@ -93,14 +95,19 @@ CryptomatteSession::CryptomatteSession(const ViewLayer *view_layer)
|
||||
init(view_layer);
|
||||
}
|
||||
|
||||
CryptomatteSession::CryptomatteSession(const Scene *scene)
|
||||
CryptomatteSession::CryptomatteSession(const Scene *scene, bool build_meta_data)
|
||||
{
|
||||
|
||||
if (build_meta_data) {
|
||||
BKE_scene_view_layers_synced_ensure(scene);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (const ViewLayer *, view_layer, &scene->view_layers) {
|
||||
init(view_layer);
|
||||
init(view_layer, build_meta_data);
|
||||
}
|
||||
}
|
||||
|
||||
void CryptomatteSession::init(const ViewLayer *view_layer)
|
||||
void CryptomatteSession::init(const ViewLayer *view_layer, bool build_meta_data)
|
||||
{
|
||||
eViewLayerCryptomatteFlags cryptoflags = static_cast<eViewLayerCryptomatteFlags>(
|
||||
view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_ALL);
|
||||
@ -108,14 +115,37 @@ void CryptomatteSession::init(const ViewLayer *view_layer)
|
||||
cryptoflags = static_cast<eViewLayerCryptomatteFlags>(VIEW_LAYER_CRYPTOMATTE_ALL);
|
||||
}
|
||||
|
||||
ListBase *object_bases = BKE_view_layer_object_bases_get(const_cast<ViewLayer *>(view_layer));
|
||||
|
||||
if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_OBJECT) {
|
||||
add_layer(blender::StringRefNull(view_layer->name) + "." + RE_PASSNAME_CRYPTOMATTE_OBJECT);
|
||||
blender::bke::cryptomatte::CryptomatteLayer &objects = add_layer(
|
||||
blender::StringRefNull(view_layer->name) + "." + RE_PASSNAME_CRYPTOMATTE_OBJECT);
|
||||
|
||||
if (build_meta_data) {
|
||||
LISTBASE_FOREACH (Base *, base, object_bases) {
|
||||
objects.add_ID(base->object->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_ASSET) {
|
||||
add_layer(blender::StringRefNull(view_layer->name) + "." + RE_PASSNAME_CRYPTOMATTE_ASSET);
|
||||
}
|
||||
|
||||
if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_MATERIAL) {
|
||||
add_layer(blender::StringRefNull(view_layer->name) + "." + RE_PASSNAME_CRYPTOMATTE_MATERIAL);
|
||||
blender::bke::cryptomatte::CryptomatteLayer &materials = add_layer(
|
||||
blender::StringRefNull(view_layer->name) + "." + RE_PASSNAME_CRYPTOMATTE_MATERIAL);
|
||||
|
||||
if (build_meta_data) {
|
||||
LISTBASE_FOREACH (Base *, base, object_bases) {
|
||||
for (int i = 0; i < base->object->totcol; i++) {
|
||||
Material *material = BKE_object_material_get(base->object, i + 1);
|
||||
if (material) {
|
||||
materials.add_ID(material->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,15 +174,21 @@ CryptomatteSession *BKE_cryptomatte_init()
|
||||
return session;
|
||||
}
|
||||
|
||||
CryptomatteSession *BKE_cryptomatte_init_from_main(const Main *bmain)
|
||||
{
|
||||
CryptomatteSession *session = new CryptomatteSession(bmain);
|
||||
return session;
|
||||
}
|
||||
|
||||
CryptomatteSession *BKE_cryptomatte_init_from_render_result(const RenderResult *render_result)
|
||||
{
|
||||
CryptomatteSession *session = new CryptomatteSession(render_result->stamp_data);
|
||||
return session;
|
||||
}
|
||||
|
||||
CryptomatteSession *BKE_cryptomatte_init_from_scene(const Scene *scene)
|
||||
CryptomatteSession *BKE_cryptomatte_init_from_scene(const Scene *scene, bool build_meta_data)
|
||||
{
|
||||
CryptomatteSession *session = new CryptomatteSession(scene);
|
||||
CryptomatteSession *session = new CryptomatteSession(scene, build_meta_data);
|
||||
return session;
|
||||
}
|
||||
|
||||
|
@ -13,16 +13,20 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_string_ref.hh"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_cryptomatte.h"
|
||||
#include "BKE_image.h"
|
||||
#include "BKE_material.h"
|
||||
#include "BKE_report.hh"
|
||||
#include "BKE_screen.hh"
|
||||
|
||||
@ -174,6 +178,40 @@ static void eyedropper_exit(bContext *C, wmOperator *op)
|
||||
|
||||
/* *** eyedropper_color_ helper functions *** */
|
||||
|
||||
static bool eyedropper_cryptomatte_sample_view3d_fl(bContext *C,
|
||||
const char *type_name,
|
||||
const int mval[2],
|
||||
float r_col[3])
|
||||
{
|
||||
int material_slot = 0;
|
||||
Object *object = ED_view3d_give_material_slot_under_cursor(C, mval, &material_slot);
|
||||
if (!object) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ID *id = nullptr;
|
||||
if (blender::StringRef(type_name).endswith(RE_PASSNAME_CRYPTOMATTE_OBJECT)) {
|
||||
id = &object->id;
|
||||
}
|
||||
else if (blender::StringRef(type_name).endswith(RE_PASSNAME_CRYPTOMATTE_MATERIAL)) {
|
||||
Material *material = BKE_object_material_get(object, material_slot);
|
||||
if (!material) {
|
||||
return false;
|
||||
}
|
||||
id = &material->id;
|
||||
}
|
||||
|
||||
if (!id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *name = &id->name[2];
|
||||
const int name_length = BLI_strnlen(name, MAX_NAME - 2);
|
||||
uint32_t cryptomatte_hash = BKE_cryptomatte_hash(name, name_length);
|
||||
r_col[0] = BKE_cryptomatte_hash_to_float(cryptomatte_hash);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool eyedropper_cryptomatte_sample_renderlayer_fl(RenderLayer *render_layer,
|
||||
const char *prefix,
|
||||
const float fpos[2],
|
||||
@ -214,6 +252,7 @@ static bool eyedropper_cryptomatte_sample_renderlayer_fl(RenderLayer *render_lay
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool eyedropper_cryptomatte_sample_render_fl(const bNode *node,
|
||||
const char *prefix,
|
||||
const float fpos[2],
|
||||
@ -297,7 +336,7 @@ static bool eyedropper_cryptomatte_sample_fl(bContext *C,
|
||||
ED_region_tag_redraw(CTX_wm_region(C));
|
||||
}
|
||||
|
||||
if (!area || !ELEM(area->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP)) {
|
||||
if (!area || !ELEM(area->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP, SPACE_VIEW3D)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -334,7 +373,9 @@ static bool eyedropper_cryptomatte_sample_fl(bContext *C,
|
||||
}
|
||||
}
|
||||
|
||||
if (fpos[0] < 0.0f || fpos[1] < 0.0f || fpos[0] >= 1.0f || fpos[1] >= 1.0f) {
|
||||
if (area->spacetype != SPACE_VIEW3D &&
|
||||
(fpos[0] < 0.0f || fpos[1] < 0.0f || fpos[0] >= 1.0f || fpos[1] >= 1.0f))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -352,6 +393,23 @@ static bool eyedropper_cryptomatte_sample_fl(bContext *C,
|
||||
ntreeCompositCryptomatteLayerPrefix(scene, node, prefix, sizeof(prefix) - 1);
|
||||
prefix[MAX_NAME] = '\0';
|
||||
|
||||
if (area->spacetype == SPACE_VIEW3D) {
|
||||
wmWindow *win_prev = CTX_wm_window(C);
|
||||
ScrArea *area_prev = CTX_wm_area(C);
|
||||
ARegion *region_prev = CTX_wm_region(C);
|
||||
|
||||
CTX_wm_window_set(C, win);
|
||||
CTX_wm_area_set(C, area);
|
||||
CTX_wm_region_set(C, region);
|
||||
|
||||
const bool success = eyedropper_cryptomatte_sample_view3d_fl(C, prefix, mval, r_col);
|
||||
|
||||
CTX_wm_window_set(C, win_prev);
|
||||
CTX_wm_area_set(C, area_prev);
|
||||
CTX_wm_region_set(C, region_prev);
|
||||
|
||||
return success;
|
||||
}
|
||||
if (node->custom1 == CMP_NODE_CRYPTOMATTE_SOURCE_RENDER) {
|
||||
return eyedropper_cryptomatte_sample_render_fl(node, prefix, fpos, r_col);
|
||||
}
|
||||
|
@ -54,7 +54,7 @@
|
||||
* \{ */
|
||||
|
||||
static blender::bke::cryptomatte::CryptomatteSessionPtr cryptomatte_init_from_node_render(
|
||||
const bNode &node, const bool use_meta_data)
|
||||
const bNode &node, const bool build_meta_data)
|
||||
{
|
||||
blender::bke::cryptomatte::CryptomatteSessionPtr session;
|
||||
|
||||
@ -64,22 +64,8 @@ static blender::bke::cryptomatte::CryptomatteSessionPtr cryptomatte_init_from_no
|
||||
}
|
||||
BLI_assert(GS(scene->id.name) == ID_SCE);
|
||||
|
||||
if (use_meta_data) {
|
||||
Render *render = RE_GetSceneRender(scene);
|
||||
RenderResult *render_result = render ? RE_AcquireResultRead(render) : nullptr;
|
||||
if (render_result) {
|
||||
session = blender::bke::cryptomatte::CryptomatteSessionPtr(
|
||||
BKE_cryptomatte_init_from_render_result(render_result));
|
||||
}
|
||||
if (render) {
|
||||
RE_ReleaseResult(render);
|
||||
}
|
||||
}
|
||||
|
||||
if (session == nullptr) {
|
||||
session = blender::bke::cryptomatte::CryptomatteSessionPtr(
|
||||
BKE_cryptomatte_init_from_scene(scene));
|
||||
}
|
||||
BKE_cryptomatte_init_from_scene(scene, build_meta_data));
|
||||
return session;
|
||||
}
|
||||
|
||||
@ -107,7 +93,7 @@ static blender::bke::cryptomatte::CryptomatteSessionPtr cryptomatte_init_from_no
|
||||
}
|
||||
|
||||
static blender::bke::cryptomatte::CryptomatteSessionPtr cryptomatte_init_from_node(
|
||||
const Scene &scene, const bNode &node, const bool use_meta_data)
|
||||
const Scene &scene, const bNode &node, const bool build_meta_data)
|
||||
{
|
||||
blender::bke::cryptomatte::CryptomatteSessionPtr session;
|
||||
if (node.type != CMP_NODE_CRYPTOMATTE) {
|
||||
@ -116,7 +102,7 @@ static blender::bke::cryptomatte::CryptomatteSessionPtr cryptomatte_init_from_no
|
||||
|
||||
switch (node.custom1) {
|
||||
case CMP_NODE_CRYPTOMATTE_SOURCE_RENDER: {
|
||||
return cryptomatte_init_from_node_render(node, use_meta_data);
|
||||
return cryptomatte_init_from_node_render(node, build_meta_data);
|
||||
}
|
||||
|
||||
case CMP_NODE_CRYPTOMATTE_SOURCE_IMAGE: {
|
||||
|
Loading…
Reference in New Issue
Block a user