Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brecht@blender.org>2021-02-11 20:48:21 +0300
committerBrecht Van Lommel <brecht@blender.org>2021-02-12 17:01:29 +0300
commit9febda912b04559277d465b9610334c04a73d2ce (patch)
treeed64b83783214e4605924de6fd4ab28001a132d5
parent9fa6e06287dc49f1fcf2bbfa150c0ff368668fed (diff)
Baking: support vertex color baking of normal material, UV discontinuities
Baking vertex colors per-corner leads to unwanted discontinuities when there is sampling noise, for example in ambient occlusion or with a bevel shader node for normals. For this reason the code used to always average results per-vertex. However when using split normals, multiple materials or UV islands, we do want to preserve discontinuities. So now bake per corner, but make sure the sampling seed is shared for vertices. Fix T85550: vertex color baking crash with split normals, Ref D10399 Fix T84663: vertex color baking blending at UV seams
-rw-r--r--intern/cycles/kernel/kernel_bake.h3
-rw-r--r--source/blender/editors/object/object_bake_api.c90
-rw-r--r--source/blender/render/RE_bake.h1
-rw-r--r--source/blender/render/intern/bake.c3
-rw-r--r--source/blender/render/intern/engine.c2
5 files changed, 66 insertions, 33 deletions
diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h
index e876e5d8ca6..359099d78c6 100644
--- a/intern/cycles/kernel/kernel_bake.h
+++ b/intern/cycles/kernel/kernel_bake.h
@@ -233,6 +233,7 @@ ccl_device void kernel_bake_evaluate(
ccl_global float *differential = buffer + kernel_data.film.pass_bake_differential;
ccl_global float *output = buffer + kernel_data.film.pass_combined;
+ int seed = __float_as_uint(primitive[0]);
int prim = __float_as_uint(primitive[1]);
if (prim == -1)
return;
@@ -240,7 +241,7 @@ ccl_device void kernel_bake_evaluate(
prim += kernel_data.bake.tri_offset;
/* Random number generator. */
- uint rng_hash = hash_uint2(x, y) ^ kernel_data.integrator.seed;
+ uint rng_hash = hash_uint(seed) ^ kernel_data.integrator.seed;
int num_samples = kernel_data.integrator.aa_samples;
float filter_x, filter_y;
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index db9e51a490d..7179cc26fc1 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -44,6 +44,7 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_object.h"
@@ -946,7 +947,7 @@ static bool bake_targets_init_vertex_colors(BakeTargets *targets, Object *ob, Re
targets->num_materials = ob->totcol;
BakeImage *bk_image = &targets->images[0];
- bk_image->width = me->totvert;
+ bk_image->width = me->totloop;
bk_image->height = 1;
bk_image->offset = 0;
bk_image->image = NULL;
@@ -968,6 +969,7 @@ static void bake_targets_populate_pixels_vertex_colors(BakeTargets *targets,
pixel->primitive_id = -1;
pixel->object_id = 0;
+ pixel->seed = 0;
pixel->du_dx = 0.0f;
pixel->du_dy = 0.0f;
pixel->dv_dx = 0.0f;
@@ -986,8 +988,8 @@ static void bake_targets_populate_pixels_vertex_colors(BakeTargets *targets,
const MLoopTri *lt = &looptri[i];
for (int j = 0; j < 3; j++) {
- const unsigned int v = me->mloop[lt->tri[j]].v;
- BakePixel *pixel = &pixel_array[v];
+ const unsigned int l = lt->tri[j];
+ BakePixel *pixel = &pixel_array[l];
if (pixel->primitive_id != -1) {
continue;
@@ -995,6 +997,11 @@ static void bake_targets_populate_pixels_vertex_colors(BakeTargets *targets,
pixel->primitive_id = i;
+ /* Seed is the vertex, so that sampling noise is coherent for the same
+ * vertex, but different corners can still have different normals,
+ * materials and UVs. */
+ pixel->seed = me->mloop[l].v;
+
/* Barycentric coordinates, nudged a bit to avoid precision issues that
* may happen when exactly at the vertex coordinate. */
if (j == 0) {
@@ -1015,24 +1022,24 @@ static void bake_targets_populate_pixels_vertex_colors(BakeTargets *targets,
MEM_freeN(looptri);
}
-static void bake_result_to_rgba(float rgba[4], const float *result, const int num_channels)
+static void bake_result_add_to_rgba(float rgba[4], const float *result, const int num_channels)
{
if (num_channels == 4) {
- copy_v4_v4(rgba, result);
+ add_v4_v4(rgba, result);
}
else if (num_channels == 3) {
- copy_v3_v3(rgba, result);
- rgba[3] = 1.0f;
+ add_v3_v3(rgba, result);
+ rgba[3] += 1.0f;
}
else {
- rgba[0] = result[0];
- rgba[1] = result[0];
- rgba[2] = result[0];
- rgba[3] = 1.0f;
+ rgba[0] += result[0];
+ rgba[1] += result[0];
+ rgba[2] += result[0];
+ rgba[3] += 1.0f;
}
}
-static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob)
+static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob, Mesh *me_split)
{
Mesh *me = ob->data;
MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
@@ -1040,26 +1047,45 @@ static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob)
const int num_channels = targets->num_channels;
const float *result = targets->result;
+ /* We bake using a mesh with additional vertices for split normals, but the
+ * number of loops must match to be able to transfer the vertex colors. */
+ BLI_assert(me->totloop == me_split->totloop);
+ UNUSED_VARS_NDEBUG(me_split);
+
if (mcol) {
- /* Float vertex colors in scene linear color space. */
const int totvert = me->totvert;
- for (int i = 0; i < totvert; i++, mcol++) {
- bake_result_to_rgba(mcol->color, &result[i * num_channels], num_channels);
+ const int totloop = me->totloop;
+
+ /* Accumulate float vertex colors in scene linear color space. */
+ int *num_loops_for_vertex = MEM_callocN(sizeof(int) * me->totvert, "num_loops_for_vertex");
+ memset(mcol, 0, sizeof(MPropCol) * me->totvert);
+
+ MLoop *mloop = me->mloop;
+ for (int i = 0; i < totloop; i++, mloop++) {
+ const int v = mloop->v;
+ bake_result_add_to_rgba(mcol[v].color, &result[i * num_channels], num_channels);
+ num_loops_for_vertex[v]++;
}
+
+ /* Normalize for number of loops. */
+ for (int i = 0; i < totvert; i++) {
+ if (num_loops_for_vertex[i] > 0) {
+ mul_v4_fl(mcol[i].color, 1.0f / num_loops_for_vertex[i]);
+ }
+ }
+
+ MEM_SAFE_FREE(num_loops_for_vertex);
}
else {
- /* Byte loop colors in sRGB colors space.
- *
- * Note that colors have been baked per vertex and not per corner, which
- * could be useful to preserve material discontinuities. However this also
- * leads to unintended discontinuities due to sampling noise. */
+ /* Byte loop colors in sRGB colors space. */
MLoop *mloop = me->mloop;
const int totloop = me->totloop;
const bool is_noncolor = targets->is_noncolor;
for (int i = 0; i < totloop; i++, mloop++, mloopcol++) {
float rgba[4];
- bake_result_to_rgba(rgba, &result[mloop->v * num_channels], num_channels);
+ zero_v4(rgba);
+ bake_result_add_to_rgba(rgba, &result[i * num_channels], num_channels);
if (is_noncolor) {
unit_float_to_uchar_clamp_v4(&mloopcol->r, rgba);
@@ -1142,7 +1168,7 @@ static bool bake_targets_output(const BakeAPIRender *bkr,
}
}
else if (bkr->target == R_BAKE_TARGET_VERTEX_COLORS) {
- return bake_targets_output_vertex_colors(targets, ob);
+ return bake_targets_output_vertex_colors(targets, ob, me);
}
return false;
@@ -1212,10 +1238,6 @@ static int bake(const BakeAPIRender *bkr,
}
}
- if (!bake_targets_init(bkr, &targets, ob_low, reports)) {
- goto cleanup;
- }
-
if (bkr->is_selected_to_active) {
CollectionPointerLink *link;
tot_highpoly = 0;
@@ -1245,9 +1267,6 @@ static int bake(const BakeAPIRender *bkr,
}
}
- pixel_array_low = MEM_mallocN(sizeof(BakePixel) * targets.num_pixels, "bake pixels low poly");
- pixel_array_high = MEM_mallocN(sizeof(BakePixel) * targets.num_pixels, "bake pixels high poly");
-
/* for multires bake, use linear UV subdivision to match low res UVs */
if (bkr->pass_type == SCE_PASS_NORMAL && bkr->normal_space == R_BAKE_SPACE_TANGENT &&
!bkr->is_selected_to_active) {
@@ -1265,11 +1284,17 @@ static int bake(const BakeAPIRender *bkr,
/* get the mesh as it arrives in the renderer */
me_low = bake_mesh_new_from_object(ob_low_eval);
- /* populate the pixel array with the face data */
+ /* Initialize bake targets. */
+ if (!bake_targets_init(bkr, &targets, ob_low_eval, reports)) {
+ goto cleanup;
+ }
+
+ /* Populate the pixel array with the face data. Except if we use a cage, then
+ * it is populated later with the cage mesh (smoothed version of the mesh). */
+ pixel_array_low = MEM_mallocN(sizeof(BakePixel) * targets.num_pixels, "bake pixels low poly");
if ((bkr->is_selected_to_active && (ob_cage == NULL) && bkr->is_cage) == false) {
bake_targets_populate_pixels(bkr, &targets, me_low, pixel_array_low);
}
- /* else populate the pixel array with the 'cage' mesh (the smooth version of the mesh) */
if (bkr->is_selected_to_active) {
CollectionPointerLink *link;
@@ -1358,6 +1383,9 @@ static int bake(const BakeAPIRender *bkr,
ob_low_eval->base_flag &= ~(BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER);
/* populate the pixel arrays with the corresponding face data for each high poly object */
+ pixel_array_high = MEM_mallocN(sizeof(BakePixel) * targets.num_pixels,
+ "bake pixels high poly");
+
if (!RE_bake_pixels_populate_from_objects(me_low,
pixel_array_low,
pixel_array_high,
diff --git a/source/blender/render/RE_bake.h b/source/blender/render/RE_bake.h
index 3463362adb1..bb30b524b61 100644
--- a/source/blender/render/RE_bake.h
+++ b/source/blender/render/RE_bake.h
@@ -59,6 +59,7 @@ typedef struct BakeTargets {
typedef struct BakePixel {
int primitive_id, object_id;
+ int seed;
float uv[2];
float du_dx, du_dy;
float dv_dx, dv_dy;
diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c
index caf81870fac..7af6d3e234f 100644
--- a/source/blender/render/intern/bake.c
+++ b/source/blender/render/intern/bake.c
@@ -135,6 +135,7 @@ static void store_bake_pixel(void *handle, int x, int y, float u, float v)
pixel->dv_dx = bd->dv_dx;
pixel->dv_dy = bd->dv_dy;
pixel->object_id = 0;
+ pixel->seed = i;
}
void RE_bake_mask_fill(const BakePixel pixel_array[], const size_t num_pixels, char *mask)
@@ -383,6 +384,7 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData,
pixel_high->primitive_id = primitive_id_high;
pixel_high->object_id = hit_mesh;
+ pixel_high->seed = pixel_id;
/* ray direction in high poly object space */
float dir_high[3];
@@ -434,6 +436,7 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData,
else {
pixel_array[pixel_id].primitive_id = -1;
pixel_array[pixel_id].object_id = -1;
+ pixel_array[pixel_id].seed = 0;
}
MEM_freeN(hits);
diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c
index 151d994dddf..b199b1b0743 100644
--- a/source/blender/render/intern/engine.c
+++ b/source/blender/render/intern/engine.c
@@ -194,7 +194,7 @@ static RenderResult *render_result_from_bake(RenderEngine *engine, int x, int y,
primitive[1] = int_as_float(-1);
}
else {
- primitive[0] = int_as_float(bake_pixel->object_id);
+ primitive[0] = int_as_float(bake_pixel->seed);
primitive[1] = int_as_float(bake_pixel->primitive_id);
primitive[2] = bake_pixel->uv[0];
primitive[3] = bake_pixel->uv[1];