Compositor: Use RBF Interpolation in Keying Screen node
This patch changes the interpolation algorithm utilized by the Keying Screen node to a Gaussian Radial Basis Function Interpolation. This is proposed because the current Voronoi triangulation based interpolation has the following properties: - Not temporally stable since the triangulation can abruptly change as tracking markers change position. - Not smooth in the mathematical sense, which is also readily visible in the artists sense. - Computationally expensive due to the triangulation and naive rasterization algorithm. On the other hand, the RBF interpolation method is temporally stable and continuous, smooth and infinitely differentiable, and relatively simple to compute assuming low number of markers, which is typically the case for keying screen objects. This breaks backward compatibility, but the keying screen is only used as a secondary input for keying in typical compositor setups, so one should expect minimal difference in outputs. Pull Request: https://projects.blender.org/blender/blender/pulls/112480
This commit is contained in:
parent
0b302d2139
commit
75c947a467
|
@ -25,6 +25,7 @@ void KeyingScreenNode::convert_to_operations(NodeConverter &converter,
|
|||
KeyingScreenOperation *operation = new KeyingScreenOperation();
|
||||
operation->set_movie_clip(clip);
|
||||
operation->set_tracking_object(keyingscreen_data->tracking_object);
|
||||
operation->set_smoothness(keyingscreen_data->smoothness);
|
||||
operation->set_framenumber(context.get_framenumber());
|
||||
converter.add_operation(operation);
|
||||
|
||||
|
|
|
@ -6,8 +6,11 @@
|
|||
|
||||
#include "DNA_defaults.h"
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_math_color.h"
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
#include "BKE_movieclip.h"
|
||||
#include "BKE_tracking.h"
|
||||
|
@ -24,58 +27,32 @@ KeyingScreenOperation::KeyingScreenOperation()
|
|||
framenumber_ = 0;
|
||||
tracking_object_[0] = 0;
|
||||
flags_.complex = true;
|
||||
cached_triangulation_ = nullptr;
|
||||
cached_marker_points_ = nullptr;
|
||||
}
|
||||
|
||||
void KeyingScreenOperation::init_execution()
|
||||
{
|
||||
init_mutex();
|
||||
if (execution_model_ == eExecutionModel::FullFrame) {
|
||||
BLI_assert(cached_triangulation_ == nullptr);
|
||||
BLI_assert(cached_marker_points_ == nullptr);
|
||||
if (movie_clip_) {
|
||||
cached_triangulation_ = build_voronoi_triangulation();
|
||||
cached_marker_points_ = compute_marker_points();
|
||||
}
|
||||
}
|
||||
else {
|
||||
cached_triangulation_ = nullptr;
|
||||
cached_marker_points_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void KeyingScreenOperation::deinit_execution()
|
||||
{
|
||||
if (cached_triangulation_) {
|
||||
TriangulationData *triangulation = cached_triangulation_;
|
||||
|
||||
if (triangulation->triangulated_points) {
|
||||
MEM_freeN(triangulation->triangulated_points);
|
||||
}
|
||||
|
||||
if (triangulation->triangles) {
|
||||
MEM_freeN(triangulation->triangles);
|
||||
}
|
||||
|
||||
if (triangulation->triangles_AABB) {
|
||||
MEM_freeN(triangulation->triangles_AABB);
|
||||
}
|
||||
|
||||
MEM_freeN(cached_triangulation_);
|
||||
|
||||
cached_triangulation_ = nullptr;
|
||||
}
|
||||
delete cached_marker_points_;
|
||||
cached_marker_points_ = nullptr;
|
||||
}
|
||||
|
||||
KeyingScreenOperation::TriangulationData *KeyingScreenOperation::build_voronoi_triangulation()
|
||||
Array<KeyingScreenOperation::MarkerPoint> *KeyingScreenOperation::compute_marker_points()
|
||||
{
|
||||
MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
|
||||
TriangulationData *triangulation;
|
||||
MovieTracking *tracking = &movie_clip_->tracking;
|
||||
ImBuf *ibuf;
|
||||
ListBase edges = {nullptr, nullptr};
|
||||
int sites_total;
|
||||
int i;
|
||||
int width = this->get_width();
|
||||
int height = this->get_height();
|
||||
int clip_frame = BKE_movieclip_remap_scene_to_clip_frame(movie_clip_, framenumber_);
|
||||
|
||||
const MovieTrackingObject *tracking_object = nullptr;
|
||||
if (tracking_object_[0]) {
|
||||
|
@ -87,10 +64,12 @@ KeyingScreenOperation::TriangulationData *KeyingScreenOperation::build_voronoi_t
|
|||
else {
|
||||
tracking_object = BKE_tracking_object_get_active(tracking);
|
||||
}
|
||||
BLI_assert(tracking_object != 0);
|
||||
BLI_assert(tracking_object != nullptr);
|
||||
|
||||
int clip_frame = BKE_movieclip_remap_scene_to_clip_frame(movie_clip_, framenumber_);
|
||||
|
||||
/* count sites */
|
||||
sites_total = 0;
|
||||
int sites_total = 0;
|
||||
LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
|
||||
const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame);
|
||||
|
||||
|
@ -112,17 +91,16 @@ KeyingScreenOperation::TriangulationData *KeyingScreenOperation::build_voronoi_t
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
|
||||
BKE_movieclip_user_set_frame(&user, clip_frame);
|
||||
ibuf = BKE_movieclip_get_ibuf(movie_clip_, &user);
|
||||
ImBuf *ibuf = BKE_movieclip_get_ibuf(movie_clip_, &user);
|
||||
|
||||
if (!ibuf) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
triangulation = MEM_cnew<TriangulationData>("keying screen triangulation data");
|
||||
Array<MarkerPoint> *marker_points = new Array<MarkerPoint>(sites_total);
|
||||
|
||||
VoronoiSite *sites = (VoronoiSite *)MEM_callocN(sizeof(VoronoiSite) * sites_total,
|
||||
"keyingscreen voronoi sites");
|
||||
int track_index = 0;
|
||||
LISTBASE_FOREACH_INDEX (MovieTrackingTrack *, track, &tracking_object->tracks, track_index) {
|
||||
const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame);
|
||||
|
@ -130,155 +108,57 @@ KeyingScreenOperation::TriangulationData *KeyingScreenOperation::build_voronoi_t
|
|||
continue;
|
||||
}
|
||||
|
||||
float pos[2];
|
||||
add_v2_v2v2(pos, marker->pos, track->offset);
|
||||
const float2 position = float2(marker->pos) + float2(track->offset);
|
||||
|
||||
if (!IN_RANGE_INCL(pos[0], 0.0f, 1.0f) || !IN_RANGE_INCL(pos[1], 0.0f, 1.0f)) {
|
||||
if (!IN_RANGE_INCL(position.x, 0.0f, 1.0f) || !IN_RANGE_INCL(position.y, 0.0f, 1.0f)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ImBuf *pattern_ibuf = BKE_tracking_get_pattern_imbuf(ibuf, track, marker, true, false);
|
||||
|
||||
VoronoiSite *site = &sites[track_index];
|
||||
zero_v3(site->color);
|
||||
MarkerPoint &marker_point = (*marker_points)[track_index];
|
||||
marker_point.position = position;
|
||||
|
||||
marker_point.color = float4(0.0f);
|
||||
if (pattern_ibuf) {
|
||||
for (int j = 0; j < pattern_ibuf->x * pattern_ibuf->y; j++) {
|
||||
if (pattern_ibuf->float_buffer.data) {
|
||||
add_v3_v3(site->color, &pattern_ibuf->float_buffer.data[4 * j]);
|
||||
marker_point.color += float4(&pattern_ibuf->float_buffer.data[4 * j]);
|
||||
}
|
||||
else {
|
||||
uchar *rrgb = pattern_ibuf->byte_buffer.data;
|
||||
|
||||
site->color[0] += srgb_to_linearrgb(float(rrgb[4 * j + 0]) / 255.0f);
|
||||
site->color[1] += srgb_to_linearrgb(float(rrgb[4 * j + 1]) / 255.0f);
|
||||
site->color[2] += srgb_to_linearrgb(float(rrgb[4 * j + 2]) / 255.0f);
|
||||
marker_point.color += float4(srgb_to_linearrgb(float(rrgb[4 * j + 0]) / 255.0f),
|
||||
srgb_to_linearrgb(float(rrgb[4 * j + 1]) / 255.0f),
|
||||
srgb_to_linearrgb(float(rrgb[4 * j + 2]) / 255.0f),
|
||||
srgb_to_linearrgb(float(rrgb[4 * j + 3]) / 255.0f));
|
||||
}
|
||||
}
|
||||
|
||||
mul_v3_fl(site->color, 1.0f / (pattern_ibuf->x * pattern_ibuf->y));
|
||||
marker_point.color /= pattern_ibuf->x * pattern_ibuf->y;
|
||||
IMB_freeImBuf(pattern_ibuf);
|
||||
}
|
||||
|
||||
site->co[0] = pos[0] * width;
|
||||
site->co[1] = pos[1] * height;
|
||||
|
||||
site++;
|
||||
}
|
||||
|
||||
IMB_freeImBuf(ibuf);
|
||||
|
||||
BLI_voronoi_compute(sites, sites_total, width, height, &edges);
|
||||
|
||||
BLI_voronoi_triangulate(sites,
|
||||
sites_total,
|
||||
&edges,
|
||||
width,
|
||||
height,
|
||||
&triangulation->triangulated_points,
|
||||
&triangulation->triangulated_points_total,
|
||||
&triangulation->triangles,
|
||||
&triangulation->triangles_total);
|
||||
|
||||
MEM_freeN(sites);
|
||||
BLI_freelistN(&edges);
|
||||
|
||||
if (triangulation->triangles_total) {
|
||||
rcti *rect;
|
||||
rect = triangulation->triangles_AABB = (rcti *)MEM_callocN(
|
||||
sizeof(rcti) * triangulation->triangles_total, "voronoi triangulation AABB");
|
||||
|
||||
for (i = 0; i < triangulation->triangles_total; i++, rect++) {
|
||||
int *triangle = triangulation->triangles[i];
|
||||
VoronoiTriangulationPoint *a = &triangulation->triangulated_points[triangle[0]],
|
||||
*b = &triangulation->triangulated_points[triangle[1]],
|
||||
*c = &triangulation->triangulated_points[triangle[2]];
|
||||
|
||||
float min[2], max[2];
|
||||
|
||||
INIT_MINMAX2(min, max);
|
||||
|
||||
minmax_v2v2_v2(min, max, a->co);
|
||||
minmax_v2v2_v2(min, max, b->co);
|
||||
minmax_v2v2_v2(min, max, c->co);
|
||||
|
||||
rect->xmin = int(min[0]);
|
||||
rect->ymin = int(min[1]);
|
||||
|
||||
rect->xmax = int(max[0]) + 1;
|
||||
rect->ymax = int(max[1]) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return triangulation;
|
||||
return marker_points;
|
||||
}
|
||||
|
||||
KeyingScreenOperation::TileData *KeyingScreenOperation::triangulate(const rcti *rect)
|
||||
{
|
||||
TileData *tile_data;
|
||||
TriangulationData *triangulation;
|
||||
int triangles_allocated = 0;
|
||||
int chunk_size = 20;
|
||||
int i;
|
||||
|
||||
triangulation = cached_triangulation_;
|
||||
|
||||
if (!triangulation) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
tile_data = MEM_cnew<TileData>("keying screen tile data");
|
||||
|
||||
for (i = 0; i < triangulation->triangles_total; i++) {
|
||||
if (BLI_rcti_isect(rect, &triangulation->triangles_AABB[i], nullptr)) {
|
||||
tile_data->triangles_total++;
|
||||
|
||||
if (tile_data->triangles_total > triangles_allocated) {
|
||||
if (!tile_data->triangles) {
|
||||
tile_data->triangles = (int *)MEM_mallocN(sizeof(int) * chunk_size,
|
||||
"keying screen tile triangles chunk");
|
||||
}
|
||||
else {
|
||||
tile_data->triangles = (int *)MEM_reallocN(
|
||||
tile_data->triangles, sizeof(int) * (triangles_allocated + chunk_size));
|
||||
}
|
||||
|
||||
triangles_allocated += chunk_size;
|
||||
}
|
||||
|
||||
tile_data->triangles[tile_data->triangles_total - 1] = i;
|
||||
}
|
||||
}
|
||||
|
||||
return tile_data;
|
||||
}
|
||||
|
||||
void *KeyingScreenOperation::initialize_tile_data(rcti *rect)
|
||||
void *KeyingScreenOperation::initialize_tile_data(rcti * /* rect*/)
|
||||
{
|
||||
if (movie_clip_ == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!cached_triangulation_) {
|
||||
if (!cached_marker_points_) {
|
||||
lock_mutex();
|
||||
if (cached_triangulation_ == nullptr) {
|
||||
cached_triangulation_ = build_voronoi_triangulation();
|
||||
if (cached_marker_points_ == nullptr) {
|
||||
cached_marker_points_ = compute_marker_points();
|
||||
}
|
||||
unlock_mutex();
|
||||
}
|
||||
|
||||
return triangulate(rect);
|
||||
}
|
||||
|
||||
void KeyingScreenOperation::deinitialize_tile_data(rcti * /*rect*/, void *data)
|
||||
{
|
||||
TileData *tile_data = (TileData *)data;
|
||||
|
||||
if (tile_data->triangles) {
|
||||
MEM_freeN(tile_data->triangles);
|
||||
}
|
||||
|
||||
MEM_freeN(tile_data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void KeyingScreenOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
|
||||
|
@ -298,95 +178,59 @@ void KeyingScreenOperation::determine_canvas(const rcti &preferred_area, rcti &r
|
|||
}
|
||||
}
|
||||
|
||||
void KeyingScreenOperation::execute_pixel(float output[4], int x, int y, void *data)
|
||||
void KeyingScreenOperation::execute_pixel(float output[4], int x, int y, void * /* data */)
|
||||
{
|
||||
output[0] = 0.0f;
|
||||
output[1] = 0.0f;
|
||||
output[2] = 0.0f;
|
||||
output[3] = 1.0f;
|
||||
|
||||
if (movie_clip_ && data) {
|
||||
TriangulationData *triangulation = cached_triangulation_;
|
||||
TileData *tile_data = (TileData *)data;
|
||||
int i;
|
||||
float co[2] = {float(x), float(y)};
|
||||
|
||||
for (i = 0; i < tile_data->triangles_total; i++) {
|
||||
int triangle_idx = tile_data->triangles[i];
|
||||
rcti *rect = &triangulation->triangles_AABB[triangle_idx];
|
||||
|
||||
if (IN_RANGE_INCL(x, rect->xmin, rect->xmax) && IN_RANGE_INCL(y, rect->ymin, rect->ymax)) {
|
||||
int *triangle = triangulation->triangles[triangle_idx];
|
||||
VoronoiTriangulationPoint *a = &triangulation->triangulated_points[triangle[0]],
|
||||
*b = &triangulation->triangulated_points[triangle[1]],
|
||||
*c = &triangulation->triangulated_points[triangle[2]];
|
||||
float w[3];
|
||||
|
||||
if (barycentric_coords_v2(a->co, b->co, c->co, co, w)) {
|
||||
if (barycentric_inside_triangle_v2(w)) {
|
||||
output[0] = a->color[0] * w[0] + b->color[0] * w[1] + c->color[0] * w[2];
|
||||
output[1] = a->color[1] * w[0] + b->color[1] * w[1] + c->color[1] * w[2];
|
||||
output[2] = a->color[2] * w[0] + b->color[2] * w[1] + c->color[2] * w[2];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!cached_marker_points_) {
|
||||
copy_v4_fl(output, 0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
const int2 size = int2(this->get_width(), this->get_height());
|
||||
const float2 normalized_pixel_location = float2(x, y) / float2(size);
|
||||
const float squared_shape_parameter = math::square(1.0f / smoothness_);
|
||||
|
||||
float4 weighted_sum = float4(0.0f);
|
||||
float sum_of_weights = 0.0f;
|
||||
for (const MarkerPoint &marker_point : *cached_marker_points_) {
|
||||
const float2 difference = normalized_pixel_location - marker_point.position;
|
||||
const float squared_distance = math::dot(difference, difference);
|
||||
const float gaussian = math::exp(-squared_distance * squared_shape_parameter);
|
||||
weighted_sum += marker_point.color * gaussian;
|
||||
sum_of_weights += gaussian;
|
||||
}
|
||||
weighted_sum /= sum_of_weights;
|
||||
|
||||
copy_v4_v4(output, weighted_sum);
|
||||
}
|
||||
|
||||
void KeyingScreenOperation::update_memory_buffer_partial(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs)
|
||||
{
|
||||
if (movie_clip_ == nullptr) {
|
||||
output->fill(area, COM_COLOR_BLACK);
|
||||
if (!cached_marker_points_) {
|
||||
output->fill(area, COM_COLOR_TRANSPARENT);
|
||||
return;
|
||||
}
|
||||
|
||||
TileData *tri_area = this->triangulate(&area);
|
||||
BLI_assert(tri_area != nullptr);
|
||||
const int2 size = int2(this->get_width(), this->get_height());
|
||||
const float squared_shape_parameter = math::square(1.0f / smoothness_);
|
||||
|
||||
const int *triangles = tri_area->triangles;
|
||||
const int num_triangles = tri_area->triangles_total;
|
||||
const TriangulationData *triangulation = cached_triangulation_;
|
||||
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
|
||||
copy_v4_v4(it.out, COM_COLOR_BLACK);
|
||||
const float2 normalized_pixel_location = float2(it.x, it.y) / float2(size);
|
||||
|
||||
const float co[2] = {float(it.x), float(it.y)};
|
||||
for (int i = 0; i < num_triangles; i++) {
|
||||
const int triangle_idx = triangles[i];
|
||||
const rcti *rect = &triangulation->triangles_AABB[triangle_idx];
|
||||
|
||||
if (!BLI_rcti_isect_pt(rect, it.x, it.y)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int *triangle = triangulation->triangles[triangle_idx];
|
||||
const VoronoiTriangulationPoint &a = triangulation->triangulated_points[triangle[0]];
|
||||
const VoronoiTriangulationPoint &b = triangulation->triangulated_points[triangle[1]];
|
||||
const VoronoiTriangulationPoint &c = triangulation->triangulated_points[triangle[2]];
|
||||
|
||||
float w[3];
|
||||
if (!barycentric_coords_v2(a.co, b.co, c.co, co, w)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (barycentric_inside_triangle_v2(w)) {
|
||||
it.out[0] = a.color[0] * w[0] + b.color[0] * w[1] + c.color[0] * w[2];
|
||||
it.out[1] = a.color[1] * w[0] + b.color[1] * w[1] + c.color[1] * w[2];
|
||||
it.out[2] = a.color[2] * w[0] + b.color[2] * w[1] + c.color[2] * w[2];
|
||||
break;
|
||||
}
|
||||
float4 weighted_sum = float4(0.0f);
|
||||
float sum_of_weights = 0.0f;
|
||||
for (const MarkerPoint &marker_point : *cached_marker_points_) {
|
||||
const float2 difference = normalized_pixel_location - marker_point.position;
|
||||
const float squared_distance = math::dot(difference, difference);
|
||||
const float gaussian = math::exp(-squared_distance * squared_shape_parameter);
|
||||
weighted_sum += marker_point.color * gaussian;
|
||||
sum_of_weights += gaussian;
|
||||
}
|
||||
}
|
||||
weighted_sum /= sum_of_weights;
|
||||
|
||||
if (tri_area->triangles) {
|
||||
MEM_freeN(tri_area->triangles);
|
||||
copy_v4_v4(it.out, weighted_sum);
|
||||
}
|
||||
|
||||
MEM_freeN(tri_area);
|
||||
}
|
||||
|
||||
} // namespace blender::compositor
|
||||
|
|
|
@ -10,11 +10,12 @@
|
|||
|
||||
#include "DNA_movieclip_types.h"
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_base.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BLI_voronoi_2d.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
/**
|
||||
|
@ -22,22 +23,15 @@ namespace blender::compositor {
|
|||
*/
|
||||
class KeyingScreenOperation : public MultiThreadedOperation {
|
||||
protected:
|
||||
typedef struct TriangulationData {
|
||||
VoronoiTriangulationPoint *triangulated_points;
|
||||
int (*triangles)[3];
|
||||
int triangulated_points_total, triangles_total;
|
||||
rcti *triangles_AABB;
|
||||
} TriangulationData;
|
||||
|
||||
/* TODO(manzanilla): rename to #TrianguledArea on removing tiled implementation. */
|
||||
typedef struct TileData {
|
||||
int *triangles;
|
||||
int triangles_total;
|
||||
} TileData;
|
||||
struct MarkerPoint {
|
||||
float2 position;
|
||||
float4 color;
|
||||
};
|
||||
|
||||
MovieClip *movie_clip_;
|
||||
float smoothness_;
|
||||
int framenumber_;
|
||||
TriangulationData *cached_triangulation_;
|
||||
Array<MarkerPoint> *cached_marker_points_;
|
||||
char tracking_object_[64];
|
||||
|
||||
/**
|
||||
|
@ -45,7 +39,7 @@ class KeyingScreenOperation : public MultiThreadedOperation {
|
|||
*/
|
||||
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
|
||||
|
||||
TriangulationData *build_voronoi_triangulation();
|
||||
Array<MarkerPoint> *compute_marker_points();
|
||||
|
||||
public:
|
||||
KeyingScreenOperation();
|
||||
|
@ -54,7 +48,6 @@ class KeyingScreenOperation : public MultiThreadedOperation {
|
|||
void deinit_execution() override;
|
||||
|
||||
void *initialize_tile_data(rcti *rect) override;
|
||||
void deinitialize_tile_data(rcti *rect, void *data) override;
|
||||
|
||||
void set_movie_clip(MovieClip *clip)
|
||||
{
|
||||
|
@ -64,6 +57,10 @@ class KeyingScreenOperation : public MultiThreadedOperation {
|
|||
{
|
||||
BLI_strncpy(tracking_object_, object, sizeof(tracking_object_));
|
||||
}
|
||||
void set_smoothness(float smoothness)
|
||||
{
|
||||
smoothness_ = math::interpolate(0.15f, 1.0f, smoothness);
|
||||
}
|
||||
void set_framenumber(int framenumber)
|
||||
{
|
||||
framenumber_ = framenumber;
|
||||
|
@ -74,9 +71,6 @@ class KeyingScreenOperation : public MultiThreadedOperation {
|
|||
void update_memory_buffer_partial(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs) override;
|
||||
|
||||
private:
|
||||
TileData *triangulate(const rcti *rect);
|
||||
};
|
||||
|
||||
} // namespace blender::compositor
|
||||
|
|
|
@ -1345,6 +1345,7 @@ typedef struct TexNodeOutput {
|
|||
|
||||
typedef struct NodeKeyingScreenData {
|
||||
char tracking_object[64];
|
||||
float smoothness;
|
||||
} NodeKeyingScreenData;
|
||||
|
||||
typedef struct NodeKeyingData {
|
||||
|
|
|
@ -8146,6 +8146,12 @@ static void def_cmp_keyingscreen(StructRNA *srna)
|
|||
RNA_def_property_string_sdna(prop, nullptr, "tracking_object");
|
||||
RNA_def_property_ui_text(prop, "Tracking Object", "");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
prop = RNA_def_property(srna, "smoothness", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "smoothness");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Smoothness", "");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void def_cmp_keying(StructRNA *srna)
|
||||
|
|
|
@ -41,6 +41,7 @@ static void node_composit_init_keyingscreen(const bContext *C, PointerRNA *ptr)
|
|||
bNode *node = (bNode *)ptr->data;
|
||||
|
||||
NodeKeyingScreenData *data = MEM_cnew<NodeKeyingScreenData>(__func__);
|
||||
data->smoothness = 0.0f;
|
||||
node->storage = data;
|
||||
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
|
@ -78,6 +79,8 @@ static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, Point
|
|||
col = uiLayoutColumn(layout, true);
|
||||
uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
|
||||
}
|
||||
|
||||
uiItemR(layout, ptr, "smoothness", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
}
|
||||
|
||||
using namespace blender::realtime_compositor;
|
||||
|
|
Loading…
Reference in New Issue