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