Blender V4.3
keying_screen.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <cstdint>
6#include <memory>
7#include <string>
8
9#include "BLI_hash.hh"
10#include "BLI_listbase.h"
11#include "BLI_math_color.h"
12#include "BLI_math_vector.hh"
14#include "BLI_vector.hh"
15
16#include "IMB_imbuf.hh"
17
18#include "DNA_defaults.h"
19#include "DNA_movieclip_types.h"
20#include "DNA_tracking_types.h"
21
22#include "GPU_shader.hh"
23#include "GPU_storage_buffer.hh"
24#include "GPU_texture.hh"
25
26#include "BKE_movieclip.h"
27#include "BKE_tracking.h"
28
29#include "COM_context.hh"
30#include "COM_keying_screen.hh"
31#include "COM_result.hh"
32#include "COM_utilities.hh"
33
35
36/* --------------------------------------------------------------------
37 * Keying Screen Key.
38 */
39
40KeyingScreenKey::KeyingScreenKey(int frame, float smoothness)
41 : frame(frame), smoothness(smoothness)
42{
43}
44
46{
47 return get_default_hash(frame, smoothness);
48}
49
51{
52 return a.frame == b.frame && a.smoothness == b.smoothness;
53}
54
55/* --------------------------------------------------------------------
56 * Keying Screen.
57 */
58
59/* Computes the color and normalized positions of the keying screen markers in the given movie
60 * tracking object. The color is computed as the mean color of the search pattern of the marker. */
61static void compute_marker_points(MovieClip *movie_clip,
62 MovieClipUser &movie_clip_user,
63 MovieTrackingObject *movie_tracking_object,
64 Vector<float2> &marker_positions,
65 Vector<float4> &marker_colors)
66{
67 BLI_assert(marker_positions.is_empty());
68 BLI_assert(marker_colors.is_empty());
69
70 ImBuf *image_buffer = BKE_movieclip_get_ibuf(movie_clip, &movie_clip_user);
71 if (!image_buffer) {
72 return;
73 }
74
75 LISTBASE_FOREACH (MovieTrackingTrack *, track, &movie_tracking_object->tracks) {
76 const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, movie_clip_user.framenr);
77 if (marker->flag & MARKER_DISABLED) {
78 continue;
79 }
80
81 /* Skip out of bound markers since they have no corresponding color. */
82 const float2 position = float2(marker->pos) + float2(track->offset);
83 if (math::clamp(position, float2(0.0f), float2(1.0f)) != position) {
84 continue;
85 }
86
87 ImBuf *pattern_image_buffer = BKE_tracking_get_pattern_imbuf(
88 image_buffer, track, marker, true, false);
89 if (!pattern_image_buffer) {
90 continue;
91 }
92
93 /* Find the mean color of the rectangular search pattern of the marker. */
94 float4 mean_color = float4(0.0f);
95 for (int i = 0; i < pattern_image_buffer->x * pattern_image_buffer->y; i++) {
96 if (pattern_image_buffer->float_buffer.data) {
97 mean_color += float4(&pattern_image_buffer->float_buffer.data[i * 4]);
98 }
99 else {
100 float4 linear_color;
101 uchar4 srgb_color = uchar4(&pattern_image_buffer->byte_buffer.data[i * 4]);
102 srgb_to_linearrgb_uchar4(linear_color, srgb_color);
103 mean_color += linear_color;
104 }
105 }
106 mean_color /= pattern_image_buffer->x * pattern_image_buffer->y;
107
108 marker_colors.append(mean_color);
109 marker_positions.append(position);
110
111 IMB_freeImBuf(pattern_image_buffer);
112 }
113
114 IMB_freeImBuf(image_buffer);
115}
116
117/* Get a MovieClipUser with an initialized clip frame number. */
119{
121 const int scene_frame = context.get_frame_number();
122 const int clip_frame = BKE_movieclip_remap_scene_to_clip_frame(movie_clip, scene_frame);
123 BKE_movieclip_user_set_frame(&movie_clip_user, clip_frame);
124 return movie_clip_user;
125}
126
128 MovieClip *movie_clip,
129 MovieTrackingObject *movie_tracking_object,
130 float smoothness)
131{
132 int2 size;
133 MovieClipUser movie_clip_user = get_movie_clip_user(context, movie_clip);
134 BKE_movieclip_get_size(movie_clip, &movie_clip_user, &size.x, &size.y);
135
136 Vector<float2> marker_positions;
137 Vector<float4> marker_colors;
139 movie_clip, movie_clip_user, movie_tracking_object, marker_positions, marker_colors);
140
141 GPUShader *shader = context.get_shader("compositor_keying_screen");
142 GPU_shader_bind(shader);
143
144 GPU_shader_uniform_1f(shader, "smoothness", smoothness);
145 GPU_shader_uniform_1i(shader, "number_of_markers", marker_positions.size());
146
147 /* SSBO needs to be aligned to 16 bytes, and since sizeof(float2) is only 8 bytes, we need to add
148 * a dummy element at the end for odd sizes to satisfy the alignment requirement. Notice that the
149 * number_of_markers uniform was already assigned above to the original size, so the dummy
150 * element has no effect in the shader. Also notice that the marker colors are always 16 byte
151 * aligned since sizeof(float4) is 16 bytes, so not need to add anything there. */
152 if (marker_positions.size() % 2 == 1) {
153 marker_positions.append(float2(0.0f));
154 }
155
156 GPUStorageBuf *positions_ssbo = GPU_storagebuf_create_ex(marker_positions.size() *
157 sizeof(float2),
158 marker_positions.data(),
160 "Marker Positions");
161 const int positions_ssbo_location = GPU_shader_get_ssbo_binding(shader, "marker_positions");
162 GPU_storagebuf_bind(positions_ssbo, positions_ssbo_location);
163
164 GPUStorageBuf *colors_ssbo = GPU_storagebuf_create_ex(marker_colors.size() * sizeof(float4),
165 marker_colors.data(),
167 "Marker Colors");
168 const int colors_ssbo_location = GPU_shader_get_ssbo_binding(shader, "marker_colors");
169 GPU_storagebuf_bind(colors_ssbo, colors_ssbo_location);
170
171 texture_ = GPU_texture_create_2d(
172 "Keying Screen",
173 size.x,
174 size.y,
175 1,
176 Result::gpu_texture_format(ResultType::Color, context.get_precision()),
178 nullptr);
179 const int image_unit = GPU_shader_get_sampler_binding(shader, "output_img");
180 GPU_texture_image_bind(texture_, image_unit);
181
183
184 GPU_texture_image_unbind(texture_);
185 GPU_storagebuf_unbind(positions_ssbo);
186 GPU_storagebuf_unbind(colors_ssbo);
188
189 GPU_storagebuf_free(positions_ssbo);
190 GPU_storagebuf_free(colors_ssbo);
191}
192
197
198void KeyingScreen::bind_as_texture(GPUShader *shader, const char *texture_name) const
199{
200 const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture_name);
201 GPU_texture_bind(texture_, texture_image_unit);
202}
203
205{
206 GPU_texture_unbind(texture_);
207}
208
209GPUTexture *KeyingScreen::texture() const
210{
211 return texture_;
212}
213
214/* --------------------------------------------------------------------
215 * Keying Screen Container.
216 */
217
219{
220 /* First, delete all cached keying screens that are no longer needed. */
221 for (auto &cached_keying_screens_for_id : map_.values()) {
222 cached_keying_screens_for_id.remove_if([](auto item) { return !item.value->needed; });
223 }
224 map_.remove_if([](auto item) { return item.value.is_empty(); });
225
226 /* Second, reset the needed status of the remaining cached keying screens to false to ready them
227 * to track their needed status for the next evaluation. */
228 for (auto &cached_keying_screens_for_id : map_.values()) {
229 for (auto &value : cached_keying_screens_for_id.values()) {
230 value->needed = false;
231 }
232 }
233}
234
236 MovieClip *movie_clip,
237 MovieTrackingObject *movie_tracking_object,
238 float smoothness)
239{
240 const KeyingScreenKey key(context.get_frame_number(), smoothness);
241
242 /* We concatenate the movie clip ID name with the tracking object name to cache multiple tracking
243 * objects per movie clip. */
244 const std::string library_key = movie_clip->id.lib ? movie_clip->id.lib->id.name : "";
245 const std::string id_key = std::string(movie_clip->id.name) + library_key;
246 const std::string object_key = id_key + movie_tracking_object->name;
247 auto &cached_keying_screens_for_id = map_.lookup_or_add_default(object_key);
248
249 /* Invalidate the keying screen cache for that MovieClip ID if it was changed and reset the
250 * recalculate flag. */
251 if (context.query_id_recalc_flag(reinterpret_cast<ID *>(movie_clip)) & ID_RECALC_ALL) {
252 cached_keying_screens_for_id.clear();
253 }
254
255 auto &keying_screen = *cached_keying_screens_for_id.lookup_or_add_cb(key, [&]() {
256 return std::make_unique<KeyingScreen>(context, movie_clip, movie_tracking_object, smoothness);
257 });
258
259 keying_screen.needed = true;
260 return keying_screen;
261}
262
263} // namespace blender::realtime_compositor
float BKE_movieclip_remap_scene_to_clip_frame(const struct MovieClip *clip, float framenr)
void BKE_movieclip_user_set_frame(struct MovieClipUser *user, int framenr)
void BKE_movieclip_get_size(struct MovieClip *clip, const struct MovieClipUser *user, int *r_width, int *r_height)
struct ImBuf * BKE_movieclip_get_ibuf(struct MovieClip *clip, const struct MovieClipUser *user)
struct MovieTrackingMarker * BKE_tracking_marker_get(struct MovieTrackingTrack *track, int framenr)
Definition tracking.cc:1358
struct ImBuf * BKE_tracking_get_pattern_imbuf(const struct ImBuf *ibuf, const struct MovieTrackingTrack *track, const struct MovieTrackingMarker *marker, bool anchored, bool disable_channels)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
MINLINE void srgb_to_linearrgb_uchar4(float linear[4], const unsigned char srgb[4])
@ ID_RECALC_ALL
Definition DNA_ID.h:1155
#define DNA_struct_default_get(struct_name)
@ MARKER_DISABLED
int GPU_shader_get_sampler_binding(GPUShader *shader, const char *name)
void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value)
void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float value)
int GPU_shader_get_ssbo_binding(GPUShader *shader, const char *name)
void GPU_shader_bind(GPUShader *shader)
void GPU_shader_unbind()
void GPU_storagebuf_bind(GPUStorageBuf *ssbo, int slot)
GPUStorageBuf * GPU_storagebuf_create_ex(size_t size, const void *data, GPUUsageType usage, const char *name)
void GPU_storagebuf_unbind(GPUStorageBuf *ssbo)
void GPU_storagebuf_free(GPUStorageBuf *ssbo)
void GPU_texture_bind(GPUTexture *texture, int unit)
GPUTexture * GPU_texture_create_2d(const char *name, int width, int height, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_free(GPUTexture *texture)
void GPU_texture_unbind(GPUTexture *texture)
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_SHADER_WRITE
void GPU_texture_image_unbind(GPUTexture *texture)
void GPU_texture_image_bind(GPUTexture *texture, int unit)
@ GPU_USAGE_STATIC
struct GPUShader GPUShader
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
int64_t size() const
void append(const T &value)
bool is_empty() const
KeyingScreen & get(Context &context, MovieClip *movie_clip, MovieTrackingObject *movie_tracking_object, float smoothness)
KeyingScreenKey(int frame, float smoothness)
KeyingScreen(Context &context, MovieClip *movie_clip, MovieTrackingObject *movie_tracking_object, float smoothness)
void bind_as_texture(GPUShader *shader, const char *texture_name) const
static eGPUTextureFormat gpu_texture_format(ResultType type, ResultPrecision precision)
Definition result.cc:29
local_group_size(16, 16) .push_constant(Type b
void IMB_freeImBuf(ImBuf *)
T clamp(const T &a, const T &min, const T &max)
static MovieClipUser get_movie_clip_user(Context &context, MovieClip *movie_clip)
bool operator==(const BokehKernelKey &a, const BokehKernelKey &b)
static void compute_marker_points(MovieClip *movie_clip, MovieClipUser &movie_clip_user, MovieTrackingObject *movie_tracking_object, Vector< float2 > &marker_positions, Vector< float4 > &marker_colors)
void compute_dispatch_threads_at_least(GPUShader *shader, int2 threads_range, int2 local_size=int2(16))
Definition utilities.cc:131
blender::VecBase< uint8_t, 4 > uchar4
VecBase< float, 4 > float4
VecBase< float, 2 > float2
uint64_t get_default_hash(const T &v)
Definition BLI_hash.hh:219
unsigned __int64 uint64_t
Definition stdint.h:90
Definition DNA_ID.h:413
struct Library * lib
Definition DNA_ID.h:419
char name[66]
Definition DNA_ID.h:425
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
ID id
Definition DNA_ID.h:529