Compositor: Full frame vector nodes
Adds full frame implementation to Map Range, Map Value, Normal and Normalize nodes. The other nodes in "Vector" sub-menu are submitted separately. Part of T88150. Reviewed By: jbakker Differential Revision: https://developer.blender.org/D12233
This commit is contained in:
@@ -28,6 +28,7 @@ DotproductOperation::DotproductOperation()
|
|||||||
this->setResolutionInputSocketIndex(0);
|
this->setResolutionInputSocketIndex(0);
|
||||||
this->m_input1Operation = nullptr;
|
this->m_input1Operation = nullptr;
|
||||||
this->m_input2Operation = nullptr;
|
this->m_input2Operation = nullptr;
|
||||||
|
flags.can_be_constant = true;
|
||||||
}
|
}
|
||||||
void DotproductOperation::initExecution()
|
void DotproductOperation::initExecution()
|
||||||
{
|
{
|
||||||
@@ -55,4 +56,15 @@ void DotproductOperation::executePixelSampled(float output[4],
|
|||||||
output[0] = -(input1[0] * input2[0] + input1[1] * input2[1] + input1[2] * input2[2]);
|
output[0] = -(input1[0] * input2[0] + input1[1] * input2[1] + input1[2] * input2[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DotproductOperation::update_memory_buffer_partial(MemoryBuffer *output,
|
||||||
|
const rcti &area,
|
||||||
|
Span<MemoryBuffer *> inputs)
|
||||||
|
{
|
||||||
|
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
|
||||||
|
const float *input1 = it.in(0);
|
||||||
|
const float *input2 = it.in(1);
|
||||||
|
*it.out = -(input1[0] * input2[0] + input1[1] * input2[1] + input1[2] * input2[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace blender::compositor
|
} // namespace blender::compositor
|
||||||
|
|||||||
@@ -18,11 +18,11 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "COM_NodeOperation.h"
|
#include "COM_MultiThreadedOperation.h"
|
||||||
|
|
||||||
namespace blender::compositor {
|
namespace blender::compositor {
|
||||||
|
|
||||||
class DotproductOperation : public NodeOperation {
|
class DotproductOperation : public MultiThreadedOperation {
|
||||||
private:
|
private:
|
||||||
SocketReader *m_input1Operation;
|
SocketReader *m_input1Operation;
|
||||||
SocketReader *m_input2Operation;
|
SocketReader *m_input2Operation;
|
||||||
@@ -33,6 +33,10 @@ class DotproductOperation : public NodeOperation {
|
|||||||
|
|
||||||
void initExecution() override;
|
void initExecution() override;
|
||||||
void deinitExecution() override;
|
void deinitExecution() override;
|
||||||
|
|
||||||
|
void update_memory_buffer_partial(MemoryBuffer *output,
|
||||||
|
const rcti &area,
|
||||||
|
Span<MemoryBuffer *> inputs) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blender::compositor
|
} // namespace blender::compositor
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ MapRangeOperation::MapRangeOperation()
|
|||||||
this->addOutputSocket(DataType::Value);
|
this->addOutputSocket(DataType::Value);
|
||||||
this->m_inputOperation = nullptr;
|
this->m_inputOperation = nullptr;
|
||||||
this->m_useClamp = false;
|
this->m_useClamp = false;
|
||||||
|
flags.can_be_constant = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapRangeOperation::initExecution()
|
void MapRangeOperation::initExecution()
|
||||||
@@ -104,4 +105,43 @@ void MapRangeOperation::deinitExecution()
|
|||||||
this->m_destMaxOperation = nullptr;
|
this->m_destMaxOperation = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MapRangeOperation::update_memory_buffer_partial(MemoryBuffer *output,
|
||||||
|
const rcti &area,
|
||||||
|
Span<MemoryBuffer *> inputs)
|
||||||
|
{
|
||||||
|
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
|
||||||
|
const float source_min = *it.in(1);
|
||||||
|
const float source_max = *it.in(2);
|
||||||
|
if (fabsf(source_max - source_min) < 1e-6f) {
|
||||||
|
it.out[0] = 0.0f;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float value = *it.in(0);
|
||||||
|
const float dest_min = *it.in(3);
|
||||||
|
const float dest_max = *it.in(4);
|
||||||
|
if (value >= -BLENDER_ZMAX && value <= BLENDER_ZMAX) {
|
||||||
|
value = (value - source_min) / (source_max - source_min);
|
||||||
|
value = dest_min + value * (dest_max - dest_min);
|
||||||
|
}
|
||||||
|
else if (value > BLENDER_ZMAX) {
|
||||||
|
value = dest_max;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
value = dest_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_useClamp) {
|
||||||
|
if (dest_max > dest_min) {
|
||||||
|
CLAMP(value, dest_min, dest_max);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
CLAMP(value, dest_max, dest_min);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it.out[0] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace blender::compositor
|
} // namespace blender::compositor
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "COM_NodeOperation.h"
|
#include "COM_MultiThreadedOperation.h"
|
||||||
#include "DNA_texture_types.h"
|
#include "DNA_texture_types.h"
|
||||||
|
|
||||||
namespace blender::compositor {
|
namespace blender::compositor {
|
||||||
@@ -27,7 +27,7 @@ namespace blender::compositor {
|
|||||||
* this program converts an input color to an output value.
|
* this program converts an input color to an output value.
|
||||||
* it assumes we are in sRGB color space.
|
* it assumes we are in sRGB color space.
|
||||||
*/
|
*/
|
||||||
class MapRangeOperation : public NodeOperation {
|
class MapRangeOperation : public MultiThreadedOperation {
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Cached reference to the inputProgram
|
* Cached reference to the inputProgram
|
||||||
@@ -68,6 +68,10 @@ class MapRangeOperation : public NodeOperation {
|
|||||||
{
|
{
|
||||||
this->m_useClamp = value;
|
this->m_useClamp = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void update_memory_buffer_partial(MemoryBuffer *output,
|
||||||
|
const rcti &area,
|
||||||
|
Span<MemoryBuffer *> inputs) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blender::compositor
|
} // namespace blender::compositor
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ MapValueOperation::MapValueOperation()
|
|||||||
this->addInputSocket(DataType::Value);
|
this->addInputSocket(DataType::Value);
|
||||||
this->addOutputSocket(DataType::Value);
|
this->addOutputSocket(DataType::Value);
|
||||||
this->m_inputOperation = nullptr;
|
this->m_inputOperation = nullptr;
|
||||||
|
flags.can_be_constant = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapValueOperation::initExecution()
|
void MapValueOperation::initExecution()
|
||||||
@@ -60,4 +61,27 @@ void MapValueOperation::deinitExecution()
|
|||||||
this->m_inputOperation = nullptr;
|
this->m_inputOperation = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MapValueOperation::update_memory_buffer_partial(MemoryBuffer *output,
|
||||||
|
const rcti &area,
|
||||||
|
Span<MemoryBuffer *> inputs)
|
||||||
|
{
|
||||||
|
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
|
||||||
|
const float input = *it.in(0);
|
||||||
|
TexMapping *texmap = this->m_settings;
|
||||||
|
float value = (input + texmap->loc[0]) * texmap->size[0];
|
||||||
|
if (texmap->flag & TEXMAP_CLIP_MIN) {
|
||||||
|
if (value < texmap->min[0]) {
|
||||||
|
value = texmap->min[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (texmap->flag & TEXMAP_CLIP_MAX) {
|
||||||
|
if (value > texmap->max[0]) {
|
||||||
|
value = texmap->max[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it.out[0] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace blender::compositor
|
} // namespace blender::compositor
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "COM_NodeOperation.h"
|
#include "COM_MultiThreadedOperation.h"
|
||||||
#include "DNA_texture_types.h"
|
#include "DNA_texture_types.h"
|
||||||
|
|
||||||
namespace blender::compositor {
|
namespace blender::compositor {
|
||||||
@@ -27,7 +27,7 @@ namespace blender::compositor {
|
|||||||
* this program converts an input color to an output value.
|
* this program converts an input color to an output value.
|
||||||
* it assumes we are in sRGB color space.
|
* it assumes we are in sRGB color space.
|
||||||
*/
|
*/
|
||||||
class MapValueOperation : public NodeOperation {
|
class MapValueOperation : public MultiThreadedOperation {
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Cached reference to the inputProgram
|
* Cached reference to the inputProgram
|
||||||
@@ -63,6 +63,10 @@ class MapValueOperation : public NodeOperation {
|
|||||||
{
|
{
|
||||||
this->m_settings = settings;
|
this->m_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void update_memory_buffer_partial(MemoryBuffer *output,
|
||||||
|
const rcti &area,
|
||||||
|
Span<MemoryBuffer *> inputs) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blender::compositor
|
} // namespace blender::compositor
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ NormalizeOperation::NormalizeOperation()
|
|||||||
this->m_imageReader = nullptr;
|
this->m_imageReader = nullptr;
|
||||||
this->m_cachedInstance = nullptr;
|
this->m_cachedInstance = nullptr;
|
||||||
this->flags.complex = true;
|
this->flags.complex = true;
|
||||||
|
flags.can_be_constant = true;
|
||||||
}
|
}
|
||||||
void NormalizeOperation::initExecution()
|
void NormalizeOperation::initExecution()
|
||||||
{
|
{
|
||||||
@@ -56,6 +57,7 @@ void NormalizeOperation::deinitExecution()
|
|||||||
{
|
{
|
||||||
this->m_imageReader = nullptr;
|
this->m_imageReader = nullptr;
|
||||||
delete this->m_cachedInstance;
|
delete this->m_cachedInstance;
|
||||||
|
m_cachedInstance = nullptr;
|
||||||
NodeOperation::deinitMutex();
|
NodeOperation::deinitMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,4 +129,60 @@ void NormalizeOperation::deinitializeTileData(rcti * /*rect*/, void * /*data*/)
|
|||||||
/* pass */
|
/* pass */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NormalizeOperation::get_area_of_interest(const int UNUSED(input_idx),
|
||||||
|
const rcti &UNUSED(output_area),
|
||||||
|
rcti &r_input_area)
|
||||||
|
{
|
||||||
|
NodeOperation *input = get_input_operation(0);
|
||||||
|
r_input_area.xmin = 0;
|
||||||
|
r_input_area.xmax = input->getWidth();
|
||||||
|
r_input_area.ymin = 0;
|
||||||
|
r_input_area.ymax = input->getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NormalizeOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output),
|
||||||
|
const rcti &UNUSED(area),
|
||||||
|
Span<MemoryBuffer *> inputs)
|
||||||
|
{
|
||||||
|
if (m_cachedInstance == nullptr) {
|
||||||
|
MemoryBuffer *input = inputs[0];
|
||||||
|
|
||||||
|
/* Using generic two floats struct to store `x: min`, `y: multiply`. */
|
||||||
|
NodeTwoFloats *minmult = new NodeTwoFloats();
|
||||||
|
|
||||||
|
float minv = 1.0f + BLENDER_ZMAX;
|
||||||
|
float maxv = -1.0f - BLENDER_ZMAX;
|
||||||
|
for (const float *elem : input->as_range()) {
|
||||||
|
const float value = *elem;
|
||||||
|
if ((value > maxv) && (value <= BLENDER_ZMAX)) {
|
||||||
|
maxv = value;
|
||||||
|
}
|
||||||
|
if ((value < minv) && (value >= -BLENDER_ZMAX)) {
|
||||||
|
minv = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
minmult->x = minv;
|
||||||
|
/* The case of a flat buffer would cause a divide by 0. */
|
||||||
|
minmult->y = ((maxv != minv) ? 1.0f / (maxv - minv) : 0.0f);
|
||||||
|
|
||||||
|
m_cachedInstance = minmult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NormalizeOperation::update_memory_buffer_partial(MemoryBuffer *output,
|
||||||
|
const rcti &area,
|
||||||
|
Span<MemoryBuffer *> inputs)
|
||||||
|
{
|
||||||
|
NodeTwoFloats *minmult = m_cachedInstance;
|
||||||
|
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
|
||||||
|
const float input_value = *it.in(0);
|
||||||
|
|
||||||
|
*it.out = (input_value - minmult->x) * minmult->y;
|
||||||
|
|
||||||
|
/* Clamp infinities. */
|
||||||
|
CLAMP(*it.out, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace blender::compositor
|
} // namespace blender::compositor
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "COM_NodeOperation.h"
|
#include "COM_MultiThreadedOperation.h"
|
||||||
#include "DNA_node_types.h"
|
#include "DNA_node_types.h"
|
||||||
|
|
||||||
namespace blender::compositor {
|
namespace blender::compositor {
|
||||||
@@ -27,7 +27,7 @@ namespace blender::compositor {
|
|||||||
* \brief base class of normalize, implementing the simple normalize
|
* \brief base class of normalize, implementing the simple normalize
|
||||||
* \ingroup operation
|
* \ingroup operation
|
||||||
*/
|
*/
|
||||||
class NormalizeOperation : public NodeOperation {
|
class NormalizeOperation : public MultiThreadedOperation {
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* \brief Cached reference to the reader
|
* \brief Cached reference to the reader
|
||||||
@@ -64,6 +64,14 @@ class NormalizeOperation : public NodeOperation {
|
|||||||
bool determineDependingAreaOfInterest(rcti *input,
|
bool determineDependingAreaOfInterest(rcti *input,
|
||||||
ReadBufferOperation *readOperation,
|
ReadBufferOperation *readOperation,
|
||||||
rcti *output) override;
|
rcti *output) override;
|
||||||
|
|
||||||
|
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
|
||||||
|
void update_memory_buffer_started(MemoryBuffer *output,
|
||||||
|
const rcti &area,
|
||||||
|
Span<MemoryBuffer *> inputs) override;
|
||||||
|
void update_memory_buffer_partial(MemoryBuffer *output,
|
||||||
|
const rcti &area,
|
||||||
|
Span<MemoryBuffer *> inputs) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blender::compositor
|
} // namespace blender::compositor
|
||||||
|
|||||||
Reference in New Issue
Block a user