Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/nodeitems_builtins.py1
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.h9
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.hh5
-rw-r--r--source/blender/blenkernel/BKE_node.h20
-rw-r--r--source/blender/blenkernel/intern/cryptomatte.cc58
-rw-r--r--source/blender/blenkernel/intern/node.cc9
-rw-r--r--source/blender/blenkernel/intern/scene.c5
-rw-r--r--source/blender/blenloader/intern/versioning_290.c2
-rw-r--r--source/blender/compositor/intern/COM_Converter.cc3
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.cc255
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.h62
-rw-r--r--source/blender/editors/include/ED_clip.h4
-rw-r--r--source/blender/editors/include/ED_image.h4
-rw-r--r--source/blender/editors/include/ED_node.h5
-rw-r--r--source/blender/editors/include/UI_interface.h5
-rw-r--r--source/blender/editors/interface/CMakeLists.txt1
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c179
-rw-r--r--source/blender/editors/interface/interface_templates.c8
-rw-r--r--source/blender/editors/space_clip/clip_editor.c17
-rw-r--r--source/blender/editors/space_image/image_ops.c17
-rw-r--r--source/blender/editors/space_node/drawnode.c81
-rw-r--r--source/blender/editors/space_node/node_edit.c10
-rw-r--r--source/blender/editors/space_node/node_view.c26
-rw-r--r--source/blender/makesdna/DNA_node_types.h30
-rw-r--r--source/blender/makesrna/RNA_access.h2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c215
-rw-r--r--source/blender/nodes/NOD_composite.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc271
29 files changed, 1166 insertions, 142 deletions
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index e6e2c25e383..fefb266e591 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -390,6 +390,7 @@ compositor_node_categories = [
NodeItem("CompositorNodeColorMatte"),
NodeItem("CompositorNodeDoubleEdgeMask"),
NodeItem("CompositorNodeCryptomatte"),
+ NodeItem("CompositorNodeCryptomatteV2"),
]),
CompositorNodeCategory("CMP_DISTORT", "Distort", items=[
NodeItem("CompositorNodeScale"),
diff --git a/source/blender/blenkernel/BKE_cryptomatte.h b/source/blender/blenkernel/BKE_cryptomatte.h
index 7d295929e77..576a2c1effd 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.h
+++ b/source/blender/blenkernel/BKE_cryptomatte.h
@@ -30,14 +30,17 @@
extern "C" {
#endif
+/* Forward declarations. */
struct CryptomatteSession;
struct Material;
struct Object;
struct RenderResult;
+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);
void BKE_cryptomatte_free(struct CryptomatteSession *session);
void BKE_cryptomatte_add_layer(struct CryptomatteSession *session, const char *layer_name);
@@ -52,6 +55,10 @@ 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);
+bool BKE_cryptomatte_find_name(const struct CryptomatteSession *session,
+ const float encoded_hash,
+ char *r_name,
+ int name_len);
char *BKE_cryptomatte_entries_to_matte_id(struct NodeCryptomatte *node_storage);
void BKE_cryptomatte_matte_id_to_entries(struct NodeCryptomatte *node_storage,
@@ -63,4 +70,4 @@ void BKE_cryptomatte_store_metadata(const struct CryptomatteSession *session,
#ifdef __cplusplus
}
-#endif
+#endif \ No newline at end of file
diff --git a/source/blender/blenkernel/BKE_cryptomatte.hh b/source/blender/blenkernel/BKE_cryptomatte.hh
index 98fdfc965bc..9e205d01765 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.hh
+++ b/source/blender/blenkernel/BKE_cryptomatte.hh
@@ -26,6 +26,8 @@
#include <optional>
#include <string>
+#include "BKE_cryptomatte.h"
+
#include "BLI_map.hh"
#include "BLI_string_ref.hh"
@@ -105,6 +107,9 @@ struct CryptomatteStampDataCallbackData {
static void extract_layer_manifest(void *_data, const char *propname, char *propvalue, int len);
};
+const blender::Vector<std::string> &BKE_cryptomatte_layer_names_get(
+ const CryptomatteSession &session);
+
struct CryptomatteSessionDeleter {
void operator()(CryptomatteSession *session)
{
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 0379dea9e8c..42022cce5a5 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -47,6 +47,7 @@ struct BlendLibReader;
struct BlendWriter;
struct ColorManagedDisplaySettings;
struct ColorManagedViewSettings;
+struct CryptomatteSession;
struct FreestyleLineStyle;
struct GPUMaterial;
struct GPUNodeStack;
@@ -1204,9 +1205,10 @@ void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
#define CMP_NODE_PLANETRACKDEFORM 320
#define CMP_NODE_CORNERPIN 321
#define CMP_NODE_SWITCH_VIEW 322
-#define CMP_NODE_CRYPTOMATTE 323
+#define CMP_NODE_CRYPTOMATTE_LEGACY 323
#define CMP_NODE_DENOISE 324
#define CMP_NODE_EXPOSURE 325
+#define CMP_NODE_CRYPTOMATTE 326
/* channel toggles */
#define CMP_CHAN_RGB 1
@@ -1236,6 +1238,10 @@ void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
#define CMP_TRACKPOS_RELATIVE_FRAME 2
#define CMP_TRACKPOS_ABSOLUTE_FRAME 3
+/* Cryptomatte source. */
+#define CMP_CRYPTOMATTE_SRC_RENDER 0
+#define CMP_CRYPTOMATTE_SRC_IMAGE 1
+
/* API */
void ntreeCompositExecTree(struct Scene *scene,
struct bNodeTree *ntree,
@@ -1278,11 +1284,15 @@ void ntreeCompositOutputFileUniqueLayer(struct ListBase *list,
void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *ntree, bNode *node);
void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *ntree, bNode *node);
-void ntreeCompositCryptomatteSyncFromAdd(bNodeTree *ntree, bNode *node);
-void ntreeCompositCryptomatteSyncFromRemove(bNodeTree *ntree, bNode *node);
-struct bNodeSocket *ntreeCompositCryptomatteAddSocket(struct bNodeTree *ntree, struct bNode *node);
-int ntreeCompositCryptomatteRemoveSocket(struct bNodeTree *ntree, struct bNode *node);
+void ntreeCompositCryptomatteSyncFromAdd(bNode *node);
+void ntreeCompositCryptomatteSyncFromRemove(bNode *node);
+bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node);
+int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node);
+void ntreeCompositCryptomatteLayerPrefix(const bNode *node, char *r_prefix, size_t prefix_len);
+/* Update the runtime layer names with the cryptomatte layer names of the references
+ * render layer or image. */
+void ntreeCompositCryptomatteUpdateLayerNames(bNode *node);
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc
index 55426f738ff..74576b8bbbb 100644
--- a/source/blender/blenkernel/intern/cryptomatte.cc
+++ b/source/blender/blenkernel/intern/cryptomatte.cc
@@ -30,6 +30,7 @@
#include "DNA_material_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "BLI_compiler_attrs.h"
#include "BLI_dynstr.h"
@@ -50,10 +51,13 @@
struct CryptomatteSession {
blender::Map<std::string, blender::bke::cryptomatte::CryptomatteLayer> layers;
+ /* Layer names in order of creation. */
+ blender::Vector<std::string> layer_names;
CryptomatteSession();
CryptomatteSession(const Main *bmain);
CryptomatteSession(StampData *stamp_data);
+ CryptomatteSession(const Scene *scene);
blender::bke::cryptomatte::CryptomatteLayer &add_layer(std::string layer_name);
std::optional<std::string> operator[](float encoded_hash) const;
@@ -99,8 +103,32 @@ CryptomatteSession::CryptomatteSession(StampData *stamp_data)
false);
}
+CryptomatteSession::CryptomatteSession(const Scene *scene)
+{
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ eViewLayerCryptomatteFlags cryptoflags = static_cast<eViewLayerCryptomatteFlags>(
+ view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_ALL);
+ if (cryptoflags == 0) {
+ cryptoflags = static_cast<eViewLayerCryptomatteFlags>(VIEW_LAYER_CRYPTOMATTE_ALL);
+ }
+
+ if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_OBJECT) {
+ add_layer(blender::StringRefNull(view_layer->name) + ".CryptoObject");
+ }
+ if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_ASSET) {
+ add_layer(blender::StringRefNull(view_layer->name) + ".CryptoAsset");
+ }
+ if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_MATERIAL) {
+ add_layer(blender::StringRefNull(view_layer->name) + ".CryptoMaterial");
+ }
+ }
+}
+
blender::bke::cryptomatte::CryptomatteLayer &CryptomatteSession::add_layer(std::string layer_name)
{
+ if (!layer_names.contains(layer_name)) {
+ layer_names.append(layer_name);
+ }
return layers.lookup_or_add_default(layer_name);
}
@@ -128,6 +156,12 @@ struct CryptomatteSession *BKE_cryptomatte_init_from_render_result(
return session;
}
+struct CryptomatteSession *BKE_cryptomatte_init_from_scene(const struct Scene *scene)
+{
+ CryptomatteSession *session = new CryptomatteSession(scene);
+ return session;
+}
+
void BKE_cryptomatte_add_layer(struct CryptomatteSession *session, const char *layer_name)
{
session->add_layer(layer_name);
@@ -182,6 +216,21 @@ float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
return blender::bke::cryptomatte::CryptomatteHash(cryptomatte_hash).float_encoded();
}
+/* Find an ID in the given main that matches the given encoded float. */
+bool BKE_cryptomatte_find_name(const CryptomatteSession *session,
+ const float encoded_hash,
+ char *r_name,
+ int name_len)
+{
+ std::optional<std::string> name = (*session)[encoded_hash];
+ if (!name) {
+ return false;
+ }
+
+ BLI_strncpy(r_name, name->c_str(), name_len);
+ return true;
+}
+
char *BKE_cryptomatte_entries_to_matte_id(NodeCryptomatte *node_storage)
{
DynStr *matte_id = BLI_dynstr_new();
@@ -213,7 +262,8 @@ void BKE_cryptomatte_matte_id_to_entries(NodeCryptomatte *node_storage, const ch
}
/* Update the matte_id so the files can be opened in versions that don't
* use `CryptomatteEntry`. */
- if (matte_id != node_storage->matte_id && STREQ(node_storage->matte_id, matte_id)) {
+ if (matte_id != node_storage->matte_id && node_storage->matte_id &&
+ STREQ(node_storage->matte_id, matte_id)) {
MEM_SAFE_FREE(node_storage->matte_id);
node_storage->matte_id = static_cast<char *>(MEM_dupallocN(matte_id));
}
@@ -599,4 +649,10 @@ void CryptomatteStampDataCallbackData::extract_layer_manifest(void *_data,
blender::bke::cryptomatte::manifest::from_manifest(layer, propvalue);
}
+const blender::Vector<std::string> &BKE_cryptomatte_layer_names_get(
+ const CryptomatteSession &session)
+{
+ return session.layer_names;
+}
+
} // namespace blender::bke::cryptomatte
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index b6f02128353..66c0e724fdf 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -538,7 +538,8 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
}
BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage);
}
- else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_CRYPTOMATTE)) {
+ else if ((ntree->type == NTREE_COMPOSIT) &&
+ (ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY))) {
NodeCryptomatte *nc = (NodeCryptomatte *)node->storage;
BLO_write_string(writer, nc->matte_id);
LISTBASE_FOREACH (CryptomatteEntry *, entry, &nc->entries) {
@@ -703,10 +704,12 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
iuser->scene = nullptr;
break;
}
+ case CMP_NODE_CRYPTOMATTE_LEGACY:
case CMP_NODE_CRYPTOMATTE: {
NodeCryptomatte *nc = (NodeCryptomatte *)node->storage;
BLO_read_data_address(reader, &nc->matte_id);
BLO_read_list(reader, &nc->entries);
+ BLI_listbase_clear(&nc->runtime.layers);
break;
}
case TEX_NODE_IMAGE: {
@@ -903,7 +906,8 @@ void ntreeBlendReadExpand(BlendExpander *expander, bNodeTree *ntree)
}
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id && node->type != CMP_NODE_R_LAYERS) {
+ if (node->id && !(node->type == CMP_NODE_R_LAYERS) &&
+ !(node->type == CMP_NODE_CRYPTOMATTE && node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER)) {
BLO_expand(expander, node->id);
}
@@ -4607,6 +4611,7 @@ static void registerCompositNodes()
register_node_type_cmp_keyingscreen();
register_node_type_cmp_keying();
register_node_type_cmp_cryptomatte();
+ register_node_type_cmp_cryptomatte_legacy();
register_node_type_cmp_translate();
register_node_type_cmp_rotate();
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 3633dff8690..de3e1023b08 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -1377,9 +1377,10 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
/* patch for missing scene IDs, can't be in do-versions */
static void composite_patch(bNodeTree *ntree, Scene *scene)
{
-
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id == NULL && node->type == CMP_NODE_R_LAYERS) {
+ if (node->id == NULL &&
+ ((node->type == CMP_NODE_R_LAYERS) ||
+ (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER))) {
node->id = &scene->id;
}
}
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index 05762c479ff..06bafb20c35 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -1482,7 +1482,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
if (scene->nodetree) {
LISTBASE_FOREACH (bNode *, node, &scene->nodetree->nodes) {
- if (node->type == CMP_NODE_CRYPTOMATTE) {
+ if (node->type == CMP_NODE_CRYPTOMATTE_LEGACY) {
NodeCryptomatte *storage = (NodeCryptomatte *)node->storage;
char *matte_id = storage->matte_id;
if (matte_id == NULL || strlen(storage->matte_id) == 0) {
diff --git a/source/blender/compositor/intern/COM_Converter.cc b/source/blender/compositor/intern/COM_Converter.cc
index 7d897d29576..91439f54710 100644
--- a/source/blender/compositor/intern/COM_Converter.cc
+++ b/source/blender/compositor/intern/COM_Converter.cc
@@ -406,6 +406,9 @@ Node *COM_convert_bnode(bNode *b_node)
case CMP_NODE_SUNBEAMS:
node = new SunBeamsNode(b_node);
break;
+ case CMP_NODE_CRYPTOMATTE_LEGACY:
+ node = new CryptomatteLegacyNode(b_node);
+ break;
case CMP_NODE_CRYPTOMATTE:
node = new CryptomatteNode(b_node);
break;
diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cc b/source/blender/compositor/nodes/COM_CryptomatteNode.cc
index 27ef98af8f3..4c698b5609f 100644
--- a/source/blender/compositor/nodes/COM_CryptomatteNode.cc
+++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cc
@@ -17,64 +17,247 @@
*/
#include "COM_CryptomatteNode.h"
-#include "COM_ConvertOperation.h"
-#include "COM_CryptomatteOperation.h"
-
+#include "BKE_node.h"
#include "BLI_assert.h"
#include "BLI_hash_mm3.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
-
+#include "COM_ConvertOperation.h"
+#include "COM_CryptomatteOperation.h"
+#include "COM_MultilayerImageOperation.h"
+#include "COM_RenderLayersProg.h"
#include "COM_SetAlphaMultiplyOperation.h"
+#include "COM_SetColorOperation.h"
#include <iterator>
+#include <string>
+
+/** \name Cryptomatte base
+ * \{ */
-CryptomatteNode::CryptomatteNode(bNode *editorNode) : Node(editorNode)
+void CryptomatteBaseNode::convertToOperations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- /* pass */
+ NodeOutput *output_image_socket = this->getOutputSocket(0);
+
+ bNode *node = this->getbNode();
+ NodeCryptomatte *cryptomatte_settings = static_cast<NodeCryptomatte *>(node->storage);
+
+ CryptomatteOperation *cryptomatte_operation = create_cryptomatte_operation(
+ converter, context, *node, cryptomatte_settings);
+ converter.addOperation(cryptomatte_operation);
+
+ NodeOutput *output_matte_socket = this->getOutputSocket(1);
+ SeparateChannelOperation *extract_mask_operation = new SeparateChannelOperation;
+ extract_mask_operation->setChannel(3);
+ converter.addOperation(extract_mask_operation);
+ converter.addLink(cryptomatte_operation->getOutputSocket(0),
+ extract_mask_operation->getInputSocket(0));
+ converter.mapOutputSocket(output_matte_socket, extract_mask_operation->getOutputSocket(0));
+
+ NodeInput *input_image_socket = this->getInputSocket(0);
+ SetAlphaMultiplyOperation *apply_mask_operation = new SetAlphaMultiplyOperation();
+ converter.mapInputSocket(input_image_socket, apply_mask_operation->getInputSocket(0));
+ converter.addOperation(apply_mask_operation);
+ converter.addLink(extract_mask_operation->getOutputSocket(0),
+ apply_mask_operation->getInputSocket(1));
+ converter.mapOutputSocket(output_image_socket, apply_mask_operation->getOutputSocket(0));
+
+ NodeOutput *output_pick_socket = this->getOutputSocket(2);
+ SetAlphaMultiplyOperation *extract_pick_operation = new SetAlphaMultiplyOperation();
+ converter.addOperation(extract_pick_operation);
+ converter.addInputValue(extract_pick_operation->getInputSocket(1), 1.0f);
+ converter.addLink(cryptomatte_operation->getOutputSocket(0),
+ extract_pick_operation->getInputSocket(0));
+ converter.mapOutputSocket(output_pick_socket, extract_pick_operation->getOutputSocket(0));
}
-void CryptomatteNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+/* \} */
+
+/** \name Cryptomatte V2
+ * \{ */
+static std::string prefix_from_node(const bNode &node)
{
- NodeInput *inputSocketImage = this->getInputSocket(0);
- NodeOutput *outputSocketImage = this->getOutputSocket(0);
- NodeOutput *outputSocketMatte = this->getOutputSocket(1);
- NodeOutput *outputSocketPick = this->getOutputSocket(2);
+ char prefix[MAX_NAME];
+ ntreeCompositCryptomatteLayerPrefix(&node, prefix, sizeof(prefix));
+ return std::string(prefix, BLI_strnlen(prefix, sizeof(prefix)));
+}
- bNode *node = this->getbNode();
- NodeCryptomatte *cryptoMatteSettings = (NodeCryptomatte *)node->storage;
+static std::string combined_layer_pass_name(RenderLayer *render_layer, RenderPass *render_pass)
+{
+ if (render_layer->name[0] == '\0') {
+ return std::string(render_pass->name,
+ BLI_strnlen(render_pass->name, sizeof(render_pass->name)));
+ }
- CryptomatteOperation *operation = new CryptomatteOperation(getNumberOfInputSockets() - 1);
- if (cryptoMatteSettings) {
- LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptoMatteSettings->entries) {
- operation->addObjectIndex(cryptomatte_entry->encoded_hash);
+ std::string combined_name =
+ blender::StringRef(render_layer->name,
+ BLI_strnlen(render_layer->name, sizeof(render_layer->name))) +
+ "." +
+ blender::StringRef(render_pass->name,
+ BLI_strnlen(render_pass->name, sizeof(render_pass->name)));
+ return combined_name;
+}
+
+void CryptomatteNode::input_operations_from_render_source(
+ const CompositorContext &context,
+ const bNode &node,
+ blender::Vector<NodeOperation *> &r_input_operations)
+{
+ Scene *scene = (Scene *)node.id;
+ if (!scene) {
+ return;
+ }
+
+ BLI_assert(GS(scene->id.name) == ID_SCE);
+ Render *render = RE_GetSceneRender(scene);
+ RenderResult *render_result = render ? RE_AcquireResultRead(render) : nullptr;
+
+ if (!render_result) {
+ return;
+ }
+
+ const short cryptomatte_layer_id = 0;
+ const std::string prefix = prefix_from_node(node);
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ RenderLayer *render_layer = RE_GetRenderLayer(render_result, view_layer->name);
+ if (render_layer) {
+ LISTBASE_FOREACH (RenderPass *, render_pass, &render_layer->passes) {
+ const std::string combined_name = combined_layer_pass_name(render_layer, render_pass);
+ if (blender::StringRef(combined_name).startswith(prefix)) {
+ RenderLayersProg *op = new RenderLayersProg(
+ render_pass->name, COM_DT_COLOR, render_pass->channels);
+ op->setScene(scene);
+ op->setLayerId(cryptomatte_layer_id);
+ op->setRenderData(context.getRenderData());
+ op->setViewName(context.getViewName());
+ r_input_operations.append(op);
+ }
+ }
}
}
+ RE_ReleaseResult(render);
+}
- converter.addOperation(operation);
+void CryptomatteNode::input_operations_from_image_source(
+ const CompositorContext &context,
+ const bNode &node,
+ blender::Vector<NodeOperation *> &r_input_operations)
+{
+ NodeCryptomatte *cryptomatte_settings = (NodeCryptomatte *)node.storage;
+ Image *image = (Image *)node.id;
+ if (!image) {
+ return;
+ }
- for (int i = 0; i < getNumberOfInputSockets() - 1; i++) {
- converter.mapInputSocket(this->getInputSocket(i + 1), operation->getInputSocket(i));
+ BLI_assert(GS(image->id.name) == ID_IM);
+ if (image->type != IMA_TYPE_MULTILAYER) {
+ return;
}
- SeparateChannelOperation *separateOperation = new SeparateChannelOperation;
- separateOperation->setChannel(3);
- converter.addOperation(separateOperation);
+ ImageUser *iuser = &cryptomatte_settings->iuser;
+ BKE_image_user_frame_calc(image, iuser, context.getFramenumber());
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, nullptr);
- SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation();
- converter.addOperation(operationAlpha);
+ if (image->rr) {
+ int view = 0;
+ if (BLI_listbase_count_at_most(&image->rr->views, 2) > 1) {
+ if (iuser->view == 0) {
+ /* Heuristic to match image name with scene names, check if the view name exists in the
+ * image. */
+ view = BLI_findstringindex(
+ &image->rr->views, context.getViewName(), offsetof(RenderView, name));
+ if (view == -1) {
+ view = 0;
+ }
+ }
+ else {
+ view = iuser->view - 1;
+ }
+ }
- converter.addLink(operation->getOutputSocket(0), separateOperation->getInputSocket(0));
- converter.addLink(separateOperation->getOutputSocket(0), operationAlpha->getInputSocket(1));
+ const std::string prefix = prefix_from_node(node);
+ LISTBASE_FOREACH (RenderLayer *, render_layer, &image->rr->layers) {
+ LISTBASE_FOREACH (RenderPass *, render_pass, &render_layer->passes) {
+ const std::string combined_name = combined_layer_pass_name(render_layer, render_pass);
+ if (blender::StringRef(combined_name).startswith(prefix)) {
+ MultilayerColorOperation *op = new MultilayerColorOperation(
+ render_layer, render_pass, view);
+ op->setImage(image);
+ op->setImageUser(iuser);
+ op->setFramenumber(context.getFramenumber());
+ r_input_operations.append(op);
+ }
+ }
+ }
+ }
+ BKE_image_release_ibuf(image, ibuf, nullptr);
+}
- SetAlphaMultiplyOperation *clearAlphaOperation = new SetAlphaMultiplyOperation();
- converter.addOperation(clearAlphaOperation);
- converter.addInputValue(clearAlphaOperation->getInputSocket(1), 1.0f);
+blender::Vector<NodeOperation *> CryptomatteNode::create_input_operations(
+ const CompositorContext &context, const bNode &node)
+{
+ blender::Vector<NodeOperation *> input_operations;
+ switch (node.custom1) {
+ case CMP_CRYPTOMATTE_SRC_RENDER:
+ input_operations_from_render_source(context, node, input_operations);
+ break;
+ case CMP_CRYPTOMATTE_SRC_IMAGE:
+ input_operations_from_image_source(context, node, input_operations);
+ break;
+ }
- converter.addLink(operation->getOutputSocket(0), clearAlphaOperation->getInputSocket(0));
+ if (input_operations.is_empty()) {
+ SetColorOperation *op = new SetColorOperation();
+ op->setChannel1(0.0f);
+ op->setChannel2(1.0f);
+ op->setChannel3(0.0f);
+ op->setChannel4(0.0f);
+ input_operations.append(op);
+ }
+ return input_operations;
+}
+CryptomatteOperation *CryptomatteNode::create_cryptomatte_operation(
+ NodeConverter &converter,
+ const CompositorContext &context,
+ const bNode &node,
+ const NodeCryptomatte *cryptomatte_settings) const
+{
+ blender::Vector<NodeOperation *> input_operations = create_input_operations(context, node);
+ CryptomatteOperation *operation = new CryptomatteOperation(input_operations.size());
+ LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptomatte_settings->entries) {
+ operation->addObjectIndex(cryptomatte_entry->encoded_hash);
+ }
+ for (int i = 0; i < input_operations.size(); ++i) {
+ converter.addOperation(input_operations[i]);
+ converter.addLink(input_operations[i]->getOutputSocket(), operation->getInputSocket(i));
+ }
+ return operation;
+}
+
+/* \} */
+
+/** \name Cryptomatte legacy
+ * \{ */
- converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0));
- converter.mapOutputSocket(outputSocketMatte, separateOperation->getOutputSocket(0));
- converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket(0));
- converter.mapOutputSocket(outputSocketPick, clearAlphaOperation->getOutputSocket(0));
+CryptomatteOperation *CryptomatteLegacyNode::create_cryptomatte_operation(
+ NodeConverter &converter,
+ const CompositorContext &UNUSED(context),
+ const bNode &UNUSED(node),
+ const NodeCryptomatte *cryptomatte_settings) const
+{
+ const int num_inputs = getNumberOfInputSockets() - 1;
+ CryptomatteOperation *operation = new CryptomatteOperation(num_inputs);
+ if (cryptomatte_settings) {
+ LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptomatte_settings->entries) {
+ operation->addObjectIndex(cryptomatte_entry->encoded_hash);
+ }
+ }
+
+ for (int i = 0; i < num_inputs; i++) {
+ converter.mapInputSocket(this->getInputSocket(i + 1), operation->getInputSocket(i));
+ }
+
+ return operation;
}
+
+/* \} */ \ No newline at end of file
diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.h b/source/blender/compositor/nodes/COM_CryptomatteNode.h
index 1fb8893efa0..e99a104c914 100644
--- a/source/blender/compositor/nodes/COM_CryptomatteNode.h
+++ b/source/blender/compositor/nodes/COM_CryptomatteNode.h
@@ -18,14 +18,72 @@
#pragma once
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+
+#include "COM_CryptomatteOperation.h"
#include "COM_Node.h"
/**
* \brief CryptomatteNode
* \ingroup Node
*/
-class CryptomatteNode : public Node {
+class CryptomatteBaseNode : public Node {
+ protected:
+ CryptomatteBaseNode(bNode *editor_node) : Node(editor_node)
+ {
+ /* pass */
+ }
+
public:
- CryptomatteNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
+
+ protected:
+ virtual CryptomatteOperation *create_cryptomatte_operation(
+ NodeConverter &converter,
+ const CompositorContext &context,
+ const bNode &node,
+ const NodeCryptomatte *cryptomatte_settings) const = 0;
+};
+
+class CryptomatteNode : public CryptomatteBaseNode {
+ public:
+ CryptomatteNode(bNode *editor_node) : CryptomatteBaseNode(editor_node)
+ {
+ /* pass */
+ }
+
+ protected:
+ CryptomatteOperation *create_cryptomatte_operation(
+ NodeConverter &converter,
+ const CompositorContext &context,
+ const bNode &node,
+ const NodeCryptomatte *cryptomatte_settings) const override;
+
+ private:
+ static blender::Vector<NodeOperation *> create_input_operations(const CompositorContext &context,
+ const bNode &node);
+ static void input_operations_from_render_source(
+ const CompositorContext &context,
+ const bNode &node,
+ blender::Vector<NodeOperation *> &r_input_operations);
+ static void input_operations_from_image_source(
+ const CompositorContext &context,
+ const bNode &node,
+ blender::Vector<NodeOperation *> &r_input_operations);
+};
+
+class CryptomatteLegacyNode : public CryptomatteBaseNode {
+ public:
+ CryptomatteLegacyNode(bNode *editor_node) : CryptomatteBaseNode(editor_node)
+ {
+ /* pass */
+ }
+
+ protected:
+ CryptomatteOperation *create_cryptomatte_operation(
+ NodeConverter &converter,
+ const CompositorContext &context,
+ const bNode &node,
+ const NodeCryptomatte *cryptomatte_settings) const override;
};
diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h
index 56494f87bfe..21d8a28e2c9 100644
--- a/source/blender/editors/include/ED_clip.h
+++ b/source/blender/editors/include/ED_clip.h
@@ -64,6 +64,10 @@ struct ImBuf *ED_space_clip_get_stable_buffer(struct SpaceClip *sc,
float *scale,
float *angle);
+bool ED_space_clip_get_position(struct SpaceClip *sc,
+ struct ARegion *ar,
+ int mval[2],
+ float fpos[2]);
bool ED_space_clip_color_sample(struct SpaceClip *sc,
struct ARegion *region,
int mval[2],
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index b139b0765a3..ec525806b81 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -53,6 +53,10 @@ void ED_space_image_auto_set(const struct bContext *C, struct SpaceImage *sima);
struct Mask *ED_space_image_get_mask(struct SpaceImage *sima);
void ED_space_image_set_mask(struct bContext *C, struct SpaceImage *sima, struct Mask *mask);
+bool ED_space_image_get_position(struct SpaceImage *sima,
+ struct ARegion *region,
+ int mval[2],
+ float fpos[2]);
bool ED_space_image_color_sample(
struct SpaceImage *sima, struct ARegion *region, int mval[2], float r_col[3], bool *r_is_data);
struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock, int tile);
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index ea2383457c2..67a50b83bd6 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -121,6 +121,11 @@ void ED_node_composite_job(const struct bContext *C,
void ED_operatormacros_node(void);
/* node_view.c */
+bool ED_space_node_get_position(struct Main *bmain,
+ struct SpaceNode *snode,
+ struct ARegion *region,
+ const int mval[2],
+ float fpos[2]);
bool ED_space_node_color_sample(struct Main *bmain,
struct SpaceNode *snode,
struct ARegion *region,
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 5620d39ab16..d23daf7f0e3 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -2078,7 +2078,10 @@ void uiTemplatePalette(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
bool colors);
-void uiTemplateCryptoPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
+void uiTemplateCryptoPicker(uiLayout *layout,
+ struct PointerRNA *ptr,
+ const char *propname,
+ int icon);
void uiTemplateLayers(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 82bcd5d7eb4..421019bebb8 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -29,6 +29,7 @@ set(INC
../../makesdna
../../makesrna
../../python
+ ../../render
../../windowmanager
../../../../intern/glew-mx
../../../../intern/guardedalloc
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 5af290db037..349086132dc 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -31,10 +31,14 @@
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "BLI_listbase.h"
#include "BLI_math_vector.h"
+#include "BLI_string.h"
#include "BKE_context.h"
+#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_node.h"
#include "BKE_screen.h"
#include "RNA_access.h"
@@ -42,6 +46,7 @@
#include "UI_interface.h"
#include "IMB_colormanagement.h"
+#include "IMB_imbuf_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -54,6 +59,8 @@
#include "ED_image.h"
#include "ED_node.h"
+#include "RE_pipeline.h"
+
#include "interface_eyedropper_intern.h"
typedef struct Eyedropper {
@@ -71,13 +78,12 @@ typedef struct Eyedropper {
float accum_col[3];
int accum_tot;
- bool use_accum;
+ bNode *crypto_node;
} Eyedropper;
static bool eyedropper_init(bContext *C, wmOperator *op)
{
Eyedropper *eye = MEM_callocN(sizeof(Eyedropper), __func__);
- eye->use_accum = RNA_boolean_get(op->ptr, "use_accumulate");
uiBut *but = UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
const enum PropertySubType prop_subtype = eye->prop ? RNA_property_subtype(eye->prop) : 0;
@@ -96,6 +102,13 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
float col[4];
RNA_property_float_get_array(&eye->ptr, eye->prop, col);
+ if (ELEM(eye->ptr.type, &RNA_CompositorNodeCryptomatteV2, &RNA_CompositorNodeCryptomatte)) {
+ eye->crypto_node = (bNode *)eye->ptr.data;
+ }
+ else {
+ eye->crypto_node = NULL;
+ }
+
if (prop_subtype != PROP_COLOR) {
Scene *scene = CTX_data_scene(C);
const char *display_device;
@@ -125,6 +138,150 @@ static void eyedropper_exit(bContext *C, wmOperator *op)
/* *** eyedropper_color_ helper functions *** */
+static bool eyedropper_cryptomatte_sample_renderlayer_fl(RenderLayer *render_layer,
+ const char *prefix,
+ const float fpos[2],
+ float r_col[3])
+{
+ if (!render_layer) {
+ return false;
+ }
+
+ const int render_layer_name_len = BLI_strnlen(render_layer->name, sizeof(render_layer->name));
+ if (strncmp(prefix, render_layer->name, render_layer_name_len) != 0) {
+ return false;
+ }
+
+ const int prefix_len = strlen(prefix);
+ if (prefix_len <= render_layer_name_len + 1) {
+ return false;
+ }
+
+ /* RenderResult from images can have no render layer name. */
+ const char *render_pass_name_prefix = render_layer_name_len ?
+ prefix + 1 + render_layer_name_len :
+ prefix;
+
+ LISTBASE_FOREACH (RenderPass *, render_pass, &render_layer->passes) {
+ if (STRPREFIX(render_pass->name, render_pass_name_prefix) &&
+ !STREQLEN(render_pass->name, render_pass_name_prefix, sizeof(render_pass->name))) {
+ BLI_assert(render_pass->channels == 4);
+ const int x = (int)(fpos[0] * render_pass->rectx);
+ const int y = (int)(fpos[1] * render_pass->recty);
+ const int offset = 4 * (y * render_pass->rectx + x);
+ zero_v3(r_col);
+ r_col[0] = render_pass->rect[offset];
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool eyedropper_cryptomatte_sample_fl(
+ bContext *C, Eyedropper *eye, int mx, int my, float r_col[3])
+{
+ bNode *node = eye->crypto_node;
+ NodeCryptomatte *crypto = node ? ((NodeCryptomatte *)node->storage) : NULL;
+
+ if (!crypto) {
+ return false;
+ }
+
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ if (!sa || !ELEM(sa->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP)) {
+ return false;
+ }
+
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (!ar) {
+ return false;
+ }
+
+ int mval[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin};
+ float fpos[2] = {-1.0f, -1.0};
+ switch (sa->spacetype) {
+ case SPACE_IMAGE: {
+ SpaceImage *sima = sa->spacedata.first;
+ ED_space_image_get_position(sima, ar, mval, fpos);
+ break;
+ }
+ case SPACE_NODE: {
+ Main *bmain = CTX_data_main(C);
+ SpaceNode *snode = sa->spacedata.first;
+ ED_space_node_get_position(bmain, snode, ar, mval, fpos);
+ break;
+ }
+ case SPACE_CLIP: {
+ SpaceClip *sc = sa->spacedata.first;
+ ED_space_clip_get_position(sc, ar, mval, fpos);
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ if (fpos[0] < 0.0f || fpos[1] < 0.0f || fpos[0] >= 1.0f || fpos[1] >= 1.0f) {
+ return false;
+ }
+
+ /* CMP_CRYPTOMATTE_SRC_RENDER and CMP_CRYPTOMATTE_SRC_IMAGE require a referenced image/scene to
+ * work properly. */
+ if (!node->id) {
+ return false;
+ }
+
+ bool success = false;
+ /* TODO(jbakker): Migrate this file to cc and use std::string as return param. */
+ char prefix[MAX_NAME + 1];
+ ntreeCompositCryptomatteLayerPrefix(node, prefix, sizeof(prefix) - 1);
+ prefix[MAX_NAME] = '\0';
+
+ if (node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER) {
+ Scene *scene = (Scene *)node->id;
+ BLI_assert(GS(scene->id.name) == ID_SCE);
+ Render *re = RE_GetSceneRender(scene);
+
+ if (re) {
+ RenderResult *rr = RE_AcquireResultRead(re);
+ if (rr) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ RenderLayer *render_layer = RE_GetRenderLayer(rr, view_layer->name);
+ success = eyedropper_cryptomatte_sample_renderlayer_fl(
+ render_layer, prefix, fpos, r_col);
+ if (success) {
+ break;
+ }
+ }
+ }
+ RE_ReleaseResult(re);
+ }
+ }
+ else if (node->custom1 == CMP_CRYPTOMATTE_SRC_IMAGE) {
+ Image *image = (Image *)node->id;
+ BLI_assert(GS(image->id.name) == ID_IM);
+ ImageUser *iuser = &crypto->iuser;
+
+ if (image && image->type == IMA_TYPE_MULTILAYER) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, NULL);
+ if (image->rr) {
+ LISTBASE_FOREACH (RenderLayer *, render_layer, &image->rr->layers) {
+ success = eyedropper_cryptomatte_sample_renderlayer_fl(
+ render_layer, prefix, fpos, r_col);
+ if (success) {
+ break;
+ }
+ }
+ }
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+ }
+
+ return success;
+}
+
/**
* \brief get the color from the screen.
*
@@ -230,9 +387,16 @@ static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my
{
/* Accumulate color. */
float col[3];
- eyedropper_color_sample_fl(C, mx, my, col);
+ if (eye->crypto_node) {
+ if (!eyedropper_cryptomatte_sample_fl(C, eye, mx, my, col)) {
+ return;
+ }
+ }
+ else {
+ eyedropper_color_sample_fl(C, mx, my, col);
+ }
- if (eye->use_accum) {
+ if (!eye->crypto_node) {
add_v3_v3(eye->accum_col, col);
eye->accum_tot++;
}
@@ -360,11 +524,4 @@ void UI_OT_eyedropper_color(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_INTERNAL;
-
- /* properties */
- PropertyRNA *prop;
-
- /* Needed for color picking with crypto-matte. */
- prop = RNA_def_boolean(ot->srna, "use_accumulate", true, "Accumulate", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index fed011d78d7..08895564a26 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -5485,7 +5485,7 @@ void uiTemplatePalette(uiLayout *layout,
}
}
-void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propname)
+void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propname, int icon)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
@@ -5500,7 +5500,7 @@ void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propn
UI_BTYPE_BUT,
"UI_OT_eyedropper_color",
WM_OP_INVOKE_DEFAULT,
- ICON_EYEDROPPER,
+ icon,
RNA_property_ui_name(prop),
0,
0,
@@ -5510,10 +5510,6 @@ void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propn
but->rnapoin = *ptr;
but->rnaprop = prop;
but->rnaindex = -1;
-
- PointerRNA *opptr = UI_but_operator_ptr_get(but);
- /* Important for crypto-matte operation. */
- RNA_boolean_set(opptr, "use_accumulate", false);
}
/** \} */
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index e1172458f67..36375ad1ef3 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -269,6 +269,23 @@ ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale
return NULL;
}
+bool ED_space_clip_get_position(struct SpaceClip *sc,
+ struct ARegion *ar,
+ int mval[2],
+ float fpos[2])
+{
+ ImBuf *ibuf = ED_space_clip_get_buffer(sc);
+ if (!ibuf) {
+ return false;
+ }
+
+ /* map the mouse coords to the backdrop image space */
+ ED_clip_mouse_pos(sc, ar, mval, fpos);
+
+ IMB_freeImBuf(ibuf);
+ return true;
+}
+
/* Returns color in linear space, matching ED_space_image_color_sample(). */
bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, int mval[2], float r_col[3])
{
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index fc3619f01b9..72405a51aca 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -3147,6 +3147,23 @@ void IMAGE_OT_unpack(wmOperatorType *ot)
/** \name Sample Image Operator
* \{ */
+/* Returns mouse position in image space. */
+bool ED_space_image_get_position(SpaceImage *sima, struct ARegion *ar, int mval[2], float fpos[2])
+{
+ void *lock;
+ ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
+
+ if (ibuf == NULL) {
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ return false;
+ }
+
+ UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fpos[0], &fpos[1]);
+
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ return true;
+}
+
/* Returns color in linear space, matching ED_space_node_color_sample(). */
bool ED_space_image_color_sample(
SpaceImage *sima, ARegion *region, int mval[2], float r_col[3], bool *r_is_data)
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 75ea5b9a1bf..0f2b2b435bc 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -643,7 +643,8 @@ static void node_buts_image_user(uiLayout *layout,
PointerRNA *ptr,
PointerRNA *imaptr,
PointerRNA *iuserptr,
- bool compositor)
+ const bool show_layer_selection,
+ const bool show_color_management)
{
if (!imaptr->data) {
return;
@@ -677,20 +678,22 @@ static void node_buts_image_user(uiLayout *layout,
uiItemR(col, ptr, "use_auto_refresh", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- if (compositor && RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER &&
+ if (show_layer_selection && RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER &&
RNA_boolean_get(ptr, "has_layers")) {
col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "layer", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- uiLayout *split = uiLayoutSplit(layout, 0.5f, true);
- PointerRNA colorspace_settings_ptr = RNA_pointer_get(imaptr, "colorspace_settings");
- uiItemL(split, IFACE_("Color Space"), ICON_NONE);
- uiItemR(split, &colorspace_settings_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
+ if (show_color_management) {
+ uiLayout *split = uiLayoutSplit(layout, 0.5f, true);
+ PointerRNA colorspace_settings_ptr = RNA_pointer_get(imaptr, "colorspace_settings");
+ uiItemL(split, IFACE_("Color Space"), ICON_NONE);
+ uiItemR(split, &colorspace_settings_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
- /* Avoid losing changes image is painted. */
- if (BKE_image_is_dirty(imaptr->data)) {
- uiLayoutSetEnabled(split, false);
+ /* Avoid losing changes image is painted. */
+ if (BKE_image_is_dirty(imaptr->data)) {
+ uiLayoutSetEnabled(split, false);
+ }
}
}
@@ -756,7 +759,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
/* note: image user properties used directly here, unlike compositor image node,
* which redefines them in the node struct RNA to get proper updates.
*/
- node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false);
+ node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false, true);
}
static void node_shader_buts_tex_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -785,7 +788,7 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin
uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, "", ICON_NONE);
uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, "", ICON_NONE);
- node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false);
+ node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false, true);
}
static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -1374,7 +1377,7 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
PointerRNA imaptr = RNA_pointer_get(ptr, "image");
- node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr, true);
+ node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr, true, true);
node_buts_image_views(layout, C, ptr, &imaptr);
}
@@ -2665,27 +2668,64 @@ static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), P
uiItemR(layout, ptr, "ray_length", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
-static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_composit_buts_cryptomatte_legacy(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
{
uiLayout *col = uiLayoutColumn(layout, true);
uiItemL(col, IFACE_("Matte Objects:"), ICON_NONE);
uiLayout *row = uiLayoutRow(col, true);
- uiTemplateCryptoPicker(row, ptr, "add");
- uiTemplateCryptoPicker(row, ptr, "remove");
+ uiTemplateCryptoPicker(row, ptr, "add", ICON_ADD);
+ uiTemplateCryptoPicker(row, ptr, "remove", ICON_REMOVE);
uiItemR(col, ptr, "matte_id", DEFAULT_FLAGS, "", ICON_NONE);
}
-static void node_composit_buts_cryptomatte_ex(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *UNUSED(ptr))
+static void node_composit_buts_cryptomatte_legacy_ex(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr))
{
uiItemO(layout, IFACE_("Add Crypto Layer"), ICON_ADD, "NODE_OT_cryptomatte_layer_add");
uiItemO(layout, IFACE_("Remove Crypto Layer"), ICON_REMOVE, "NODE_OT_cryptomatte_layer_remove");
}
+static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = ptr->data;
+
+ uiLayout *row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "source", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+
+ uiLayout *col = uiLayoutColumn(layout, false);
+ if (node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER) {
+ uiTemplateID(col, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
+ }
+ else {
+ uiTemplateID(
+ col, C, ptr, "image", NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
+
+ NodeCryptomatte *crypto = (NodeCryptomatte *)node->storage;
+ PointerRNA imaptr = RNA_pointer_get(ptr, "image");
+ PointerRNA iuserptr;
+ RNA_pointer_create((ID *)ptr->owner_id, &RNA_ImageUser, &crypto->iuser, &iuserptr);
+ uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
+
+ node_buts_image_user(col, C, ptr, &imaptr, &iuserptr, false, false);
+ node_buts_image_views(col, C, ptr, &imaptr);
+ }
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "layer_name", 0, "", ICON_NONE);
+ uiItemL(col, IFACE_("Matte ID:"), ICON_NONE);
+
+ row = uiLayoutRow(col, true);
+ uiItemR(row, ptr, "matte_id", DEFAULT_FLAGS, "", ICON_NONE);
+ uiTemplateCryptoPicker(row, ptr, "add", ICON_ADD);
+ uiTemplateCryptoPicker(row, ptr, "remove", ICON_REMOVE);
+}
+
static void node_composit_buts_brightcontrast(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
@@ -2938,7 +2978,10 @@ static void node_composit_set_butfunc(bNodeType *ntype)
break;
case CMP_NODE_CRYPTOMATTE:
ntype->draw_buttons = node_composit_buts_cryptomatte;
- ntype->draw_buttons_ex = node_composit_buts_cryptomatte_ex;
+ break;
+ case CMP_NODE_CRYPTOMATTE_LEGACY:
+ ntype->draw_buttons = node_composit_buts_cryptomatte_legacy;
+ ntype->draw_buttons_ex = node_composit_buts_cryptomatte_legacy_ex;
break;
case CMP_NODE_BRIGHTCONTRAST:
ntype->draw_buttons = node_composit_buts_brightcontrast;
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index afdc9efb78b..b72a6503749 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -1404,8 +1404,12 @@ static int node_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
}
LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
- if (node->type == CMP_NODE_R_LAYERS) {
+ if ((node->type == CMP_NODE_R_LAYERS) ||
+ (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER)) {
ID *id = node->id;
+ if (id == NULL) {
+ continue;
+ }
if (id->tag & LIB_TAG_DOIT) {
RE_ReadRenderResult(curscene, (Scene *)id);
ntreeCompositTagRender((Scene *)id);
@@ -2742,7 +2746,7 @@ static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator *UNUSED(op))
node = nodeGetActive(snode->edittree);
}
- if (!node || node->type != CMP_NODE_CRYPTOMATTE) {
+ if (!node || node->type != CMP_NODE_CRYPTOMATTE_LEGACY) {
return OPERATOR_CANCELLED;
}
@@ -2786,7 +2790,7 @@ static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *UNUSED(o
node = nodeGetActive(snode->edittree);
}
- if (!node || node->type != CMP_NODE_CRYPTOMATTE) {
+ if (!node || node->type != CMP_NODE_CRYPTOMATTE_LEGACY) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c
index 8f1dc3c8c3e..8ecab92aa26 100644
--- a/source/blender/editors/space_node/node_view.c
+++ b/source/blender/editors/space_node/node_view.c
@@ -443,6 +443,32 @@ static void sample_draw(const bContext *C, ARegion *region, void *arg_info)
}
}
+/* Returns mouse position in image space. */
+bool ED_space_node_get_position(
+ Main *bmain, SpaceNode *snode, struct ARegion *ar, const int mval[2], float fpos[2])
+{
+ if (!ED_node_is_compositor(snode) || (snode->flag & SNODE_BACKDRAW) == 0) {
+ return false;
+ }
+
+ void *lock;
+ Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
+ if (!ibuf) {
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ return false;
+ }
+
+ /* map the mouse coords to the backdrop image space */
+ float bufx = ibuf->x * snode->zoom;
+ float bufy = ibuf->y * snode->zoom;
+ fpos[0] = (bufx > 0.0f ? ((float)mval[0] - 0.5f * ar->winx - snode->xof) / bufx + 0.5f : 0.0f);
+ fpos[1] = (bufy > 0.0f ? ((float)mval[1] - 0.5f * ar->winy - snode->yof) / bufy + 0.5f : 0.0f);
+
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ return true;
+}
+
/* Returns color in linear space, matching ED_space_image_color_sample().
* And here we've got recursion in the comments tips...
*/
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index ad1def0f3ec..967258f1b81 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1066,15 +1066,39 @@ typedef struct CryptomatteEntry {
char _pad[4];
} CryptomatteEntry;
-typedef struct NodeCryptomatte {
+typedef struct CryptomatteLayer {
+ struct CryptomatteEntry *next, *prev;
+ char name[64];
+} CryptomatteLayer;
+
+typedef struct NodeCryptomatte_Runtime {
+ /* Contains `CryptomatteLayer`. */
+ ListBase layers;
+ /* Temp storage for the cryptomatte picker. */
float add[3];
float remove[3];
- /* Stores `entries` as a string for opening in 2.80-2.91. */
- char *matte_id;
+} NodeCryptomatte_Runtime;
+
+typedef struct NodeCryptomatte {
+ /* iuser needs to be first element due to RNA limitations.
+ * When we define the ImageData properties, we can't define them from
+ * storage->iuser, so storage needs to be casted to ImageUser directly. */
+ ImageUser iuser;
+
/* Contains `CryptomatteEntry`. */
ListBase entries;
+
+ /* MAX_NAME */
+ char layer_name[64];
+ /* Stores `entries` as a string for opening in 2.80-2.91. */
+ char *matte_id;
+
+ /** Legacy attributes */
+ /* Number of input sockets. */
int num_inputs;
+
char _pad[4];
+ NodeCryptomatte_Runtime runtime;
} NodeCryptomatte;
typedef struct NodeDenoise {
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index d41220eb22c..a9125c78229 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -142,6 +142,8 @@ extern StructRNA RNA_CompositorNodeCombYUVA;
extern StructRNA RNA_CompositorNodeComposite;
extern StructRNA RNA_CompositorNodeCornerPin;
extern StructRNA RNA_CompositorNodeCrop;
+extern StructRNA RNA_CompositorNodeCryptomatte;
+extern StructRNA RNA_CompositorNodeCryptomatteV2;
extern StructRNA RNA_CompositorNodeCurveRGB;
extern StructRNA RNA_CompositorNodeCurveVec;
extern StructRNA RNA_CompositorNodeDBlur;
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 622460979e7..35c319c2f79 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -398,6 +398,12 @@ static const EnumPropertyItem prop_shader_output_target_items[] = {
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem node_cryptomatte_layer_name_items[] = {
+ {0, "CryptoObject", 0, "Object", "Use Object layer"},
+ {1, "CryptoMaterial", 0, "Material", "Use Material layer"},
+ {2, "CryptoAsset", 0, "Asset", "Use Asset layer"},
+ {0, NULL, 0, NULL, NULL}};
+
#endif
#define ITEM_ATTRIBUTE \
@@ -3444,6 +3450,10 @@ static void rna_Node_image_layer_update(Main *bmain, Scene *scene, PointerRNA *p
Image *ima = (Image *)node->id;
ImageUser *iuser = node->storage;
+ if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) {
+ return;
+ }
+
BKE_image_multilayer_index(ima->rr, iuser);
BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_SRC_CHANGE);
@@ -3490,6 +3500,10 @@ static const EnumPropertyItem *rna_Node_image_layer_itemf(bContext *UNUSED(C),
const EnumPropertyItem *item = NULL;
RenderLayer *rl;
+ if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) {
+ return DummyRNA_NULL_items;
+ }
+
if (ima == NULL || ima->rr == NULL) {
*r_free = false;
return DummyRNA_NULL_items;
@@ -3508,8 +3522,12 @@ static bool rna_Node_image_has_layers_get(PointerRNA *ptr)
bNode *node = (bNode *)ptr->data;
Image *ima = (Image *)node->id;
+ if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) {
+ return false;
+ }
+
if (!ima || !(ima->rr)) {
- return 0;
+ return false;
}
return RE_layers_have_name(ima->rr);
@@ -3520,8 +3538,12 @@ static bool rna_Node_image_has_views_get(PointerRNA *ptr)
bNode *node = (bNode *)ptr->data;
Image *ima = (Image *)node->id;
+ if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) {
+ return false;
+ }
+
if (!ima || !(ima->rr)) {
- return 0;
+ return false;
}
return BLI_listbase_count_at_most(&ima->rr->views, 2) > 1;
@@ -3566,6 +3588,10 @@ static const EnumPropertyItem *rna_Node_image_view_itemf(bContext *UNUSED(C),
const EnumPropertyItem *item = NULL;
RenderView *rv;
+ if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) {
+ return DummyRNA_NULL_items;
+ }
+
if (ima == NULL || ima->rr == NULL) {
*r_free = false;
return DummyRNA_NULL_items;
@@ -3722,6 +3748,115 @@ static void rna_NodeColorBalance_update_cdl(Main *bmain, Scene *scene, PointerRN
rna_Node_update(bmain, scene, ptr);
}
+static void rna_NodeCryptomatte_source_set(PointerRNA *ptr, int value)
+{
+ bNode *node = (bNode *)ptr->data;
+ if (node->id && node->custom1 != value) {
+ id_us_min((ID *)node->id);
+ node->id = NULL;
+ }
+ node->custom1 = value;
+}
+
+static int rna_NodeCryptomatte_layer_name_get(PointerRNA *ptr)
+{
+ int index = 0;
+ bNode *node = (bNode *)ptr->data;
+ NodeCryptomatte *storage = node->storage;
+ LISTBASE_FOREACH_INDEX (CryptomatteLayer *, layer, &storage->runtime.layers, index) {
+ if (STREQLEN(storage->layer_name, layer->name, sizeof(storage->layer_name))) {
+ return index;
+ }
+ }
+ return 0;
+}
+
+static void rna_NodeCryptomatte_layer_name_set(PointerRNA *ptr, int new_value)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeCryptomatte *storage = node->storage;
+
+ CryptomatteLayer *layer = BLI_findlink(&storage->runtime.layers, new_value);
+ if (layer) {
+ STRNCPY(storage->layer_name, layer->name);
+ }
+}
+
+static const EnumPropertyItem *rna_NodeCryptomatte_layer_name_itemf(bContext *UNUSED(C),
+ PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeCryptomatte *storage = node->storage;
+ EnumPropertyItem *item = NULL;
+ EnumPropertyItem template = {0, "", 0, "", ""};
+ int totitem = 0;
+
+ ntreeCompositCryptomatteUpdateLayerNames(node);
+ int layer_index;
+ LISTBASE_FOREACH_INDEX (CryptomatteLayer *, layer, &storage->runtime.layers, layer_index) {
+ template.value = layer_index;
+ template.identifier = layer->name;
+ template.name = layer->name;
+ RNA_enum_item_add(&item, &totitem, &template);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static PointerRNA rna_NodeCryptomatte_scene_get(PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ Scene *scene = (node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER) ? (Scene *)node->id : NULL;
+ return rna_pointer_inherit_refine(ptr, &RNA_Scene, scene);
+}
+
+static void rna_NodeCryptomatte_scene_set(PointerRNA *ptr,
+ PointerRNA value,
+ struct ReportList *reports)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ if (node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER) {
+ rna_Node_scene_set(ptr, value, reports);
+ }
+}
+
+static PointerRNA rna_NodeCryptomatte_image_get(PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ Image *image = (node->custom1 == CMP_CRYPTOMATTE_SRC_IMAGE) ? (Image *)node->id : NULL;
+ return rna_pointer_inherit_refine(ptr, &RNA_Image, image);
+}
+
+static void rna_NodeCryptomatte_image_set(PointerRNA *ptr,
+ PointerRNA value,
+ struct ReportList *UNUSED(reports))
+{
+ bNode *node = (bNode *)ptr->data;
+
+ if (node->custom1 == CMP_CRYPTOMATTE_SRC_IMAGE) {
+ if (node->id)
+ id_us_min((ID *)node->id);
+ if (value.data)
+ id_us_plus((ID *)value.data);
+
+ node->id = value.data;
+ }
+}
+
+static bool rna_NodeCryptomatte_image_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
+{
+ Image *image = (Image *)value.owner_id;
+ return image->type == IMA_TYPE_MULTILAYER;
+}
+
static void rna_NodeCryptomatte_matte_get(PointerRNA *ptr, char *value)
{
bNode *node = (bNode *)ptr->data;
@@ -3750,13 +3885,13 @@ static void rna_NodeCryptomatte_matte_set(PointerRNA *ptr, const char *value)
static void rna_NodeCryptomatte_update_add(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- ntreeCompositCryptomatteSyncFromAdd((bNodeTree *)ptr->owner_id, ptr->data);
+ ntreeCompositCryptomatteSyncFromAdd(ptr->data);
rna_Node_update(bmain, scene, ptr);
}
static void rna_NodeCryptomatte_update_remove(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- ntreeCompositCryptomatteSyncFromRemove((bNodeTree *)ptr->owner_id, ptr->data);
+ ntreeCompositCryptomatteSyncFromRemove(ptr->data);
rna_Node_update(bmain, scene, ptr);
}
@@ -8409,12 +8544,11 @@ static void def_cmp_cryptomatte_entry(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop);
}
-static void def_cmp_cryptomatte(StructRNA *srna)
+static void def_cmp_cryptomatte_common(StructRNA *srna)
{
PropertyRNA *prop;
static float default_1[3] = {1.0f, 1.0f, 1.0f};
- RNA_def_struct_sdna_from(srna, "NodeCryptomatte", "storage");
prop = RNA_def_property(srna, "matte_id", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop,
"rna_NodeCryptomatte_matte_get",
@@ -8425,6 +8559,7 @@ static void def_cmp_cryptomatte(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "add", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "runtime.add");
RNA_def_property_float_array_default(prop, default_1);
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
RNA_def_property_ui_text(
@@ -8432,6 +8567,7 @@ static void def_cmp_cryptomatte(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeCryptomatte_update_add");
prop = RNA_def_property(srna, "remove", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "runtime.remove");
RNA_def_property_float_array_default(prop, default_1);
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
RNA_def_property_ui_text(
@@ -8441,6 +8577,73 @@ static void def_cmp_cryptomatte(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeCryptomatte_update_remove");
}
+static void def_cmp_cryptomatte_legacy(StructRNA *srna)
+{
+ RNA_def_struct_sdna_from(srna, "NodeCryptomatte", "storage");
+ def_cmp_cryptomatte_common(srna);
+}
+
+static void def_cmp_cryptomatte(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem cryptomatte_source_items[] = {
+ {CMP_CRYPTOMATTE_SRC_RENDER, "RENDER", 0, "Render", "Use Cryptomatte passes from a render"},
+ {CMP_CRYPTOMATTE_SRC_IMAGE, "IMAGE", 0, "Image", "Use Cryptomatte passes from an image"},
+ {0, NULL, 0, NULL, NULL}};
+
+ prop = RNA_def_property(srna, "source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, cryptomatte_source_items);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_NodeCryptomatte_source_set", NULL);
+ RNA_def_property_ui_text(prop, "Source", "Where the Cryptomatte passes are loaded from");
+
+ prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_funcs(
+ prop, "rna_NodeCryptomatte_scene_get", "rna_NodeCryptomatte_scene_set", NULL, NULL);
+ RNA_def_property_struct_type(prop, "Scene");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
+ RNA_def_property_ui_text(prop, "Scene", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_funcs(prop,
+ "rna_NodeCryptomatte_image_get",
+ "rna_NodeCryptomatte_image_set",
+ NULL,
+ "rna_NodeCryptomatte_image_poll");
+ RNA_def_property_struct_type(prop, "Image");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Image", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ RNA_def_struct_sdna_from(srna, "NodeCryptomatte", "storage");
+ def_cmp_cryptomatte_common(srna);
+
+ prop = RNA_def_property(srna, "layer_name", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, node_cryptomatte_layer_name_items);
+ RNA_def_property_enum_funcs(prop,
+ "rna_NodeCryptomatte_layer_name_get",
+ "rna_NodeCryptomatte_layer_name_set",
+ "rna_NodeCryptomatte_layer_name_itemf");
+ RNA_def_property_ui_text(prop, "Cryptomatte Layer", "What Cryptomatte layer is used");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "entries", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "entries", NULL);
+ RNA_def_property_struct_type(prop, "CryptomatteEntry");
+ RNA_def_property_ui_text(prop, "Mattes", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ /* Included here instead of defining image_user as a property of the node,
+ * see def_cmp_image for details.
+ * As mentioned in DNA_node_types.h, iuser is the first member of the Cryptomatte
+ * storage type, so we can cast node->storage to ImageUser.
+ * That is required since we can't define the properties from storage->iuser directly... */
+ RNA_def_struct_sdna_from(srna, "ImageUser", "storage");
+ def_node_image_user(srna);
+}
+
static void def_cmp_denoise(StructRNA *srna)
{
PropertyRNA *prop;
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index 6ad02986010..b0dd0edeec5 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -106,6 +106,7 @@ void register_node_type_cmp_doubleedgemask(void);
void register_node_type_cmp_keyingscreen(void);
void register_node_type_cmp_keying(void);
void register_node_type_cmp_cryptomatte(void);
+void register_node_type_cmp_cryptomatte_legacy(void);
void register_node_type_cmp_translate(void);
void register_node_type_cmp_rotate(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 493aaa05675..e9983d7e92c 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -220,7 +220,8 @@ DefNode(CompositorNode, CMP_NODE_PIXELATE, 0, "PIXELA
DefNode(CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLANETRACKDEFORM",PlaneTrackDeform,"Plane Track Deform","" )
DefNode(CompositorNode, CMP_NODE_CORNERPIN, 0, "CORNERPIN", CornerPin, "Corner Pin", "" )
DefNode(CompositorNode, CMP_NODE_SUNBEAMS, def_cmp_sunbeams, "SUNBEAMS", SunBeams, "Sun Beams", "" )
-DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE, def_cmp_cryptomatte, "CRYPTOMATTE", Cryptomatte, "Cryptomatte", "" )
+DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE, def_cmp_cryptomatte, "CRYPTOMATTE_V2", CryptomatteV2, "Cryptomatte", "" )
+DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE_LEGACY, def_cmp_cryptomatte_legacy, "CRYPTOMATTE", Cryptomatte, "Cryptomatte (Legacy)", "" )
DefNode(CompositorNode, CMP_NODE_DENOISE, def_cmp_denoise, "DENOISE", Denoise, "Denoise", "" )
DefNode(CompositorNode, CMP_NODE_EXPOSURE, 0, "EXPOSURE", Exposure, "Exposure", "" )
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
index 84cd84e41c7..d81076c2fa6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
@@ -21,11 +21,84 @@
* \ingroup cmpnodes
*/
+#include "node_composite_util.h"
+
#include "BLI_assert.h"
#include "BLI_dynstr.h"
#include "BLI_hash_mm3.h"
+#include "BLI_string_ref.hh"
#include "BLI_utildefines.h"
-#include "node_composite_util.h"
+
+#include "BKE_context.h"
+#include "BKE_cryptomatte.hh"
+#include "BKE_global.h"
+#include "BKE_lib_id.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+
+#include <optional>
+
+/** \name Cryptomatte
+ * \{ */
+
+static blender::bke::cryptomatte::CryptomatteSessionPtr cryptomatte_init_from_node(
+ const bNode &node, const int frame_number, const bool use_meta_data)
+{
+ blender::bke::cryptomatte::CryptomatteSessionPtr session;
+ if (node.type != CMP_NODE_CRYPTOMATTE) {
+ return session;
+ }
+
+ NodeCryptomatte *node_cryptomatte = static_cast<NodeCryptomatte *>(node.storage);
+ switch (node.custom1) {
+ case CMP_CRYPTOMATTE_SRC_RENDER: {
+ Scene *scene = (Scene *)node.id;
+ if (!scene) {
+ return session;
+ }
+ BLI_assert(GS(scene->id.name) == ID_SCE);
+
+ if (use_meta_data) {
+ Render *render = (scene) ? RE_GetSceneRender(scene) : nullptr;
+ 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));
+ }
+
+ break;
+ }
+
+ case CMP_CRYPTOMATTE_SRC_IMAGE: {
+ Image *image = (Image *)node.id;
+ BLI_assert(!image || GS(image->id.name) == ID_IM);
+ if (!image || image->type != IMA_TYPE_MULTILAYER) {
+ break;
+ }
+
+ ImageUser *iuser = &node_cryptomatte->iuser;
+ BKE_image_user_frame_calc(image, iuser, frame_number);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, nullptr);
+ RenderResult *render_result = image->rr;
+ if (render_result) {
+ session = blender::bke::cryptomatte::CryptomatteSessionPtr(
+ BKE_cryptomatte_init_from_render_result(render_result));
+ }
+ BKE_image_release_ibuf(image, ibuf, nullptr);
+ break;
+ }
+ }
+ return session;
+}
extern "C" {
static CryptomatteEntry *cryptomatte_find(const NodeCryptomatte &n, float encoded_hash)
@@ -38,21 +111,29 @@ static CryptomatteEntry *cryptomatte_find(const NodeCryptomatte &n, float encode
return nullptr;
}
-static void cryptomatte_add(NodeCryptomatte &n, float f)
+static void cryptomatte_add(bNode &node, NodeCryptomatte &node_cryptomatte, float encoded_hash)
{
/* Check if entry already exist. */
- if (cryptomatte_find(n, f)) {
+ if (cryptomatte_find(node_cryptomatte, encoded_hash)) {
return;
}
+
CryptomatteEntry *entry = static_cast<CryptomatteEntry *>(
MEM_callocN(sizeof(CryptomatteEntry), __func__));
- entry->encoded_hash = f;
- BLI_addtail(&n.entries, entry);
+ entry->encoded_hash = encoded_hash;
+ /* TODO(jbakker): Get current frame from scene. */
+ blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node(
+ node, 0, true);
+ if (session) {
+ BKE_cryptomatte_find_name(session.get(), encoded_hash, entry->name, sizeof(entry->name));
+ }
+
+ BLI_addtail(&node_cryptomatte.entries, entry);
}
-static void cryptomatte_remove(NodeCryptomatte &n, float f)
+static void cryptomatte_remove(NodeCryptomatte &n, float encoded_hash)
{
- CryptomatteEntry *entry = cryptomatte_find(n, f);
+ CryptomatteEntry *entry = cryptomatte_find(n, encoded_hash);
if (!entry) {
return;
}
@@ -60,73 +141,104 @@ static void cryptomatte_remove(NodeCryptomatte &n, float f)
MEM_freeN(entry);
}
-static bNodeSocketTemplate outputs[] = {
+static bNodeSocketTemplate cmp_node_cryptomatte_in[] = {
+ {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f}, {-1, ""}};
+
+static bNodeSocketTemplate cmp_node_cryptomatte_out[] = {
{SOCK_RGBA, N_("Image")},
{SOCK_FLOAT, N_("Matte")},
{SOCK_RGBA, N_("Pick")},
{-1, ""},
};
-void ntreeCompositCryptomatteSyncFromAdd(bNodeTree *UNUSED(ntree), bNode *node)
+void ntreeCompositCryptomatteSyncFromAdd(bNode *node)
{
+ BLI_assert(ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY));
NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
- if (n->add[0] != 0.0f) {
- cryptomatte_add(*n, n->add[0]);
- zero_v3(n->add);
+ if (n->runtime.add[0] != 0.0f) {
+ cryptomatte_add(*node, *n, n->runtime.add[0]);
+ zero_v3(n->runtime.add);
}
}
-void ntreeCompositCryptomatteSyncFromRemove(bNodeTree *UNUSED(ntree), bNode *node)
+void ntreeCompositCryptomatteSyncFromRemove(bNode *node)
{
+ BLI_assert(ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY));
NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
- if (n->remove[0] != 0.0f) {
- cryptomatte_remove(*n, n->remove[0]);
- zero_v3(n->remove);
+ if (n->runtime.remove[0] != 0.0f) {
+ cryptomatte_remove(*n, n->runtime.remove[0]);
+ zero_v3(n->runtime.remove);
}
}
-
-bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node)
+void ntreeCompositCryptomatteUpdateLayerNames(bNode *node)
{
+ BLI_assert(node->type == CMP_NODE_CRYPTOMATTE);
NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
- char sockname[32];
- n->num_inputs++;
- BLI_snprintf(sockname, sizeof(sockname), "Crypto %.2d", n->num_inputs - 1);
- bNodeSocket *sock = nodeAddStaticSocket(
- ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, nullptr, sockname);
- return sock;
+ BLI_freelistN(&n->runtime.layers);
+
+ blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node(
+ *node, 0, false);
+
+ if (session) {
+ for (blender::StringRef layer_name :
+ blender::bke::cryptomatte::BKE_cryptomatte_layer_names_get(*session)) {
+ CryptomatteLayer *layer = static_cast<CryptomatteLayer *>(
+ MEM_callocN(sizeof(CryptomatteLayer), __func__));
+ layer_name.copy(layer->name);
+ BLI_addtail(&n->runtime.layers, layer);
+ }
+ }
}
-int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node)
+void ntreeCompositCryptomatteLayerPrefix(const bNode *node, char *r_prefix, size_t prefix_len)
{
- NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
- if (n->num_inputs < 2) {
- return 0;
+ BLI_assert(node->type == CMP_NODE_CRYPTOMATTE);
+ NodeCryptomatte *node_cryptomatte = (NodeCryptomatte *)node->storage;
+ blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node(
+ *node, 0, false);
+ std::string first_layer_name;
+
+ if (session) {
+ for (blender::StringRef layer_name :
+ blender::bke::cryptomatte::BKE_cryptomatte_layer_names_get(*session)) {
+ if (first_layer_name.empty()) {
+ first_layer_name = layer_name;
+ }
+
+ if (layer_name == node_cryptomatte->layer_name) {
+ BLI_strncpy(r_prefix, node_cryptomatte->layer_name, prefix_len);
+ return;
+ }
+ }
}
- bNodeSocket *sock = static_cast<bNodeSocket *>(node->inputs.last);
- nodeRemoveSocket(ntree, node, sock);
- n->num_inputs--;
- return 1;
+
+ const char *cstr = first_layer_name.c_str();
+ BLI_strncpy(r_prefix, cstr, prefix_len);
}
-static void init(bNodeTree *ntree, bNode *node)
+static void node_init_cryptomatte(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeCryptomatte *user = static_cast<NodeCryptomatte *>(
MEM_callocN(sizeof(NodeCryptomatte), __func__));
node->storage = user;
+}
- nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "image", "Image");
-
- /* Add three inputs by default, as recommended by the Cryptomatte specification. */
- ntreeCompositCryptomatteAddSocket(ntree, node);
- ntreeCompositCryptomatteAddSocket(ntree, node);
- ntreeCompositCryptomatteAddSocket(ntree, node);
+static void node_init_api_cryptomatte(const bContext *C, PointerRNA *ptr)
+{
+ Scene *scene = CTX_data_scene(C);
+ bNode *node = static_cast<bNode *>(ptr->data);
+ BLI_assert(node->type == CMP_NODE_CRYPTOMATTE);
+ node->id = &scene->id;
+ id_us_plus(node->id);
}
static void node_free_cryptomatte(bNode *node)
{
+ BLI_assert(ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY));
NodeCryptomatte *nc = static_cast<NodeCryptomatte *>(node->storage);
if (nc) {
+ BLI_freelistN(&nc->runtime.layers);
BLI_freelistN(&nc->entries);
MEM_freeN(nc);
}
@@ -140,17 +252,92 @@ static void node_copy_cryptomatte(bNodeTree *UNUSED(dest_ntree),
NodeCryptomatte *dest_nc = static_cast<NodeCryptomatte *>(MEM_dupallocN(src_nc));
BLI_duplicatelist(&dest_nc->entries, &src_nc->entries);
+ BLI_listbase_clear(&dest_nc->runtime.layers);
dest_node->storage = dest_nc;
}
+static bool node_poll_cryptomatte(bNodeType *UNUSED(ntype), bNodeTree *ntree)
+{
+ if (STREQ(ntree->idname, "CompositorNodeTree")) {
+ Scene *scene;
+
+ /* See node_composit_poll_rlayers. */
+ for (scene = static_cast<Scene *>(G.main->scenes.first); scene;
+ scene = static_cast<Scene *>(scene->id.next)) {
+ if (scene->nodetree == ntree) {
+ break;
+ }
+ }
+
+ return scene != nullptr;
+ }
+ return false;
+}
+
void register_node_type_cmp_cryptomatte(void)
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_CONVERTOR, 0);
- node_type_socket_templates(&ntype, nullptr, outputs);
- node_type_init(&ntype, init);
+ cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_MATTE, 0);
+ node_type_socket_templates(&ntype, cmp_node_cryptomatte_in, cmp_node_cryptomatte_out);
+ node_type_init(&ntype, node_init_cryptomatte);
+ ntype.initfunc_api = node_init_api_cryptomatte;
+ ntype.poll = node_poll_cryptomatte;
+ node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte);
+ nodeRegisterType(&ntype);
+}
+
+/** \} */
+
+/** \name Cryptomatte Legacy
+ * \{ */
+static void node_init_cryptomatte_legacy(bNodeTree *ntree, bNode *node)
+{
+ node_init_cryptomatte(ntree, node);
+
+ nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "image", "Image");
+
+ /* Add three inputs by default, as recommended by the Cryptomatte specification. */
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+}
+
+bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node)
+{
+ BLI_assert(node->type == CMP_NODE_CRYPTOMATTE_LEGACY);
+ NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
+ char sockname[32];
+ n->num_inputs++;
+ BLI_snprintf(sockname, sizeof(sockname), "Crypto %.2d", n->num_inputs - 1);
+ bNodeSocket *sock = nodeAddStaticSocket(
+ ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, nullptr, sockname);
+ return sock;
+}
+
+int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node)
+{
+ BLI_assert(node->type == CMP_NODE_CRYPTOMATTE_LEGACY);
+ NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
+ if (n->num_inputs < 2) {
+ return 0;
+ }
+ bNodeSocket *sock = static_cast<bNodeSocket *>(node->inputs.last);
+ nodeRemoveSocket(ntree, node, sock);
+ n->num_inputs--;
+ return 1;
+}
+
+void register_node_type_cmp_cryptomatte_legacy(void)
+{
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE_LEGACY, "Cryptomatte", NODE_CLASS_MATTE, 0);
+ node_type_socket_templates(&ntype, nullptr, cmp_node_cryptomatte_out);
+ node_type_init(&ntype, node_init_cryptomatte_legacy);
node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte);
nodeRegisterType(&ntype);
}
+
+/** \} */
}