diff options
-rw-r--r-- | source/blender/blenkernel/BKE_image.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/image.cc | 27 | ||||
-rw-r--r-- | source/blender/editors/object/object_bake.c | 67 | ||||
-rw-r--r-- | source/blender/editors/object/object_bake_api.c | 138 | ||||
-rw-r--r-- | source/blender/render/RE_bake.h | 7 | ||||
-rw-r--r-- | source/blender/render/RE_texture_margin.h | 11 | ||||
-rw-r--r-- | source/blender/render/intern/bake.c | 49 | ||||
-rw-r--r-- | source/blender/render/intern/multires_bake.c | 193 | ||||
-rw-r--r-- | source/blender/render/intern/texture_margin.cc | 38 |
9 files changed, 316 insertions, 216 deletions
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index fff3b2a8f89..42d0e66cf49 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -414,6 +414,8 @@ int BKE_image_get_tile_from_pos(struct Image *ima, const float uv[2], float r_uv[2], float r_ofs[2]); +void BKE_image_get_tile_uv(const struct Image *ima, const int tile_number, float r_uv[2]); + /** * Return the tile_number for the closest UDIM tile. */ diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc index 53ec148fd2d..dfa820519a5 100644 --- a/source/blender/blenkernel/intern/image.cc +++ b/source/blender/blenkernel/intern/image.cc @@ -829,10 +829,7 @@ ImageTile *BKE_image_get_tile_from_iuser(Image *ima, const ImageUser *iuser) return BKE_image_get_tile(ima, image_get_tile_number_from_iuser(ima, iuser)); } -int BKE_image_get_tile_from_pos(struct Image *ima, - const float uv[2], - float r_uv[2], - float r_ofs[2]) +int BKE_image_get_tile_from_pos(Image *ima, const float uv[2], float r_uv[2], float r_ofs[2]) { float local_ofs[2]; if (r_ofs == nullptr) { @@ -860,6 +857,18 @@ int BKE_image_get_tile_from_pos(struct Image *ima, return tile_number; } +void BKE_image_get_tile_uv(const Image *ima, const int tile_number, float r_uv[2]) +{ + if (ima->source != IMA_SRC_TILED) { + zero_v2(r_uv); + } + else { + const int tile_index = tile_number - 1001; + r_uv[0] = static_cast<float>(tile_index % 10); + r_uv[1] = static_cast<float>(tile_index / 10); + } +} + int BKE_image_find_nearest_tile(const Image *image, const float co[2]) { const float co_floor[2] = {floorf(co[0]), floorf(co[1])}; @@ -868,17 +877,15 @@ int BKE_image_find_nearest_tile(const Image *image, const float co[2]) int tile_number_best = -1; LISTBASE_FOREACH (const ImageTile *, tile, &image->tiles) { - const int tile_index = tile->tile_number - 1001; - /* Coordinates of the current tile. */ - const float tile_index_co[2] = {static_cast<float>(tile_index % 10), - static_cast<float>(tile_index / 10)}; + float uv_offset[2]; + BKE_image_get_tile_uv(image, tile->tile_number, uv_offset); - if (equals_v2v2(co_floor, tile_index_co)) { + if (equals_v2v2(co_floor, uv_offset)) { return tile->tile_number; } /* Distance between co[2] and UDIM tile. */ - const float dist_sq = len_squared_v2v2(tile_index_co, co); + const float dist_sq = len_squared_v2v2(uv_offset, co); if (dist_sq < dist_best_sq) { dist_best_sq = dist_sq; diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index d469efbd0a1..1483c24ac70 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -172,28 +172,35 @@ static bool multiresbake_check(bContext *C, wmOperator *op) ok = false; } else { - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { + ImageUser iuser; + BKE_imageuser_default(&iuser); + iuser.tile = tile->tile_number; - if (!ibuf) { - BKE_report(op->reports, RPT_ERROR, "Baking should happen to image with image buffer"); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); - ok = false; - } - else { - if (ibuf->rect == NULL && ibuf->rect_float == NULL) { - ok = false; - } + if (!ibuf) { + BKE_report( + op->reports, RPT_ERROR, "Baking should happen to image with image buffer"); - if (ibuf->rect_float && !(ELEM(ibuf->channels, 0, 4))) { ok = false; } - - if (!ok) { - BKE_report(op->reports, RPT_ERROR, "Baking to unsupported image type"); + else { + if (ibuf->rect == NULL && ibuf->rect_float == NULL) { + ok = false; + } + + if (ibuf->rect_float && !(ELEM(ibuf->channels, 0, 4))) { + ok = false; + } + + if (!ok) { + BKE_report(op->reports, RPT_ERROR, "Baking to unsupported image type"); + } } - } - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_release_ibuf(ima, ibuf, NULL); + } } } } @@ -274,21 +281,27 @@ static void clear_single_image(Image *image, ClearFlag flag) const float disp_solid[4] = {0.5f, 0.5f, 0.5f, 1.0f}; if ((image->id.tag & LIB_TAG_DOIT) == 0) { - ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL); + LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) { + ImageUser iuser; + BKE_imageuser_default(&iuser); + iuser.tile = tile->tile_number; - if (flag == CLEAR_TANGENT_NORMAL) { - IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid); - } - else if (flag == CLEAR_DISPLACEMENT) { - IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? disp_alpha : disp_solid); - } - else { - IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid); - } + ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, NULL); - image->id.tag |= LIB_TAG_DOIT; + if (flag == CLEAR_TANGENT_NORMAL) { + IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid); + } + else if (flag == CLEAR_DISPLACEMENT) { + IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? disp_alpha : disp_solid); + } + else { + IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid); + } + + image->id.tag |= LIB_TAG_DOIT; - BKE_image_release_ibuf(image, ibuf, NULL); + BKE_image_release_ibuf(image, ibuf, NULL); + } } } diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 4ec8b7a05d5..a7379d7e492 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -19,6 +19,7 @@ #include "BLI_fileops.h" #include "BLI_listbase.h" #include "BLI_path_util.h" +#include "BLI_string.h" #include "BKE_context.h" #include "BKE_global.h" @@ -165,6 +166,7 @@ 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, @@ -174,7 +176,8 @@ static bool write_internal_bake_pixels(Image *image, const bool is_clear, const bool is_noncolor, Mesh const *mesh_eval, - char const *uv_layer) + char const *uv_layer, + const float uv_offset[2]) { ImBuf *ibuf; void *lock; @@ -182,7 +185,10 @@ static bool write_internal_bake_pixels(Image *image, char *mask_buffer = NULL; const size_t pixels_num = (size_t)width * (size_t)height; - ibuf = BKE_image_acquire_ibuf(image, NULL, &lock); + ImageUser iuser; + BKE_imageuser_default(&iuser); + iuser.tile = image_tile_number; + ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock); if (!ibuf) { return false; @@ -270,7 +276,7 @@ static bool write_internal_bake_pixels(Image *image, /* margins */ if (margin > 0) { - RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh_eval, uv_layer); + RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh_eval, uv_layer, uv_offset); } ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; @@ -303,10 +309,8 @@ static void bake_targets_refresh(BakeTargets *targets) if (ima) { BKE_image_partial_update_mark_full_update(ima); - LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { - BKE_image_free_gputextures(ima); - DEG_id_tag_update(&ima->id, 0); - } + BKE_image_free_gputextures(ima); + DEG_id_tag_update(&ima->id, 0); } } } @@ -321,7 +325,8 @@ static bool write_external_bake_pixels(const char *filepath, ImageFormatData *im_format, const bool is_noncolor, Mesh const *mesh_eval, - char const *uv_layer) + char const *uv_layer, + const float uv_offset[2]) { ImBuf *ibuf = NULL; bool ok = false; @@ -378,7 +383,7 @@ static bool write_external_bake_pixels(const char *filepath, mask_buffer = MEM_callocN(sizeof(char) * pixels_num, "Bake Mask"); RE_bake_mask_fill(pixel_array, pixels_num, mask_buffer); - RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh_eval, uv_layer); + RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh_eval, uv_layer, uv_offset); if (mask_buffer) { MEM_freeN(mask_buffer); @@ -467,7 +472,6 @@ static bool bake_object_check(ViewLayer *view_layer, ED_object_get_active_image(ob, mat_nr, &image, NULL, &node, &ntree); if (image) { - ImBuf *ibuf; if (node) { if (BKE_node_is_connected_to_output(ntree, node)) { @@ -482,21 +486,27 @@ static bool bake_object_check(ViewLayer *view_layer, } } - void *lock; - ibuf = BKE_image_acquire_ibuf(image, NULL, &lock); + LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) { + ImageUser iuser; + BKE_imageuser_default(&iuser); + iuser.tile = tile->tile_number; - if (ibuf) { - BKE_image_release_ibuf(image, ibuf, lock); - } - else { - BKE_reportf(reports, - RPT_ERROR, - "Uninitialized image \"%s\" from object \"%s\"", - image->id.name + 2, - ob->id.name + 2); + void *lock; + ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock); + + if (ibuf) { + BKE_image_release_ibuf(image, ibuf, lock); + } + else { + BKE_reportf(reports, + RPT_ERROR, + "Uninitialized image \"%s\" from object \"%s\"", + image->id.name + 2, + ob->id.name + 2); - BKE_image_release_ibuf(image, ibuf, lock); - return false; + BKE_image_release_ibuf(image, ibuf, lock); + return false; + } } } else { @@ -687,36 +697,35 @@ static bool bake_targets_init_image_textures(const BakeAPIRender *bkr, } } - /* Over-allocate in case there is more materials than images. */ + /* Allocate material mapping. */ targets->materials_num = materials_num; - targets->images = MEM_callocN(sizeof(BakeImage) * targets->materials_num, "BakeTargets.images"); - targets->material_to_image = MEM_callocN(sizeof(int) * targets->materials_num, + targets->material_to_image = MEM_callocN(sizeof(Image *) * targets->materials_num, "BakeTargets.material_to_image"); /* Error handling and tag (in case multiple materials share the same image). */ BKE_main_id_tag_idcode(bkr->main, ID_IM, LIB_TAG_DOIT, false); + targets->images = NULL; + for (int i = 0; i < materials_num; i++) { Image *image; ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL); - /* Some materials have no image, we just ignore those cases. */ - if (image == NULL) { - targets->material_to_image[i] = -1; - } - else if (image->id.tag & LIB_TAG_DOIT) { - for (int j = 0; j < i; j++) { - if (targets->images[j].image == image) { - targets->material_to_image[i] = j; - break; - } + targets->material_to_image[i] = image; + + /* Some materials have no image, we just ignore those cases. + * Also setup each image only once. */ + if (image && !(image->id.tag & LIB_TAG_DOIT)) { + LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) { + /* Add bake image. */ + targets->images = MEM_recallocN(targets->images, + sizeof(BakeImage) * (targets->images_num + 1)); + targets->images[targets->images_num].image = image; + targets->images[targets->images_num].tile_number = tile->tile_number; + targets->images_num++; } - } - else { - targets->material_to_image[i] = targets->images_num; - targets->images[targets->images_num].image = image; + image->id.tag |= LIB_TAG_DOIT; - targets->images_num++; } } @@ -735,13 +744,19 @@ static bool bake_targets_init_internal(const BakeAPIRender *bkr, /* Saving to image datablocks. */ for (int i = 0; i < targets->images_num; i++) { BakeImage *bk_image = &targets->images[i]; + + ImageUser iuser; + BKE_imageuser_default(&iuser); + iuser.tile = bk_image->tile_number; + void *lock; - ImBuf *ibuf = BKE_image_acquire_ibuf(bk_image->image, NULL, &lock); + ImBuf *ibuf = BKE_image_acquire_ibuf(bk_image->image, &iuser, &lock); if (ibuf) { bk_image->width = ibuf->x; bk_image->height = ibuf->y; bk_image->offset = targets->pixels_num; + BKE_image_get_tile_uv(bk_image->image, bk_image->tile_number, bk_image->uv_offset); targets->pixels_num += (size_t)ibuf->x * (size_t)ibuf->y; } @@ -768,6 +783,7 @@ static bool bake_targets_output_internal(const BakeAPIRender *bkr, for (int i = 0; i < targets->images_num; i++) { BakeImage *bk_image = &targets->images[i]; const bool ok = write_internal_bake_pixels(bk_image->image, + bk_image->tile_number, pixel_array + bk_image->offset, targets->result + bk_image->offset * targets->channels_num, @@ -778,7 +794,8 @@ static bool bake_targets_output_internal(const BakeAPIRender *bkr, bkr->is_clear, targets->is_noncolor, mesh_eval, - bkr->uv_layer); + bkr->uv_layer, + bk_image->uv_offset); /* might be read by UI to set active image for display */ bake_update_image(bkr->area, bk_image->image); @@ -815,7 +832,6 @@ static bool bake_targets_init_external(const BakeAPIRender *bkr, bk_image->width = bkr->width; bk_image->height = bkr->height; bk_image->offset = targets->pixels_num; - bk_image->image = NULL; targets->pixels_num += (size_t)bkr->width * (size_t)bkr->height; @@ -827,7 +843,7 @@ static bool bake_targets_init_external(const BakeAPIRender *bkr, if (!bkr->is_split_materials) { /* saving a single image */ for (int i = 0; i < targets->materials_num; i++) { - targets->material_to_image[i] = 0; + targets->material_to_image[i] = targets->images[0].image; } } @@ -865,25 +881,26 @@ static bool bake_targets_output_external(const BakeAPIRender *bkr, } if (bkr->is_split_materials) { - if (bk_image->image) { - BLI_path_suffix(name, FILE_MAX, bk_image->image->id.name + 2, "_"); + if (ob_eval->mat[i]) { + BLI_path_suffix(name, FILE_MAX, ob_eval->mat[i]->id.name + 2, "_"); + } + else if (mesh_eval->mat[i]) { + BLI_path_suffix(name, FILE_MAX, mesh_eval->mat[i]->id.name + 2, "_"); } else { - if (ob_eval->mat[i]) { - BLI_path_suffix(name, FILE_MAX, ob_eval->mat[i]->id.name + 2, "_"); - } - else if (mesh_eval->mat[i]) { - BLI_path_suffix(name, FILE_MAX, mesh_eval->mat[i]->id.name + 2, "_"); - } - else { - /* if everything else fails, use the material index */ - char tmp[5]; - sprintf(tmp, "%d", i % 1000); - BLI_path_suffix(name, FILE_MAX, tmp, "_"); - } + /* if everything else fails, use the material index */ + char tmp[5]; + sprintf(tmp, "%d", i % 1000); + BLI_path_suffix(name, FILE_MAX, tmp, "_"); } } + if (bk_image->tile_number) { + char tmp[FILE_MAX]; + SNPRINTF(tmp, "%d", bk_image->tile_number); + BLI_path_suffix(name, FILE_MAX, tmp, "_"); + } + /* save it externally */ const bool ok = write_external_bake_pixels(name, pixel_array + bk_image->offset, @@ -896,7 +913,8 @@ static bool bake_targets_output_external(const BakeAPIRender *bkr, &bake->im_format, targets->is_noncolor, mesh_eval, - bkr->uv_layer); + bkr->uv_layer, + bk_image->uv_offset); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name); diff --git a/source/blender/render/RE_bake.h b/source/blender/render/RE_bake.h index da48599fdf9..56c66df5925 100644 --- a/source/blender/render/RE_bake.h +++ b/source/blender/render/RE_bake.h @@ -19,6 +19,8 @@ extern "C" { typedef struct BakeImage { struct Image *image; + int tile_number; + float uv_offset[2]; int width; int height; size_t offset; @@ -30,7 +32,7 @@ typedef struct BakeTargets { int images_num; /* Lookup table from Material number to BakeImage. */ - int *material_to_image; + struct Image **material_to_image; int materials_num; /* Pixel buffer to bake to. */ @@ -104,7 +106,8 @@ void RE_bake_margin(struct ImBuf *ibuf, int margin, char margin_type, struct Mesh const *me, - char const *uv_layer); + char const *uv_layer, + const float uv_offset[2]); void RE_bake_normal_world_to_object(const BakePixel pixel_array[], size_t pixels_num, diff --git a/source/blender/render/RE_texture_margin.h b/source/blender/render/RE_texture_margin.h index 85bd06b9940..0c91abeaddd 100644 --- a/source/blender/render/RE_texture_margin.h +++ b/source/blender/render/RE_texture_margin.h @@ -25,13 +25,18 @@ struct Mesh; * \param me: the mesh to use the polygons of. * \param uv_layer: The UV layer to use. */ -void RE_generate_texturemargin_adjacentfaces( - struct ImBuf *ibuf, char *mask, const int margin, struct Mesh const *me, char const *uv_layer); +void RE_generate_texturemargin_adjacentfaces(struct ImBuf *ibuf, + char *mask, + const int margin, + struct Mesh const *me, + char const *uv_layer, + const float uv_offset[2]); void RE_generate_texturemargin_adjacentfaces_dm(struct ImBuf *ibuf, char *mask, const int margin, - struct DerivedMesh *dm); + struct DerivedMesh *dm, + const float uv_offset[2]); #ifdef __cplusplus } diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c index 69235fb6cb1..5953c0f0f8f 100644 --- a/source/blender/render/intern/bake.c +++ b/source/blender/render/intern/bake.c @@ -146,12 +146,13 @@ void RE_bake_margin(ImBuf *ibuf, const int margin, const char margin_type, Mesh const *me, - char const *uv_layer) + char const *uv_layer, + const float uv_offset[2]) { /* margin */ switch (margin_type) { case R_BAKE_ADJACENT_FACES: - RE_generate_texturemargin_adjacentfaces(ibuf, mask, margin, me, uv_layer); + RE_generate_texturemargin_adjacentfaces(ibuf, mask, margin, me, uv_layer, uv_offset); break; default: /* fall through */ @@ -746,30 +747,36 @@ void RE_bake_pixels_populate(Mesh *me, for (int i = 0; i < tottri; i++) { const MLoopTri *lt = &looptri[i]; const MPoly *mp = &me->mpoly[lt->poly]; - float vec[3][2]; - int mat_nr = mp->mat_nr; - int image_id = targets->material_to_image[mat_nr]; - if (image_id < 0) { - continue; - } - - bd.bk_image = &targets->images[image_id]; bd.primitive_id = i; - for (int a = 0; a < 3; a++) { - const float *uv = mloopuv[lt->tri[a]].uv; + /* Find images matching this material. */ + Image *image = targets->material_to_image[mp->mat_nr]; + for (int image_id = 0; image_id < targets->images_num; image_id++) { + BakeImage *bk_image = &targets->images[image_id]; + if (bk_image->image != image) { + continue; + } - /* NOTE(campbell): workaround for pixel aligned UVs which are common and can screw up our - * intersection tests where a pixel gets in between 2 faces or the middle of a quad, - * camera aligned quads also have this problem but they are less common. - * Add a small offset to the UVs, fixes bug T18685. */ - vec[a][0] = uv[0] * (float)bd.bk_image->width - (0.5f + 0.001f); - vec[a][1] = uv[1] * (float)bd.bk_image->height - (0.5f + 0.002f); - } + /* Compute triangle vertex UV coordinates. */ + float vec[3][2]; + for (int a = 0; a < 3; a++) { + const float *uv = mloopuv[lt->tri[a]].uv; + + /* NOTE(campbell): workaround for pixel aligned UVs which are common and can screw up our + * intersection tests where a pixel gets in between 2 faces or the middle of a quad, + * camera aligned quads also have this problem but they are less common. + * Add a small offset to the UVs, fixes bug T18685. */ + vec[a][0] = (uv[0] - bk_image->uv_offset[0]) * (float)bk_image->width - (0.5f + 0.001f); + vec[a][1] = (uv[1] - bk_image->uv_offset[1]) * (float)bk_image->height - (0.5f + 0.002f); + } - bake_differentials(&bd, vec[0], vec[1], vec[2]); - zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[1], vec[2], store_bake_pixel); + /* Rasterize triangle. */ + bd.bk_image = bk_image; + bake_differentials(&bd, vec[0], vec[1], vec[2]); + zspan_scanconvert( + &bd.zspan[image_id], (void *)&bd, vec[0], vec[1], vec[2], store_bake_pixel); + } } for (int i = 0; i < targets->images_num; i++) { diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c index 33d961c027d..f93397eedab 100644 --- a/source/blender/render/intern/multires_bake.c +++ b/source/blender/render/intern/multires_bake.c @@ -51,7 +51,7 @@ typedef void (*MPassKnownData)(DerivedMesh *lores_dm, const int x, const int y); -typedef void *(*MInitBakeData)(MultiresBakeRender *bkr, Image *ima); +typedef void *(*MInitBakeData)(MultiresBakeRender *bkr, ImBuf *ibuf); typedef void (*MFreeBakeData)(void *bake_data); typedef struct MultiresBakeResult { @@ -64,6 +64,7 @@ typedef struct { MPoly *mpoly; MLoop *mloop; MLoopUV *mloopuv; + float uv_offset[2]; const MLoopTri *mlooptri; float *pvtangent; const float (*precomputed_normals)[3]; @@ -91,7 +92,6 @@ typedef struct { typedef struct { float *heights; - Image *ima; DerivedMesh *ssdm; const int *orig_index_mp_to_orig; } MHeightBakeData; @@ -148,7 +148,8 @@ static void init_bake_rast(MBakeRast *bake_rast, static void flush_pixel(const MResolvePixelData *data, const int x, const int y) { - const float st[2] = {(x + 0.5f) / data->w, (y + 0.5f) / data->h}; + const float st[2] = {(x + 0.5f) / data->w + data->uv_offset[0], + (y + 0.5f) / data->h + data->uv_offset[1]}; const float *st0, *st1, *st2; const float *tang0, *tang1, *tang2; float no0[3], no1[3], no2[3]; @@ -395,8 +396,12 @@ static void *do_multires_bake_thread(void *data_v) data->tri_index = tri_index; - bake_rasterize( - bake_rast, mloopuv[lt->tri[0]].uv, mloopuv[lt->tri[1]].uv, mloopuv[lt->tri[2]].uv); + float uv[3][2]; + sub_v2_v2v2(uv[0], mloopuv[lt->tri[0]].uv, data->uv_offset); + sub_v2_v2v2(uv[1], mloopuv[lt->tri[1]].uv, data->uv_offset); + sub_v2_v2v2(uv[2], mloopuv[lt->tri[2]].uv, data->uv_offset); + + bake_rasterize(bake_rast, uv[0], uv[1], uv[2]); /* tag image buffer for refresh */ if (data->ibuf->rect_float) { @@ -447,6 +452,8 @@ static void init_ccgdm_arrays(DerivedMesh *dm) static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, + ImageTile *tile, + ImBuf *ibuf, bool require_tangent, MPassKnownData passKnownData, MInitBakeData initBakeData, @@ -462,7 +469,6 @@ static void do_multires_bake(MultiresBakeRender *bkr, MultiresBakeThread *handles; MultiresBakeQueue queue; - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); MVert *mvert = dm->getVertArray(dm); MPoly *mpoly = dm->getPolyArray(dm); MLoop *mloop = dm->getLoopArray(dm); @@ -511,7 +517,7 @@ static void do_multires_bake(MultiresBakeRender *bkr, /* all threads shares the same custom bake data */ if (initBakeData) { - bake_data = initBakeData(bkr, ima); + bake_data = initBakeData(bkr, ibuf); } if (tot_thread > 1) { @@ -539,6 +545,7 @@ static void do_multires_bake(MultiresBakeRender *bkr, handle->data.mvert = mvert; handle->data.vert_normals = vert_normals; handle->data.mloopuv = mloopuv; + BKE_image_get_tile_uv(ima, tile->tile_number, handle->data.uv_offset); handle->data.mlooptri = mlooptri; handle->data.mloop = mloop; handle->data.pvtangent = pvtangent; @@ -590,8 +597,6 @@ static void do_multires_bake(MultiresBakeRender *bkr, MEM_freeN(handles); BKE_id_free(NULL, temp_mesh); - - BKE_image_release_ibuf(ima, ibuf, NULL); } } @@ -758,10 +763,9 @@ static void interp_barycentric_mlooptri(DerivedMesh *dm, /* **************** Displacement Baker **************** */ -static void *init_heights_data(MultiresBakeRender *bkr, Image *ima) +static void *init_heights_data(MultiresBakeRender *bkr, ImBuf *ibuf) { MHeightBakeData *height_data; - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); DerivedMesh *lodm = bkr->lores_dm; BakeImBufuserData *userdata = ibuf->userdata; @@ -772,7 +776,6 @@ static void *init_heights_data(MultiresBakeRender *bkr, Image *ima) height_data = MEM_callocN(sizeof(MHeightBakeData), "MultiresBake heightData"); - height_data->ima = ima; height_data->heights = userdata->displacement_buffer; if (!bkr->use_lores_mesh) { @@ -794,8 +797,6 @@ static void *init_heights_data(MultiresBakeRender *bkr, Image *ima) height_data->orig_index_mp_to_orig = lodm->getPolyDataArray(lodm, CD_ORIGINDEX); - BKE_image_release_ibuf(ima, ibuf, NULL); - return (void *)height_data; } @@ -903,7 +904,7 @@ static void apply_heights_callback(DerivedMesh *lores_dm, /* **************** Normal Maps Baker **************** */ -static void *init_normal_data(MultiresBakeRender *bkr, Image *UNUSED(ima)) +static void *init_normal_data(MultiresBakeRender *bkr, ImBuf *UNUSED(ibuf)) { MNormalBakeData *normal_data; DerivedMesh *lodm = bkr->lores_dm; @@ -1099,7 +1100,7 @@ static void create_ao_raytree(MultiresBakeRender *bkr, MAOBakeData *ao_data) RE_rayobject_done(raytree); } -static void *init_ao_data(MultiresBakeRender *bkr, Image *UNUSED(ima)) +static void *init_ao_data(MultiresBakeRender *bkr, ImBuf *UNUSED(ibuf)) { MAOBakeData *ao_data; DerivedMesh *lodm = bkr->lores_dm; @@ -1313,8 +1314,12 @@ static void apply_ao_callback(DerivedMesh *lores_dm, /* ******$***************** Post processing ************************* */ -static void bake_ibuf_filter( - ImBuf *ibuf, char *mask, const int margin, const char margin_type, DerivedMesh *dm) +static void bake_ibuf_filter(ImBuf *ibuf, + char *mask, + const int margin, + const char margin_type, + DerivedMesh *dm, + const float uv_offset[2]) { /* must check before filtering */ const bool is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf); @@ -1322,7 +1327,7 @@ static void bake_ibuf_filter( if (margin) { switch (margin_type) { case R_BAKE_ADJACENT_FACES: - RE_generate_texturemargin_adjacentfaces_dm(ibuf, mask, margin, dm); + RE_generate_texturemargin_adjacentfaces_dm(ibuf, mask, margin, dm, uv_offset); break; default: /* fall through */ @@ -1427,38 +1432,54 @@ static void bake_images(MultiresBakeRender *bkr, MultiresBakeResult *result) for (link = bkr->image.first; link; link = link->next) { Image *ima = (Image *)link->data; - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - - if (ibuf->x > 0 && ibuf->y > 0) { - BakeImBufuserData *userdata = MEM_callocN(sizeof(BakeImBufuserData), - "MultiresBake userdata"); - userdata->mask_buffer = MEM_callocN(ibuf->y * ibuf->x, "MultiresBake imbuf mask"); - ibuf->userdata = userdata; - - switch (bkr->mode) { - case RE_BAKE_NORMALS: - do_multires_bake( - bkr, ima, true, apply_tangmat_callback, init_normal_data, free_normal_data, result); - break; - case RE_BAKE_DISPLACEMENT: - do_multires_bake(bkr, - ima, - false, - apply_heights_callback, - init_heights_data, - free_heights_data, - result); - break; -/* TODO: restore ambient occlusion baking support. */ + + LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { + ImageUser iuser; + BKE_imageuser_default(&iuser); + iuser.tile = tile->tile_number; + + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); + + if (ibuf->x > 0 && ibuf->y > 0) { + BakeImBufuserData *userdata = MEM_callocN(sizeof(BakeImBufuserData), + "MultiresBake userdata"); + userdata->mask_buffer = MEM_callocN(ibuf->y * ibuf->x, "MultiresBake imbuf mask"); + ibuf->userdata = userdata; + + switch (bkr->mode) { + case RE_BAKE_NORMALS: + do_multires_bake(bkr, + ima, + tile, + ibuf, + true, + apply_tangmat_callback, + init_normal_data, + free_normal_data, + result); + break; + case RE_BAKE_DISPLACEMENT: + do_multires_bake(bkr, + ima, + tile, + ibuf, + false, + apply_heights_callback, + init_heights_data, + free_heights_data, + result); + break; + /* TODO: restore ambient occlusion baking support. */ #if 0 - case RE_BAKE_AO: - do_multires_bake(bkr, ima, false, apply_ao_callback, init_ao_data, free_ao_data, result); - break; + case RE_BAKE_AO: + do_multires_bake(bkr, ima, tile, ibuf, false, apply_ao_callback, init_ao_data, free_ao_data, result); + break; #endif + } } - } - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_release_ibuf(ima, ibuf, NULL); + } ima->id.tag |= LIB_TAG_DOIT; } @@ -1471,48 +1492,62 @@ static void finish_images(MultiresBakeRender *bkr, MultiresBakeResult *result) for (link = bkr->image.first; link; link = link->next) { Image *ima = (Image *)link->data; - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - BakeImBufuserData *userdata = (BakeImBufuserData *)ibuf->userdata; - if (ibuf->x <= 0 || ibuf->y <= 0) { - continue; - } + LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { + ImageUser iuser; + BKE_imageuser_default(&iuser); + iuser.tile = tile->tile_number; - if (use_displacement_buffer) { - bake_ibuf_normalize_displacement(ibuf, - userdata->displacement_buffer, - userdata->mask_buffer, - result->height_min, - result->height_max); - } + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); + BakeImBufuserData *userdata = (BakeImBufuserData *)ibuf->userdata; - bake_ibuf_filter( - ibuf, userdata->mask_buffer, bkr->bake_margin, bkr->bake_margin_type, bkr->lores_dm); + if (ibuf->x <= 0 || ibuf->y <= 0) { + continue; + } - ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; - BKE_image_mark_dirty(ima, ibuf); + if (use_displacement_buffer) { + bake_ibuf_normalize_displacement(ibuf, + userdata->displacement_buffer, + userdata->mask_buffer, + result->height_min, + result->height_max); + } - if (ibuf->rect_float) { - ibuf->userflags |= IB_RECT_INVALID; - } + float uv_offset[2]; + BKE_image_get_tile_uv(ima, tile->tile_number, uv_offset); - if (ibuf->mipmap[0]) { - ibuf->userflags |= IB_MIPMAP_INVALID; - imb_freemipmapImBuf(ibuf); - } + bake_ibuf_filter(ibuf, + userdata->mask_buffer, + bkr->bake_margin, + bkr->bake_margin_type, + bkr->lores_dm, + uv_offset); + + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + BKE_image_mark_dirty(ima, ibuf); - if (ibuf->userdata) { - if (userdata->displacement_buffer) { - MEM_freeN(userdata->displacement_buffer); + if (ibuf->rect_float) { + ibuf->userflags |= IB_RECT_INVALID; } - MEM_freeN(userdata->mask_buffer); - MEM_freeN(userdata); - ibuf->userdata = NULL; - } + if (ibuf->mipmap[0]) { + ibuf->userflags |= IB_MIPMAP_INVALID; + imb_freemipmapImBuf(ibuf); + } + + if (ibuf->userdata) { + if (userdata->displacement_buffer) { + MEM_freeN(userdata->displacement_buffer); + } - BKE_image_release_ibuf(ima, ibuf, NULL); - DEG_id_tag_update(&ima->id, 0); + MEM_freeN(userdata->mask_buffer); + MEM_freeN(userdata); + ibuf->userdata = NULL; + } + + BKE_image_release_ibuf(ima, ibuf, NULL); + DEG_id_tag_update(&ima->id, 0); + } } } diff --git a/source/blender/render/intern/texture_margin.cc b/source/blender/render/intern/texture_margin.cc index d01c0dbea71..2d68148a86a 100644 --- a/source/blender/render/intern/texture_margin.cc +++ b/source/blender/render/intern/texture_margin.cc @@ -46,6 +46,7 @@ class TextureMarginMap { Vector<int> loop_to_poly_map_; int w_, h_; + float uv_offset_[2]; Vector<uint32_t> pixel_data_; ZSpan zspan_; uint32_t value_to_store_; @@ -61,6 +62,7 @@ class TextureMarginMap { public: TextureMarginMap(size_t w, size_t h, + const float uv_offset[2], MPoly const *mpoly, MLoop const *mloop, MLoopUV const *mloopuv, @@ -76,6 +78,8 @@ class TextureMarginMap { totloop_(totloop), totedge_(totedge) { + copy_v2_v2(uv_offset_, uv_offset); + pixel_data_.resize(w_ * h_, 0xFFFFFFFF); zbuf_alloc_span(&zspan_, w_, h_); @@ -277,8 +281,8 @@ class TextureMarginMap { float2 uv_to_xy(MLoopUV const &mloopuv) const { float2 ret; - ret.x = ((mloopuv.uv[0] * w_) - (0.5f + 0.001f)); - ret.y = ((mloopuv.uv[1] * h_) - (0.5f + 0.001f)); + ret.x = (((mloopuv.uv[0] - uv_offset_[0]) * w_) - (0.5f + 0.001f)); + ret.y = (((mloopuv.uv[1] - uv_offset_[1]) * h_) - (0.5f + 0.001f)); return ret; } @@ -482,7 +486,8 @@ static void generate_margin(ImBuf *ibuf, const int margin, const Mesh *me, DerivedMesh *dm, - char const *uv_layer) + char const *uv_layer, + const float uv_offset[2]) { MPoly *mpoly; @@ -531,7 +536,8 @@ static void generate_margin(ImBuf *ibuf, tottri = dm->getNumLoopTri(dm); } - TextureMarginMap map(ibuf->x, ibuf->y, mpoly, mloop, mloopuv, totpoly, totloop, totedge); + TextureMarginMap map( + ibuf->x, ibuf->y, uv_offset, mpoly, mloop, mloopuv, totpoly, totloop, totedge); bool draw_new_mask = false; /* Now the map contains 3 sorts of values: 0xFFFFFFFF for empty pixels, `0x80000000 + polyindex` @@ -555,8 +561,8 @@ static void generate_margin(ImBuf *ibuf, * intersection tests where a pixel gets in between 2 faces or the middle of a quad, * camera aligned quads also have this problem but they are less common. * Add a small offset to the UVs, fixes bug T18685. */ - vec[a][0] = uv[0] * (float)ibuf->x - (0.5f + 0.001f); - vec[a][1] = uv[1] * (float)ibuf->y - (0.5f + 0.002f); + vec[a][0] = (uv[0] - uv_offset[0]) * (float)ibuf->x - (0.5f + 0.001f); + vec[a][1] = (uv[1] - uv_offset[1]) * (float)ibuf->y - (0.5f + 0.002f); } /* NOTE: we need the top bit for the dijkstra distance map. */ @@ -592,16 +598,20 @@ static void generate_margin(ImBuf *ibuf, } // namespace blender::render::texturemargin -void RE_generate_texturemargin_adjacentfaces( - ImBuf *ibuf, char *mask, const int margin, const Mesh *me, char const *uv_layer) +void RE_generate_texturemargin_adjacentfaces(ImBuf *ibuf, + char *mask, + const int margin, + const Mesh *me, + char const *uv_layer, + const float uv_offset[2]) { - blender::render::texturemargin::generate_margin(ibuf, mask, margin, me, nullptr, uv_layer); + blender::render::texturemargin::generate_margin( + ibuf, mask, margin, me, nullptr, uv_layer, uv_offset); } -void RE_generate_texturemargin_adjacentfaces_dm(ImBuf *ibuf, - char *mask, - const int margin, - DerivedMesh *dm) +void RE_generate_texturemargin_adjacentfaces_dm( + ImBuf *ibuf, char *mask, const int margin, DerivedMesh *dm, const float uv_offset[2]) { - blender::render::texturemargin::generate_margin(ibuf, mask, margin, nullptr, dm, nullptr); + blender::render::texturemargin::generate_margin( + ibuf, mask, margin, nullptr, dm, nullptr, uv_offset); } |