Compositor: Use SMAA for anti-aliasing in all nodes
Some checks failed
buildbot/vdev-code-daily-lint Build done.
buildbot/vdev-code-daily-linux-x86_64 Build done.
buildbot/vdev-code-daily-darwin-arm64 Build done.
buildbot/vdev-code-daily-windows-amd64 Build done.
buildbot/vdev-code-daily-coordinator Build done.
buildbot/vdev-code-daily-darwin-x86_64 Build done.
Some checks failed
buildbot/vdev-code-daily-lint Build done.
buildbot/vdev-code-daily-linux-x86_64 Build done.
buildbot/vdev-code-daily-darwin-arm64 Build done.
buildbot/vdev-code-daily-windows-amd64 Build done.
buildbot/vdev-code-daily-coordinator Build done.
buildbot/vdev-code-daily-darwin-x86_64 Build done.
This patch changes all anti-aliasing operations to use SMAA instead of the Scale3x-based operation. That's because SMAA is more accurate while the Scale3x one is more a hack.
This commit is contained in:
parent
5c6376fd0a
commit
1aafb6802b
@ -587,9 +587,6 @@ if(WITH_COMPOSITOR_CPU)
|
||||
operations/COM_MovieClipOperation.cc
|
||||
operations/COM_MovieClipOperation.h
|
||||
|
||||
operations/COM_AntiAliasOperation.cc
|
||||
operations/COM_AntiAliasOperation.h
|
||||
|
||||
operations/COM_MaskOperation.cc
|
||||
operations/COM_MaskOperation.h
|
||||
)
|
||||
|
@ -3,10 +3,10 @@
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "COM_DilateErodeNode.h"
|
||||
#include "COM_AntiAliasOperation.h"
|
||||
#include "COM_DilateErodeOperation.h"
|
||||
#include "COM_GaussianAlphaXBlurOperation.h"
|
||||
#include "COM_GaussianAlphaYBlurOperation.h"
|
||||
#include "COM_SMAAOperation.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
@ -38,11 +38,26 @@ void DilateErodeNode::convert_to_operations(NodeConverter &converter,
|
||||
converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
|
||||
|
||||
if (editor_node->custom3 < 2.0f) {
|
||||
AntiAliasOperation *anti_alias = new AntiAliasOperation();
|
||||
converter.add_operation(anti_alias);
|
||||
SMAAEdgeDetectionOperation *smaa_edge_detection = new SMAAEdgeDetectionOperation();
|
||||
converter.add_operation(smaa_edge_detection);
|
||||
|
||||
converter.add_link(operation->get_output_socket(), anti_alias->get_input_socket(0));
|
||||
converter.map_output_socket(get_output_socket(0), anti_alias->get_output_socket(0));
|
||||
converter.add_link(operation->get_output_socket(), smaa_edge_detection->get_input_socket(0));
|
||||
|
||||
SMAABlendingWeightCalculationOperation *smaa_blending_weights =
|
||||
new SMAABlendingWeightCalculationOperation();
|
||||
converter.add_operation(smaa_blending_weights);
|
||||
|
||||
converter.add_link(smaa_edge_detection->get_output_socket(),
|
||||
smaa_blending_weights->get_input_socket(0));
|
||||
|
||||
SMAANeighborhoodBlendingOperation *smaa_neighborhood =
|
||||
new SMAANeighborhoodBlendingOperation();
|
||||
converter.add_operation(smaa_neighborhood);
|
||||
|
||||
converter.add_link(operation->get_output_socket(), smaa_neighborhood->get_input_socket(0));
|
||||
converter.add_link(smaa_blending_weights->get_output_socket(),
|
||||
smaa_neighborhood->get_input_socket(1));
|
||||
converter.map_output_socket(get_output_socket(0), smaa_neighborhood->get_output_socket());
|
||||
}
|
||||
else {
|
||||
converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
#include "COM_ZCombineNode.h"
|
||||
|
||||
#include "COM_AntiAliasOperation.h"
|
||||
#include "COM_MathBaseOperation.h"
|
||||
#include "COM_SMAAOperation.h"
|
||||
#include "COM_ZCombineOperation.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
@ -54,11 +54,25 @@ void ZCombineNode::convert_to_operations(NodeConverter &converter,
|
||||
converter.map_input_socket(get_input_socket(3), maskoperation->get_input_socket(1));
|
||||
|
||||
/* Step 2 anti alias mask bit of an expensive operation, but does the trick. */
|
||||
AntiAliasOperation *antialiasoperation = new AntiAliasOperation();
|
||||
converter.add_operation(antialiasoperation);
|
||||
SMAAEdgeDetectionOperation *smaa_edge_detection = new SMAAEdgeDetectionOperation();
|
||||
converter.add_operation(smaa_edge_detection);
|
||||
|
||||
converter.add_link(maskoperation->get_output_socket(),
|
||||
antialiasoperation->get_input_socket(0));
|
||||
smaa_edge_detection->get_input_socket(0));
|
||||
|
||||
SMAABlendingWeightCalculationOperation *smaa_blending_weights =
|
||||
new SMAABlendingWeightCalculationOperation();
|
||||
converter.add_operation(smaa_blending_weights);
|
||||
|
||||
converter.add_link(smaa_edge_detection->get_output_socket(),
|
||||
smaa_blending_weights->get_input_socket(0));
|
||||
|
||||
SMAANeighborhoodBlendingOperation *smaa_neighborhood = new SMAANeighborhoodBlendingOperation();
|
||||
converter.add_operation(smaa_neighborhood);
|
||||
|
||||
converter.add_link(maskoperation->get_output_socket(), smaa_neighborhood->get_input_socket(0));
|
||||
converter.add_link(smaa_blending_weights->get_output_socket(),
|
||||
smaa_neighborhood->get_input_socket(1));
|
||||
|
||||
/* use mask to blend between the input colors. */
|
||||
ZCombineMaskOperation *zcombineoperation = this->get_bnode()->custom1 ?
|
||||
@ -66,7 +80,7 @@ void ZCombineNode::convert_to_operations(NodeConverter &converter,
|
||||
new ZCombineMaskOperation();
|
||||
converter.add_operation(zcombineoperation);
|
||||
|
||||
converter.add_link(antialiasoperation->get_output_socket(),
|
||||
converter.add_link(smaa_neighborhood->get_output_socket(),
|
||||
zcombineoperation->get_input_socket(0));
|
||||
converter.map_input_socket(get_input_socket(0), zcombineoperation->get_input_socket(1));
|
||||
converter.map_input_socket(get_input_socket(2), zcombineoperation->get_input_socket(2));
|
||||
|
@ -1,258 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2011 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "COM_AntiAliasOperation.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
/* An implementation of the Scale3X edge-extrapolation algorithm.
|
||||
*
|
||||
* Code from GIMP plugin, based on code from Adam D. Moss <adam@gimp.org>
|
||||
* licensed by the MIT license.
|
||||
*/
|
||||
static int extrapolate9(float *E0,
|
||||
float *E1,
|
||||
float *E2,
|
||||
float *E3,
|
||||
float *E4,
|
||||
float *E5,
|
||||
float *E6,
|
||||
float *E7,
|
||||
float *E8,
|
||||
const float *A,
|
||||
const float *B,
|
||||
const float *C,
|
||||
const float *D,
|
||||
const float *E,
|
||||
const float *F,
|
||||
const float *G,
|
||||
const float *H,
|
||||
const float *I)
|
||||
{
|
||||
#define PEQ(X, Y) (fabsf(*X - *Y) < 1e-3f)
|
||||
#define PCPY(DST, SRC) \
|
||||
do { \
|
||||
*DST = *SRC; \
|
||||
} while (0)
|
||||
if (!PEQ(B, H) && !PEQ(D, F)) {
|
||||
if (PEQ(D, B)) {
|
||||
PCPY(E0, D);
|
||||
}
|
||||
else {
|
||||
PCPY(E0, E);
|
||||
}
|
||||
if ((PEQ(D, B) && !PEQ(E, C)) || (PEQ(B, F) && !PEQ(E, A))) {
|
||||
PCPY(E1, B);
|
||||
}
|
||||
else {
|
||||
PCPY(E1, E);
|
||||
}
|
||||
if (PEQ(B, F)) {
|
||||
PCPY(E2, F);
|
||||
}
|
||||
else {
|
||||
PCPY(E2, E);
|
||||
}
|
||||
if ((PEQ(D, B) && !PEQ(E, G)) || (PEQ(D, H) && !PEQ(E, A))) {
|
||||
PCPY(E3, D);
|
||||
}
|
||||
else {
|
||||
PCPY(E3, E);
|
||||
}
|
||||
PCPY(E4, E);
|
||||
if ((PEQ(B, F) && !PEQ(E, I)) || (PEQ(H, F) && !PEQ(E, C))) {
|
||||
PCPY(E5, F);
|
||||
}
|
||||
else {
|
||||
PCPY(E5, E);
|
||||
}
|
||||
if (PEQ(D, H)) {
|
||||
PCPY(E6, D);
|
||||
}
|
||||
else {
|
||||
PCPY(E6, E);
|
||||
}
|
||||
if ((PEQ(D, H) && !PEQ(E, I)) || (PEQ(H, F) && !PEQ(E, G))) {
|
||||
PCPY(E7, H);
|
||||
}
|
||||
else {
|
||||
PCPY(E7, E);
|
||||
}
|
||||
if (PEQ(H, F)) {
|
||||
PCPY(E8, F);
|
||||
}
|
||||
else {
|
||||
PCPY(E8, E);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
#undef PEQ
|
||||
#undef PCPY
|
||||
}
|
||||
|
||||
AntiAliasOperation::AntiAliasOperation()
|
||||
{
|
||||
this->add_input_socket(DataType::Value);
|
||||
this->add_output_socket(DataType::Value);
|
||||
value_reader_ = nullptr;
|
||||
flags_.complex = true;
|
||||
flags_.can_be_constant = true;
|
||||
}
|
||||
|
||||
void AntiAliasOperation::init_execution()
|
||||
{
|
||||
value_reader_ = this->get_input_socket_reader(0);
|
||||
}
|
||||
|
||||
void AntiAliasOperation::execute_pixel(float output[4], int x, int y, void *data)
|
||||
{
|
||||
MemoryBuffer *input_buffer = (MemoryBuffer *)data;
|
||||
const int buffer_width = input_buffer->get_width(), buffer_height = input_buffer->get_height();
|
||||
if (y < 0 || y >= buffer_height || x < 0 || x >= buffer_width) {
|
||||
output[0] = 0.0f;
|
||||
}
|
||||
else {
|
||||
const float *buffer = input_buffer->get_buffer();
|
||||
const float *row_curr = &buffer[y * buffer_width];
|
||||
if (x == 0 || x == buffer_width - 1 || y == 0 || y == buffer_height - 1) {
|
||||
output[0] = row_curr[x];
|
||||
return;
|
||||
}
|
||||
const float *row_prev = &buffer[(y - 1) * buffer_width],
|
||||
*row_next = &buffer[(y + 1) * buffer_width];
|
||||
float ninepix[9];
|
||||
if (extrapolate9(&ninepix[0],
|
||||
&ninepix[1],
|
||||
&ninepix[2],
|
||||
&ninepix[3],
|
||||
&ninepix[4],
|
||||
&ninepix[5],
|
||||
&ninepix[6],
|
||||
&ninepix[7],
|
||||
&ninepix[8],
|
||||
&row_prev[x - 1],
|
||||
&row_prev[x],
|
||||
&row_prev[x + 1],
|
||||
&row_curr[x - 1],
|
||||
&row_curr[x],
|
||||
&row_curr[x + 1],
|
||||
&row_next[x - 1],
|
||||
&row_next[x],
|
||||
&row_next[x + 1]))
|
||||
{
|
||||
/* Some rounding magic to so make weighting correct with the
|
||||
* original coefficients.
|
||||
*/
|
||||
uchar result = ((3 * ninepix[0] + 5 * ninepix[1] + 3 * ninepix[2] + 5 * ninepix[3] +
|
||||
6 * ninepix[4] + 5 * ninepix[5] + 3 * ninepix[6] + 5 * ninepix[7] +
|
||||
3 * ninepix[8]) *
|
||||
255.0f +
|
||||
19.0f) /
|
||||
38.0f;
|
||||
output[0] = result / 255.0f;
|
||||
}
|
||||
else {
|
||||
output[0] = row_curr[x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AntiAliasOperation::deinit_execution()
|
||||
{
|
||||
value_reader_ = nullptr;
|
||||
}
|
||||
|
||||
bool AntiAliasOperation::determine_depending_area_of_interest(rcti *input,
|
||||
ReadBufferOperation *read_operation,
|
||||
rcti *output)
|
||||
{
|
||||
rcti image_input;
|
||||
NodeOperation *operation = get_input_operation(0);
|
||||
image_input.xmax = input->xmax + 1;
|
||||
image_input.xmin = input->xmin - 1;
|
||||
image_input.ymax = input->ymax + 1;
|
||||
image_input.ymin = input->ymin - 1;
|
||||
return operation->determine_depending_area_of_interest(&image_input, read_operation, output);
|
||||
}
|
||||
|
||||
void *AntiAliasOperation::initialize_tile_data(rcti *rect)
|
||||
{
|
||||
return get_input_operation(0)->initialize_tile_data(rect);
|
||||
}
|
||||
|
||||
void AntiAliasOperation::get_area_of_interest(const int input_idx,
|
||||
const rcti &output_area,
|
||||
rcti &r_input_area)
|
||||
{
|
||||
BLI_assert(input_idx == 0);
|
||||
UNUSED_VARS_NDEBUG(input_idx);
|
||||
r_input_area.xmax = output_area.xmax + 1;
|
||||
r_input_area.xmin = output_area.xmin - 1;
|
||||
r_input_area.ymax = output_area.ymax + 1;
|
||||
r_input_area.ymin = output_area.ymin - 1;
|
||||
}
|
||||
|
||||
void AntiAliasOperation::update_memory_buffer_partial(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs)
|
||||
{
|
||||
const MemoryBuffer *input = inputs[0];
|
||||
const rcti &input_area = input->get_rect();
|
||||
float ninepix[9];
|
||||
for (int y = area.ymin; y < area.ymax; y++) {
|
||||
float *out = output->get_elem(area.xmin, y);
|
||||
const float *row_curr = input->get_elem(area.xmin, y);
|
||||
const float *row_prev = row_curr - input->row_stride;
|
||||
const float *row_next = row_curr + input->row_stride;
|
||||
int x_offset = 0;
|
||||
for (int x = area.xmin; x < area.xmax;
|
||||
x++, out += output->elem_stride, x_offset += input->elem_stride)
|
||||
{
|
||||
if (x == input_area.xmin || x == input_area.xmax - 1 || y == input_area.xmin ||
|
||||
y == input_area.ymax - 1)
|
||||
{
|
||||
out[0] = row_curr[x_offset];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (extrapolate9(&ninepix[0],
|
||||
&ninepix[1],
|
||||
&ninepix[2],
|
||||
&ninepix[3],
|
||||
&ninepix[4],
|
||||
&ninepix[5],
|
||||
&ninepix[6],
|
||||
&ninepix[7],
|
||||
&ninepix[8],
|
||||
&row_prev[x_offset - input->elem_stride],
|
||||
&row_prev[x_offset],
|
||||
&row_prev[x_offset + input->elem_stride],
|
||||
&row_curr[x_offset - input->elem_stride],
|
||||
&row_curr[x_offset],
|
||||
&row_curr[x_offset + input->elem_stride],
|
||||
&row_next[x_offset - input->elem_stride],
|
||||
&row_next[x_offset],
|
||||
&row_next[x_offset + input->elem_stride]))
|
||||
{
|
||||
/* Some rounding magic to make weighting correct with the
|
||||
* original coefficients. */
|
||||
uchar result = ((3 * ninepix[0] + 5 * ninepix[1] + 3 * ninepix[2] + 5 * ninepix[3] +
|
||||
6 * ninepix[4] + 5 * ninepix[5] + 3 * ninepix[6] + 5 * ninepix[7] +
|
||||
3 * ninepix[8]) *
|
||||
255.0f +
|
||||
19.0f) /
|
||||
38.0f;
|
||||
out[0] = result / 255.0f;
|
||||
}
|
||||
else {
|
||||
out[0] = row_curr[x_offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::compositor
|
@ -1,54 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2011 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "COM_MultiThreadedOperation.h"
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
/**
|
||||
* \brief AntiAlias operations
|
||||
* it only supports anti aliasing on BW buffers.
|
||||
* \ingroup operation
|
||||
*/
|
||||
class AntiAliasOperation : public MultiThreadedOperation {
|
||||
protected:
|
||||
/**
|
||||
* \brief Cached reference to the reader
|
||||
*/
|
||||
SocketReader *value_reader_;
|
||||
|
||||
public:
|
||||
AntiAliasOperation();
|
||||
|
||||
/**
|
||||
* The inner loop of this operation.
|
||||
*/
|
||||
void execute_pixel(float output[4], int x, int y, void *data) override;
|
||||
|
||||
/**
|
||||
* Initialize the execution
|
||||
*/
|
||||
void init_execution() override;
|
||||
|
||||
void *initialize_tile_data(rcti *rect) override;
|
||||
|
||||
/**
|
||||
* Deinitialize the execution
|
||||
*/
|
||||
void deinit_execution() override;
|
||||
bool determine_depending_area_of_interest(rcti *input,
|
||||
ReadBufferOperation *read_operation,
|
||||
rcti *output) override;
|
||||
|
||||
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
|
||||
|
||||
void update_memory_buffer_partial(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs) override;
|
||||
};
|
||||
|
||||
} // namespace blender::compositor
|
Loading…
x
Reference in New Issue
Block a user