Files
test2/source/blender/compositor/nodes/COM_ImageNode.cc
Sergey Sharybin e1b60fdb91 Remove Z Buffer from ImBuf
It was only used by OpenEXR and Iris images, and saving the Z Buffer
in those formats was disabled by default. This option comes from the
times prior to the addition of the Multilayer EXR.

It also worth noting that it was not possible to save Iris with Depth
pass from Blender as internally it is called IRIZ format and it was
not exposed. But even after exposing this format option something still
was missing as saving and loading ITIZ did not show up the Depth pass.

The reason of removal is to make it a more clear match of the ImBuf
with a render pass, and use it instead of a custom type in the render
result and render pass API. This will simplify the API and also avoid
stealing buffers and making shallow copies when showing the render
result.

For the cases when Depth is needed a Multilayer EXR is to be used,
as most likely more than just the Depth will be needed.

On a user level this change:

- Removes the "Z Buffer" option from the interface.

- It preserves existing sockets in compositor nodes, but it will
  output black image. Also changing the image data-block will
  remove the socket unless a Multilayer EXR with Depth pass image
  is selected.

- Removes "Depth" socket of the Viewer and Composite nodes.

Ref #108618

Pull Request: https://projects.blender.org/blender/blender/pulls/109687
2023-07-04 17:03:02 +02:00

270 lines
11 KiB
C++

/* SPDX-FileCopyrightText: 2011 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "COM_ImageNode.h"
#include "COM_ConvertOperation.h"
#include "COM_MultilayerImageOperation.h"
#include "COM_SetColorOperation.h"
#include "COM_SetValueOperation.h"
#include "COM_SetVectorOperation.h"
namespace blender::compositor {
ImageNode::ImageNode(bNode *editor_node) : Node(editor_node)
{
/* pass */
}
NodeOperation *ImageNode::do_multilayer_check(NodeConverter &converter,
RenderLayer *render_layer,
RenderPass *render_pass,
Image *image,
ImageUser *user,
int framenumber,
int outputsocket_index,
int view,
DataType datatype) const
{
NodeOutput *output_socket = this->get_output_socket(outputsocket_index);
MultilayerBaseOperation *operation = nullptr;
switch (datatype) {
case DataType::Value:
operation = new MultilayerValueOperation(render_layer, render_pass, view);
break;
case DataType::Vector:
operation = new MultilayerVectorOperation(render_layer, render_pass, view);
break;
case DataType::Color:
operation = new MultilayerColorOperation(render_layer, render_pass, view);
break;
default:
break;
}
operation->set_image(image);
operation->set_image_user(user);
operation->set_framenumber(framenumber);
converter.add_operation(operation);
converter.map_output_socket(output_socket, operation->get_output_socket());
return operation;
}
void ImageNode::convert_to_operations(NodeConverter &converter,
const CompositorContext &context) const
{
/** Image output */
NodeOutput *output_image = this->get_output_socket(0);
const bNode *editor_node = this->get_bnode();
Image *image = (Image *)editor_node->id;
ImageUser *imageuser = (ImageUser *)editor_node->storage;
int framenumber = context.get_framenumber();
bool output_straight_alpha = (editor_node->custom1 & CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT) != 0;
BKE_image_user_frame_calc(image, imageuser, context.get_framenumber());
/* Force a load, we assume #ImageUser index will be set OK anyway. */
if (image && image->type == IMA_TYPE_MULTILAYER) {
bool is_multilayer_ok = false;
ImBuf *ibuf = BKE_image_acquire_ibuf(image, imageuser, nullptr);
if (image->rr) {
RenderLayer *rl = (RenderLayer *)BLI_findlink(&image->rr->layers, imageuser->layer);
if (rl) {
is_multilayer_ok = true;
for (int64_t index = 0; index < outputs_.size(); index++) {
NodeOutput *socket = outputs_[index];
NodeOperation *operation = nullptr;
bNodeSocket *bnode_socket = socket->get_bnode_socket();
NodeImageLayer *storage = (NodeImageLayer *)bnode_socket->storage;
RenderPass *rpass = (RenderPass *)BLI_findstring(
&rl->passes, storage->pass_name, offsetof(RenderPass, name));
int view = 0;
if (STREQ(storage->pass_name, RE_PASSNAME_COMBINED) &&
STREQ(bnode_socket->name, "Alpha")) {
/* Alpha output is already handled with the associated combined output. */
continue;
}
/* returns the image view to use for the current active view */
if (BLI_listbase_count_at_most(&image->rr->views, 2) > 1) {
const int view_image = imageuser->view;
const bool is_allview = (view_image == 0); /* if view selected == All (0) */
if (is_allview) {
/* heuristic to match image name with scene names
* check if the view name exists in the image */
view = BLI_findstringindex(
&image->rr->views, context.get_view_name(), offsetof(RenderView, name));
if (view == -1) {
view = 0;
}
}
else {
view = view_image - 1;
}
}
if (rpass) {
switch (rpass->channels) {
case 1:
operation = do_multilayer_check(converter,
rl,
rpass,
image,
imageuser,
framenumber,
index,
view,
DataType::Value);
break;
/* using image operations for both 3 and 4 channels (RGB and RGBA respectively) */
/* XXX any way to detect actual vector images? */
case 3:
operation = do_multilayer_check(converter,
rl,
rpass,
image,
imageuser,
framenumber,
index,
view,
DataType::Vector);
break;
case 4:
operation = do_multilayer_check(converter,
rl,
rpass,
image,
imageuser,
framenumber,
index,
view,
DataType::Color);
break;
default:
/* dummy operation is added below */
break;
}
if (index == 0 && operation) {
converter.add_preview(operation->get_output_socket());
}
if (STREQ(rpass->name, RE_PASSNAME_COMBINED) && !(bnode_socket->flag & SOCK_UNAVAIL)) {
for (NodeOutput *alpha_socket : get_output_sockets()) {
bNodeSocket *bnode_alpha_socket = alpha_socket->get_bnode_socket();
if (!STREQ(bnode_alpha_socket->name, "Alpha")) {
continue;
}
NodeImageLayer *alpha_storage = (NodeImageLayer *)bnode_socket->storage;
if (!STREQ(alpha_storage->pass_name, RE_PASSNAME_COMBINED)) {
continue;
}
SeparateChannelOperation *separate_operation;
separate_operation = new SeparateChannelOperation();
separate_operation->set_channel(3);
converter.add_operation(separate_operation);
converter.add_link(operation->get_output_socket(),
separate_operation->get_input_socket(0));
converter.map_output_socket(alpha_socket, separate_operation->get_output_socket());
break;
}
}
}
/* In case we can't load the layer. */
if (operation == nullptr) {
converter.set_invalid_output(get_output_socket(index));
}
}
}
}
BKE_image_release_ibuf(image, ibuf, nullptr);
/* without this, multilayer that fail to load will crash blender #32490. */
if (is_multilayer_ok == false) {
for (NodeOutput *output : get_output_sockets()) {
converter.set_invalid_output(output);
}
}
}
else {
const int64_t number_of_outputs = get_output_sockets().size();
if (number_of_outputs > 0) {
ImageOperation *operation = new ImageOperation();
operation->set_image(image);
operation->set_image_user(imageuser);
operation->set_framenumber(framenumber);
operation->set_render_data(context.get_render_data());
operation->set_view_name(context.get_view_name());
converter.add_operation(operation);
if (output_straight_alpha) {
NodeOperation *alpha_convert_operation = new ConvertPremulToStraightOperation();
converter.add_operation(alpha_convert_operation);
converter.map_output_socket(output_image, alpha_convert_operation->get_output_socket());
converter.add_link(operation->get_output_socket(0),
alpha_convert_operation->get_input_socket(0));
}
else {
converter.map_output_socket(output_image, operation->get_output_socket());
}
converter.add_preview(operation->get_output_socket());
}
if (number_of_outputs > 1) {
NodeOutput *alpha_image = this->get_output_socket(1);
ImageAlphaOperation *alpha_operation = new ImageAlphaOperation();
alpha_operation->set_image(image);
alpha_operation->set_image_user(imageuser);
alpha_operation->set_framenumber(framenumber);
alpha_operation->set_render_data(context.get_render_data());
alpha_operation->set_view_name(context.get_view_name());
converter.add_operation(alpha_operation);
converter.map_output_socket(alpha_image, alpha_operation->get_output_socket());
}
else {
/* happens when unlinking image datablock from multilayer node */
for (int i = 2; i < number_of_outputs; i++) {
NodeOutput *output = this->get_output_socket(i);
NodeOperation *operation = nullptr;
switch (output->get_data_type()) {
case DataType::Value: {
SetValueOperation *valueoperation = new SetValueOperation();
valueoperation->set_value(0.0f);
operation = valueoperation;
break;
}
case DataType::Vector: {
SetVectorOperation *vectoroperation = new SetVectorOperation();
vectoroperation->setX(0.0f);
vectoroperation->setY(0.0f);
vectoroperation->setW(0.0f);
operation = vectoroperation;
break;
}
case DataType::Color: {
SetColorOperation *coloroperation = new SetColorOperation();
coloroperation->set_channel1(0.0f);
coloroperation->set_channel2(0.0f);
coloroperation->set_channel3(0.0f);
coloroperation->set_channel4(0.0f);
operation = coloroperation;
break;
}
}
if (operation) {
/* not supporting multiview for this generic case */
converter.add_operation(operation);
converter.map_output_socket(output, operation->get_output_socket());
}
}
}
}
} // namespace blender::compositor
} // namespace blender::compositor