70 bool *stop, *do_update;
87 bool use_current_frame;
93 TurnPolicy turnpolicy;
101 void ensure_output_object();
104void TraceJob::ensure_output_object()
109 if (this->ob_grease_pencil ==
nullptr) {
110 const ushort local_view_bits = (this->v3d && this->v3d->localvd) ? this->v3d->local_view_uid :
117 this->ob_active->loc,
118 this->ob_active->rot,
121 copy_v3_v3(this->ob_grease_pencil->scale, this->ob_active->scale);
122 this->was_ob_created =
true;
127 this->layer = grease_pencil.get_active_layer();
128 if (this->layer ==
nullptr) {
129 Layer &new_layer = grease_pencil.add_layer(
DATA_(
"Trace"));
130 grease_pencil.set_active_layer(&new_layer);
131 this->layer = &new_layer;
135static float4x4 pixel_to_object_transform(
const Object &image_object,
139 const float3 pixel_center_3d =
float3(pixel_center.x, pixel_center.y, 0);
143 const float3 image_aspect_3d = (ibuf.
x > ibuf.
y ?
float3(1,
float(ibuf.
y) /
float(ibuf.
x), 1) :
150 return to_normalized;
153static int ensure_foreground_material(Main *bmain,
Object *ob,
const StringRefNull name)
165static int ensure_background_material(Main *bmain,
Object *ob,
const StringRefNull name)
180static bke::CurvesGeometry grease_pencil_trace_image(TraceJob &trace_job,
const ImBuf &ibuf)
189 image_trace::TraceParams
params;
190 params.size_threshold = 0;
191 params.turn_policy = trace_job.turnpolicy;
196 const StringRef hole_attribute_id =
"is_hole";
199 const float4x4 transform = pixel_to_object_transform(*trace_job.ob_active, ibuf);
201 *trace, hole_attribute_id, transform);
206 const int material_fg = ensure_foreground_material(
207 trace_job.bmain, trace_job.ob_grease_pencil,
"Stroke");
208 const int material_bg = ensure_background_material(
209 trace_job.bmain, trace_job.ob_grease_pencil,
"Holdout");
210 const VArraySpan<bool> holes = *attributes.
lookup<
bool>(hole_attribute_id);
214 for (const int curve_i : range) {
215 const bool is_hole = holes[curve_i];
216 material_indices.span[curve_i] = (is_hole ? material_bg : material_fg);
219 material_indices.
finish();
221 attributes.
remove(hole_attribute_id);
226 radii.
span.fill(trace_job.radius);
234 TraceJob &trace_job = *
static_cast<TraceJob *
>(customdata);
236 trace_job.stop = &worker_status->
stop;
237 trace_job.do_update = &worker_status->
do_update;
238 trace_job.progress = &worker_status->
progress;
239 trace_job.was_canceled =
false;
240 const int init_frame = std::max((trace_job.use_current_frame) ? trace_job.frame_target : 0, 0);
245 if (trace_job.image->source ==
IMA_SRC_FILE || trace_job.mode == TraceMode::Single) {
246 ImageUser &iuser = *trace_job.ob_active->iuser;
247 trace_job.traced_curves.reinitialize(1);
249 iuser.
framenr = ((trace_job.frame_number == 0) || (trace_job.frame_number > iuser.
frames)) ?
251 trace_job.frame_number;
255 trace_job.traced_curves.first() = grease_pencil_trace_image(trace_job, *ibuf);
257 *(trace_job.progress) = 1.0f;
262 ImageUser &iuser = *trace_job.ob_active->iuser;
263 const int num_frames = iuser.
frames - init_frame + 1;
264 trace_job.traced_curves.reinitialize(num_frames);
267 trace_job.was_canceled =
true;
271 const int frame_number = init_frame + i;
272 *(trace_job.progress) =
float(frame_number) /
float(iuser.
frames);
280 trace_job.traced_curves[i] = grease_pencil_trace_image(trace_job, *ibuf);
286 trace_job.success = !trace_job.was_canceled;
288 worker_status->
stop =
false;
291static void trace_end_job(
void *customdata)
293 TraceJob &trace_job = *
static_cast<TraceJob *
>(customdata);
298 switch (trace_job.mode) {
299 case TraceMode::Single: {
300 BLI_assert(trace_job.traced_curves.size() == 1);
302 trace_job.frame_target);
303 if (drawing ==
nullptr) {
304 drawing = grease_pencil.insert_frame(*trace_job.layer, trace_job.frame_target);
311 case TraceMode::Sequence: {
312 const ImageUser &iuser = *trace_job.ob_active->iuser;
313 const int init_frame = std::max((trace_job.use_current_frame) ? trace_job.frame_target : 0,
315 const int num_frames = iuser.
frames - init_frame + 1;
316 BLI_assert(trace_job.traced_curves.size() == num_frames);
318 const int frame_number = init_frame + i;
321 if (drawing ==
nullptr) {
322 drawing = grease_pencil.insert_frame(*trace_job.layer, frame_number);
333 if ((trace_job.was_canceled) && (trace_job.was_ob_created) && (trace_job.ob_grease_pencil)) {
334 BKE_id_delete(trace_job.bmain, &trace_job.ob_grease_pencil->id);
338 if (trace_job.success) {
349static void trace_free_job(
void *customdata)
351 TraceJob *tj =
static_cast<TraceJob *
>(customdata);
356static bool grease_pencil_trace_image_poll(
bContext *
C)
375 TraceJob *job = MEM_new<TraceJob>(
"TraceJob");
384 job->ob_active = job->base_active->object;
385 job->image =
static_cast<Image *
>(job->ob_active->data);
386 job->frame_target = scene->
r.
cfra;
391 job->ob_grease_pencil = (target == TargetObjectMode::Selected) ?
396 if (job->ob_grease_pencil !=
nullptr) {
399 job->ob_grease_pencil =
nullptr;
403 job->ob_grease_pencil =
nullptr;
407 job->was_ob_created =
false;
415 job->ensure_output_object();
420 if ((job->image->source ==
IMA_SRC_FILE) || (job->frame_number > 0)) {
422 trace_start_job(job, &worker_status);
456 {
int(TurnPolicy::Foreground),
460 "Prefers to connect foreground components"},
461 {
int(TurnPolicy::Background),
465 "Prefers to connect background components"},
466 {
int(TurnPolicy::Left),
"LEFT", 0,
"Left",
"Always take a left turn"},
467 {
int(TurnPolicy::Right),
"RIGHT", 0,
"Right",
"Always take a right turn"},
468 {
int(TurnPolicy::Minority),
472 "Prefers to connect the color that occurs least frequently in the local "
473 "neighborhood of the current position"},
474 {
int(TurnPolicy::Majority),
478 "Prefers to connect the color that occurs most frequently in the local "
479 "neighborhood of the current position"},
480 {
int(TurnPolicy::Random),
"RANDOM", 0,
"Random",
"Choose pseudo-randomly"},
481 {0,
nullptr, 0,
nullptr,
nullptr},
485 {
int(TraceMode::Single),
"SINGLE", 0,
"Single",
"Trace the current frame of the image"},
486 {
int(TraceMode::Sequence),
"SEQUENCE", 0,
"Sequence",
"Trace full sequence"},
487 {0,
nullptr, 0,
nullptr,
nullptr},
491 {
int(TargetObjectMode::New),
"NEW", 0,
"New Object",
""},
492 {
int(TargetObjectMode::Selected),
"SELECTED", 0,
"Selected Object",
""},
493 {0,
nullptr, 0,
nullptr,
nullptr},
497 ot->name =
"Trace Image to Grease Pencil";
498 ot->idname =
"GREASE_PENCIL_OT_trace_image";
499 ot->description =
"Extract Grease Pencil strokes from image";
502 ot->invoke = grease_pencil_trace_image_invoke;
503 ot->exec = grease_pencil_trace_image_exec;
504 ot->poll = grease_pencil_trace_image_poll;
513 int(TargetObjectMode::New),
515 "Target grease pencil");
518 RNA_def_float(
ot->srna,
"radius", 0.01f, 0.001f, 1.0f,
"Radius",
"", 0.001, 1.0f);
526 "Determine the lightness threshold above which strokes are generated",
532 int(TurnPolicy::Minority),
534 "Determines how to resolve ambiguities during decomposition of bitmaps into paths");
538 int(TraceMode::Single),
540 "Determines if trace simple image or full sequence");
544 "Start At Current Frame",
545 "Trace Image starting in current image frame");
553 "Used to trace only one frame of the image sequence, set to zero to trace all",
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
wmWindow * CTX_wm_window(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Base * CTX_data_active_base(const bContext *C)
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
Low-level operations for curves.
Low-level operations for grease pencil.
Material * BKE_grease_pencil_object_material_new(Main *bmain, Object *ob, const char *name, int *r_index)
int BKE_grease_pencil_object_material_index_get_by_name(Object *ob, const char *name)
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
Object * BKE_view_layer_non_active_selected_object(const Scene *scene, ViewLayer *view_layer, const View3D *v3d)
void BKE_id_delete(Main *bmain, void *idv) ATTR_NONNULL()
General operations, lookup, etc. for materials.
General operations, lookup, etc. for blender objects.
bool BKE_object_obdata_is_libdata(const Object *ob)
void BKE_report(ReportList *reports, eReportType type, const char *message)
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ GP_MATERIAL_IS_STROKE_HOLDOUT
@ GP_MATERIAL_STROKE_SHOW
@ GP_MATERIAL_IS_FILL_HOLDOUT
Object is a sort of wrapper for general info.
Contains defines and structs used throughout the imbuf module.
Read Guarded memory(de)allocation.
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
@ WM_JOB_TYPE_TRACE_IMAGE
ATTR_WARN_UNUSED_RESULT BMesh * bm
constexpr const char * c_str() const
GAttributeReader lookup(const StringRef attribute_id) const
IndexRange curves_range() const
MutableAttributeAccessor attributes_for_write()
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
bool remove(const StringRef attribute_id)
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
bke::CurvesGeometry & strokes_for_write()
void tag_topology_changed()
input_tx image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img") .compute_source("compositor_compute_preview.glsl") .do_static_compilation(true)
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
void ED_operatortypes_grease_pencil_trace()
void free_bitmap(Bitmap *bm)
Bitmap * image_to_bitmap(const ImBuf &ibuf, ThresholdFn fn)
bke::CurvesGeometry trace_to_curves(const Trace &trace, StringRef hole_attribute_id, const float4x4 &transform)
void free_trace(Trace *trace)
Trace * trace_bitmap(const TraceParams ¶ms, Bitmap &bm)
Object * add_type(bContext *C, int type, const char *name, const float loc[3], const float rot[3], bool enter_editmode, unsigned short local_view_bits) ATTR_NONNULL(1) ATTR_RETURNS_NONNULL
void base_activate(bContext *C, Base *base)
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
T average(const VecBase< T, Size > &a)
MatT from_scale(const VecBase< typename MatT::base_type, ScaleDim > &scale)
MatBase< T, NumCol, NumRow > translate(const MatBase< T, NumCol, NumRow > &mat, const VectorT &translation)
void transform(Context &context, Result &input, Result &output, const float3x3 &transformation, RealizationOptions realization_options)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< float, 2 > float2
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
VecBase< float, 3 > float3
int RNA_int_get(PointerRNA *ptr, const char *name)
float RNA_float_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float_factor(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
struct MaterialGPencilStyle * gp_style
MutableVArraySpan< T > span
struct ReportList * reports
void WM_main_add_notifier(uint type, void *reference)
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, const eWM_JobFlag flag, const eWM_JobType job_type)
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, std::optional< std::string > title, std::optional< std::string > confirm_text, const bool cancel_default)