Cleanup: Improve precision during UV packing.
Simplify API and improve accuracy of uv packing placement by using pre-translation and double precision internally. Will protect against future precision problems with UDIM. No user visible changes expected. Maniphest Tasks: T68889 Differential Revision: https://developer.blender.org/D16362
This commit is contained in:
@@ -113,17 +113,6 @@ void BM_face_uv_minmax(const BMFace *f, float min[2], float max[2], const int cd
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
}
|
||||
|
||||
void BM_face_uv_transform(BMFace *f, const float matrix[2][2], const int cd_loop_uv_offset)
|
||||
{
|
||||
BMLoop *l_iter;
|
||||
BMLoop *l_first;
|
||||
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
||||
do {
|
||||
MLoopUV *luv = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
|
||||
mul_m2_v2(matrix, luv->uv);
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
}
|
||||
|
||||
bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
|
||||
{
|
||||
BLI_assert(l_a->e == l_b->e);
|
||||
|
||||
@@ -34,7 +34,6 @@ float BM_face_uv_calc_cross(const BMFace *f, int cd_loop_uv_offset) ATTR_WARN_UN
|
||||
ATTR_NONNULL();
|
||||
|
||||
void BM_face_uv_minmax(const BMFace *f, float min[2], float max[2], int cd_loop_uv_offset);
|
||||
void BM_face_uv_transform(BMFace *f, const float matrix[2][2], int cd_loop_uv_offset);
|
||||
|
||||
bool BM_loop_uv_share_edge_check_with_limit(BMLoop *l_a,
|
||||
BMLoop *l_b,
|
||||
|
||||
@@ -36,28 +36,47 @@
|
||||
|
||||
#include "bmesh.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name UV Face Utilities
|
||||
* \{ */
|
||||
|
||||
static void bm_face_uv_translate_and_scale_around_pivot(BMFace *f,
|
||||
const float offset[2],
|
||||
const float scale[2],
|
||||
const float pivot[2],
|
||||
const int cd_loop_uv_offset)
|
||||
static void mul_v2_m2_add_v2v2(float r[2],
|
||||
const float mat[2][2],
|
||||
const float a[2],
|
||||
const float b[2])
|
||||
{
|
||||
BMLoop *l_iter;
|
||||
BMLoop *l_first;
|
||||
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
||||
do {
|
||||
MLoopUV *luv = static_cast<MLoopUV *>(BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset));
|
||||
for (int i = 0; i < 2; i++) {
|
||||
luv->uv[i] = offset[i] + (((luv->uv[i] - pivot[i]) * scale[i]) + pivot[i]);
|
||||
}
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
/* Compute `r = mat * (a + b)` with high precision. */
|
||||
const double x = static_cast<double>(a[0]) + static_cast<double>(b[0]);
|
||||
const double y = static_cast<double>(a[1]) + static_cast<double>(b[1]);
|
||||
|
||||
r[0] = static_cast<float>(mat[0][0] * x + mat[1][0] * y);
|
||||
r[1] = static_cast<float>(mat[0][1] * x + mat[1][1] * y);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
static void island_uv_transform(FaceIsland *island,
|
||||
const float matrix[2][2], /* Scale and rotation. */
|
||||
const float pre_translate[2] /* (pre) Translation. */
|
||||
)
|
||||
{
|
||||
/* Use a pre-transform to compute `A * (x+b)`
|
||||
*
|
||||
* \note Ordinarily, we'd use a post_transform like `A * x + b`
|
||||
* In general, post-transforms are easier to work with when using homogenous co-ordinates.
|
||||
*
|
||||
* When UV mapping into the unit square, post-transforms can lose precision on small islands.
|
||||
* Instead we're using a pre-transform to maintain precision.
|
||||
*
|
||||
* To convert post-transform to pre-transform, use `A * x + b == A * (x + c), c = A^-1 * b`
|
||||
*/
|
||||
|
||||
const int cd_loop_uv_offset = island->cd_loop_uv_offset;
|
||||
const int faces_len = island->faces_len;
|
||||
for (int i = 0; i < faces_len; i++) {
|
||||
BMFace *f = island->faces[i];
|
||||
BMLoop *l;
|
||||
BMIter iter;
|
||||
BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
|
||||
MLoopUV *luv = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
|
||||
mul_v2_m2_add_v2v2(luv->uv, matrix, luv->uv, pre_translate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name UV Face Array Utilities
|
||||
@@ -198,13 +217,12 @@ static void face_island_uv_rotate_fit_aabb(FaceIsland *island)
|
||||
/* Apply rotation back to BMesh. */
|
||||
if (angle != 0.0f) {
|
||||
float matrix[2][2];
|
||||
float pre_translate[2] = {0, 0};
|
||||
angle_to_mat2(matrix, angle);
|
||||
matrix[1][0] *= 1.0f / aspect_y;
|
||||
/* matrix[1][1] *= aspect_y / aspect_y; */
|
||||
matrix[0][1] *= aspect_y;
|
||||
for (int i = 0; i < faces_len; i++) {
|
||||
BM_face_uv_transform(faces[i], matrix, cd_loop_uv_offset);
|
||||
}
|
||||
island_uv_transform(island, matrix, pre_translate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -769,21 +787,24 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
|
||||
}
|
||||
}
|
||||
|
||||
float matrix[2][2];
|
||||
float matrix_inverse[2][2];
|
||||
float pre_translate[2];
|
||||
for (int i = 0; i < island_vector.size(); i++) {
|
||||
FaceIsland *island = island_vector[box_array[i].index];
|
||||
const float pivot[2] = {
|
||||
island->bounds_rect.xmin,
|
||||
island->bounds_rect.ymin,
|
||||
};
|
||||
const float offset[2] = {
|
||||
((box_array[i].x * scale[0]) - island->bounds_rect.xmin) + base_offset[0],
|
||||
((box_array[i].y * scale[1]) - island->bounds_rect.ymin) + base_offset[1],
|
||||
};
|
||||
for (int j = 0; j < island->faces_len; j++) {
|
||||
BMFace *efa = island->faces[j];
|
||||
bm_face_uv_translate_and_scale_around_pivot(
|
||||
efa, offset, scale, pivot, island->cd_loop_uv_offset);
|
||||
}
|
||||
matrix[0][0] = scale[0];
|
||||
matrix[0][1] = 0.0f;
|
||||
matrix[1][0] = 0.0f;
|
||||
matrix[1][1] = scale[1];
|
||||
invert_m2_m2(matrix_inverse, matrix);
|
||||
|
||||
/* Add base_offset, post transform. */
|
||||
mul_v2_m2v2(pre_translate, matrix_inverse, base_offset);
|
||||
|
||||
/* Translate to box_array from bounds_rect. */
|
||||
pre_translate[0] += box_array[i].x - island->bounds_rect.xmin;
|
||||
pre_translate[1] += box_array[i].y - island->bounds_rect.ymin;
|
||||
island_uv_transform(island, matrix, pre_translate);
|
||||
}
|
||||
|
||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||
|
||||
Reference in New Issue
Block a user