Fix #72011: Visible artifacts after baking normals with bevel shader

Pull Request: https://projects.blender.org/blender/blender/pulls/106988
This commit is contained in:
Lukas Stockner
2023-05-07 22:41:47 +02:00
committed by Lukas Stockner
parent c502d3ac53
commit c431b69a8a

View File

@@ -169,6 +169,39 @@ static void bake_update_image(ScrArea *area, Image *image)
}
}
/* Bias almost-flat normals in tangent space to be flat to avoid artifacts in byte textures.
* For some types of normal baking, especially bevels, you can end up with a small amount
* of noise in the result. Since the border between pixel value 127 and 128 is exactly 0.5,
* the tiniest amount of deviation will flip between those two, and increasing samples won't
* help - you always end up with visible "dents" in the resulting normal map.
* Therefore, this function snaps values that are less than half a quantization level away
* from 0.5 to 0.5, so that they consistently become pixel value 128.
* This only makes sense for byte textures of course, and is not used when baking to float
* textures (which includes 16-bit formats). Also, it's only applied to the first two channels,
* since on flat surfaces the Z channel will be close enough to 1.0 to reliably end up on 255.
*/
void bias_tangent_normal_pixels(float *rect,
int channels,
int width,
int height,
int stride)
{
BLI_assert(channels >= 3);
for (int y = 0; y < height; y++) {
float *pixels = rect + ((size_t)stride) * y * channels;
for (int x = 0; x < width; x++, pixels += channels) {
if (fabsf(pixels[0] - 0.5f) < 1.0f / 255.0f) {
pixels[0] = 0.5f + 1e-5f;
}
if (fabsf(pixels[1] - 0.5f) < 1.0f / 255.0f) {
pixels[1] = 0.5f + 1e-5f;
}
}
}
}
static bool write_internal_bake_pixels(Image *image,
const int image_tile_number,
BakePixel pixel_array[],
@@ -179,6 +212,7 @@ static bool write_internal_bake_pixels(Image *image,
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])
@@ -224,6 +258,10 @@ static bool write_internal_bake_pixels(Image *image,
buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, false);
}
}
else if (!is_float && is_tangent_normal) {
/* bias neutral values when converting tangent-space normal maps to byte textures */
bias_tangent_normal_pixels(buffer, ibuf->channels, ibuf->x, ibuf->y, ibuf->x);
}
/* populates the ImBuf */
if (is_clear) {
@@ -328,6 +366,7 @@ static bool write_external_bake_pixels(const char *filepath,
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])
@@ -366,6 +405,10 @@ static bool write_external_bake_pixels(const char *filepath,
IMB_colormanagement_transform(
buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, false);
}
else if (is_tangent_normal) {
/* bias neutral values when converting tangent-space normal maps to byte textures */
bias_tangent_normal_pixels(buffer, ibuf->channels, ibuf->x, ibuf->y, ibuf->x);
}
IMB_buffer_byte_from_float((uchar *)ibuf->rect,
buffer,
@@ -789,6 +832,7 @@ static bool bake_targets_output_internal(const BakeAPIRender *bkr,
Mesh *mesh_eval)
{
bool all_ok = true;
const bool is_tangent_normal = (bkr->pass_type == SCE_PASS_NORMAL) && (bkr->normal_space == R_BAKE_SPACE_TANGENT);
for (int i = 0; i < targets->images_num; i++) {
BakeImage *bk_image = &targets->images[i];
@@ -803,6 +847,7 @@ static bool bake_targets_output_internal(const BakeAPIRender *bkr,
bkr->margin_type,
bkr->is_clear,
targets->is_noncolor,
is_tangent_normal,
mesh_eval,
bkr->uv_layer,
bk_image->uv_offset);
@@ -869,6 +914,7 @@ static bool bake_targets_output_external(const BakeAPIRender *bkr,
ReportList *reports)
{
bool all_ok = true;
const bool is_tangent_normal = (bkr->pass_type == SCE_PASS_NORMAL) && (bkr->normal_space == R_BAKE_SPACE_TANGENT);
for (int i = 0; i < targets->images_num; i++) {
BakeImage *bk_image = &targets->images[i];
@@ -922,6 +968,7 @@ static bool bake_targets_output_external(const BakeAPIRender *bkr,
bkr->margin_type,
&bake->im_format,
targets->is_noncolor,
is_tangent_normal,
mesh_eval,
bkr->uv_layer,
bk_image->uv_offset);