1 /* SPDX-FileCopyrightText: 2004 Blender Authors
3 * SPDX-License-Identifier: GPL-2.0-or-later */
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"
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);
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
);
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) */
75 DerivedMesh
*lores_dm
, *hires_dm
;
80 /* data passing to multires-baker job */
81 struct MultiresBakeJob
{
84 /** Clear the images before baking */
86 /** Margin size in pixels. */
89 char bake_margin_type
;
90 /** mode of baking (displacement, normals, AO) */
92 /** Use low-resolution mesh when baking displacement maps */
94 /** Number of rays to be cast when doing AO baking */
96 /** Bias between object and start ray point when doing AO baking */
98 /** Number of threads to be used for baking */
100 /** User scale used to scale displacement when baking derivative map. */
104 static bool multiresbake_check(bContext
*C
, wmOperator
*op
)
106 using namespace blender
;
107 Scene
*scene
= CTX_data_scene(C
);
110 MultiresModifierData
*mmd
;
114 CTX_DATA_BEGIN (C
, Base
*, base
, selected_editable_bases
) {
117 if (ob
->type
!= OB_MESH
) {
119 op
->reports
, RPT_ERROR
, "Baking of multires data only works with an active mesh object");
125 mesh
= (Mesh
*)ob
->data
;
126 mmd
= get_multires_modifier(scene
, ob
, false);
128 /* Multi-resolution should be and be last in the stack */
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
)) {
145 BKE_report(op
->reports
, RPT_ERROR
, "Multires data baking requires multi-resolution object");
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");
156 const bke::AttributeAccessor attributes
= mesh
->attributes();
157 const VArraySpan material_indices
= *attributes
.lookup
<int>("material_index",
158 bke::AttrDomain::Face
);
161 Image
*ima
= bake_object_image_get(ob
,
162 material_indices
.is_empty() ? 0 : material_indices
[a
]);
166 op
->reports
, RPT_ERROR
, "You should have active texture to use multires baker");
171 LISTBASE_FOREACH (ImageTile
*, tile
, &ima
->tiles
) {
173 BKE_imageuser_default(&iuser
);
174 iuser
.tile
= tile
->tile_number
;
176 ImBuf
*ibuf
= BKE_image_acquire_ibuf(ima
, &iuser
, nullptr);
180 op
->reports
, RPT_ERROR
, "Baking should happen to image with image buffer");
185 if (ibuf
->byte_buffer
.data
== nullptr && ibuf
->float_buffer
.data
== nullptr) {
189 if (ibuf
->float_buffer
.data
&& !ELEM(ibuf
->channels
, 0, 4)) {
194 BKE_report(op
->reports
, RPT_ERROR
, "Baking to unsupported image type");
198 BKE_image_release_ibuf(ima
, ibuf
, nullptr);
213 static DerivedMesh
*multiresbake_create_loresdm(Scene
*scene
, Object
*ob
, int *lvl
)
216 MultiresModifierData
*mmd
= get_multires_modifier(scene
, ob
, false);
217 Mesh
*mesh
= (Mesh
*)ob
->data
;
218 MultiresModifierData tmp_mmd
= blender::dna::shallow_copy(*mmd
);
223 DerivedMesh
*cddm
= CDDM_from_mesh(mesh
);
224 DM_set_only_copy(cddm
, &CD_MASK_BAREMESH
);
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
);
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
);
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
);
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
);
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
) {
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
);
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
];
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
];
316 clear_single_image(image
, flag
);
320 for (int i
= 0; i
< ob_image_array_len
; i
++) {
321 Image
*image
= ob_image_array
[i
];
323 image
->id
.tag
&= ~LIB_TAG_DOIT
;
328 static int multiresbake_image_exec_locked(bContext
*C
, wmOperator
*op
)
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);
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
);
361 CTX_DATA_BEGIN (C
, Base
*, base
, selected_editable_bases
) {
362 MultiresBakeRender bkr
= {nullptr};
366 multires_flush_sculpt_updates(ob
);
368 /* copy data stored in job descriptor */
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
;
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
);
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
);
420 /* backup scene settings, so their changing in UI would take no effect on baker */
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
;
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
) {
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
);
455 BLI_addtail(&bkj
->data
, data
);
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
;
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
;
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
);
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
);
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
;
567 wmJob
*wm_job
= WM_jobs_get(CTX_wm_manager(C
),
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);
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
;
599 switch (event
->type
) {
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
;
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
);
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
)) {
637 result
= multiresbake_image_exec_locked(C
, op
);
639 WM_event_add_notifier(C
, NC_SCENE
| ND_RENDER_RESULT
, scene
);
644 void OBJECT_OT_bake_image(wmOperatorType
*ot
)
648 ot
->description
= "Bake image textures of selected objects";
649 ot
->idname
= "OBJECT_OT_bake_image";
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
;