Merge branch 'blender-v4.1-release'
[blender.git] / source / blender / editors / object / object_bake.cc
blob4a991b889aa9c6774841c7b803a6ca55335ddbcf
1 /* SPDX-FileCopyrightText: 2004 Blender Authors
3 * SPDX-License-Identifier: GPL-2.0-or-later */
5 /** \file
6 * \ingroup edobj
7 */
9 #include <cstring>
11 #include "MEM_guardedalloc.h"
13 #include "DNA_mesh_types.h"
14 #include "DNA_object_types.h"
15 #include "DNA_scene_types.h"
16 #include "DNA_screen_types.h"
17 #include "DNA_space_types.h"
19 #include "BLI_utildefines.h"
21 #include "BKE_DerivedMesh.hh"
22 #include "BKE_attribute.hh"
23 #include "BKE_cdderivedmesh.h"
24 #include "BKE_context.hh"
25 #include "BKE_customdata.hh"
26 #include "BKE_global.hh"
27 #include "BKE_image.h"
28 #include "BKE_modifier.hh"
29 #include "BKE_multires.hh"
30 #include "BKE_report.hh"
31 #include "BKE_scene.hh"
33 #include "RE_multires_bake.h"
34 #include "RE_pipeline.h"
36 #include "IMB_imbuf.hh"
37 #include "IMB_imbuf_types.hh"
39 #include "WM_api.hh"
40 #include "WM_types.hh"
42 #include "ED_screen.hh"
43 #include "ED_uvedit.hh"
45 #include "object_intern.h"
47 static Image *bake_object_image_get(Object *ob, int mat_nr)
49 Image *image = nullptr;
50 ED_object_get_active_image(ob, mat_nr + 1, &image, nullptr, nullptr, nullptr);
51 return image;
54 static Image **bake_object_image_get_array(Object *ob)
56 Image **image_array = static_cast<Image **>(
57 MEM_mallocN(sizeof(Material *) * ob->totcol, __func__));
58 for (int i = 0; i < ob->totcol; i++) {
59 image_array[i] = bake_object_image_get(ob, i);
61 return image_array;
64 /* ****************** multires BAKING ********************** */
66 /* holder of per-object data needed for bake job
67 * needed to make job totally thread-safe */
68 struct MultiresBakerJobData {
69 MultiresBakerJobData *next, *prev;
70 /* material aligned image array (for per-face bake image) */
71 struct {
72 Image **array;
73 int len;
74 } ob_image;
75 DerivedMesh *lores_dm, *hires_dm;
76 int lvl, tot_lvl;
77 ListBase images;
80 /* data passing to multires-baker job */
81 struct MultiresBakeJob {
82 Scene *scene;
83 ListBase data;
84 /** Clear the images before baking */
85 bool bake_clear;
86 /** Margin size in pixels. */
87 int bake_margin;
88 /** margin type */
89 char bake_margin_type;
90 /** mode of baking (displacement, normals, AO) */
91 short mode;
92 /** Use low-resolution mesh when baking displacement maps */
93 bool use_lores_mesh;
94 /** Number of rays to be cast when doing AO baking */
95 int number_of_rays;
96 /** Bias between object and start ray point when doing AO baking */
97 float bias;
98 /** Number of threads to be used for baking */
99 int threads;
100 /** User scale used to scale displacement when baking derivative map. */
101 float user_scale;
104 static bool multiresbake_check(bContext *C, wmOperator *op)
106 using namespace blender;
107 Scene *scene = CTX_data_scene(C);
108 Object *ob;
109 Mesh *mesh;
110 MultiresModifierData *mmd;
111 bool ok = true;
112 int a;
114 CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) {
115 ob = base->object;
117 if (ob->type != OB_MESH) {
118 BKE_report(
119 op->reports, RPT_ERROR, "Baking of multires data only works with an active mesh object");
121 ok = false;
122 break;
125 mesh = (Mesh *)ob->data;
126 mmd = get_multires_modifier(scene, ob, false);
128 /* Multi-resolution should be and be last in the stack */
129 if (ok && mmd) {
130 ModifierData *md;
132 ok = mmd->totlvl > 0;
134 for (md = (ModifierData *)mmd->modifier.next; md && ok; md = md->next) {
135 if (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
136 ok = false;
140 else {
141 ok = false;
144 if (!ok) {
145 BKE_report(op->reports, RPT_ERROR, "Multires data baking requires multi-resolution object");
147 break;
150 if (!CustomData_has_layer(&mesh->corner_data, CD_PROP_FLOAT2)) {
151 BKE_report(op->reports, RPT_ERROR, "Mesh should be unwrapped before multires data baking");
153 ok = false;
155 else {
156 const bke::AttributeAccessor attributes = mesh->attributes();
157 const VArraySpan material_indices = *attributes.lookup<int>("material_index",
158 bke::AttrDomain::Face);
159 a = mesh->faces_num;
160 while (ok && a--) {
161 Image *ima = bake_object_image_get(ob,
162 material_indices.is_empty() ? 0 : material_indices[a]);
164 if (!ima) {
165 BKE_report(
166 op->reports, RPT_ERROR, "You should have active texture to use multires baker");
168 ok = false;
170 else {
171 LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
172 ImageUser iuser;
173 BKE_imageuser_default(&iuser);
174 iuser.tile = tile->tile_number;
176 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
178 if (!ibuf) {
179 BKE_report(
180 op->reports, RPT_ERROR, "Baking should happen to image with image buffer");
182 ok = false;
184 else {
185 if (ibuf->byte_buffer.data == nullptr && ibuf->float_buffer.data == nullptr) {
186 ok = false;
189 if (ibuf->float_buffer.data && !ELEM(ibuf->channels, 0, 4)) {
190 ok = false;
193 if (!ok) {
194 BKE_report(op->reports, RPT_ERROR, "Baking to unsupported image type");
198 BKE_image_release_ibuf(ima, ibuf, nullptr);
204 if (!ok) {
205 break;
208 CTX_DATA_END;
210 return ok;
213 static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *lvl)
215 DerivedMesh *dm;
216 MultiresModifierData *mmd = get_multires_modifier(scene, ob, false);
217 Mesh *mesh = (Mesh *)ob->data;
218 MultiresModifierData tmp_mmd = blender::dna::shallow_copy(*mmd);
220 *lvl = mmd->lvl;
222 if (mmd->lvl == 0) {
223 DerivedMesh *cddm = CDDM_from_mesh(mesh);
224 DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
225 return cddm;
228 DerivedMesh *cddm = CDDM_from_mesh(mesh);
229 DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
230 tmp_mmd.lvl = mmd->lvl;
231 tmp_mmd.sculptlvl = mmd->lvl;
232 dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, MULTIRES_IGNORE_SIMPLIFY);
234 cddm->release(cddm);
236 return dm;
239 static DerivedMesh *multiresbake_create_hiresdm(Scene *scene, Object *ob, int *lvl)
241 Mesh *mesh = (Mesh *)ob->data;
242 MultiresModifierData *mmd = get_multires_modifier(scene, ob, false);
243 MultiresModifierData tmp_mmd = blender::dna::shallow_copy(*mmd);
244 DerivedMesh *cddm = CDDM_from_mesh(mesh);
245 DerivedMesh *dm;
247 DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
249 /* TODO: DM_set_only_copy wouldn't set mask for loop and poly data,
250 * but we really need BAREMESH only to save lots of memory
252 CustomData_set_only_copy(&cddm->loopData, CD_MASK_BAREMESH.lmask);
253 CustomData_set_only_copy(&cddm->polyData, CD_MASK_BAREMESH.pmask);
255 *lvl = mmd->totlvl;
257 tmp_mmd.lvl = mmd->totlvl;
258 tmp_mmd.sculptlvl = mmd->totlvl;
259 dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, MULTIRES_IGNORE_SIMPLIFY);
260 cddm->release(cddm);
262 return dm;
265 enum ClearFlag {
266 CLEAR_TANGENT_NORMAL = 1,
267 CLEAR_DISPLACEMENT = 2,
270 static void clear_single_image(Image *image, ClearFlag flag)
272 const float vec_alpha[4] = {0.0f, 0.0f, 0.0f, 0.0f};
273 const float vec_solid[4] = {0.0f, 0.0f, 0.0f, 1.0f};
274 const float nor_alpha[4] = {0.5f, 0.5f, 1.0f, 0.0f};
275 const float nor_solid[4] = {0.5f, 0.5f, 1.0f, 1.0f};
276 const float disp_alpha[4] = {0.5f, 0.5f, 0.5f, 0.0f};
277 const float disp_solid[4] = {0.5f, 0.5f, 0.5f, 1.0f};
279 if ((image->id.tag & LIB_TAG_DOIT) == 0) {
280 LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) {
281 ImageUser iuser;
282 BKE_imageuser_default(&iuser);
283 iuser.tile = tile->tile_number;
285 ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, nullptr);
287 if (flag == CLEAR_TANGENT_NORMAL) {
288 IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid);
290 else if (flag == CLEAR_DISPLACEMENT) {
291 IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? disp_alpha : disp_solid);
293 else {
294 IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid);
297 image->id.tag |= LIB_TAG_DOIT;
299 BKE_image_release_ibuf(image, ibuf, nullptr);
304 static void clear_images_poly(Image **ob_image_array, int ob_image_array_len, ClearFlag flag)
306 for (int i = 0; i < ob_image_array_len; i++) {
307 Image *image = ob_image_array[i];
308 if (image) {
309 image->id.tag &= ~LIB_TAG_DOIT;
313 for (int i = 0; i < ob_image_array_len; i++) {
314 Image *image = ob_image_array[i];
315 if (image) {
316 clear_single_image(image, flag);
320 for (int i = 0; i < ob_image_array_len; i++) {
321 Image *image = ob_image_array[i];
322 if (image) {
323 image->id.tag &= ~LIB_TAG_DOIT;
328 static int multiresbake_image_exec_locked(bContext *C, wmOperator *op)
330 Object *ob;
331 Scene *scene = CTX_data_scene(C);
332 int objects_baked = 0;
334 if (!multiresbake_check(C, op)) {
335 return OPERATOR_CANCELLED;
338 if (scene->r.bake_flag & R_BAKE_CLEAR) { /* clear images */
339 CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) {
340 ClearFlag clear_flag = ClearFlag(0);
342 ob = base->object;
343 // mesh = (Mesh *)ob->data;
345 if (scene->r.bake_mode == RE_BAKE_NORMALS) {
346 clear_flag = CLEAR_TANGENT_NORMAL;
348 else if (scene->r.bake_mode == RE_BAKE_DISPLACEMENT) {
349 clear_flag = CLEAR_DISPLACEMENT;
353 Image **ob_image_array = bake_object_image_get_array(ob);
354 clear_images_poly(ob_image_array, ob->totcol, clear_flag);
355 MEM_freeN(ob_image_array);
358 CTX_DATA_END;
361 CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) {
362 MultiresBakeRender bkr = {nullptr};
364 ob = base->object;
366 multires_flush_sculpt_updates(ob);
368 /* copy data stored in job descriptor */
369 bkr.scene = scene;
370 bkr.bake_margin = scene->r.bake_margin;
371 if (scene->r.bake_mode == RE_BAKE_NORMALS) {
372 bkr.bake_margin_type = R_BAKE_EXTEND;
374 else {
375 bkr.bake_margin_type = scene->r.bake_margin_type;
377 bkr.mode = scene->r.bake_mode;
378 bkr.use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH;
379 bkr.bias = scene->r.bake_biasdist;
380 bkr.number_of_rays = scene->r.bake_samples;
381 bkr.threads = BKE_scene_num_threads(scene);
382 bkr.user_scale = (scene->r.bake_flag & R_BAKE_USERSCALE) ? scene->r.bake_user_scale : -1.0f;
383 // bkr.reports= op->reports;
385 /* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */
386 bkr.ob_image.array = bake_object_image_get_array(ob);
387 bkr.ob_image.len = ob->totcol;
389 bkr.hires_dm = multiresbake_create_hiresdm(scene, ob, &bkr.tot_lvl);
390 bkr.lores_dm = multiresbake_create_loresdm(scene, ob, &bkr.lvl);
392 RE_multires_bake_images(&bkr);
394 MEM_freeN(bkr.ob_image.array);
396 BLI_freelistN(&bkr.image);
398 bkr.lores_dm->release(bkr.lores_dm);
399 bkr.hires_dm->release(bkr.hires_dm);
401 objects_baked++;
403 CTX_DATA_END;
405 if (!objects_baked) {
406 BKE_report(op->reports, RPT_ERROR, "No objects found to bake from");
409 return OPERATOR_FINISHED;
413 * Multi-resolution-bake adopted for job-system executing.
415 static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj)
417 Scene *scene = CTX_data_scene(C);
418 Object *ob;
420 /* backup scene settings, so their changing in UI would take no effect on baker */
421 bkj->scene = scene;
422 bkj->bake_margin = scene->r.bake_margin;
423 if (scene->r.bake_mode == RE_BAKE_NORMALS) {
424 bkj->bake_margin_type = R_BAKE_EXTEND;
426 else {
427 bkj->bake_margin_type = scene->r.bake_margin_type;
429 bkj->mode = scene->r.bake_mode;
430 bkj->use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH;
431 bkj->bake_clear = scene->r.bake_flag & R_BAKE_CLEAR;
432 bkj->bias = scene->r.bake_biasdist;
433 bkj->number_of_rays = scene->r.bake_samples;
434 bkj->threads = BKE_scene_num_threads(scene);
435 bkj->user_scale = (scene->r.bake_flag & R_BAKE_USERSCALE) ? scene->r.bake_user_scale : -1.0f;
436 // bkj->reports = op->reports;
438 CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) {
439 int lvl;
441 ob = base->object;
443 multires_flush_sculpt_updates(ob);
445 MultiresBakerJobData *data = MEM_cnew<MultiresBakerJobData>(__func__);
447 data->ob_image.array = bake_object_image_get_array(ob);
448 data->ob_image.len = ob->totcol;
450 /* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */
451 data->hires_dm = multiresbake_create_hiresdm(scene, ob, &data->tot_lvl);
452 data->lores_dm = multiresbake_create_loresdm(scene, ob, &lvl);
453 data->lvl = lvl;
455 BLI_addtail(&bkj->data, data);
457 CTX_DATA_END;
460 static void multiresbake_startjob(void *bkv, wmJobWorkerStatus *worker_status)
462 MultiresBakeJob *bkj = static_cast<MultiresBakeJob *>(bkv);
463 int baked_objects = 0, tot_obj;
465 tot_obj = BLI_listbase_count(&bkj->data);
467 if (bkj->bake_clear) { /* clear images */
468 LISTBASE_FOREACH (MultiresBakerJobData *, data, &bkj->data) {
469 ClearFlag clear_flag = ClearFlag(0);
471 if (bkj->mode == RE_BAKE_NORMALS) {
472 clear_flag = CLEAR_TANGENT_NORMAL;
474 else if (bkj->mode == RE_BAKE_DISPLACEMENT) {
475 clear_flag = CLEAR_DISPLACEMENT;
478 clear_images_poly(data->ob_image.array, data->ob_image.len, clear_flag);
482 LISTBASE_FOREACH (MultiresBakerJobData *, data, &bkj->data) {
483 MultiresBakeRender bkr = {nullptr};
485 /* copy data stored in job descriptor */
486 bkr.scene = bkj->scene;
487 bkr.bake_margin = bkj->bake_margin;
488 bkr.bake_margin_type = bkj->bake_margin_type;
489 bkr.mode = bkj->mode;
490 bkr.use_lores_mesh = bkj->use_lores_mesh;
491 bkr.user_scale = bkj->user_scale;
492 // bkr.reports = bkj->reports;
493 bkr.ob_image.array = data->ob_image.array;
494 bkr.ob_image.len = data->ob_image.len;
496 /* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */
497 bkr.lores_dm = data->lores_dm;
498 bkr.hires_dm = data->hires_dm;
499 bkr.tot_lvl = data->tot_lvl;
500 bkr.lvl = data->lvl;
502 /* needed for proper progress bar */
503 bkr.tot_obj = tot_obj;
504 bkr.baked_objects = baked_objects;
506 bkr.stop = &worker_status->stop;
507 bkr.do_update = &worker_status->do_update;
508 bkr.progress = &worker_status->progress;
510 bkr.bias = bkj->bias;
511 bkr.number_of_rays = bkj->number_of_rays;
512 bkr.threads = bkj->threads;
514 RE_multires_bake_images(&bkr);
516 data->images = bkr.image;
518 baked_objects++;
522 static void multiresbake_freejob(void *bkv)
524 MultiresBakeJob *bkj = static_cast<MultiresBakeJob *>(bkv);
525 MultiresBakerJobData *data, *next;
527 data = static_cast<MultiresBakerJobData *>(bkj->data.first);
528 while (data) {
529 next = data->next;
530 data->lores_dm->release(data->lores_dm);
531 data->hires_dm->release(data->hires_dm);
533 /* delete here, since this delete will be called from main thread */
534 LISTBASE_FOREACH (LinkData *, link, &data->images) {
535 Image *ima = (Image *)link->data;
536 BKE_image_partial_update_mark_full_update(ima);
539 MEM_freeN(data->ob_image.array);
541 BLI_freelistN(&data->images);
543 MEM_freeN(data);
544 data = next;
547 MEM_freeN(bkj);
550 static int multiresbake_image_exec(bContext *C, wmOperator *op)
552 Scene *scene = CTX_data_scene(C);
554 if (!multiresbake_check(C, op)) {
555 return OPERATOR_CANCELLED;
558 MultiresBakeJob *bkr = MEM_cnew<MultiresBakeJob>(__func__);
559 init_multiresbake_job(C, bkr);
561 if (!bkr->data.first) {
562 BKE_report(op->reports, RPT_ERROR, "No objects found to bake from");
563 return OPERATOR_CANCELLED;
566 /* setup job */
567 wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
568 CTX_wm_window(C),
569 scene,
570 "Multires Bake",
571 WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS,
572 WM_JOB_TYPE_OBJECT_BAKE_TEXTURE);
573 WM_jobs_customdata_set(wm_job, bkr, multiresbake_freejob);
574 WM_jobs_timer(wm_job, 0.5, NC_IMAGE, 0); /* TODO: only draw bake image, can we enforce this. */
575 WM_jobs_callbacks(wm_job, multiresbake_startjob, nullptr, nullptr, nullptr);
577 G.is_break = false;
579 WM_jobs_start(CTX_wm_manager(C), wm_job);
580 WM_cursor_wait(false);
582 /* add modal handler for ESC */
583 WM_event_add_modal_handler(C, op);
585 return OPERATOR_RUNNING_MODAL;
588 /* ****************** render BAKING ********************** */
590 /** Catch escape key to cancel. */
591 static int objects_bake_render_modal(bContext *C, wmOperator * /*op*/, const wmEvent *event)
593 /* no running blender, remove handler and pass through */
594 if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_BAKE_TEXTURE)) {
595 return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
598 /* running render */
599 switch (event->type) {
600 case EVT_ESCKEY:
601 return OPERATOR_RUNNING_MODAL;
603 return OPERATOR_PASS_THROUGH;
606 static bool is_multires_bake(Scene *scene)
608 if (ELEM(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT, RE_BAKE_AO)) {
609 return scene->r.bake_flag & R_BAKE_MULTIRES;
612 return false;
615 static int objects_bake_render_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
617 Scene *scene = CTX_data_scene(C);
618 int result = OPERATOR_CANCELLED;
620 result = multiresbake_image_exec(C, op);
622 WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene);
624 return result;
627 static int bake_image_exec(bContext *C, wmOperator *op)
629 Scene *scene = CTX_data_scene(C);
630 int result = OPERATOR_CANCELLED;
632 if (!is_multires_bake(scene)) {
633 BLI_assert(0);
634 return result;
637 result = multiresbake_image_exec_locked(C, op);
639 WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene);
641 return result;
644 void OBJECT_OT_bake_image(wmOperatorType *ot)
646 /* identifiers */
647 ot->name = "Bake";
648 ot->description = "Bake image textures of selected objects";
649 ot->idname = "OBJECT_OT_bake_image";
651 /* api callbacks */
652 ot->exec = bake_image_exec;
653 ot->invoke = objects_bake_render_invoke;
654 ot->modal = objects_bake_render_modal;
655 ot->poll = ED_operator_object_active;