Blender V4.3
object_bake_api.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2004 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "MEM_guardedalloc.h"
10
11#include "DNA_material_types.h"
12#include "DNA_mesh_types.h"
13#include "DNA_meshdata_types.h"
14#include "DNA_object_types.h"
15
16#include "RNA_access.hh"
17#include "RNA_define.hh"
18#include "RNA_enum_types.hh"
19
20#include "BLI_fileops.h"
21#include "BLI_listbase.h"
22#include "BLI_math_geom.h"
23#include "BLI_path_utils.hh"
24#include "BLI_string.h"
25
26#include "BLT_translation.hh"
27
28#include "BKE_attribute.hh"
29#include "BKE_callbacks.hh"
30#include "BKE_context.hh"
31#include "BKE_editmesh.hh"
32#include "BKE_global.hh"
33#include "BKE_image.hh"
34#include "BKE_image_format.hh"
35#include "BKE_layer.hh"
36#include "BKE_lib_id.hh"
37#include "BKE_main.hh"
38#include "BKE_material.h"
39#include "BKE_mesh.hh"
40#include "BKE_modifier.hh"
41#include "BKE_node.hh"
42#include "BKE_object.hh"
43#include "BKE_report.hh"
44#include "BKE_scene.hh"
45#include "BKE_screen.hh"
46
47#include "DEG_depsgraph.hh"
50
51#include "RE_engine.h"
52#include "RE_pipeline.h"
53
55#include "IMB_imbuf.hh"
56#include "IMB_imbuf_types.hh"
57
58#include "WM_api.hh"
59#include "WM_types.hh"
60
61#include "ED_mesh.hh"
62#include "ED_object.hh"
63#include "ED_screen.hh"
64#include "ED_uvedit.hh"
65
66#include "object_intern.hh"
67
68namespace blender::ed::object {
69
70/* prototypes */
71static void bake_set_props(wmOperator *op, Scene *scene);
72
74 /* Data to work on. */
80
81 /* Baking settings. */
83
86 int margin;
88
91 bool is_cage;
92
97
100
101 /* Settings for external image saving. */
106 int width;
108 const char *identifier;
109
110 /* Baking render session. */
112
113 /* Progress Callbacks. */
114 float *progress;
116
117 /* Operator state. */
121};
122
123/* callbacks */
124
125static void bake_progress_update(void *bjv, float progress)
126{
127 BakeAPIRender *bj = static_cast<BakeAPIRender *>(bjv);
128
129 if (bj->progress && *bj->progress != progress) {
130 *bj->progress = progress;
131
132 /* make jobs timer to send notifier */
133 *(bj->do_update) = true;
134 }
135}
136
138static int bake_modal(bContext *C, wmOperator * /*op*/, const wmEvent *event)
139{
140 /* no running blender, remove handler and pass through */
143 }
144
145 /* running render */
146 switch (event->type) {
147 case EVT_ESCKEY: {
148 G.is_break = true;
150 }
151 }
153}
154
159static bool bake_break(void * /*rjv*/)
160{
161 if (G.is_break) {
162 return true;
163 }
164 return false;
165}
166
167static void bake_update_image(ScrArea *area, Image *image)
168{
169 if (area && area->spacetype == SPACE_IMAGE) { /* in case the user changed while baking */
170 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
171 if (sima) {
172 sima->image = image;
173 }
174 }
175}
176
177/* Bias almost-flat normals in tangent space to be flat to avoid artifacts in byte textures.
178 * For some types of normal baking, especially bevels, you can end up with a small amount
179 * of noise in the result. Since the border between pixel value 127 and 128 is exactly 0.5,
180 * the tiniest amount of deviation will flip between those two, and increasing samples won't
181 * help - you always end up with visible "dents" in the resulting normal map.
182 * Therefore, this function snaps values that are less than half a quantization level away
183 * from 0.5 to 0.5, so that they consistently become pixel value 128.
184 * This only makes sense for byte textures of course, and is not used when baking to float
185 * textures (which includes 16-bit formats). Also, it's only applied to the first two channels,
186 * since on flat surfaces the Z channel will be close enough to 1.0 to reliably end up on 255.
187 */
189 float *rect, int channels, int width, int height, int stride)
190{
191 BLI_assert(channels >= 3);
192
193 for (int y = 0; y < height; y++) {
194 float *pixels = rect + size_t(stride) * y * channels;
195 for (int x = 0; x < width; x++, pixels += channels) {
196 if (fabsf(pixels[0] - 0.5f) < 1.0f / 255.0f) {
197 pixels[0] = 0.5f + 1e-5f;
198 }
199 if (fabsf(pixels[1] - 0.5f) < 1.0f / 255.0f) {
200 pixels[1] = 0.5f + 1e-5f;
201 }
202 }
203 }
204}
205
207 const int image_tile_number,
208 BakePixel pixel_array[],
209 float *buffer,
210 const int width,
211 const int height,
212 const int margin,
213 const char margin_type,
214 const bool is_clear,
215 const bool is_noncolor,
216 const bool is_tangent_normal,
217 Mesh const *mesh_eval,
218 char const *uv_layer,
219 const float uv_offset[2])
220{
221 ImBuf *ibuf;
222 void *lock;
223 bool is_float;
224 char *mask_buffer = nullptr;
225 const size_t pixels_num = size_t(width) * size_t(height);
226
227 ImageUser iuser;
228 BKE_imageuser_default(&iuser);
229 iuser.tile = image_tile_number;
230 ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
231
232 if (!ibuf) {
233 return false;
234 }
235
236 if (margin > 0 || !is_clear) {
237 mask_buffer = static_cast<char *>(MEM_callocN(sizeof(char) * pixels_num, "Bake Mask"));
238 RE_bake_mask_fill(pixel_array, pixels_num, mask_buffer);
239 }
240
241 is_float = (ibuf->float_buffer.data != nullptr);
242
243 /* colormanagement conversions */
244 if (!is_noncolor) {
245 const char *from_colorspace;
246 const char *to_colorspace;
247
249
250 if (is_float) {
251 to_colorspace = IMB_colormanagement_get_float_colorspace(ibuf);
252 }
253 else {
254 to_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf);
255 }
256
257 if (from_colorspace != to_colorspace) {
259 buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, false);
260 }
261 }
262 else if (!is_float && is_tangent_normal) {
263 /* bias neutral values when converting tangent-space normal maps to byte textures */
264 bias_tangent_normal_pixels(buffer, ibuf->channels, ibuf->x, ibuf->y, ibuf->x);
265 }
266
267 /* populates the ImBuf */
268 if (is_clear) {
269 if (is_float) {
271 buffer,
272 ibuf->channels,
275 false,
276 ibuf->x,
277 ibuf->y,
278 ibuf->x,
279 ibuf->x);
280 }
281 else {
283 buffer,
284 ibuf->channels,
285 ibuf->dither,
288 false,
289 ibuf->x,
290 ibuf->y,
291 ibuf->x,
292 ibuf->x);
293 }
294 }
295 else {
296 if (is_float) {
298 buffer,
299 ibuf->channels,
300 ibuf->x,
301 ibuf->y,
302 ibuf->x,
303 ibuf->x,
304 mask_buffer);
305 }
306 else {
308 buffer,
309 ibuf->channels,
310 ibuf->dither,
311 false,
312 ibuf->x,
313 ibuf->y,
314 ibuf->x,
315 ibuf->x,
316 mask_buffer);
317 }
318 }
319
320 /* margins */
321 if (margin > 0) {
322 RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh_eval, uv_layer, uv_offset);
323 }
324
326 BKE_image_mark_dirty(image, ibuf);
327
328 if (ibuf->float_buffer.data) {
329 ibuf->userflags |= IB_RECT_INVALID;
330 }
331
332 /* force mipmap recalc */
333 if (ibuf->mipmap[0]) {
336 }
337
338 BKE_image_release_ibuf(image, ibuf, nullptr);
339
340 if (mask_buffer) {
341 MEM_freeN(mask_buffer);
342 }
343
344 return true;
345}
346
347/* force OpenGL reload */
349{
350 for (int i = 0; i < targets->images_num; i++) {
351 Image *ima = targets->images[i].image;
352
353 if (ima) {
356 DEG_id_tag_update(&ima->id, 0);
357 }
358 }
359}
360
361static bool write_external_bake_pixels(const char *filepath,
362 BakePixel pixel_array[],
363 float *buffer,
364 const int width,
365 const int height,
366 const int margin,
367 const int margin_type,
368 ImageFormatData const *im_format,
369 const bool is_noncolor,
370 const bool is_tangent_normal,
371 Mesh const *mesh_eval,
372 char const *uv_layer,
373 const float uv_offset[2])
374{
375 ImBuf *ibuf = nullptr;
376 bool ok = false;
377 bool is_float;
378
379 is_float = im_format->depth > 8;
380
381 /* create a new ImBuf */
382 ibuf = IMB_allocImBuf(width, height, im_format->planes, (is_float ? IB_rectfloat : IB_rect));
383
384 if (!ibuf) {
385 return false;
386 }
387
388 /* populates the ImBuf */
389 if (is_float) {
391 buffer,
392 ibuf->channels,
395 false,
396 ibuf->x,
397 ibuf->y,
398 ibuf->x,
399 ibuf->x);
400 }
401 else {
402 if (!is_noncolor) {
403 const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(
405 const char *to_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf);
407 buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, false);
408 }
409 else if (is_tangent_normal) {
410 /* bias neutral values when converting tangent-space normal maps to byte textures */
411 bias_tangent_normal_pixels(buffer, ibuf->channels, ibuf->x, ibuf->y, ibuf->x);
412 }
413
415 buffer,
416 ibuf->channels,
417 ibuf->dither,
420 false,
421 ibuf->x,
422 ibuf->y,
423 ibuf->x,
424 ibuf->x);
425 }
426
427 /* margins */
428 if (margin > 0) {
429 char *mask_buffer = nullptr;
430 const size_t pixels_num = size_t(width) * size_t(height);
431
432 mask_buffer = static_cast<char *>(MEM_callocN(sizeof(char) * pixels_num, "Bake Mask"));
433 RE_bake_mask_fill(pixel_array, pixels_num, mask_buffer);
434 RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh_eval, uv_layer, uv_offset);
435
436 if (mask_buffer) {
437 MEM_freeN(mask_buffer);
438 }
439 }
440
441 if ((ok = BKE_imbuf_write(ibuf, filepath, im_format))) {
442#ifndef WIN32
443 chmod(filepath, S_IRUSR | S_IWUSR);
444#endif
445 // printf("%s saving bake map: '%s'\n", __func__, filepath);
446 }
447
448 /* garbage collection */
449 IMB_freeImBuf(ibuf);
450
451 return ok;
452}
453
454static bool is_noncolor_pass(eScenePassType pass_type)
455{
456 return ELEM(pass_type,
464}
465
466/* if all is good tag image and return true */
467static bool bake_object_check(const Scene *scene,
468 ViewLayer *view_layer,
469 Object *ob,
470 const eBakeTarget target,
471 ReportList *reports)
472{
473 BKE_view_layer_synced_ensure(scene, view_layer);
474 Base *base = BKE_view_layer_base_find(view_layer, ob);
475
476 if (base == nullptr) {
477 BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not in view layer", ob->id.name + 2);
478 return false;
479 }
480
481 if (!(base->flag & BASE_ENABLED_RENDER)) {
482 BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not enabled for rendering", ob->id.name + 2);
483 return false;
484 }
485
486 if (ob->type != OB_MESH) {
487 BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not a mesh", ob->id.name + 2);
488 return false;
489 }
490
491 Mesh *mesh = (Mesh *)ob->data;
492
493 if (mesh->faces_num == 0) {
494 BKE_reportf(reports, RPT_ERROR, "No faces found in the object \"%s\"", ob->id.name + 2);
495 return false;
496 }
497
498 if (target == R_BAKE_TARGET_VERTEX_COLORS) {
499 if (!BKE_id_attributes_color_find(&mesh->id, mesh->active_color_attribute)) {
500 BKE_reportf(reports,
501 RPT_ERROR,
502 "Mesh does not have an active color attribute \"%s\"",
503 mesh->id.name + 2);
504 return false;
505 }
506 }
507 else if (target == R_BAKE_TARGET_IMAGE_TEXTURES) {
508 if (CustomData_get_active_layer_index(&mesh->corner_data, CD_PROP_FLOAT2) == -1) {
510 reports, RPT_ERROR, "No active UV layer found in the object \"%s\"", ob->id.name + 2);
511 return false;
512 }
513
514 for (int i = 0; i < ob->totcol; i++) {
515 const bNodeTree *ntree = nullptr;
516 const bNode *node = nullptr;
517 const int mat_nr = i + 1;
518 Image *image;
519 ED_object_get_active_image(ob, mat_nr, &image, nullptr, &node, &ntree);
520
521 if (image) {
522
523 if (node) {
524 if (bke::node_is_connected_to_output(ntree, node)) {
525 /* we don't return false since this may be a false positive
526 * this can't be RPT_ERROR though, otherwise it prevents
527 * multiple highpoly objects to be baked at once */
528 BKE_reportf(reports,
529 RPT_INFO,
530 "Circular dependency for image \"%s\" from object \"%s\"",
531 image->id.name + 2,
532 ob->id.name + 2);
533 }
534 }
535
536 LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) {
537 ImageUser iuser;
538 BKE_imageuser_default(&iuser);
539 iuser.tile = tile->tile_number;
540
541 void *lock;
542 ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
543
544 if (ibuf) {
545 BKE_image_release_ibuf(image, ibuf, lock);
546 }
547 else {
548 BKE_reportf(reports,
549 RPT_ERROR,
550 "Uninitialized image \"%s\" from object \"%s\"",
551 image->id.name + 2,
552 ob->id.name + 2);
553
554 BKE_image_release_ibuf(image, ibuf, lock);
555 return false;
556 }
557 }
558 }
559 else {
560 Material *mat = BKE_object_material_get(ob, mat_nr);
561 if (mat != nullptr) {
562 BKE_reportf(reports,
563 RPT_INFO,
564 "No active image found in material \"%s\" (%d) for object \"%s\"",
565 mat->id.name + 2,
566 i,
567 ob->id.name + 2);
568 }
569 else {
570 BKE_reportf(reports,
571 RPT_INFO,
572 "No active image found in material slot (%d) for object \"%s\"",
573 i,
574 ob->id.name + 2);
575 }
576 continue;
577 }
578
579 image->id.tag |= ID_TAG_DOIT;
580 }
581 }
582
583 return true;
584}
585
587 const int pass_filter,
588 ReportList *reports)
589{
590 switch (pass_type) {
592 if ((pass_filter & R_BAKE_PASS_FILTER_EMIT) != 0) {
593 return true;
594 }
595
596 if (((pass_filter & R_BAKE_PASS_FILTER_DIRECT) != 0) ||
597 ((pass_filter & R_BAKE_PASS_FILTER_INDIRECT) != 0))
598 {
599 if (((pass_filter & R_BAKE_PASS_FILTER_DIFFUSE) != 0) ||
600 ((pass_filter & R_BAKE_PASS_FILTER_GLOSSY) != 0) ||
601 ((pass_filter & R_BAKE_PASS_FILTER_TRANSM) != 0) ||
602 ((pass_filter & R_BAKE_PASS_FILTER_SUBSURFACE) != 0))
603 {
604 return true;
605 }
606
607 BKE_report(reports,
608 RPT_ERROR,
609 "Combined bake pass requires Emit, or a light pass with "
610 "Direct or Indirect contributions enabled");
611
612 return false;
613 }
614 BKE_report(reports,
615 RPT_ERROR,
616 "Combined bake pass requires Emit, or a light pass with "
617 "Direct or Indirect contributions enabled");
618 return false;
623 if (((pass_filter & R_BAKE_PASS_FILTER_COLOR) != 0) ||
624 ((pass_filter & R_BAKE_PASS_FILTER_DIRECT) != 0) ||
625 ((pass_filter & R_BAKE_PASS_FILTER_INDIRECT) != 0))
626 {
627 return true;
628 }
629 else {
630 BKE_report(reports,
631 RPT_ERROR,
632 "Bake pass requires Direct, Indirect, or Color contributions to be enabled");
633 return false;
634 }
635 break;
636 default:
637 return true;
638 break;
639 }
640}
641
642/* before even getting in the bake function we check for some basic errors */
643static bool bake_objects_check(Main *bmain,
644 const Scene *scene,
645 ViewLayer *view_layer,
646 Object *ob,
647 Span<PointerRNA> selected_objects,
648 ReportList *reports,
649 const bool is_selected_to_active,
650 const eBakeTarget target)
651{
652 /* error handling and tag (in case multiple materials share the same image) */
654
655 if (is_selected_to_active) {
656 int tot_objects = 0;
657
658 if (!bake_object_check(scene, view_layer, ob, target, reports)) {
659 return false;
660 }
661
662 for (const PointerRNA &ptr : selected_objects) {
663 Object *ob_iter = (Object *)ptr.data;
664 if (ob_iter == ob) {
665 continue;
666 }
667
668 if (ELEM(ob_iter->type, OB_MESH, OB_FONT, OB_CURVES_LEGACY, OB_SURF, OB_MBALL) == false) {
669 BKE_reportf(reports,
670 RPT_ERROR,
671 "Object \"%s\" is not a mesh or can't be converted to a mesh (Curve, Text, "
672 "Surface or Metaball)",
673 ob_iter->id.name + 2);
674 return false;
675 }
676 tot_objects += 1;
677 }
678
679 if (tot_objects == 0) {
680 BKE_report(reports, RPT_ERROR, "No valid selected objects");
681 return false;
682 }
683 }
684 else {
685 if (selected_objects.is_empty()) {
686 BKE_report(reports, RPT_ERROR, "No valid selected objects");
687 return false;
688 }
689
690 for (const PointerRNA &ptr : selected_objects) {
691 if (!bake_object_check(scene, view_layer, static_cast<Object *>(ptr.data), target, reports))
692 {
693 return false;
694 }
695 }
696 }
697 return true;
698}
699
700/* it needs to be called after bake_objects_check since the image tagging happens there */
701static void bake_targets_clear(Main *bmain, const bool is_tangent)
702{
703 LISTBASE_FOREACH (Image *, image, &bmain->images) {
704 if ((image->id.tag & ID_TAG_DOIT) != 0) {
705 RE_bake_ibuf_clear(image, is_tangent);
706 }
707 }
708}
709
710/* create new mesh with edit mode changes and modifiers applied */
712 Object *object,
713 const bool preserve_origindex)
714{
715 Mesh *mesh = BKE_mesh_new_from_object(depsgraph, object, false, preserve_origindex);
716
717 if (mesh->normals_domain() == bke::MeshNormalDomain::Corner) {
719 }
720
721 return mesh;
722}
723
724/* Image Bake Targets */
725
727 BakeTargets *targets,
728 Object *ob,
729 ReportList *reports)
730{
731 int materials_num = ob->totcol;
732
733 if (materials_num == 0) {
734 if (bkr->save_mode == R_BAKE_SAVE_INTERNAL) {
736 reports, RPT_ERROR, "No active image found, add a material or bake to an external file");
737 return false;
738 }
739 if (bkr->is_split_materials) {
741 reports,
742 RPT_ERROR,
743 "No active image found, add a material or bake without the Split Materials option");
744 return false;
745 }
746 }
747
748 /* Allocate material mapping. */
749 targets->materials_num = materials_num;
750 targets->material_to_image = static_cast<Image **>(
751 MEM_callocN(sizeof(Image *) * targets->materials_num, __func__));
752
753 /* Error handling and tag (in case multiple materials share the same image). */
755
756 targets->images = nullptr;
757
758 for (int i = 0; i < materials_num; i++) {
759 Image *image;
760 ED_object_get_active_image(ob, i + 1, &image, nullptr, nullptr, nullptr);
761
762 targets->material_to_image[i] = image;
763
764 /* Some materials have no image, we just ignore those cases.
765 * Also setup each image only once. */
766 if (image && !(image->id.tag & ID_TAG_DOIT)) {
767 LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) {
768 /* Add bake image. */
769 targets->images = static_cast<BakeImage *>(
770 MEM_recallocN(targets->images, sizeof(BakeImage) * (targets->images_num + 1)));
771 targets->images[targets->images_num].image = image;
772 targets->images[targets->images_num].tile_number = tile->tile_number;
773 targets->images_num++;
774 }
775
776 image->id.tag |= ID_TAG_DOIT;
777 }
778 }
779
780 return true;
781}
782
784 BakeTargets *targets,
785 Object *ob,
786 ReportList *reports)
787{
788 if (!bake_targets_init_image_textures(bkr, targets, ob, reports)) {
789 return false;
790 }
791
792 /* Saving to image datablocks. */
793 for (int i = 0; i < targets->images_num; i++) {
794 BakeImage *bk_image = &targets->images[i];
795
796 ImageUser iuser;
797 BKE_imageuser_default(&iuser);
798 iuser.tile = bk_image->tile_number;
799
800 void *lock;
801 ImBuf *ibuf = BKE_image_acquire_ibuf(bk_image->image, &iuser, &lock);
802
803 if (ibuf) {
804 bk_image->width = ibuf->x;
805 bk_image->height = ibuf->y;
806 bk_image->offset = targets->pixels_num;
807 BKE_image_get_tile_uv(bk_image->image, bk_image->tile_number, bk_image->uv_offset);
808
809 targets->pixels_num += size_t(ibuf->x) * size_t(ibuf->y);
810 }
811 else {
812 BKE_image_release_ibuf(bk_image->image, ibuf, lock);
813 BKE_reportf(reports, RPT_ERROR, "Uninitialized image %s", bk_image->image->id.name + 2);
814 return false;
815 }
816 BKE_image_release_ibuf(bk_image->image, ibuf, lock);
817 }
818
819 return true;
820}
821
823 BakeTargets *targets,
824 Object *ob,
825 BakePixel *pixel_array,
826 ReportList *reports,
827 Mesh *mesh_eval)
828{
829 bool all_ok = true;
830 const bool is_tangent_normal = (bkr->pass_type == SCE_PASS_NORMAL) &&
832
833 for (int i = 0; i < targets->images_num; i++) {
834 BakeImage *bk_image = &targets->images[i];
835 const bool ok = write_internal_bake_pixels(bk_image->image,
836 bk_image->tile_number,
837 pixel_array + bk_image->offset,
838 targets->result +
839 bk_image->offset * targets->channels_num,
840 bk_image->width,
841 bk_image->height,
842 bkr->margin,
843 bkr->margin_type,
844 bkr->is_clear,
845 targets->is_noncolor,
846 is_tangent_normal,
847 mesh_eval,
848 bkr->uv_layer,
849 bk_image->uv_offset);
850
851 /* might be read by UI to set active image for display */
852 bake_update_image(bkr->area, bk_image->image);
853
854 if (!ok) {
855 BKE_reportf(reports,
856 RPT_ERROR,
857 "Problem saving the bake map internally for object \"%s\"",
858 ob->id.name + 2);
859 all_ok = false;
860 }
861 else {
863 reports, RPT_INFO, "Baking map saved to internal image, save it externally or pack it");
864 }
865 }
866
867 return all_ok;
868}
869
871 BakeTargets *targets,
872 Object *ob,
873 ReportList *reports)
874{
875 if (!bake_targets_init_image_textures(bkr, targets, ob, reports)) {
876 return false;
877 }
878
879 /* Saving to disk. */
880 for (int i = 0; i < targets->images_num; i++) {
881 BakeImage *bk_image = &targets->images[i];
882
883 bk_image->width = bkr->width;
884 bk_image->height = bkr->height;
885 bk_image->offset = targets->pixels_num;
886
887 targets->pixels_num += size_t(bkr->width) * size_t(bkr->height);
888
889 if (!bkr->is_split_materials) {
890 break;
891 }
892 }
893
894 if (!bkr->is_split_materials) {
895 /* saving a single image */
896 for (int i = 0; i < targets->materials_num; i++) {
897 targets->material_to_image[i] = targets->images[0].image;
898 }
899 }
900
901 return true;
902}
903
905 BakeTargets *targets,
906 Object *ob,
907 Object *ob_eval,
908 Mesh *mesh_eval,
909 BakePixel *pixel_array,
910 ReportList *reports)
911{
912 bool all_ok = true;
913 const bool is_tangent_normal = (bkr->pass_type == SCE_PASS_NORMAL) &&
915
916 for (int i = 0; i < targets->images_num; i++) {
917 BakeImage *bk_image = &targets->images[i];
918
919 BakeData *bake = &bkr->scene->r.bake;
920 char filepath[FILE_MAX];
921
923 bkr->filepath,
925 0,
926 bake->im_format.imtype,
927 true,
928 false,
929 nullptr);
930
931 if (bkr->is_automatic_name) {
932 BLI_path_suffix(filepath, FILE_MAX, ob->id.name + 2, "_");
933 BLI_path_suffix(filepath, FILE_MAX, bkr->identifier, "_");
934 }
935
936 if (bkr->is_split_materials) {
937 if (ob_eval->mat[i]) {
938 BLI_path_suffix(filepath, FILE_MAX, ob_eval->mat[i]->id.name + 2, "_");
939 }
940 else if (mesh_eval->mat[i]) {
941 BLI_path_suffix(filepath, FILE_MAX, mesh_eval->mat[i]->id.name + 2, "_");
942 }
943 else {
944 /* if everything else fails, use the material index */
945 char tmp[5];
946 SNPRINTF(tmp, "%d", i % 1000);
947 BLI_path_suffix(filepath, FILE_MAX, tmp, "_");
948 }
949 }
950
951 if (bk_image->tile_number) {
952 char tmp[12];
953 SNPRINTF(tmp, "%d", bk_image->tile_number);
954 BLI_path_suffix(filepath, FILE_MAX, tmp, "_");
955 }
956
957 /* save it externally */
958 const bool ok = write_external_bake_pixels(filepath,
959 pixel_array + bk_image->offset,
960 targets->result +
961 bk_image->offset * targets->channels_num,
962 bk_image->width,
963 bk_image->height,
964 bkr->margin,
965 bkr->margin_type,
966 &bake->im_format,
967 targets->is_noncolor,
968 is_tangent_normal,
969 mesh_eval,
970 bkr->uv_layer,
971 bk_image->uv_offset);
972
973 if (!ok) {
974 BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", filepath);
975 all_ok = false;
976 }
977 else {
978 BKE_reportf(reports, RPT_INFO, "Baking map written to \"%s\"", filepath);
979 }
980
981 if (!bkr->is_split_materials) {
982 break;
983 }
984 }
985
986 return all_ok;
987}
988
989/* Vertex Color Bake Targets */
990
992 BakeTargets *targets,
993 Object *ob,
994 ReportList *reports)
995{
996 if (ob->type != OB_MESH) {
997 BKE_report(reports, RPT_ERROR, "Color attribute baking is only supported for mesh objects");
998 return false;
999 }
1000
1001 Mesh *mesh = static_cast<Mesh *>(ob->data);
1002 if (!BKE_id_attributes_color_find(&mesh->id, mesh->active_color_attribute)) {
1003 BKE_report(reports, RPT_ERROR, "No active color attribute to bake to");
1004 return false;
1005 }
1006
1007 /* Ensure mesh and editmesh topology are in sync. */
1008 editmode_load(bmain, ob);
1009
1010 targets->images = MEM_cnew<BakeImage>(__func__);
1011 targets->images_num = 1;
1012
1013 targets->material_to_image = static_cast<Image **>(
1014 MEM_callocN(sizeof(Image *) * ob->totcol, __func__));
1015 targets->materials_num = ob->totcol;
1016
1017 BakeImage *bk_image = &targets->images[0];
1018 bk_image->width = mesh->corners_num;
1019 bk_image->height = 1;
1020 bk_image->offset = 0;
1021 bk_image->image = nullptr;
1022
1023 targets->pixels_num = bk_image->width * bk_image->height;
1024
1025 return true;
1026}
1027
1028static int find_original_loop(const OffsetIndices<int> orig_faces,
1029 const Span<int> orig_corner_verts,
1030 const int *vert_origindex,
1031 const int *poly_origindex,
1032 const int poly_eval,
1033 const int vert_eval)
1034{
1035 /* Get original vertex and face index. There is currently no loop mapping
1036 * in modifier stack evaluation. */
1037 const int vert_orig = vert_origindex[vert_eval];
1038 const int poly_orig_index = poly_origindex[poly_eval];
1039
1040 if (vert_orig == ORIGINDEX_NONE || poly_orig_index == ORIGINDEX_NONE) {
1041 return ORIGINDEX_NONE;
1042 }
1043
1044 /* Find matching loop with original vertex in original face. */
1045 const IndexRange orig_face = orig_faces[poly_orig_index];
1046 const int *poly_verts_orig = &orig_corner_verts[orig_face.start()];
1047 for (int j = 0; j < orig_face.size(); ++j) {
1048 if (poly_verts_orig[j] == vert_orig) {
1049 return orig_face.start() + j;
1050 }
1051 }
1052
1053 return ORIGINDEX_NONE;
1054}
1055
1057 Object *ob,
1058 Mesh *mesh_eval,
1059 BakePixel *pixel_array)
1060{
1061 Mesh *mesh = static_cast<Mesh *>(ob->data);
1062 const int pixels_num = targets->pixels_num;
1063
1064 /* Initialize blank pixels. */
1065 for (int i = 0; i < pixels_num; i++) {
1066 BakePixel *pixel = &pixel_array[i];
1067
1068 pixel->primitive_id = -1;
1069 pixel->object_id = 0;
1070 pixel->seed = 0;
1071 pixel->du_dx = 0.0f;
1072 pixel->du_dy = 0.0f;
1073 pixel->dv_dx = 0.0f;
1074 pixel->dv_dy = 0.0f;
1075 pixel->uv[0] = 0.0f;
1076 pixel->uv[1] = 0.0f;
1077 }
1078
1079 /* Populate through adjacent triangles, first triangle wins. */
1080 const int corner_tris_num = poly_to_tri_count(mesh_eval->faces_num, mesh_eval->corners_num);
1081 int3 *corner_tris = static_cast<int3 *>(
1082 MEM_mallocN(sizeof(*corner_tris) * corner_tris_num, __func__));
1083
1084 const Span<int> corner_verts = mesh_eval->corner_verts();
1085 bke::mesh::corner_tris_calc(mesh_eval->vert_positions(),
1086 mesh_eval->faces(),
1087 corner_verts,
1088 {corner_tris, corner_tris_num});
1089 const Span<int> tri_faces = mesh_eval->corner_tri_faces();
1090
1091 /* For mapping back to original mesh in case there are modifiers. */
1092 const int *vert_origindex = static_cast<const int *>(
1094 const int *poly_origindex = static_cast<const int *>(
1096 const OffsetIndices orig_faces = mesh->faces();
1097 const Span<int> orig_corner_verts = mesh->corner_verts();
1098
1099 for (int i = 0; i < corner_tris_num; i++) {
1100 const int3 &tri = corner_tris[i];
1101 const int face_i = tri_faces[i];
1102
1103 for (int j = 0; j < 3; j++) {
1104 uint l = tri[j];
1105 const int v = corner_verts[l];
1106
1107 /* Map back to original loop if there are modifiers. */
1108 if (vert_origindex != nullptr && poly_origindex != nullptr) {
1110 orig_faces, orig_corner_verts, vert_origindex, poly_origindex, face_i, v);
1111 if (l == ORIGINDEX_NONE || l >= mesh->corners_num) {
1112 continue;
1113 }
1114 }
1115
1116 BakePixel *pixel = &pixel_array[l];
1117
1118 if (pixel->primitive_id != -1) {
1119 continue;
1120 }
1121
1122 pixel->primitive_id = i;
1123
1124 /* Seed is the vertex, so that sampling noise is coherent for the same
1125 * vertex, but different corners can still have different normals,
1126 * materials and UVs. */
1127 pixel->seed = v;
1128
1129 /* Barycentric coordinates. */
1130 if (j == 0) {
1131 pixel->uv[0] = 1.0f;
1132 pixel->uv[1] = 0.0f;
1133 }
1134 else if (j == 1) {
1135 pixel->uv[0] = 0.0f;
1136 pixel->uv[1] = 1.0f;
1137 }
1138 else if (j == 2) {
1139 pixel->uv[0] = 0.0f;
1140 pixel->uv[1] = 0.0f;
1141 }
1142 }
1143 }
1144
1145 MEM_freeN(corner_tris);
1146}
1147
1148static void bake_result_add_to_rgba(float rgba[4], const float *result, const int channels_num)
1149{
1150 if (channels_num == 4) {
1151 add_v4_v4(rgba, result);
1152 }
1153 else if (channels_num == 3) {
1154 add_v3_v3(rgba, result);
1155 rgba[3] += 1.0f;
1156 }
1157 else {
1158 rgba[0] += result[0];
1159 rgba[1] += result[0];
1160 rgba[2] += result[0];
1161 rgba[3] += 1.0f;
1162 }
1163}
1164
1165static void convert_float_color_to_byte_color(const MPropCol *float_colors,
1166 const int num,
1167 const bool is_noncolor,
1168 MLoopCol *byte_colors)
1169{
1170 if (is_noncolor) {
1171 for (int i = 0; i < num; i++) {
1172 unit_float_to_uchar_clamp_v4(&byte_colors->r, float_colors[i].color);
1173 }
1174 }
1175 else {
1176 for (int i = 0; i < num; i++) {
1177 linearrgb_to_srgb_uchar4(&byte_colors[i].r, float_colors[i].color);
1178 }
1179 }
1180}
1181
1183{
1184 Mesh *mesh = static_cast<Mesh *>(ob->data);
1185 const CustomDataLayer *active_color_layer = BKE_id_attributes_color_find(
1186 &mesh->id, mesh->active_color_attribute);
1187 BLI_assert(active_color_layer != nullptr);
1188 AttributeOwner owner = AttributeOwner::from_id(&mesh->id);
1189 const bke::AttrDomain domain = BKE_attribute_domain(owner, active_color_layer);
1190
1191 const int channels_num = targets->channels_num;
1192 const bool is_noncolor = targets->is_noncolor;
1193 const float *result = targets->result;
1194
1195 if (domain == bke::AttrDomain::Point) {
1196 const int totvert = mesh->verts_num;
1197 const int totloop = mesh->corners_num;
1198
1199 MPropCol *mcol = static_cast<MPropCol *>(
1200 MEM_malloc_arrayN(totvert, sizeof(MPropCol), __func__));
1201
1202 /* Accumulate float vertex colors in scene linear color space. */
1203 int *num_loops_for_vertex = static_cast<int *>(
1204 MEM_callocN(sizeof(int) * mesh->verts_num, "num_loops_for_vertex"));
1205 memset(mcol, 0, sizeof(MPropCol) * mesh->verts_num);
1206
1207 const Span<int> corner_verts = mesh->corner_verts();
1208 for (int i = 0; i < totloop; i++) {
1209 const int v = corner_verts[i];
1210 bake_result_add_to_rgba(mcol[v].color, &result[i * channels_num], channels_num);
1211 num_loops_for_vertex[v]++;
1212 }
1213
1214 /* Normalize for number of loops. */
1215 for (int i = 0; i < totvert; i++) {
1216 if (num_loops_for_vertex[i] > 0) {
1217 mul_v4_fl(mcol[i].color, 1.0f / num_loops_for_vertex[i]);
1218 }
1219 }
1220
1221 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
1222 /* Copy to bmesh. */
1223 const int active_color_offset = CustomData_get_offset_named(
1224 &em->bm->vdata, eCustomDataType(active_color_layer->type), active_color_layer->name);
1225 BMVert *v;
1226 BMIter viter;
1227 int i = 0;
1228 BM_ITER_MESH (v, &viter, em->bm, BM_VERTS_OF_MESH) {
1229 void *data = BM_ELEM_CD_GET_VOID_P(v, active_color_offset);
1230 if (active_color_layer->type == CD_PROP_COLOR) {
1231 memcpy(data, &mcol[i], sizeof(MPropCol));
1232 }
1233 else {
1235 &mcol[i], 1, is_noncolor, static_cast<MLoopCol *>(data));
1236 }
1237 i++;
1238 }
1239 }
1240 else {
1241 /* Copy to mesh. */
1242 if (active_color_layer->type == CD_PROP_COLOR) {
1243 memcpy(active_color_layer->data, mcol, sizeof(MPropCol) * mesh->verts_num);
1244 }
1245 else {
1247 mcol, totvert, is_noncolor, static_cast<MLoopCol *>(active_color_layer->data));
1248 }
1249 }
1250
1251 MEM_freeN(mcol);
1252
1253 MEM_SAFE_FREE(num_loops_for_vertex);
1254 }
1255 else if (domain == bke::AttrDomain::Corner) {
1256 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
1257 /* Copy to bmesh. */
1258 const int active_color_offset = CustomData_get_offset_named(
1259 &em->bm->ldata, eCustomDataType(active_color_layer->type), active_color_layer->name);
1260 BMFace *f;
1261 BMIter fiter;
1262 int i = 0;
1263 BM_ITER_MESH (f, &fiter, em->bm, BM_FACES_OF_MESH) {
1264 BMLoop *l;
1265 BMIter liter;
1266 BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
1267 MPropCol color;
1268 zero_v4(color.color);
1269 bake_result_add_to_rgba(color.color, &result[i * channels_num], channels_num);
1270 i++;
1271
1272 void *data = BM_ELEM_CD_GET_VOID_P(l, active_color_offset);
1273 if (active_color_layer->type == CD_PROP_COLOR) {
1274 memcpy(data, &color, sizeof(MPropCol));
1275 }
1276 else {
1278 &color, 1, is_noncolor, static_cast<MLoopCol *>(data));
1279 }
1280 }
1281 }
1282 }
1283 else {
1284 /* Copy to mesh. */
1285 if (active_color_layer->type == CD_PROP_COLOR) {
1286 MPropCol *colors = static_cast<MPropCol *>(active_color_layer->data);
1287 for (int i = 0; i < mesh->corners_num; i++) {
1288 zero_v4(colors[i].color);
1289 bake_result_add_to_rgba(colors[i].color, &result[i * channels_num], channels_num);
1290 }
1291 }
1292 else {
1293 MLoopCol *colors = static_cast<MLoopCol *>(active_color_layer->data);
1294 for (int i = 0; i < mesh->corners_num; i++) {
1295 MPropCol color;
1296 zero_v4(color.color);
1297 bake_result_add_to_rgba(color.color, &result[i * channels_num], channels_num);
1298 convert_float_color_to_byte_color(&color, 1, is_noncolor, &colors[i]);
1299 }
1300 }
1301 }
1302 }
1303
1305
1306 return true;
1307}
1308
1309/* Bake Targets */
1310
1311static bool bake_targets_init(const BakeAPIRender *bkr,
1312 BakeTargets *targets,
1313 Object *ob,
1314 Object *ob_eval,
1315 ReportList *reports)
1316{
1318 if (bkr->save_mode == R_BAKE_SAVE_INTERNAL) {
1319 if (!bake_targets_init_internal(bkr, targets, ob_eval, reports)) {
1320 return false;
1321 }
1322 }
1323 else if (bkr->save_mode == R_BAKE_SAVE_EXTERNAL) {
1324 if (!bake_targets_init_external(bkr, targets, ob_eval, reports)) {
1325 return false;
1326 }
1327 }
1328 }
1329 else if (bkr->target == R_BAKE_TARGET_VERTEX_COLORS) {
1330 if (!bake_targets_init_vertex_colors(bkr->main, targets, ob, reports)) {
1331 return false;
1332 }
1333 }
1334
1335 if (targets->pixels_num == 0) {
1336 return false;
1337 }
1338
1339 targets->is_noncolor = is_noncolor_pass(bkr->pass_type);
1340 targets->channels_num = RE_pass_depth(bkr->pass_type);
1341 targets->result = static_cast<float *>(MEM_callocN(
1342 sizeof(float) * targets->channels_num * targets->pixels_num, "bake return pixels"));
1343
1344 return true;
1345}
1346
1348 BakeTargets *targets,
1349 Object *ob,
1350 Mesh *mesh_eval,
1351 BakePixel *pixel_array)
1352{
1353 if (bkr->target == R_BAKE_TARGET_VERTEX_COLORS) {
1354 bake_targets_populate_pixels_color_attributes(targets, ob, mesh_eval, pixel_array);
1355 }
1356 else {
1357 RE_bake_pixels_populate(mesh_eval, pixel_array, targets->pixels_num, targets, bkr->uv_layer);
1358 }
1359}
1360
1361static bool bake_targets_output(const BakeAPIRender *bkr,
1362 BakeTargets *targets,
1363 Object *ob,
1364 Object *ob_eval,
1365 Mesh *mesh_eval,
1366 BakePixel *pixel_array,
1367 ReportList *reports)
1368{
1370 if (bkr->save_mode == R_BAKE_SAVE_INTERNAL) {
1371 return bake_targets_output_internal(bkr, targets, ob, pixel_array, reports, mesh_eval);
1372 }
1373 if (bkr->save_mode == R_BAKE_SAVE_EXTERNAL) {
1375 bkr, targets, ob, ob_eval, mesh_eval, pixel_array, reports);
1376 }
1377 }
1378 else if (bkr->target == R_BAKE_TARGET_VERTEX_COLORS) {
1379 return bake_targets_output_vertex_colors(targets, ob);
1380 }
1381
1382 return false;
1383}
1384
1385static void bake_targets_free(BakeTargets *targets)
1386{
1387 MEM_SAFE_FREE(targets->images);
1389 MEM_SAFE_FREE(targets->result);
1390}
1391
1392/* Main Bake Logic */
1393
1394static int bake(const BakeAPIRender *bkr,
1395 Object *ob_low,
1396 const Span<PointerRNA> selected_objects,
1397 ReportList *reports)
1398{
1399 Render *re = bkr->render;
1400 Main *bmain = bkr->main;
1401 Scene *scene = bkr->scene;
1402 ViewLayer *view_layer = bkr->view_layer;
1403
1404 /* We build a depsgraph for the baking,
1405 * so we don't need to change the original data to adjust visibility and modifiers. */
1406 Depsgraph *depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
1408
1409 int op_result = OPERATOR_CANCELLED;
1410 bool ok = false;
1411
1412 Object *ob_cage = nullptr;
1413 Object *ob_cage_eval = nullptr;
1414 Object *ob_low_eval = nullptr;
1415
1416 BakeHighPolyData *highpoly = nullptr;
1417 int tot_highpoly = 0;
1418
1419 Mesh *me_low_eval = nullptr;
1420 Mesh *me_cage_eval = nullptr;
1421
1422 MultiresModifierData *mmd_low = nullptr;
1423 int mmd_flags_low = 0;
1424
1425 BakePixel *pixel_array_low = nullptr;
1426 BakePixel *pixel_array_high = nullptr;
1427
1428 BakeTargets targets = {nullptr};
1429
1430 const bool preserve_origindex = (bkr->target == R_BAKE_TARGET_VERTEX_COLORS);
1431
1432 RE_bake_engine_set_engine_parameters(re, bmain, scene);
1433
1434 if (!RE_bake_has_engine(re)) {
1435 BKE_report(reports, RPT_ERROR, "Current render engine does not support baking");
1436 goto cleanup;
1437 }
1438
1439 if (bkr->uv_layer[0] != '\0') {
1440 Mesh *mesh = (Mesh *)ob_low->data;
1441 if (CustomData_get_named_layer(&mesh->corner_data, CD_PROP_FLOAT2, bkr->uv_layer) == -1) {
1442 BKE_reportf(reports,
1443 RPT_ERROR,
1444 "No UV layer named \"%s\" found in the object \"%s\"",
1445 bkr->uv_layer,
1446 ob_low->id.name + 2);
1447 goto cleanup;
1448 }
1449 }
1450
1451 if (bkr->is_selected_to_active) {
1452 tot_highpoly = 0;
1453
1454 for (const PointerRNA &ptr : selected_objects) {
1455 Object *ob_iter = static_cast<Object *>(ptr.data);
1456
1457 if (ob_iter == ob_low) {
1458 continue;
1459 }
1460
1461 tot_highpoly++;
1462 }
1463
1464 if (bkr->is_cage && bkr->custom_cage[0] != '\0') {
1465 ob_cage = static_cast<Object *>(
1466 BLI_findstring(&bmain->objects, bkr->custom_cage, offsetof(ID, name) + 2));
1467
1468 if (ob_cage == nullptr || ob_cage->type != OB_MESH) {
1469 BKE_report(reports, RPT_ERROR, "No valid cage object");
1470 goto cleanup;
1471 }
1472 else {
1473 ob_cage_eval = DEG_get_evaluated_object(depsgraph, ob_cage);
1474 ob_cage_eval->visibility_flag |= OB_HIDE_RENDER;
1477 }
1478 }
1479 }
1480
1481 /* for multires bake, use linear UV subdivision to match low res UVs */
1484 {
1486 if (mmd_low) {
1487 mmd_flags_low = mmd_low->flags;
1489 }
1490 }
1491
1492 /* Make sure depsgraph is up to date. */
1494 ob_low_eval = DEG_get_evaluated_object(depsgraph, ob_low);
1495
1496 /* get the mesh as it arrives in the renderer */
1497 me_low_eval = bake_mesh_new_from_object(depsgraph, ob_low_eval, preserve_origindex);
1498
1499 /* Initialize bake targets. */
1500 if (!bake_targets_init(bkr, &targets, ob_low, ob_low_eval, reports)) {
1501 goto cleanup;
1502 }
1503
1504 /* Populate the pixel array with the face data. Except if we use a cage, then
1505 * it is populated later with the cage mesh (smoothed version of the mesh). */
1506 pixel_array_low = static_cast<BakePixel *>(
1507 MEM_mallocN(sizeof(BakePixel) * targets.pixels_num, "bake pixels low poly"));
1508 if ((bkr->is_selected_to_active && (ob_cage == nullptr) && bkr->is_cage) == false) {
1509 bake_targets_populate_pixels(bkr, &targets, ob_low, me_low_eval, pixel_array_low);
1510 }
1511
1512 if (bkr->is_selected_to_active) {
1513 int i = 0;
1514
1515 /* prepare cage mesh */
1516 if (ob_cage) {
1517 me_cage_eval = bake_mesh_new_from_object(depsgraph, ob_cage_eval, preserve_origindex);
1518 if ((me_low_eval->faces_num != me_cage_eval->faces_num) ||
1519 (me_low_eval->corners_num != me_cage_eval->corners_num))
1520 {
1521 BKE_report(reports,
1522 RPT_ERROR,
1523 "Invalid cage object, the cage mesh must have the same number "
1524 "of faces as the active object");
1525 goto cleanup;
1526 }
1527 }
1528 else if (bkr->is_cage) {
1529 bool is_changed = false;
1530
1531 ModifierData *md = static_cast<ModifierData *>(ob_low_eval->modifiers.first);
1532 while (md) {
1533 ModifierData *md_next = md->next;
1534
1535 /* Edge Split cannot be applied in the cage,
1536 * the cage is supposed to have interpolated normals
1537 * between the faces unless the geometry is physically
1538 * split. So we create a copy of the low poly mesh without
1539 * the eventual edge split. */
1540
1541 if (md->type == eModifierType_EdgeSplit) {
1542 BLI_remlink(&ob_low_eval->modifiers, md);
1544 is_changed = true;
1545 }
1546 md = md_next;
1547 }
1548
1549 if (is_changed) {
1550 /* Make sure object is evaluated with the new modifier settings.
1551 *
1552 * NOTE: Since the dependency graph was fully evaluated prior to bake, and we only made
1553 * single modification to this object all the possible dependencies for evaluation are
1554 * already up to date. This means we can do a cheap single object update
1555 * (as an opposite of full depsgraph update). */
1556 BKE_object_eval_reset(ob_low_eval);
1557 BKE_object_handle_data_update(depsgraph, scene, ob_low_eval);
1558 }
1559
1560 me_cage_eval = BKE_mesh_new_from_object(nullptr, ob_low_eval, false, preserve_origindex);
1561 bake_targets_populate_pixels(bkr, &targets, ob_low, me_cage_eval, pixel_array_low);
1562 }
1563
1564 highpoly = static_cast<BakeHighPolyData *>(
1565 MEM_callocN(sizeof(BakeHighPolyData) * tot_highpoly, "bake high poly objects"));
1566
1567 /* populate highpoly array */
1568 for (const PointerRNA &ptr : selected_objects) {
1569 Object *ob_iter = static_cast<Object *>(ptr.data);
1570
1571 if (ob_iter == ob_low) {
1572 continue;
1573 }
1574
1575 /* initialize highpoly_data */
1576 highpoly[i].ob = ob_iter;
1577 highpoly[i].ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter);
1578 highpoly[i].ob_eval->visibility_flag &= ~OB_HIDE_RENDER;
1581 highpoly[i].mesh = BKE_mesh_new_from_object(nullptr, highpoly[i].ob_eval, false, false);
1582
1583 /* Low-poly to high-poly transformation matrix. */
1584 copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->object_to_world().ptr());
1585 invert_m4_m4(highpoly[i].imat, highpoly[i].obmat);
1586
1587 highpoly[i].is_flip_object = is_negative_m4(highpoly[i].ob->object_to_world().ptr());
1588
1589 i++;
1590 }
1591
1592 BLI_assert(i == tot_highpoly);
1593
1594 if (ob_cage != nullptr) {
1595 ob_cage_eval->visibility_flag |= OB_HIDE_RENDER;
1598 }
1599 ob_low_eval->visibility_flag |= OB_HIDE_RENDER;
1601
1602 /* populate the pixel arrays with the corresponding face data for each high poly object */
1603 pixel_array_high = static_cast<BakePixel *>(
1604 MEM_mallocN(sizeof(BakePixel) * targets.pixels_num, "bake pixels high poly"));
1605
1607 me_low_eval,
1608 pixel_array_low,
1609 pixel_array_high,
1610 highpoly,
1611 tot_highpoly,
1612 targets.pixels_num,
1613 ob_cage != nullptr,
1614 bkr->cage_extrusion,
1615 bkr->max_ray_distance,
1616 ob_low_eval->object_to_world().ptr(),
1617 (ob_cage ? ob_cage->object_to_world().ptr() : ob_low_eval->object_to_world().ptr()),
1618 me_cage_eval))
1619 {
1620 BKE_report(reports, RPT_ERROR, "Error handling selected objects");
1621 goto cleanup;
1622 }
1623
1624 /* the baking itself */
1625 for (i = 0; i < tot_highpoly; i++) {
1626 ok = RE_bake_engine(re,
1627 depsgraph,
1628 highpoly[i].ob,
1629 i,
1630 pixel_array_high,
1631 &targets,
1632 bkr->pass_type,
1633 bkr->pass_filter,
1634 targets.result);
1635 if (!ok) {
1637 reports, RPT_ERROR, "Error baking from object \"%s\"", highpoly[i].ob->id.name + 2);
1638 goto cleanup;
1639 }
1640 }
1641 }
1642 else {
1643 /* If low poly is not renderable it should have failed long ago. */
1644 BLI_assert((ob_low_eval->visibility_flag & OB_HIDE_RENDER) == 0);
1645
1646 if (RE_bake_has_engine(re)) {
1647 ok = RE_bake_engine(re,
1648 depsgraph,
1649 ob_low_eval,
1650 0,
1651 pixel_array_low,
1652 &targets,
1653 bkr->pass_type,
1654 bkr->pass_filter,
1655 targets.result);
1656 }
1657 else {
1658 BKE_report(reports, RPT_ERROR, "Current render engine does not support baking");
1659 goto cleanup;
1660 }
1661 }
1662
1663 /* normal space conversion
1664 * the normals are expected to be in world space, +X +Y +Z */
1665 if (ok && bkr->pass_type == SCE_PASS_NORMAL) {
1666 switch (bkr->normal_space) {
1667 case R_BAKE_SPACE_WORLD: {
1668 /* Cycles internal format */
1669 if ((bkr->normal_swizzle[0] == R_BAKE_POSX) && (bkr->normal_swizzle[1] == R_BAKE_POSY) &&
1670 (bkr->normal_swizzle[2] == R_BAKE_POSZ))
1671 {
1672 break;
1673 }
1674 RE_bake_normal_world_to_world(pixel_array_low,
1675 targets.pixels_num,
1676 targets.channels_num,
1677 targets.result,
1678 bkr->normal_swizzle);
1679 break;
1680 }
1681 case R_BAKE_SPACE_OBJECT: {
1682 RE_bake_normal_world_to_object(pixel_array_low,
1683 targets.pixels_num,
1684 targets.channels_num,
1685 targets.result,
1686 ob_low_eval,
1687 bkr->normal_swizzle);
1688 break;
1689 }
1690 case R_BAKE_SPACE_TANGENT: {
1691 if (bkr->is_selected_to_active) {
1692 RE_bake_normal_world_to_tangent(pixel_array_low,
1693 targets.pixels_num,
1694 targets.channels_num,
1695 targets.result,
1696 me_low_eval,
1697 bkr->normal_swizzle,
1698 ob_low_eval->object_to_world().ptr());
1699 }
1700 else {
1701 /* From multi-resolution. */
1702 Mesh *me_nores = nullptr;
1703 ModifierData *md = nullptr;
1704 int mode;
1705
1706 BKE_object_eval_reset(ob_low_eval);
1708
1709 if (md) {
1710 mode = md->mode;
1711 md->mode &= ~eModifierMode_Render;
1712
1713 /* Evaluate modifiers again. */
1714 me_nores = BKE_mesh_new_from_object(nullptr, ob_low_eval, false, false);
1715 bake_targets_populate_pixels(bkr, &targets, ob_low, me_nores, pixel_array_low);
1716 }
1717
1718 RE_bake_normal_world_to_tangent(pixel_array_low,
1719 targets.pixels_num,
1720 targets.channels_num,
1721 targets.result,
1722 (me_nores) ? me_nores : me_low_eval,
1723 bkr->normal_swizzle,
1724 ob_low_eval->object_to_world().ptr());
1725
1726 if (md) {
1727 BKE_id_free(nullptr, &me_nores->id);
1728 md->mode = mode;
1729 }
1730 }
1731 break;
1732 }
1733 default:
1734 break;
1735 }
1736 }
1737
1738 if (!ok) {
1739 BKE_reportf(reports, RPT_ERROR, "Problem baking object \"%s\"", ob_low->id.name + 2);
1740 op_result = OPERATOR_CANCELLED;
1741 }
1742 else {
1743 /* save the results */
1745 bkr, &targets, ob_low, ob_low_eval, me_low_eval, pixel_array_low, reports))
1746 {
1747 op_result = OPERATOR_FINISHED;
1748 }
1749 else {
1750 op_result = OPERATOR_CANCELLED;
1751 }
1752 }
1753
1754 bake_targets_refresh(&targets);
1755
1756cleanup:
1757
1758 if (highpoly) {
1759 for (int i = 0; i < tot_highpoly; i++) {
1760 if (highpoly[i].mesh != nullptr) {
1761 BKE_id_free(nullptr, &highpoly[i].mesh->id);
1762 }
1763 }
1764 MEM_freeN(highpoly);
1765 }
1766
1767 if (mmd_low) {
1768 mmd_low->flags = mmd_flags_low;
1769 }
1770
1771 if (pixel_array_low) {
1772 MEM_freeN(pixel_array_low);
1773 }
1774
1775 if (pixel_array_high) {
1776 MEM_freeN(pixel_array_high);
1777 }
1778
1779 bake_targets_free(&targets);
1780
1781 if (me_low_eval != nullptr) {
1782 BKE_id_free(nullptr, &me_low_eval->id);
1783 }
1784
1785 if (me_cage_eval != nullptr) {
1786 BKE_id_free(nullptr, &me_cage_eval->id);
1787 }
1788
1790
1791 return op_result;
1792}
1793
1794/* Bake Operator */
1795
1797{
1798 bScreen *screen = CTX_wm_screen(C);
1799
1800 bkr->ob = CTX_data_active_object(C);
1801 bkr->main = CTX_data_main(C);
1803 bkr->scene = CTX_data_scene(C);
1804 bkr->area = screen ? BKE_screen_find_big_area(screen, SPACE_IMAGE, 10) : nullptr;
1805
1806 bkr->pass_type = eScenePassType(RNA_enum_get(op->ptr, "type"));
1807 bkr->pass_filter = RNA_enum_get(op->ptr, "pass_filter");
1808 bkr->margin = RNA_int_get(op->ptr, "margin");
1809 bkr->margin_type = eBakeMarginType(RNA_enum_get(op->ptr, "margin_type"));
1810
1811 bkr->save_mode = (eBakeSaveMode)RNA_enum_get(op->ptr, "save_mode");
1812 bkr->target = (eBakeTarget)RNA_enum_get(op->ptr, "target");
1813
1814 bkr->is_clear = RNA_boolean_get(op->ptr, "use_clear");
1817 RNA_boolean_get(op->ptr, "use_split_materials");
1818 bkr->is_automatic_name = RNA_boolean_get(op->ptr, "use_automatic_name");
1819 bkr->is_selected_to_active = RNA_boolean_get(op->ptr, "use_selected_to_active");
1820 bkr->is_cage = RNA_boolean_get(op->ptr, "use_cage");
1821 bkr->cage_extrusion = RNA_float_get(op->ptr, "cage_extrusion");
1822 bkr->max_ray_distance = RNA_float_get(op->ptr, "max_ray_distance");
1823
1824 bkr->normal_space = RNA_enum_get(op->ptr, "normal_space");
1825 bkr->normal_swizzle[0] = eBakeNormalSwizzle(RNA_enum_get(op->ptr, "normal_r"));
1826 bkr->normal_swizzle[1] = eBakeNormalSwizzle(RNA_enum_get(op->ptr, "normal_g"));
1827 bkr->normal_swizzle[2] = eBakeNormalSwizzle(RNA_enum_get(op->ptr, "normal_b"));
1828
1829 bkr->width = RNA_int_get(op->ptr, "width");
1830 bkr->height = RNA_int_get(op->ptr, "height");
1831 bkr->identifier = "";
1832
1833 RNA_string_get(op->ptr, "uv_layer", bkr->uv_layer);
1834
1835 RNA_string_get(op->ptr, "cage_object", bkr->custom_cage);
1836
1837 if (bkr->save_mode == R_BAKE_SAVE_EXTERNAL && bkr->is_automatic_name) {
1838 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "type");
1839 RNA_property_enum_identifier(C, op->ptr, prop, bkr->pass_type, &bkr->identifier);
1840 }
1841
1843
1844 bkr->reports = op->reports;
1845
1847
1848 bkr->render = RE_NewSceneRender(bkr->scene);
1849
1850 /* XXX hack to force saving to always be internal. Whether (and how) to support
1851 * external saving will be addressed later */
1852 if (bkr->save_mode == R_BAKE_SAVE_EXTERNAL) {
1854 }
1855
1856 if (((bkr->pass_type == SCE_PASS_NORMAL) && (bkr->normal_space == R_BAKE_SPACE_TANGENT)) ||
1857 bkr->pass_type == SCE_PASS_UV)
1858 {
1860 }
1861}
1862
1863static int bake_exec(bContext *C, wmOperator *op)
1864{
1865 Render *re;
1866 int result = OPERATOR_CANCELLED;
1867 BakeAPIRender bkr = {nullptr};
1868 Scene *scene = CTX_data_scene(C);
1869
1870 G.is_break = false;
1871 G.is_rendering = true;
1872
1873 bake_set_props(op, scene);
1874
1875 bake_init_api_data(op, C, &bkr);
1876 re = bkr.render;
1877
1878 /* setup new render */
1879 RE_test_break_cb(re, nullptr, bake_break);
1880
1882 G.is_rendering = false;
1883 return result;
1884 }
1885
1886 if (!bake_objects_check(bkr.main,
1887 bkr.scene,
1888 bkr.view_layer,
1889 bkr.ob,
1890 bkr.selected_objects,
1891 bkr.reports,
1893 bkr.target))
1894 {
1895 G.is_rendering = false;
1896 return result;
1897 }
1898
1899 if (bkr.is_clear) {
1900 const bool is_tangent = ((bkr.pass_type == SCE_PASS_NORMAL) &&
1902 bake_targets_clear(bkr.main, is_tangent);
1903 }
1904
1905 RE_SetReports(re, bkr.reports);
1906
1907 if (bkr.is_selected_to_active) {
1908 result = bake(&bkr, bkr.ob, bkr.selected_objects, bkr.reports);
1909 }
1910 else {
1911 bkr.is_clear = bkr.is_clear && bkr.selected_objects.size() == 1;
1912 for (const PointerRNA &ptr : bkr.selected_objects) {
1913 Object *ob_iter = static_cast<Object *>(ptr.data);
1914 result = bake(&bkr, ob_iter, {}, bkr.reports);
1915 }
1916 }
1917
1918 RE_SetReports(re, nullptr);
1919
1920 G.is_rendering = false;
1921 return result;
1922}
1923
1924static void bake_startjob(void *bkv, wmJobWorkerStatus *worker_status)
1925{
1926 BakeAPIRender *bkr = (BakeAPIRender *)bkv;
1927
1928 /* setup new render */
1929 bkr->do_update = &worker_status->do_update;
1930 bkr->progress = &worker_status->progress;
1931
1932 RE_SetReports(bkr->render, bkr->reports);
1933
1934 if (!bake_pass_filter_check(bkr->pass_type, bkr->pass_filter, bkr->reports)) {
1936 return;
1937 }
1938
1939 if (!bake_objects_check(bkr->main,
1940 bkr->scene,
1941 bkr->view_layer,
1942 bkr->ob,
1943 bkr->selected_objects,
1944 bkr->reports,
1946 bkr->target))
1947 {
1949 return;
1950 }
1951
1952 if (bkr->is_clear) {
1953 const bool is_tangent = ((bkr->pass_type == SCE_PASS_NORMAL) &&
1955 bake_targets_clear(bkr->main, is_tangent);
1956 }
1957
1958 if (bkr->is_selected_to_active) {
1959 bkr->result = bake(bkr, bkr->ob, bkr->selected_objects, bkr->reports);
1960 }
1961 else {
1962 bkr->is_clear = bkr->is_clear && bkr->selected_objects.size() == 1;
1963 for (const PointerRNA &ptr : bkr->selected_objects) {
1964 Object *ob_iter = static_cast<Object *>(ptr.data);
1965 bkr->result = bake(bkr, ob_iter, {}, bkr->reports);
1966
1967 if (bkr->result == OPERATOR_CANCELLED) {
1968 return;
1969 }
1970 }
1971 }
1972
1973 RE_SetReports(bkr->render, nullptr);
1974}
1975
1976static void bake_job_complete(void *bkv)
1977{
1978 BakeAPIRender *bkr = (BakeAPIRender *)bkv;
1980}
1981static void bake_job_canceled(void *bkv)
1982{
1983 BakeAPIRender *bkr = (BakeAPIRender *)bkv;
1985}
1986
1987static void bake_freejob(void *bkv)
1988{
1989 BakeAPIRender *bkr = (BakeAPIRender *)bkv;
1990
1991 MEM_delete(bkr);
1992
1993 G.is_rendering = false;
1994}
1995
1996static void bake_set_props(wmOperator *op, Scene *scene)
1997{
1998 PropertyRNA *prop;
1999 BakeData *bake = &scene->r.bake;
2000
2001 prop = RNA_struct_find_property(op->ptr, "filepath");
2002 if (!RNA_property_is_set(op->ptr, prop)) {
2003 RNA_property_string_set(op->ptr, prop, bake->filepath);
2004 }
2005
2006 prop = RNA_struct_find_property(op->ptr, "width");
2007 if (!RNA_property_is_set(op->ptr, prop)) {
2008 RNA_property_int_set(op->ptr, prop, bake->width);
2009 }
2010
2011 prop = RNA_struct_find_property(op->ptr, "height");
2012 if (!RNA_property_is_set(op->ptr, prop)) {
2013 RNA_property_int_set(op->ptr, prop, bake->width);
2014 }
2015
2016 prop = RNA_struct_find_property(op->ptr, "margin");
2017 if (!RNA_property_is_set(op->ptr, prop)) {
2018 RNA_property_int_set(op->ptr, prop, bake->margin);
2019 }
2020
2021 prop = RNA_struct_find_property(op->ptr, "margin_type");
2022 if (!RNA_property_is_set(op->ptr, prop)) {
2023 RNA_property_enum_set(op->ptr, prop, bake->margin_type);
2024 }
2025
2026 prop = RNA_struct_find_property(op->ptr, "use_selected_to_active");
2027 if (!RNA_property_is_set(op->ptr, prop)) {
2028 RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_TO_ACTIVE) != 0);
2029 }
2030
2031 prop = RNA_struct_find_property(op->ptr, "max_ray_distance");
2032 if (!RNA_property_is_set(op->ptr, prop)) {
2033 RNA_property_float_set(op->ptr, prop, bake->max_ray_distance);
2034 }
2035
2036 prop = RNA_struct_find_property(op->ptr, "cage_extrusion");
2037 if (!RNA_property_is_set(op->ptr, prop)) {
2038 RNA_property_float_set(op->ptr, prop, bake->cage_extrusion);
2039 }
2040
2041 prop = RNA_struct_find_property(op->ptr, "cage_object");
2042 if (!RNA_property_is_set(op->ptr, prop)) {
2044 op->ptr, prop, (bake->cage_object) ? bake->cage_object->id.name + 2 : "");
2045 }
2046
2047 prop = RNA_struct_find_property(op->ptr, "normal_space");
2048 if (!RNA_property_is_set(op->ptr, prop)) {
2049 RNA_property_enum_set(op->ptr, prop, bake->normal_space);
2050 }
2051
2052 prop = RNA_struct_find_property(op->ptr, "normal_r");
2053 if (!RNA_property_is_set(op->ptr, prop)) {
2054 RNA_property_enum_set(op->ptr, prop, bake->normal_swizzle[0]);
2055 }
2056
2057 prop = RNA_struct_find_property(op->ptr, "normal_g");
2058 if (!RNA_property_is_set(op->ptr, prop)) {
2059 RNA_property_enum_set(op->ptr, prop, bake->normal_swizzle[1]);
2060 }
2061
2062 prop = RNA_struct_find_property(op->ptr, "normal_b");
2063 if (!RNA_property_is_set(op->ptr, prop)) {
2064 RNA_property_enum_set(op->ptr, prop, bake->normal_swizzle[2]);
2065 }
2066
2067 prop = RNA_struct_find_property(op->ptr, "target");
2068 if (!RNA_property_is_set(op->ptr, prop)) {
2069 RNA_property_enum_set(op->ptr, prop, bake->target);
2070 }
2071
2072 prop = RNA_struct_find_property(op->ptr, "save_mode");
2073 if (!RNA_property_is_set(op->ptr, prop)) {
2074 RNA_property_enum_set(op->ptr, prop, bake->save_mode);
2075 }
2076
2077 prop = RNA_struct_find_property(op->ptr, "use_clear");
2078 if (!RNA_property_is_set(op->ptr, prop)) {
2079 RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_CLEAR) != 0);
2080 }
2081
2082 prop = RNA_struct_find_property(op->ptr, "use_cage");
2083 if (!RNA_property_is_set(op->ptr, prop)) {
2084 RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_CAGE) != 0);
2085 }
2086
2087 prop = RNA_struct_find_property(op->ptr, "use_split_materials");
2088 if (!RNA_property_is_set(op->ptr, prop)) {
2089 RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_SPLIT_MAT) != 0);
2090 }
2091
2092 prop = RNA_struct_find_property(op->ptr, "use_automatic_name");
2093 if (!RNA_property_is_set(op->ptr, prop)) {
2094 RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_AUTO_NAME) != 0);
2095 }
2096
2097 prop = RNA_struct_find_property(op->ptr, "pass_filter");
2098 if (!RNA_property_is_set(op->ptr, prop)) {
2099 RNA_property_enum_set(op->ptr, prop, bake->pass_filter);
2100 }
2101}
2102
2103static int bake_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
2104{
2105 wmJob *wm_job;
2106 Render *re;
2107 Scene *scene = CTX_data_scene(C);
2108
2109 bake_set_props(op, scene);
2110
2111 /* only one render job at a time */
2113 return OPERATOR_CANCELLED;
2114 }
2115
2116 BakeAPIRender *bkr = MEM_new<BakeAPIRender>(__func__);
2117
2118 /* init bake render */
2119 bake_init_api_data(op, C, bkr);
2121 re = bkr->render;
2122
2123 /* setup new render */
2124 RE_test_break_cb(re, nullptr, bake_break);
2126
2127 /* setup job */
2128 wm_job = WM_jobs_get(CTX_wm_manager(C),
2129 CTX_wm_window(C),
2130 scene,
2131 "Texture Bake",
2135 /* TODO: only draw bake image, can we enforce this. */
2137 wm_job, 0.5, (bkr->target == R_BAKE_TARGET_VERTEX_COLORS) ? NC_GEOM | ND_DATA : NC_IMAGE, 0);
2139 wm_job, bake_startjob, nullptr, nullptr, nullptr, bake_job_complete, bake_job_canceled);
2140
2141 G.is_break = false;
2142 G.is_rendering = true;
2143
2144 WM_jobs_start(CTX_wm_manager(C), wm_job);
2145
2146 WM_cursor_wait(false);
2147
2148 /* add modal handler for ESC */
2150
2153}
2154
2156{
2157 PropertyRNA *prop;
2158
2159 /* identifiers */
2160 ot->name = "Bake";
2161 ot->description = "Bake image textures of selected objects";
2162 ot->idname = "OBJECT_OT_bake";
2163
2164 /* api callbacks */
2165 ot->exec = bake_exec;
2166 ot->modal = bake_modal;
2169
2171 ot->srna,
2172 "type",
2175 "Type",
2176 "Type of pass to bake, some of them may not be supported by the current render engine");
2177 prop = RNA_def_enum(ot->srna,
2178 "pass_filter",
2181 "Pass Filter",
2182 "Filter to combined, diffuse, glossy, transmission and subsurface passes");
2185 "filepath",
2186 nullptr,
2187 FILE_MAX,
2188 "File Path",
2189 "Image filepath to use when saving externally");
2191 "width",
2192 512,
2193 1,
2194 INT_MAX,
2195 "Width",
2196 "Horizontal dimension of the baking map (external only)",
2197 64,
2198 4096);
2200 "height",
2201 512,
2202 1,
2203 INT_MAX,
2204 "Height",
2205 "Vertical dimension of the baking map (external only)",
2206 64,
2207 4096);
2209 "margin",
2210 16,
2211 0,
2212 INT_MAX,
2213 "Margin",
2214 "Extends the baked result as a post process filter",
2215 0,
2216 64);
2218 "margin_type",
2221 "Margin Type",
2222 "Which algorithm to use to generate the margin");
2224 "use_selected_to_active",
2225 false,
2226 "Selected to Active",
2227 "Bake shading on the surface of selected objects to the active object");
2229 "max_ray_distance",
2230 0.0f,
2231 0.0f,
2232 FLT_MAX,
2233 "Max Ray Distance",
2234 "The maximum ray distance for matching points between the active and selected "
2235 "objects. If zero, there is no limit",
2236 0.0f,
2237 1.0f);
2239 "cage_extrusion",
2240 0.0f,
2241 0.0f,
2242 FLT_MAX,
2243 "Cage Extrusion",
2244 "Inflate the active object by the specified distance for baking. This helps "
2245 "matching to points nearer to the outside of the selected object meshes",
2246 0.0f,
2247 1.0f);
2249 "cage_object",
2250 nullptr,
2251 MAX_NAME,
2252 "Cage Object",
2253 "Object to use as cage, instead of calculating the cage from the active object "
2254 "with cage extrusion");
2256 "normal_space",
2259 "Normal Space",
2260 "Choose normal space for baking");
2261 prop = RNA_def_enum(ot->srna,
2262 "normal_r",
2265 "R",
2266 "Axis to bake in red channel");
2268 prop = RNA_def_enum(ot->srna,
2269 "normal_g",
2272 "G",
2273 "Axis to bake in green channel");
2275 prop = RNA_def_enum(ot->srna,
2276 "normal_b",
2279 "B",
2280 "Axis to bake in blue channel");
2283 "target",
2286 "Target",
2287 "Where to output the baked map");
2289 "save_mode",
2292 "Save Mode",
2293 "Where to save baked image textures");
2295 "use_clear",
2296 false,
2297 "Clear",
2298 "Clear images before baking (only for internal saving)");
2299 RNA_def_boolean(ot->srna, "use_cage", false, "Cage", "Cast rays to active object from a cage");
2301 ot->srna,
2302 "use_split_materials",
2303 false,
2304 "Split Materials",
2305 "Split baked maps per material, using material name in output file (external only)");
2307 "use_automatic_name",
2308 false,
2309 "Automatic Name",
2310 "Automatically name the output file with the pass type");
2312 "uv_layer",
2313 nullptr,
2315 "UV Layer",
2316 "UV layer to override active");
2317}
2318
2319} // namespace blender::ed::object
const struct CustomDataLayer * BKE_id_attributes_color_find(const struct ID *id, const char *name)
blender::bke::AttrDomain BKE_attribute_domain(const AttributeOwner &owner, const struct CustomDataLayer *layer)
void BKE_callback_exec_id(Main *bmain, ID *id, eCbEvent evt)
Definition callbacks.cc:44
@ BKE_CB_EVT_OBJECT_BAKE_CANCEL
@ BKE_CB_EVT_OBJECT_BAKE_COMPLETE
@ BKE_CB_EVT_OBJECT_BAKE_PRE
bScreen * CTX_wm_screen(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
bool CTX_data_selected_objects(const bContext *C, blender::Vector< PointerRNA > *list)
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
int CustomData_get_named_layer(const CustomData *data, eCustomDataType type, blender::StringRef name)
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
#define ORIGINDEX_NONE
int CustomData_get_active_layer_index(const CustomData *data, eCustomDataType type)
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
void BKE_image_mark_dirty(Image *image, ImBuf *ibuf)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
void BKE_image_get_tile_uv(const Image *ima, const int tile_number, float r_uv[2])
void BKE_imageuser_default(ImageUser *iuser)
void BKE_image_free_gputextures(Image *ima)
Definition image_gpu.cc:556
bool BKE_imbuf_write(ImBuf *ibuf, const char *filepath, const ImageFormatData *imf)
void BKE_image_partial_update_mark_full_update(Image *image)
Mark the whole image to be updated.
void BKE_image_path_from_imtype(char *filepath, const char *base, const char *relbase, int frame, char imtype, bool use_ext, bool use_frames, const char *suffix)
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
void BKE_main_id_tag_idcode(Main *mainvar, short type, int tag, bool value)
Definition lib_id.cc:1191
void BKE_id_free(Main *bmain, void *idv)
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:832
General operations, lookup, etc. for materials.
struct Material * BKE_object_material_get(struct Object *ob, short act)
Mesh * BKE_mesh_new_from_object(Depsgraph *depsgraph, Object *object, bool preserve_all_data_layers, bool preserve_origindex)
ModifierData * BKE_modifiers_findby_type(const Object *ob, ModifierType type)
void BKE_modifier_free(ModifierData *md)
General operations, lookup, etc. for blender objects.
void BKE_object_eval_reset(Object *ob_eval)
void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
void BKE_scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2568
ScrArea * BKE_screen_find_big_area(const bScreen *screen, int spacetype, short min)
Definition screen.cc:903
#define BLI_assert(a)
Definition BLI_assert.h:50
File and directory operations.
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
MINLINE void linearrgb_to_srgb_uchar4(unsigned char srgb[4], const float linear[4])
MINLINE int poly_to_tri_count(int poly_count, int corner_count)
void copy_m4_m4(float m1[4][4], const float m2[4][4])
bool is_negative_m4(const float mat[4][4])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
MINLINE void mul_v4_fl(float r[4], float f)
MINLINE void add_v4_v4(float r[4], const float a[4])
MINLINE void zero_v4(float r[4])
MINLINE void add_v3_v3(float r[3], const float a[3])
bool bool BLI_path_suffix(char *path, size_t path_maxncpy, const char *suffix, const char *sep) ATTR_NONNULL(1
#define FILE_MAX
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
unsigned int uint
#define ELEM(...)
#define BLT_I18NCONTEXT_COLOR
void DEG_id_tag_update(ID *id, unsigned int flags)
@ DAG_EVAL_RENDER
Depsgraph * DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
Definition depsgraph.cc:273
void DEG_graph_free(Depsgraph *graph)
Definition depsgraph.cc:301
void DEG_graph_build_from_view_layer(Depsgraph *graph)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ ID_TAG_DOIT
Definition DNA_ID.h:1003
@ ID_IM
#define MAX_CUSTOMDATA_LAYER_NAME
@ CD_PROP_COLOR
@ CD_PROP_FLOAT2
#define MAX_CUSTOMDATA_LAYER_NAME_NO_PREFIX
#define MAX_NAME
Definition DNA_defs.h:50
@ BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT
@ BASE_ENABLED_RENDER
@ eModifierType_EdgeSplit
@ eModifierType_Multires
@ SUBSURF_UV_SMOOTH_NONE
Object is a sort of wrapper for general info.
@ OB_HIDE_RENDER
@ OB_MBALL
@ OB_SURF
@ OB_FONT
@ OB_MESH
@ OB_CURVES_LEGACY
eBakeTarget
@ R_BAKE_TARGET_VERTEX_COLORS
@ R_BAKE_TARGET_IMAGE_TEXTURES
eBakeNormalSwizzle
@ R_BAKE_POSY
@ R_BAKE_POSZ
@ R_BAKE_POSX
eBakeMarginType
@ R_BAKE_EXTEND
@ R_BAKE_SPLIT_MAT
@ R_BAKE_AUTO_NAME
@ R_BAKE_TO_ACTIVE
@ R_BAKE_CAGE
@ R_BAKE_CLEAR
@ R_BAKE_SPACE_WORLD
@ R_BAKE_SPACE_TANGENT
@ R_BAKE_SPACE_OBJECT
eBakeSaveMode
@ R_BAKE_SAVE_EXTERNAL
@ R_BAKE_SAVE_INTERNAL
@ R_BAKE_PASS_FILTER_DIFFUSE
@ R_BAKE_PASS_FILTER_NONE
@ R_BAKE_PASS_FILTER_COLOR
@ R_BAKE_PASS_FILTER_SUBSURFACE
@ R_BAKE_PASS_FILTER_INDIRECT
@ R_BAKE_PASS_FILTER_DIRECT
@ R_BAKE_PASS_FILTER_GLOSSY
@ R_BAKE_PASS_FILTER_EMIT
@ R_BAKE_PASS_FILTER_TRANSM
eScenePassType
@ SCE_PASS_NORMAL
@ SCE_PASS_DIFFUSE_COLOR
@ SCE_PASS_POSITION
@ SCE_PASS_UV
@ SCE_PASS_SUBSURFACE_COLOR
@ SCE_PASS_GLOSSY_COLOR
@ SCE_PASS_INDEXMA
@ SCE_PASS_INDEXOB
@ SCE_PASS_COMBINED
@ SCE_PASS_Z
@ SCE_PASS_VECTOR
@ SCE_PASS_TRANSM_COLOR
@ SPACE_IMAGE
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_mesh_split_faces(Mesh *mesh)
bool ED_operator_object_active_editable_mesh(bContext *C)
bool ED_object_get_active_image(Object *ob, int mat_nr, Image **r_ima, ImageUser **r_iuser, const bNode **r_node, const bNodeTree **r_ntree)
const char * IMB_colormanagement_role_colorspace_name_get(int role)
@ COLOR_ROLE_SCENE_LINEAR
const char * IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf)
void IMB_colormanagement_transform(float *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace, bool predivide)
const char * IMB_colormanagement_get_float_colorspace(ImBuf *ibuf)
void IMB_buffer_float_from_float_mask(float *rect_to, const float *rect_from, int channels_from, int width, int height, int stride_to, int stride_from, char *mask)
Definition divers.cc:572
void IMB_buffer_float_from_float(float *rect_to, const float *rect_from, int channels_from, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from)
Definition divers.cc:407
void imb_freemipmapImBuf(ImBuf *ibuf)
void IMB_buffer_byte_from_float_mask(unsigned char *rect_to, const float *rect_from, int channels_from, float dither, bool predivide, int width, int height, int stride_to, int stride_from, char *mask)
Definition divers.cc:260
void IMB_buffer_byte_from_float(unsigned char *rect_to, const float *rect_from, int channels_from, float dither, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from)
Definition divers.cc:96
Contains defines and structs used throughout the imbuf module.
#define IB_PROFILE_SRGB
#define IB_PROFILE_LINEAR_RGB
@ IB_rectfloat
@ IB_rect
@ IB_RECT_INVALID
@ IB_MIPMAP_INVALID
@ IB_DISPLAY_BUFFER_INVALID
Read Guarded memory(de)allocation.
#define MEM_recallocN(vmemh, len)
#define MEM_SAFE_FREE(v)
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 producing a negative Combine Generate a color from its and blue channels(Deprecated)") DefNode(ShaderNode
@ PROP_ENUM_FLAG
Definition RNA_types.hh:293
@ WM_JOB_TYPE_OBJECT_BAKE
Definition WM_api.hh:1585
@ WM_JOB_EXCL_RENDER
Definition WM_api.hh:1565
@ WM_JOB_PROGRESS
Definition WM_api.hh:1566
@ WM_JOB_PRIORITY
Definition WM_api.hh:1560
#define NC_GEOM
Definition WM_types.hh:360
#define ND_RENDER_RESULT
Definition WM_types.hh:413
#define ND_DATA
Definition WM_types.hh:475
#define NC_SCENE
Definition WM_types.hh:345
#define NC_IMAGE
Definition WM_types.hh:351
volatile int lock
void RE_bake_normal_world_to_tangent(const BakePixel pixel_array[], const size_t pixels_num, const int depth, float result[], Mesh *mesh, const eBakeNormalSwizzle normal_swizzle[3], const float mat[4][4])
Definition bake.cc:853
int RE_pass_depth(const eScenePassType pass_type)
Definition bake.cc:1059
void RE_bake_ibuf_clear(Image *image, const bool is_tangent)
Definition bake.cc:1034
void RE_bake_normal_world_to_world(const BakePixel pixel_array[], const size_t pixels_num, const int depth, float result[], const eBakeNormalSwizzle normal_swizzle[3])
Definition bake.cc:1010
void RE_bake_pixels_populate(Mesh *mesh, BakePixel pixel_array[], const size_t pixels_num, const BakeTargets *targets, const char *uv_layer)
Definition bake.cc:715
void RE_bake_margin(ImBuf *ibuf, char *mask, const int margin, const char margin_type, const Mesh *mesh, char const *uv_layer, const float uv_offset[2])
Definition bake.cc:145
void RE_bake_normal_world_to_object(const BakePixel pixel_array[], const size_t pixels_num, const int depth, float result[], Object *ob, const eBakeNormalSwizzle normal_swizzle[3])
Definition bake.cc:978
bool RE_bake_pixels_populate_from_objects(Mesh *me_low, BakePixel pixel_array_from[], BakePixel pixel_array_to[], BakeHighPolyData highpoly[], const int tot_highpoly, const size_t pixels_num, const bool is_custom_cage, const float cage_extrusion, const float max_ray_distance, const float mat_low[4][4], const float mat_cage[4][4], Mesh *me_cage)
Definition bake.cc:545
void RE_bake_mask_fill(const BakePixel pixel_array[], const size_t pixels_num, char *mask)
Definition bake.cc:130
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_FACE
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
static AttributeOwner from_id(ID *id)
Definition attribute.cc:43
constexpr int64_t size() const
constexpr int64_t start() const
constexpr bool is_empty() const
Definition BLI_span.hh:261
int64_t size() const
input_tx image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img") .compute_source("compositor_compute_preview.glsl") .do_static_compilation(true)
const Depsgraph * depsgraph
#define offsetof(t, d)
#define fabsf(x)
struct ImBuf * IMB_allocImBuf(unsigned int, unsigned int, unsigned char, unsigned int)
void IMB_freeImBuf(ImBuf *)
bool RE_bake_engine(Render *re, Depsgraph *depsgraph, Object *object, const int object_id, const BakePixel pixel_array[], const BakeTargets *targets, const eScenePassType pass_type, const int pass_filter, float result[])
bool RE_bake_has_engine(const Render *re)
void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene)
ccl_global const KernelWorkTile * tile
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#define unit_float_to_uchar_clamp_v4(v1, v2)
#define G(x, y, z)
void corner_tris_calc(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, MutableSpan< int3 > corner_tris)
bool node_is_connected_to_output(const bNodeTree *ntree, const bNode *node)
static int bake(const BakeAPIRender *bkr, Object *ob_low, const Span< PointerRNA > selected_objects, ReportList *reports)
static void convert_float_color_to_byte_color(const MPropCol *float_colors, const int num, const bool is_noncolor, MLoopCol *byte_colors)
static bool bake_objects_check(Main *bmain, const Scene *scene, ViewLayer *view_layer, Object *ob, Span< PointerRNA > selected_objects, ReportList *reports, const bool is_selected_to_active, const eBakeTarget target)
static Mesh * bake_mesh_new_from_object(Depsgraph *depsgraph, Object *object, const bool preserve_origindex)
static bool bake_targets_init(const BakeAPIRender *bkr, BakeTargets *targets, Object *ob, Object *ob_eval, ReportList *reports)
static void bake_startjob(void *bkv, wmJobWorkerStatus *worker_status)
static void bake_targets_populate_pixels_color_attributes(BakeTargets *targets, Object *ob, Mesh *mesh_eval, BakePixel *pixel_array)
static void bake_targets_refresh(BakeTargets *targets)
static void bake_job_complete(void *bkv)
static int find_original_loop(const OffsetIndices< int > orig_faces, const Span< int > orig_corner_verts, const int *vert_origindex, const int *poly_origindex, const int poly_eval, const int vert_eval)
void OBJECT_OT_bake(wmOperatorType *ot)
static bool bake_object_check(const Scene *scene, ViewLayer *view_layer, Object *ob, const eBakeTarget target, ReportList *reports)
static bool bake_break(void *)
static void bake_job_canceled(void *bkv)
static bool bake_targets_output_internal(const BakeAPIRender *bkr, BakeTargets *targets, Object *ob, BakePixel *pixel_array, ReportList *reports, Mesh *mesh_eval)
static void bake_update_image(ScrArea *area, Image *image)
static bool write_internal_bake_pixels(Image *image, const int image_tile_number, BakePixel pixel_array[], float *buffer, const int width, const int height, const int margin, const char margin_type, const bool is_clear, const bool is_noncolor, const bool is_tangent_normal, Mesh const *mesh_eval, char const *uv_layer, const float uv_offset[2])
static void bake_targets_populate_pixels(const BakeAPIRender *bkr, BakeTargets *targets, Object *ob, Mesh *mesh_eval, BakePixel *pixel_array)
static void bake_freejob(void *bkv)
static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr)
static int bake_modal(bContext *C, wmOperator *, const wmEvent *event)
static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob)
static void bias_tangent_normal_pixels(float *rect, int channels, int width, int height, int stride)
static bool bake_pass_filter_check(eScenePassType pass_type, const int pass_filter, ReportList *reports)
static bool bake_targets_init_image_textures(const BakeAPIRender *bkr, BakeTargets *targets, Object *ob, ReportList *reports)
static bool bake_targets_output(const BakeAPIRender *bkr, BakeTargets *targets, Object *ob, Object *ob_eval, Mesh *mesh_eval, BakePixel *pixel_array, ReportList *reports)
static void bake_targets_free(BakeTargets *targets)
static bool bake_targets_init_vertex_colors(Main *bmain, BakeTargets *targets, Object *ob, ReportList *reports)
static bool write_external_bake_pixels(const char *filepath, BakePixel pixel_array[], float *buffer, const int width, const int height, const int margin, const int margin_type, ImageFormatData const *im_format, const bool is_noncolor, const bool is_tangent_normal, Mesh const *mesh_eval, char const *uv_layer, const float uv_offset[2])
static bool bake_targets_init_internal(const BakeAPIRender *bkr, BakeTargets *targets, Object *ob, ReportList *reports)
static bool bake_targets_init_external(const BakeAPIRender *bkr, BakeTargets *targets, Object *ob, ReportList *reports)
static void bake_progress_update(void *bjv, float progress)
static void bake_set_props(wmOperator *op, Scene *scene)
static void bake_targets_clear(Main *bmain, const bool is_tangent)
static bool bake_targets_output_external(const BakeAPIRender *bkr, BakeTargets *targets, Object *ob, Object *ob_eval, Mesh *mesh_eval, BakePixel *pixel_array, ReportList *reports)
static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *)
bool editmode_load(Main *bmain, Object *obedit)
static int bake_exec(bContext *C, wmOperator *op)
static bool is_noncolor_pass(eScenePassType pass_type)
static void bake_result_add_to_rgba(float rgba[4], const float *result, const int channels_num)
bool RNA_property_enum_identifier(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **r_identifier)
void RNA_property_int_set(PointerRNA *ptr, PropertyRNA *prop, int value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
int RNA_int_get(PointerRNA *ptr, const char *name)
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
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_string_file_path(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, 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_translation_context(PropertyRNA *prop, const char *context)
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)
const EnumPropertyItem rna_enum_bake_pass_type_items[]
Definition rna_render.cc:67
const EnumPropertyItem rna_enum_normal_swizzle_items[]
Definition rna_scene.cc:417
const EnumPropertyItem rna_enum_bake_pass_filter_type_items[]
Definition rna_scene.cc:548
const EnumPropertyItem rna_enum_bake_save_mode_items[]
Definition rna_scene.cc:451
const EnumPropertyItem rna_enum_bake_margin_type_items[]
Definition rna_scene.cc:427
const EnumPropertyItem rna_enum_bake_target_items[]
Definition rna_scene.cc:437
const EnumPropertyItem rna_enum_normal_space_items[]
Definition rna_scene.cc:411
void RE_progress_cb(Render *re, void *handle, void(*f)(void *handle, float))
void RE_test_break_cb(Render *re, void *handle, bool(*f)(void *handle))
Render * RE_NewSceneRender(const Scene *scene)
void RE_SetReports(Render *re, ReportList *reports)
#define FLT_MAX
Definition stdcycles.h:14
struct Mesh * mesh
Definition RE_bake.h:63
struct Object * ob
Definition RE_bake.h:61
struct Object * ob_eval
Definition RE_bake.h:62
bool is_flip_object
Definition RE_bake.h:64
int height
Definition RE_bake.h:27
int tile_number
Definition RE_bake.h:24
size_t offset
Definition RE_bake.h:28
struct Image * image
Definition RE_bake.h:23
float uv_offset[2]
Definition RE_bake.h:25
int width
Definition RE_bake.h:26
int primitive_id
Definition RE_bake.h:53
struct Image ** material_to_image
Definition RE_bake.h:40
float * result
Definition RE_bake.h:44
bool is_noncolor
Definition RE_bake.h:49
int pixels_num
Definition RE_bake.h:45
int materials_num
Definition RE_bake.h:41
int channels_num
Definition RE_bake.h:46
int images_num
Definition RE_bake.h:37
BakeImage * images
Definition RE_bake.h:36
short flag
Definition DNA_ID.h:413
char name[66]
Definition DNA_ID.h:425
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
ImBuf * mipmap[IMB_MIPMAP_LEVELS]
void * first
unsigned char r
ListBase images
Definition BKE_main.hh:218
ListBase objects
Definition BKE_main.hh:212
int corners_num
struct Material ** mat
CustomData face_data
CustomData vert_data
int faces_num
struct ModifierData * next
short base_flag
ListBase modifiers
struct Material ** mat
short visibility_flag
void * data
Definition RNA_types.hh:42
struct BakeData bake
struct RenderData r
struct Image * image
char uv_layer[MAX_CUSTOMDATA_LAYER_NAME]
short type
Definition WM_types.hh:722
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
struct ReportList * reports
struct PointerRNA * ptr
void WM_cursor_wait(bool val)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ EVT_ESCKEY
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:352
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:455
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, const eWM_JobFlag flag, const eWM_JobType job_type)
Definition wm_jobs.cc:189
void WM_jobs_callbacks_ex(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *), void(*completed)(void *), void(*canceled)(void *))
Definition wm_jobs.cc:373
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:223
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:336