Compositor: Redesign Cryptomatte node for better usability

In the current implementation, cryptomatte passes are connected to the node
and elements are picked by using the eyedropper tool on a special pick channel.

This design has two disadvantages - both connecting all passes individually
and always having to switch to the picker channel are tedious.

With the new design, the user selects the RenderLayer or Image from which the
Cryptomatte layers are directly loaded (the type of pass is determined by an
enum). This allows the node to automatically detect all relevant passes.

Then, when using the eyedropper tool, the operator looks up the selected
coordinates from the picked Image, Node backdrop or Clip and reads the picked
object directly from the Renderlayer/Image, therefore allowing to pick in any
context (e.g. by clicking on the Combined pass in the Image Viewer). The
sampled color is looked up in the metadata and the actual name is stored
in the cryptomatte node. This also allows to remove a hash by just removing
the name from the matte id.

Technically there is some loss of flexibility because the Cryptomatte pass
inputs can no longer be connected to other nodes, but since any compositing
done on them is likely to break the Cryptomatte system anyways, this isn't
really a concern in practise.

In the future, this would also allow to automatically translate values to names
by looking up the value in the associated metadata of the input, or to get a
better visualization of overlapping areas in the Pick output since we could
blend colors now that the output doesn't have to contain the exact value.

Idea + Original patch: Lucas Stockner
Reviewed By: Brecht van Lommel

Differential Revision: https://developer.blender.org/D3959
This commit is contained in:
Jeroen Bakker 2021-03-16 07:37:30 +01:00
parent 269536d47e
commit d49e7b82da
29 changed files with 1173 additions and 149 deletions

View File

@ -390,6 +390,7 @@ compositor_node_categories = [
NodeItem("CompositorNodeColorMatte"),
NodeItem("CompositorNodeDoubleEdgeMask"),
NodeItem("CompositorNodeCryptomatte"),
NodeItem("CompositorNodeCryptomatteV2"),
]),
CompositorNodeCategory("CMP_DISTORT", "Distort", items=[
NodeItem("CompositorNodeScale"),

View File

@ -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

View File

@ -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)
{

View File

@ -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);
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -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

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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) {

View File

@ -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;

View File

@ -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>
CryptomatteNode::CryptomatteNode(bNode *editorNode) : Node(editorNode)
{
/* pass */
}
/** \name Cryptomatte base
* \{ */
void CryptomatteNode::convertToOperations(NodeConverter &converter,
const CompositorContext & /*context*/) const
void CryptomatteBaseNode::convertToOperations(NodeConverter &converter,
const CompositorContext &context) const
{
NodeInput *inputSocketImage = this->getInputSocket(0);
NodeOutput *outputSocketImage = this->getOutputSocket(0);
NodeOutput *outputSocketMatte = this->getOutputSocket(1);
NodeOutput *outputSocketPick = this->getOutputSocket(2);
NodeOutput *output_image_socket = this->getOutputSocket(0);
bNode *node = this->getbNode();
NodeCryptomatte *cryptoMatteSettings = (NodeCryptomatte *)node->storage;
NodeCryptomatte *cryptomatte_settings = static_cast<NodeCryptomatte *>(node->storage);
CryptomatteOperation *operation = new CryptomatteOperation(getNumberOfInputSockets() - 1);
if (cryptoMatteSettings) {
LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptoMatteSettings->entries) {
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));
}
/* \} */
/** \name Cryptomatte V2
* \{ */
static std::string prefix_from_node(const bNode &node)
{
char prefix[MAX_NAME];
ntreeCompositCryptomatteLayerPrefix(&node, prefix, sizeof(prefix));
return std::string(prefix, BLI_strnlen(prefix, sizeof(prefix)));
}
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)));
}
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);
}
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;
}
BLI_assert(GS(image->id.name) == ID_IM);
if (image->type != IMA_TYPE_MULTILAYER) {
return;
}
ImageUser *iuser = &cryptomatte_settings->iuser;
BKE_image_user_frame_calc(image, iuser, context.getFramenumber());
ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, nullptr);
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;
}
}
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);
}
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;
}
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
* \{ */
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);
}
}
converter.addOperation(operation);
for (int i = 0; i < getNumberOfInputSockets() - 1; i++) {
for (int i = 0; i < num_inputs; i++) {
converter.mapInputSocket(this->getInputSocket(i + 1), operation->getInputSocket(i));
}
SeparateChannelOperation *separateOperation = new SeparateChannelOperation;
separateOperation->setChannel(3);
converter.addOperation(separateOperation);
SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation();
converter.addOperation(operationAlpha);
converter.addLink(operation->getOutputSocket(0), separateOperation->getInputSocket(0));
converter.addLink(separateOperation->getOutputSocket(0), operationAlpha->getInputSocket(1));
SetAlphaMultiplyOperation *clearAlphaOperation = new SetAlphaMultiplyOperation();
converter.addOperation(clearAlphaOperation);
converter.addInputValue(clearAlphaOperation->getInputSocket(1), 1.0f);
converter.addLink(operation->getOutputSocket(0), clearAlphaOperation->getInputSocket(0));
converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0));
converter.mapOutputSocket(outputSocketMatte, separateOperation->getOutputSocket(0));
converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket(0));
converter.mapOutputSocket(outputSocketPick, clearAlphaOperation->getOutputSocket(0));
return operation;
}
/* \} */

View File

@ -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;
};

View File

@ -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],

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -29,6 +29,7 @@ set(INC
../../makesdna
../../makesrna
../../python
../../render
../../windowmanager
../../../../intern/glew-mx
../../../../intern/guardedalloc

View File

@ -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);
}

View File

@ -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);
}
/** \} */

View File

@ -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])
{

View File

@ -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)

View File

@ -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;

View File

@ -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;
}

View File

@ -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...
*/

View File

@ -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 {

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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", "" )

View File

@ -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);
}
}
void ntreeCompositCryptomatteUpdateLayerNames(bNode *node)
{
BLI_assert(node->type == CMP_NODE_CRYPTOMATTE);
NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
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);
}
}
}
bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node)
void ntreeCompositCryptomatteLayerPrefix(const bNode *node, char *r_prefix, size_t prefix_len)
{
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_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;
int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node)
{
NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
if (n->num_inputs < 2) {
return 0;
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);
}
/** \} */
}