The vector pass and potentially other vectors that store 4 values are
stored wrongly, in particular, the last channel is ignored. To fix this
we identify if a vector pass is 4D and store the information in the
result meta data, then use this information to either save a 3D or a 4D
pass in the File Output node.
This is a CPU implementation of the same mechanism in the GPU compositor
implemented in 57a6832b17. The CPU implementation is a bit more complex
because the CPU compositors stores 4D vectors in color images internally
which can lead to information loss in case of implicit conversion when
the File Output has vector sockets. So what we do is force all vector
inputs to the File Output operation to be color, then save that as 3D or
4D depending on the meta data as well as the original UI socket type.
Pull Request: https://projects.blender.org/blender/blender/pulls/124580
111 lines
3.8 KiB
C++
111 lines
3.8 KiB
C++
/* SPDX-FileCopyrightText: 2011 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#pragma once
|
|
|
|
#include "BLI_vector.hh"
|
|
|
|
#include "DNA_node_types.h"
|
|
|
|
#include "COM_CompositorContext.h"
|
|
#include "COM_NodeOperation.h"
|
|
|
|
struct StampData;
|
|
|
|
namespace blender::realtime_compositor {
|
|
class FileOutput;
|
|
}
|
|
|
|
namespace blender::compositor {
|
|
|
|
struct FileOutputInput {
|
|
FileOutputInput(NodeImageMultiFileSocket *data, DataType data_type, DataType original_data_type);
|
|
|
|
NodeImageMultiFileSocket *data;
|
|
/* The internal data type of the input in the operation, which can be different from the UI type.
|
|
* See the get_input_data_type function in COM_FileOutputNode.cc for more information. */
|
|
DataType data_type;
|
|
/* Stores the original data type of socket in the UI, see data_type above for more information
|
|
* about the distinction. */
|
|
DataType original_data_type;
|
|
|
|
float *output_buffer = nullptr;
|
|
SocketReader *image_input = nullptr;
|
|
};
|
|
|
|
class FileOutputOperation : public NodeOperation {
|
|
private:
|
|
const CompositorContext *context_;
|
|
const NodeImageMultiFile *node_data_;
|
|
Vector<FileOutputInput> file_output_inputs_;
|
|
|
|
public:
|
|
FileOutputOperation(const CompositorContext *context,
|
|
const NodeImageMultiFile *node_data,
|
|
Vector<FileOutputInput> inputs);
|
|
|
|
bool is_output_operation(bool /*rendering*/) const override
|
|
{
|
|
return true;
|
|
}
|
|
void init_execution() override;
|
|
void deinit_execution() override;
|
|
eCompositorPriority get_render_priority() const override
|
|
{
|
|
return eCompositorPriority::Low;
|
|
}
|
|
|
|
void update_memory_buffer(MemoryBuffer *output,
|
|
const rcti &area,
|
|
Span<MemoryBuffer *> inputs) override;
|
|
|
|
private:
|
|
void execute_single_layer();
|
|
void execute_single_layer_multi_view_exr(const FileOutputInput &input,
|
|
const ImageFormatData &format,
|
|
const char *base_path);
|
|
void execute_multi_layer();
|
|
|
|
/* Add a pass of the given name, view, and input buffer. The pass channel identifiers follows the
|
|
* EXR conventions. */
|
|
void add_pass_for_input(realtime_compositor::FileOutput &file_output,
|
|
const FileOutputInput &input,
|
|
const char *pass_name,
|
|
const char *view_name);
|
|
|
|
/* Add a view of the given name and input buffer. */
|
|
void add_view_for_input(realtime_compositor::FileOutput &file_output,
|
|
const FileOutputInput &input,
|
|
const char *view_name);
|
|
|
|
/* Get the base path of the image to be saved, based on the base path of the node. The base name
|
|
* is an optional initial name of the image, which will later be concatenated with other
|
|
* information like the frame number, view, and extension. If the base name is empty, then the
|
|
* base path represents a directory, so a trailing slash is ensured. */
|
|
void get_single_layer_image_base_path(const char *base_name, char *base_path);
|
|
|
|
/* Get the path of the image to be saved based on the given format. */
|
|
void get_single_layer_image_path(const char *base_path,
|
|
const ImageFormatData &format,
|
|
char *image_path);
|
|
|
|
/* Get the path of the EXR image to be saved. If the given view is not empty, its corresponding
|
|
* file suffix will be appended to the name. */
|
|
void get_multi_layer_exr_image_path(const char *base_path, const char *view, char *image_path);
|
|
|
|
bool is_multi_layer();
|
|
|
|
const char *get_base_path();
|
|
|
|
/* Add the file format extensions to the rendered file name. */
|
|
bool use_file_extension();
|
|
|
|
/* If true, save views in a multi-view EXR file, otherwise, save each view in its own file. */
|
|
bool is_multi_view_exr();
|
|
|
|
bool is_multi_view_scene();
|
|
};
|
|
|
|
} // namespace blender::compositor
|