Bake: add UDIM tile baking support
Works for both Cycles and multires bake. Triangles are baked to multiple UDIM images if they span across them, though such UV layouts are generally discouraged as there is no filtering across UDIM tiles. The bake margin currently only works within UDIM tiles. For the extend method this is logical, for the adjacent faces method it may be useful to support copying pixels from other UDIM tiles, though this seems somewhat complicated. Fixes T95190 Ref T72390
This commit is contained in:
@@ -414,6 +414,8 @@ int BKE_image_get_tile_from_pos(struct Image *ima,
|
|||||||
const float uv[2],
|
const float uv[2],
|
||||||
float r_uv[2],
|
float r_uv[2],
|
||||||
float r_ofs[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.
|
* Return the tile_number for the closest UDIM tile.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -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));
|
return BKE_image_get_tile(ima, image_get_tile_number_from_iuser(ima, iuser));
|
||||||
}
|
}
|
||||||
|
|
||||||
int BKE_image_get_tile_from_pos(struct Image *ima,
|
int BKE_image_get_tile_from_pos(Image *ima, const float uv[2], float r_uv[2], float r_ofs[2])
|
||||||
const float uv[2],
|
|
||||||
float r_uv[2],
|
|
||||||
float r_ofs[2])
|
|
||||||
{
|
{
|
||||||
float local_ofs[2];
|
float local_ofs[2];
|
||||||
if (r_ofs == nullptr) {
|
if (r_ofs == nullptr) {
|
||||||
@@ -860,6 +857,18 @@ int BKE_image_get_tile_from_pos(struct Image *ima,
|
|||||||
return tile_number;
|
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])
|
int BKE_image_find_nearest_tile(const Image *image, const float co[2])
|
||||||
{
|
{
|
||||||
const float co_floor[2] = {floorf(co[0]), floorf(co[1])};
|
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;
|
int tile_number_best = -1;
|
||||||
|
|
||||||
LISTBASE_FOREACH (const ImageTile *, tile, &image->tiles) {
|
LISTBASE_FOREACH (const ImageTile *, tile, &image->tiles) {
|
||||||
const int tile_index = tile->tile_number - 1001;
|
float uv_offset[2];
|
||||||
/* Coordinates of the current tile. */
|
BKE_image_get_tile_uv(image, tile->tile_number, uv_offset);
|
||||||
const float tile_index_co[2] = {static_cast<float>(tile_index % 10),
|
|
||||||
static_cast<float>(tile_index / 10)};
|
|
||||||
|
|
||||||
if (equals_v2v2(co_floor, tile_index_co)) {
|
if (equals_v2v2(co_floor, uv_offset)) {
|
||||||
return tile->tile_number;
|
return tile->tile_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Distance between co[2] and UDIM tile. */
|
/* 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) {
|
if (dist_sq < dist_best_sq) {
|
||||||
dist_best_sq = dist_sq;
|
dist_best_sq = dist_sq;
|
||||||
|
|||||||
@@ -172,28 +172,35 @@ static bool multiresbake_check(bContext *C, wmOperator *op)
|
|||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
else {
|
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) {
|
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
|
||||||
BKE_report(op->reports, RPT_ERROR, "Baking should happen to image with image buffer");
|
|
||||||
|
if (!ibuf) {
|
||||||
|
BKE_report(
|
||||||
|
op->reports, RPT_ERROR, "Baking should happen to image with image buffer");
|
||||||
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
|
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (ibuf->rect_float && !(ELEM(ibuf->channels, 0, 4))) {
|
if (ibuf->rect_float && !(ELEM(ibuf->channels, 0, 4))) {
|
||||||
ok = false;
|
ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
BKE_report(op->reports, RPT_ERROR, "Baking to unsupported image type");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ok) {
|
BKE_image_release_ibuf(ima, ibuf, NULL);
|
||||||
BKE_report(op->reports, RPT_ERROR, "Baking to unsupported image type");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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};
|
const float disp_solid[4] = {0.5f, 0.5f, 0.5f, 1.0f};
|
||||||
|
|
||||||
if ((image->id.tag & LIB_TAG_DOIT) == 0) {
|
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) {
|
ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, NULL);
|
||||||
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;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
BKE_image_release_ibuf(image, ibuf, NULL);
|
image->id.tag |= LIB_TAG_DOIT;
|
||||||
|
|
||||||
|
BKE_image_release_ibuf(image, ibuf, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "BLI_fileops.h"
|
#include "BLI_fileops.h"
|
||||||
#include "BLI_listbase.h"
|
#include "BLI_listbase.h"
|
||||||
#include "BLI_path_util.h"
|
#include "BLI_path_util.h"
|
||||||
|
#include "BLI_string.h"
|
||||||
|
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
#include "BKE_global.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,
|
static bool write_internal_bake_pixels(Image *image,
|
||||||
|
const int image_tile_number,
|
||||||
BakePixel pixel_array[],
|
BakePixel pixel_array[],
|
||||||
float *buffer,
|
float *buffer,
|
||||||
const int width,
|
const int width,
|
||||||
@@ -174,7 +176,8 @@ static bool write_internal_bake_pixels(Image *image,
|
|||||||
const bool is_clear,
|
const bool is_clear,
|
||||||
const bool is_noncolor,
|
const bool is_noncolor,
|
||||||
Mesh const *mesh_eval,
|
Mesh const *mesh_eval,
|
||||||
char const *uv_layer)
|
char const *uv_layer,
|
||||||
|
const float uv_offset[2])
|
||||||
{
|
{
|
||||||
ImBuf *ibuf;
|
ImBuf *ibuf;
|
||||||
void *lock;
|
void *lock;
|
||||||
@@ -182,7 +185,10 @@ static bool write_internal_bake_pixels(Image *image,
|
|||||||
char *mask_buffer = NULL;
|
char *mask_buffer = NULL;
|
||||||
const size_t pixels_num = (size_t)width * (size_t)height;
|
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) {
|
if (!ibuf) {
|
||||||
return false;
|
return false;
|
||||||
@@ -270,7 +276,7 @@ static bool write_internal_bake_pixels(Image *image,
|
|||||||
|
|
||||||
/* margins */
|
/* margins */
|
||||||
if (margin > 0) {
|
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;
|
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
|
||||||
@@ -303,10 +309,8 @@ static void bake_targets_refresh(BakeTargets *targets)
|
|||||||
|
|
||||||
if (ima) {
|
if (ima) {
|
||||||
BKE_image_partial_update_mark_full_update(ima);
|
BKE_image_partial_update_mark_full_update(ima);
|
||||||
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
|
BKE_image_free_gputextures(ima);
|
||||||
BKE_image_free_gputextures(ima);
|
DEG_id_tag_update(&ima->id, 0);
|
||||||
DEG_id_tag_update(&ima->id, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,7 +325,8 @@ static bool write_external_bake_pixels(const char *filepath,
|
|||||||
ImageFormatData *im_format,
|
ImageFormatData *im_format,
|
||||||
const bool is_noncolor,
|
const bool is_noncolor,
|
||||||
Mesh const *mesh_eval,
|
Mesh const *mesh_eval,
|
||||||
char const *uv_layer)
|
char const *uv_layer,
|
||||||
|
const float uv_offset[2])
|
||||||
{
|
{
|
||||||
ImBuf *ibuf = NULL;
|
ImBuf *ibuf = NULL;
|
||||||
bool ok = false;
|
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");
|
mask_buffer = MEM_callocN(sizeof(char) * pixels_num, "Bake Mask");
|
||||||
RE_bake_mask_fill(pixel_array, pixels_num, mask_buffer);
|
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) {
|
if (mask_buffer) {
|
||||||
MEM_freeN(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);
|
ED_object_get_active_image(ob, mat_nr, &image, NULL, &node, &ntree);
|
||||||
|
|
||||||
if (image) {
|
if (image) {
|
||||||
ImBuf *ibuf;
|
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
if (BKE_node_is_connected_to_output(ntree, node)) {
|
if (BKE_node_is_connected_to_output(ntree, node)) {
|
||||||
@@ -482,21 +486,27 @@ static bool bake_object_check(ViewLayer *view_layer,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *lock;
|
LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) {
|
||||||
ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
|
ImageUser iuser;
|
||||||
|
BKE_imageuser_default(&iuser);
|
||||||
|
iuser.tile = tile->tile_number;
|
||||||
|
|
||||||
if (ibuf) {
|
void *lock;
|
||||||
BKE_image_release_ibuf(image, ibuf, lock);
|
ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, &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);
|
if (ibuf) {
|
||||||
return false;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
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->materials_num = materials_num;
|
||||||
targets->images = MEM_callocN(sizeof(BakeImage) * targets->materials_num, "BakeTargets.images");
|
targets->material_to_image = MEM_callocN(sizeof(Image *) * targets->materials_num,
|
||||||
targets->material_to_image = MEM_callocN(sizeof(int) * targets->materials_num,
|
|
||||||
"BakeTargets.material_to_image");
|
"BakeTargets.material_to_image");
|
||||||
|
|
||||||
/* Error handling and tag (in case multiple materials share the same 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);
|
BKE_main_id_tag_idcode(bkr->main, ID_IM, LIB_TAG_DOIT, false);
|
||||||
|
|
||||||
|
targets->images = NULL;
|
||||||
|
|
||||||
for (int i = 0; i < materials_num; i++) {
|
for (int i = 0; i < materials_num; i++) {
|
||||||
Image *image;
|
Image *image;
|
||||||
ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL);
|
ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL);
|
||||||
|
|
||||||
/* Some materials have no image, we just ignore those cases. */
|
targets->material_to_image[i] = image;
|
||||||
if (image == NULL) {
|
|
||||||
targets->material_to_image[i] = -1;
|
/* Some materials have no image, we just ignore those cases.
|
||||||
}
|
* Also setup each image only once. */
|
||||||
else if (image->id.tag & LIB_TAG_DOIT) {
|
if (image && !(image->id.tag & LIB_TAG_DOIT)) {
|
||||||
for (int j = 0; j < i; j++) {
|
LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) {
|
||||||
if (targets->images[j].image == image) {
|
/* Add bake image. */
|
||||||
targets->material_to_image[i] = j;
|
targets->images = MEM_recallocN(targets->images,
|
||||||
break;
|
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;
|
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. */
|
/* Saving to image datablocks. */
|
||||||
for (int i = 0; i < targets->images_num; i++) {
|
for (int i = 0; i < targets->images_num; i++) {
|
||||||
BakeImage *bk_image = &targets->images[i];
|
BakeImage *bk_image = &targets->images[i];
|
||||||
|
|
||||||
|
ImageUser iuser;
|
||||||
|
BKE_imageuser_default(&iuser);
|
||||||
|
iuser.tile = bk_image->tile_number;
|
||||||
|
|
||||||
void *lock;
|
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) {
|
if (ibuf) {
|
||||||
bk_image->width = ibuf->x;
|
bk_image->width = ibuf->x;
|
||||||
bk_image->height = ibuf->y;
|
bk_image->height = ibuf->y;
|
||||||
bk_image->offset = targets->pixels_num;
|
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;
|
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++) {
|
for (int i = 0; i < targets->images_num; i++) {
|
||||||
BakeImage *bk_image = &targets->images[i];
|
BakeImage *bk_image = &targets->images[i];
|
||||||
const bool ok = write_internal_bake_pixels(bk_image->image,
|
const bool ok = write_internal_bake_pixels(bk_image->image,
|
||||||
|
bk_image->tile_number,
|
||||||
pixel_array + bk_image->offset,
|
pixel_array + bk_image->offset,
|
||||||
targets->result +
|
targets->result +
|
||||||
bk_image->offset * targets->channels_num,
|
bk_image->offset * targets->channels_num,
|
||||||
@@ -778,7 +794,8 @@ static bool bake_targets_output_internal(const BakeAPIRender *bkr,
|
|||||||
bkr->is_clear,
|
bkr->is_clear,
|
||||||
targets->is_noncolor,
|
targets->is_noncolor,
|
||||||
mesh_eval,
|
mesh_eval,
|
||||||
bkr->uv_layer);
|
bkr->uv_layer,
|
||||||
|
bk_image->uv_offset);
|
||||||
|
|
||||||
/* might be read by UI to set active image for display */
|
/* might be read by UI to set active image for display */
|
||||||
bake_update_image(bkr->area, bk_image->image);
|
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->width = bkr->width;
|
||||||
bk_image->height = bkr->height;
|
bk_image->height = bkr->height;
|
||||||
bk_image->offset = targets->pixels_num;
|
bk_image->offset = targets->pixels_num;
|
||||||
bk_image->image = NULL;
|
|
||||||
|
|
||||||
targets->pixels_num += (size_t)bkr->width * (size_t)bkr->height;
|
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) {
|
if (!bkr->is_split_materials) {
|
||||||
/* saving a single image */
|
/* saving a single image */
|
||||||
for (int i = 0; i < targets->materials_num; i++) {
|
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 (bkr->is_split_materials) {
|
||||||
if (bk_image->image) {
|
if (ob_eval->mat[i]) {
|
||||||
BLI_path_suffix(name, FILE_MAX, bk_image->image->id.name + 2, "_");
|
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 {
|
else {
|
||||||
if (ob_eval->mat[i]) {
|
/* if everything else fails, use the material index */
|
||||||
BLI_path_suffix(name, FILE_MAX, ob_eval->mat[i]->id.name + 2, "_");
|
char tmp[5];
|
||||||
}
|
sprintf(tmp, "%d", i % 1000);
|
||||||
else if (mesh_eval->mat[i]) {
|
BLI_path_suffix(name, FILE_MAX, tmp, "_");
|
||||||
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 (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 */
|
/* save it externally */
|
||||||
const bool ok = write_external_bake_pixels(name,
|
const bool ok = write_external_bake_pixels(name,
|
||||||
pixel_array + bk_image->offset,
|
pixel_array + bk_image->offset,
|
||||||
@@ -896,7 +913,8 @@ static bool bake_targets_output_external(const BakeAPIRender *bkr,
|
|||||||
&bake->im_format,
|
&bake->im_format,
|
||||||
targets->is_noncolor,
|
targets->is_noncolor,
|
||||||
mesh_eval,
|
mesh_eval,
|
||||||
bkr->uv_layer);
|
bkr->uv_layer,
|
||||||
|
bk_image->uv_offset);
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name);
|
BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name);
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ extern "C" {
|
|||||||
|
|
||||||
typedef struct BakeImage {
|
typedef struct BakeImage {
|
||||||
struct Image *image;
|
struct Image *image;
|
||||||
|
int tile_number;
|
||||||
|
float uv_offset[2];
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
@@ -30,7 +32,7 @@ typedef struct BakeTargets {
|
|||||||
int images_num;
|
int images_num;
|
||||||
|
|
||||||
/* Lookup table from Material number to BakeImage. */
|
/* Lookup table from Material number to BakeImage. */
|
||||||
int *material_to_image;
|
struct Image **material_to_image;
|
||||||
int materials_num;
|
int materials_num;
|
||||||
|
|
||||||
/* Pixel buffer to bake to. */
|
/* Pixel buffer to bake to. */
|
||||||
@@ -104,7 +106,8 @@ void RE_bake_margin(struct ImBuf *ibuf,
|
|||||||
int margin,
|
int margin,
|
||||||
char margin_type,
|
char margin_type,
|
||||||
struct Mesh const *me,
|
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[],
|
void RE_bake_normal_world_to_object(const BakePixel pixel_array[],
|
||||||
size_t pixels_num,
|
size_t pixels_num,
|
||||||
|
|||||||
@@ -25,13 +25,18 @@ struct Mesh;
|
|||||||
* \param me: the mesh to use the polygons of.
|
* \param me: the mesh to use the polygons of.
|
||||||
* \param uv_layer: The UV layer to use.
|
* \param uv_layer: The UV layer to use.
|
||||||
*/
|
*/
|
||||||
void RE_generate_texturemargin_adjacentfaces(
|
void RE_generate_texturemargin_adjacentfaces(struct ImBuf *ibuf,
|
||||||
struct ImBuf *ibuf, char *mask, const int margin, struct Mesh const *me, char const *uv_layer);
|
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,
|
void RE_generate_texturemargin_adjacentfaces_dm(struct ImBuf *ibuf,
|
||||||
char *mask,
|
char *mask,
|
||||||
const int margin,
|
const int margin,
|
||||||
struct DerivedMesh *dm);
|
struct DerivedMesh *dm,
|
||||||
|
const float uv_offset[2]);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,12 +146,13 @@ void RE_bake_margin(ImBuf *ibuf,
|
|||||||
const int margin,
|
const int margin,
|
||||||
const char margin_type,
|
const char margin_type,
|
||||||
Mesh const *me,
|
Mesh const *me,
|
||||||
char const *uv_layer)
|
char const *uv_layer,
|
||||||
|
const float uv_offset[2])
|
||||||
{
|
{
|
||||||
/* margin */
|
/* margin */
|
||||||
switch (margin_type) {
|
switch (margin_type) {
|
||||||
case R_BAKE_ADJACENT_FACES:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
/* fall through */
|
/* fall through */
|
||||||
@@ -746,30 +747,36 @@ void RE_bake_pixels_populate(Mesh *me,
|
|||||||
for (int i = 0; i < tottri; i++) {
|
for (int i = 0; i < tottri; i++) {
|
||||||
const MLoopTri *lt = &looptri[i];
|
const MLoopTri *lt = &looptri[i];
|
||||||
const MPoly *mp = &me->mpoly[lt->poly];
|
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;
|
bd.primitive_id = i;
|
||||||
|
|
||||||
for (int a = 0; a < 3; a++) {
|
/* Find images matching this material. */
|
||||||
const float *uv = mloopuv[lt->tri[a]].uv;
|
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
|
/* Compute triangle vertex UV coordinates. */
|
||||||
* intersection tests where a pixel gets in between 2 faces or the middle of a quad,
|
float vec[3][2];
|
||||||
* camera aligned quads also have this problem but they are less common.
|
for (int a = 0; a < 3; a++) {
|
||||||
* Add a small offset to the UVs, fixes bug T18685. */
|
const float *uv = mloopuv[lt->tri[a]].uv;
|
||||||
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);
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
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++) {
|
for (int i = 0; i < targets->images_num; i++) {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ typedef void (*MPassKnownData)(DerivedMesh *lores_dm,
|
|||||||
const int x,
|
const int x,
|
||||||
const int y);
|
const int y);
|
||||||
|
|
||||||
typedef void *(*MInitBakeData)(MultiresBakeRender *bkr, Image *ima);
|
typedef void *(*MInitBakeData)(MultiresBakeRender *bkr, ImBuf *ibuf);
|
||||||
typedef void (*MFreeBakeData)(void *bake_data);
|
typedef void (*MFreeBakeData)(void *bake_data);
|
||||||
|
|
||||||
typedef struct MultiresBakeResult {
|
typedef struct MultiresBakeResult {
|
||||||
@@ -64,6 +64,7 @@ typedef struct {
|
|||||||
MPoly *mpoly;
|
MPoly *mpoly;
|
||||||
MLoop *mloop;
|
MLoop *mloop;
|
||||||
MLoopUV *mloopuv;
|
MLoopUV *mloopuv;
|
||||||
|
float uv_offset[2];
|
||||||
const MLoopTri *mlooptri;
|
const MLoopTri *mlooptri;
|
||||||
float *pvtangent;
|
float *pvtangent;
|
||||||
const float (*precomputed_normals)[3];
|
const float (*precomputed_normals)[3];
|
||||||
@@ -91,7 +92,6 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
float *heights;
|
float *heights;
|
||||||
Image *ima;
|
|
||||||
DerivedMesh *ssdm;
|
DerivedMesh *ssdm;
|
||||||
const int *orig_index_mp_to_orig;
|
const int *orig_index_mp_to_orig;
|
||||||
} MHeightBakeData;
|
} 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)
|
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 *st0, *st1, *st2;
|
||||||
const float *tang0, *tang1, *tang2;
|
const float *tang0, *tang1, *tang2;
|
||||||
float no0[3], no1[3], no2[3];
|
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;
|
data->tri_index = tri_index;
|
||||||
|
|
||||||
bake_rasterize(
|
float uv[3][2];
|
||||||
bake_rast, mloopuv[lt->tri[0]].uv, mloopuv[lt->tri[1]].uv, mloopuv[lt->tri[2]].uv);
|
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 */
|
/* tag image buffer for refresh */
|
||||||
if (data->ibuf->rect_float) {
|
if (data->ibuf->rect_float) {
|
||||||
@@ -447,6 +452,8 @@ static void init_ccgdm_arrays(DerivedMesh *dm)
|
|||||||
|
|
||||||
static void do_multires_bake(MultiresBakeRender *bkr,
|
static void do_multires_bake(MultiresBakeRender *bkr,
|
||||||
Image *ima,
|
Image *ima,
|
||||||
|
ImageTile *tile,
|
||||||
|
ImBuf *ibuf,
|
||||||
bool require_tangent,
|
bool require_tangent,
|
||||||
MPassKnownData passKnownData,
|
MPassKnownData passKnownData,
|
||||||
MInitBakeData initBakeData,
|
MInitBakeData initBakeData,
|
||||||
@@ -462,7 +469,6 @@ static void do_multires_bake(MultiresBakeRender *bkr,
|
|||||||
MultiresBakeThread *handles;
|
MultiresBakeThread *handles;
|
||||||
MultiresBakeQueue queue;
|
MultiresBakeQueue queue;
|
||||||
|
|
||||||
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
|
|
||||||
MVert *mvert = dm->getVertArray(dm);
|
MVert *mvert = dm->getVertArray(dm);
|
||||||
MPoly *mpoly = dm->getPolyArray(dm);
|
MPoly *mpoly = dm->getPolyArray(dm);
|
||||||
MLoop *mloop = dm->getLoopArray(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 */
|
/* all threads shares the same custom bake data */
|
||||||
if (initBakeData) {
|
if (initBakeData) {
|
||||||
bake_data = initBakeData(bkr, ima);
|
bake_data = initBakeData(bkr, ibuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tot_thread > 1) {
|
if (tot_thread > 1) {
|
||||||
@@ -539,6 +545,7 @@ static void do_multires_bake(MultiresBakeRender *bkr,
|
|||||||
handle->data.mvert = mvert;
|
handle->data.mvert = mvert;
|
||||||
handle->data.vert_normals = vert_normals;
|
handle->data.vert_normals = vert_normals;
|
||||||
handle->data.mloopuv = mloopuv;
|
handle->data.mloopuv = mloopuv;
|
||||||
|
BKE_image_get_tile_uv(ima, tile->tile_number, handle->data.uv_offset);
|
||||||
handle->data.mlooptri = mlooptri;
|
handle->data.mlooptri = mlooptri;
|
||||||
handle->data.mloop = mloop;
|
handle->data.mloop = mloop;
|
||||||
handle->data.pvtangent = pvtangent;
|
handle->data.pvtangent = pvtangent;
|
||||||
@@ -590,8 +597,6 @@ static void do_multires_bake(MultiresBakeRender *bkr,
|
|||||||
MEM_freeN(handles);
|
MEM_freeN(handles);
|
||||||
|
|
||||||
BKE_id_free(NULL, temp_mesh);
|
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 **************** */
|
/* **************** Displacement Baker **************** */
|
||||||
|
|
||||||
static void *init_heights_data(MultiresBakeRender *bkr, Image *ima)
|
static void *init_heights_data(MultiresBakeRender *bkr, ImBuf *ibuf)
|
||||||
{
|
{
|
||||||
MHeightBakeData *height_data;
|
MHeightBakeData *height_data;
|
||||||
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
|
|
||||||
DerivedMesh *lodm = bkr->lores_dm;
|
DerivedMesh *lodm = bkr->lores_dm;
|
||||||
BakeImBufuserData *userdata = ibuf->userdata;
|
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 = MEM_callocN(sizeof(MHeightBakeData), "MultiresBake heightData");
|
||||||
|
|
||||||
height_data->ima = ima;
|
|
||||||
height_data->heights = userdata->displacement_buffer;
|
height_data->heights = userdata->displacement_buffer;
|
||||||
|
|
||||||
if (!bkr->use_lores_mesh) {
|
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);
|
height_data->orig_index_mp_to_orig = lodm->getPolyDataArray(lodm, CD_ORIGINDEX);
|
||||||
|
|
||||||
BKE_image_release_ibuf(ima, ibuf, NULL);
|
|
||||||
|
|
||||||
return (void *)height_data;
|
return (void *)height_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -903,7 +904,7 @@ static void apply_heights_callback(DerivedMesh *lores_dm,
|
|||||||
|
|
||||||
/* **************** Normal Maps Baker **************** */
|
/* **************** 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;
|
MNormalBakeData *normal_data;
|
||||||
DerivedMesh *lodm = bkr->lores_dm;
|
DerivedMesh *lodm = bkr->lores_dm;
|
||||||
@@ -1099,7 +1100,7 @@ static void create_ao_raytree(MultiresBakeRender *bkr, MAOBakeData *ao_data)
|
|||||||
RE_rayobject_done(raytree);
|
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;
|
MAOBakeData *ao_data;
|
||||||
DerivedMesh *lodm = bkr->lores_dm;
|
DerivedMesh *lodm = bkr->lores_dm;
|
||||||
@@ -1313,8 +1314,12 @@ static void apply_ao_callback(DerivedMesh *lores_dm,
|
|||||||
|
|
||||||
/* ******$***************** Post processing ************************* */
|
/* ******$***************** Post processing ************************* */
|
||||||
|
|
||||||
static void bake_ibuf_filter(
|
static void bake_ibuf_filter(ImBuf *ibuf,
|
||||||
ImBuf *ibuf, char *mask, const int margin, const char margin_type, DerivedMesh *dm)
|
char *mask,
|
||||||
|
const int margin,
|
||||||
|
const char margin_type,
|
||||||
|
DerivedMesh *dm,
|
||||||
|
const float uv_offset[2])
|
||||||
{
|
{
|
||||||
/* must check before filtering */
|
/* must check before filtering */
|
||||||
const bool is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf);
|
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) {
|
if (margin) {
|
||||||
switch (margin_type) {
|
switch (margin_type) {
|
||||||
case R_BAKE_ADJACENT_FACES:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
/* fall through */
|
/* fall through */
|
||||||
@@ -1427,38 +1432,54 @@ static void bake_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
|
|||||||
|
|
||||||
for (link = bkr->image.first; link; link = link->next) {
|
for (link = bkr->image.first; link; link = link->next) {
|
||||||
Image *ima = (Image *)link->data;
|
Image *ima = (Image *)link->data;
|
||||||
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
|
|
||||||
|
|
||||||
if (ibuf->x > 0 && ibuf->y > 0) {
|
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
|
||||||
BakeImBufuserData *userdata = MEM_callocN(sizeof(BakeImBufuserData),
|
ImageUser iuser;
|
||||||
"MultiresBake userdata");
|
BKE_imageuser_default(&iuser);
|
||||||
userdata->mask_buffer = MEM_callocN(ibuf->y * ibuf->x, "MultiresBake imbuf mask");
|
iuser.tile = tile->tile_number;
|
||||||
ibuf->userdata = userdata;
|
|
||||||
|
|
||||||
switch (bkr->mode) {
|
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
|
||||||
case RE_BAKE_NORMALS:
|
|
||||||
do_multires_bake(
|
if (ibuf->x > 0 && ibuf->y > 0) {
|
||||||
bkr, ima, true, apply_tangmat_callback, init_normal_data, free_normal_data, result);
|
BakeImBufuserData *userdata = MEM_callocN(sizeof(BakeImBufuserData),
|
||||||
break;
|
"MultiresBake userdata");
|
||||||
case RE_BAKE_DISPLACEMENT:
|
userdata->mask_buffer = MEM_callocN(ibuf->y * ibuf->x, "MultiresBake imbuf mask");
|
||||||
do_multires_bake(bkr,
|
ibuf->userdata = userdata;
|
||||||
ima,
|
|
||||||
false,
|
switch (bkr->mode) {
|
||||||
apply_heights_callback,
|
case RE_BAKE_NORMALS:
|
||||||
init_heights_data,
|
do_multires_bake(bkr,
|
||||||
free_heights_data,
|
ima,
|
||||||
result);
|
tile,
|
||||||
break;
|
ibuf,
|
||||||
/* TODO: restore ambient occlusion baking support. */
|
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
|
#if 0
|
||||||
case RE_BAKE_AO:
|
case RE_BAKE_AO:
|
||||||
do_multires_bake(bkr, ima, false, apply_ao_callback, init_ao_data, free_ao_data, result);
|
do_multires_bake(bkr, ima, tile, ibuf, false, apply_ao_callback, init_ao_data, free_ao_data, result);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
BKE_image_release_ibuf(ima, ibuf, NULL);
|
BKE_image_release_ibuf(ima, ibuf, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
ima->id.tag |= LIB_TAG_DOIT;
|
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) {
|
for (link = bkr->image.first; link; link = link->next) {
|
||||||
Image *ima = (Image *)link->data;
|
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) {
|
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
|
||||||
continue;
|
ImageUser iuser;
|
||||||
}
|
BKE_imageuser_default(&iuser);
|
||||||
|
iuser.tile = tile->tile_number;
|
||||||
|
|
||||||
if (use_displacement_buffer) {
|
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
|
||||||
bake_ibuf_normalize_displacement(ibuf,
|
BakeImBufuserData *userdata = (BakeImBufuserData *)ibuf->userdata;
|
||||||
userdata->displacement_buffer,
|
|
||||||
userdata->mask_buffer,
|
|
||||||
result->height_min,
|
|
||||||
result->height_max);
|
|
||||||
}
|
|
||||||
|
|
||||||
bake_ibuf_filter(
|
if (ibuf->x <= 0 || ibuf->y <= 0) {
|
||||||
ibuf, userdata->mask_buffer, bkr->bake_margin, bkr->bake_margin_type, bkr->lores_dm);
|
continue;
|
||||||
|
|
||||||
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
|
|
||||||
BKE_image_mark_dirty(ima, ibuf);
|
|
||||||
|
|
||||||
if (ibuf->rect_float) {
|
|
||||||
ibuf->userflags |= IB_RECT_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ibuf->mipmap[0]) {
|
|
||||||
ibuf->userflags |= IB_MIPMAP_INVALID;
|
|
||||||
imb_freemipmapImBuf(ibuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ibuf->userdata) {
|
|
||||||
if (userdata->displacement_buffer) {
|
|
||||||
MEM_freeN(userdata->displacement_buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MEM_freeN(userdata->mask_buffer);
|
if (use_displacement_buffer) {
|
||||||
MEM_freeN(userdata);
|
bake_ibuf_normalize_displacement(ibuf,
|
||||||
ibuf->userdata = NULL;
|
userdata->displacement_buffer,
|
||||||
}
|
userdata->mask_buffer,
|
||||||
|
result->height_min,
|
||||||
|
result->height_max);
|
||||||
|
}
|
||||||
|
|
||||||
BKE_image_release_ibuf(ima, ibuf, NULL);
|
float uv_offset[2];
|
||||||
DEG_id_tag_update(&ima->id, 0);
|
BKE_image_get_tile_uv(ima, tile->tile_number, uv_offset);
|
||||||
|
|
||||||
|
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->rect_float) {
|
||||||
|
ibuf->userflags |= IB_RECT_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ibuf->mipmap[0]) {
|
||||||
|
ibuf->userflags |= IB_MIPMAP_INVALID;
|
||||||
|
imb_freemipmapImBuf(ibuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ibuf->userdata) {
|
||||||
|
if (userdata->displacement_buffer) {
|
||||||
|
MEM_freeN(userdata->displacement_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ class TextureMarginMap {
|
|||||||
Vector<int> loop_to_poly_map_;
|
Vector<int> loop_to_poly_map_;
|
||||||
|
|
||||||
int w_, h_;
|
int w_, h_;
|
||||||
|
float uv_offset_[2];
|
||||||
Vector<uint32_t> pixel_data_;
|
Vector<uint32_t> pixel_data_;
|
||||||
ZSpan zspan_;
|
ZSpan zspan_;
|
||||||
uint32_t value_to_store_;
|
uint32_t value_to_store_;
|
||||||
@@ -61,6 +62,7 @@ class TextureMarginMap {
|
|||||||
public:
|
public:
|
||||||
TextureMarginMap(size_t w,
|
TextureMarginMap(size_t w,
|
||||||
size_t h,
|
size_t h,
|
||||||
|
const float uv_offset[2],
|
||||||
MPoly const *mpoly,
|
MPoly const *mpoly,
|
||||||
MLoop const *mloop,
|
MLoop const *mloop,
|
||||||
MLoopUV const *mloopuv,
|
MLoopUV const *mloopuv,
|
||||||
@@ -76,6 +78,8 @@ class TextureMarginMap {
|
|||||||
totloop_(totloop),
|
totloop_(totloop),
|
||||||
totedge_(totedge)
|
totedge_(totedge)
|
||||||
{
|
{
|
||||||
|
copy_v2_v2(uv_offset_, uv_offset);
|
||||||
|
|
||||||
pixel_data_.resize(w_ * h_, 0xFFFFFFFF);
|
pixel_data_.resize(w_ * h_, 0xFFFFFFFF);
|
||||||
|
|
||||||
zbuf_alloc_span(&zspan_, w_, h_);
|
zbuf_alloc_span(&zspan_, w_, h_);
|
||||||
@@ -277,8 +281,8 @@ class TextureMarginMap {
|
|||||||
float2 uv_to_xy(MLoopUV const &mloopuv) const
|
float2 uv_to_xy(MLoopUV const &mloopuv) const
|
||||||
{
|
{
|
||||||
float2 ret;
|
float2 ret;
|
||||||
ret.x = ((mloopuv.uv[0] * w_) - (0.5f + 0.001f));
|
ret.x = (((mloopuv.uv[0] - uv_offset_[0]) * w_) - (0.5f + 0.001f));
|
||||||
ret.y = ((mloopuv.uv[1] * h_) - (0.5f + 0.001f));
|
ret.y = (((mloopuv.uv[1] - uv_offset_[1]) * h_) - (0.5f + 0.001f));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,7 +486,8 @@ static void generate_margin(ImBuf *ibuf,
|
|||||||
const int margin,
|
const int margin,
|
||||||
const Mesh *me,
|
const Mesh *me,
|
||||||
DerivedMesh *dm,
|
DerivedMesh *dm,
|
||||||
char const *uv_layer)
|
char const *uv_layer,
|
||||||
|
const float uv_offset[2])
|
||||||
{
|
{
|
||||||
|
|
||||||
MPoly *mpoly;
|
MPoly *mpoly;
|
||||||
@@ -531,7 +536,8 @@ static void generate_margin(ImBuf *ibuf,
|
|||||||
tottri = dm->getNumLoopTri(dm);
|
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;
|
bool draw_new_mask = false;
|
||||||
/* Now the map contains 3 sorts of values: 0xFFFFFFFF for empty pixels, `0x80000000 + polyindex`
|
/* 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,
|
* 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.
|
* camera aligned quads also have this problem but they are less common.
|
||||||
* Add a small offset to the UVs, fixes bug T18685. */
|
* Add a small offset to the UVs, fixes bug T18685. */
|
||||||
vec[a][0] = uv[0] * (float)ibuf->x - (0.5f + 0.001f);
|
vec[a][0] = (uv[0] - uv_offset[0]) * (float)ibuf->x - (0.5f + 0.001f);
|
||||||
vec[a][1] = uv[1] * (float)ibuf->y - (0.5f + 0.002f);
|
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. */
|
/* 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
|
} // namespace blender::render::texturemargin
|
||||||
|
|
||||||
void RE_generate_texturemargin_adjacentfaces(
|
void RE_generate_texturemargin_adjacentfaces(ImBuf *ibuf,
|
||||||
ImBuf *ibuf, char *mask, const int margin, const Mesh *me, char const *uv_layer)
|
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,
|
void RE_generate_texturemargin_adjacentfaces_dm(
|
||||||
char *mask,
|
ImBuf *ibuf, char *mask, const int margin, DerivedMesh *dm, const float uv_offset[2])
|
||||||
const int margin,
|
|
||||||
DerivedMesh *dm)
|
|
||||||
{
|
{
|
||||||
blender::render::texturemargin::generate_margin(ibuf, mask, margin, nullptr, dm, nullptr);
|
blender::render::texturemargin::generate_margin(
|
||||||
|
ibuf, mask, margin, nullptr, dm, nullptr, uv_offset);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user