Merge branch 'blender-v3.2-release'

This commit is contained in:
Campbell Barton
2022-05-10 11:16:27 +10:00
2 changed files with 121 additions and 47 deletions

View File

@@ -266,6 +266,10 @@ struct BMLoop **ED_uvedit_selected_verts(const struct Scene *scene,
int *r_verts_len);
void ED_uvedit_get_aspect(struct Object *obedit, float *r_aspx, float *r_aspy);
void ED_uvedit_get_aspect_from_material(Object *ob,
const int material_index,
float *r_aspx,
float *r_aspy);
void ED_uvedit_active_vert_loop_set(struct BMesh *bm, struct BMLoop *l);
struct BMLoop *ED_uvedit_active_vert_loop_get(struct BMesh *bm);

View File

@@ -267,26 +267,35 @@ static bool uvedit_have_selection_multi(const Scene *scene,
return have_select;
}
void ED_uvedit_get_aspect_from_material(Object *ob,
const int material_index,
float *r_aspx,
float *r_aspy)
{
if (UNLIKELY(material_index < 0 || material_index >= ob->totcol)) {
*r_aspx = 1.0f;
*r_aspy = 1.0f;
return;
}
Image *ima;
ED_object_get_active_image(ob, material_index + 1, &ima, NULL, NULL, NULL);
ED_image_get_uv_aspect(ima, NULL, r_aspx, r_aspy);
}
void ED_uvedit_get_aspect(Object *ob, float *r_aspx, float *r_aspy)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
BLI_assert(em != NULL);
bool sloppy = true;
bool selected = false;
BMFace *efa;
Image *ima;
efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
if (efa) {
ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL);
ED_image_get_uv_aspect(ima, NULL, r_aspx, r_aspy);
}
else {
BMFace *efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
if (!efa) {
*r_aspx = 1.0f;
*r_aspy = 1.0f;
return;
}
ED_uvedit_get_aspect_from_material(ob, efa->mat_nr, r_aspx, r_aspy);
}
static void construct_param_handle_face_add(ParamHandle *handle,
@@ -1527,49 +1536,88 @@ static void uv_transform_properties(wmOperatorType *ot, int radius)
}
}
static void shrink_loop_uv_by_aspect_ratio(BMFace *efa,
const int cd_loop_uv_offset,
const float aspect_y)
{
BLI_assert(aspect_y != 1.0f); /* Nothing to do, should be handled by caller. */
BLI_assert(aspect_y > 0.0f); /* Negative aspect ratios are not supported. */
BMLoop *l;
BMIter iter;
BM_ITER_ELEM (l, &iter, efa, BM_LOOPS_OF_FACE) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (aspect_y > 1.0f) {
/* Reduce round-off error, i.e. `u = (u - 0.5) / aspect_y + 0.5`. */
luv->uv[0] = luv->uv[0] / aspect_y + (0.5f - 0.5f / aspect_y);
}
else {
/* Reduce round-off error, i.e. `v = (v - 0.5) * aspect_y + 0.5`. */
luv->uv[1] = luv->uv[1] * aspect_y + (0.5f - 0.5f * aspect_y);
}
}
}
static void correct_uv_aspect(Object *ob, BMEditMesh *em)
{
BMLoop *l;
BMIter iter, liter;
MLoopUV *luv;
BMFace *efa;
float scale, aspx, aspy;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
float aspx, aspy;
ED_uvedit_get_aspect(ob, &aspx, &aspy);
const float aspect_y = aspx / aspy;
if (aspect_y == 1.0f) {
/* Scaling by 1.0 has no effect. */
return;
}
BMFace *efa;
BMIter iter;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
shrink_loop_uv_by_aspect_ratio(efa, cd_loop_uv_offset, aspect_y);
}
}
}
if (aspx == aspy) {
static void correct_uv_aspect_per_face(Object *ob, BMEditMesh *em)
{
const int materials_num = ob->totcol;
if (materials_num == 0) {
/* Without any materials, there is no aspect_y information and nothing to do. */
return;
}
if (aspx > aspy) {
scale = aspy / aspx;
float *material_aspect_y = BLI_array_alloca(material_aspect_y, materials_num);
/* Lazily initialize aspect ratio for materials. */
copy_vn_fl(material_aspect_y, materials_num, -1.0f);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
continue;
}
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
luv->uv[0] = ((luv->uv[0] - 0.5f) * scale) + 0.5f;
}
BMFace *efa;
BMIter iter;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
continue;
}
}
else {
scale = aspx / aspy;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
continue;
}
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
luv->uv[1] = ((luv->uv[1] - 0.5f) * scale) + 0.5f;
}
const int material_index = efa->mat_nr;
if (UNLIKELY(material_index < 0 || material_index >= materials_num)) {
/* The index might be for a material slot which is not currently setup. */
continue;
}
float aspect_y = material_aspect_y[material_index];
if (aspect_y == -1.0f) {
/* Lazily initialize aspect ratio for materials. */
float aspx, aspy;
ED_uvedit_get_aspect_from_material(ob, material_index, &aspx, &aspy);
aspect_y = aspx / aspy;
material_aspect_y[material_index] = aspect_y;
}
if (aspect_y == 1.0f) {
/* Scaling by 1.0 has no effect. */
continue;
}
shrink_loop_uv_by_aspect_ratio(efa, cd_loop_uv_offset, aspect_y);
}
}
@@ -1613,7 +1661,17 @@ static void uv_map_clip_correct_properties(wmOperatorType *ot)
uv_map_clip_correct_properties_ex(ot, true);
}
static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOperator *op)
/**
* \param per_face_aspect: Calculate the aspect ratio per-face,
* otherwise use a single aspect for all UV's based on the material of the active face.
* TODO: using per-face aspect may split UV islands so more advanced UV projection methods
* such as "Unwrap" & "Smart UV Projections" will need to handle aspect correction themselves.
* For now keep using a single aspect for all faces in this case.
*/
static void uv_map_clip_correct_multi(Object **objects,
uint objects_len,
wmOperator *op,
bool per_face_aspect)
{
BMFace *efa;
BMLoop *l;
@@ -1633,9 +1691,14 @@ static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOper
BMEditMesh *em = BKE_editmesh_from_object(ob);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
/* correct for image aspect ratio */
/* Correct for image aspect ratio. */
if (correct_aspect) {
correct_uv_aspect(ob, em);
if (per_face_aspect) {
correct_uv_aspect_per_face(ob, em);
}
else {
correct_uv_aspect(ob, em);
}
}
if (scale_to_bounds) {
@@ -1678,6 +1741,11 @@ static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOper
dy = 1.0f / dy;
}
if (dx == 1.0f && dy == 1.0f) {
/* Scaling by 1.0 has no effect. */
return;
}
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *ob = objects[ob_index];
@@ -1702,7 +1770,7 @@ static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOper
static void uv_map_clip_correct(Object *ob, wmOperator *op)
{
uv_map_clip_correct_multi(&ob, 1, op);
uv_map_clip_correct_multi(&ob, 1, op, true);
}
/** \} */
@@ -2283,7 +2351,9 @@ static int smart_project_exec(bContext *C, wmOperator *op)
.use_seams = true,
});
uv_map_clip_correct_multi(objects_changed, object_changed_len, op);
/* #ED_uvedit_pack_islands_multi only supports `per_face_aspect = false`. */
const bool per_face_aspect = false;
uv_map_clip_correct_multi(objects_changed, object_changed_len, op, per_face_aspect);
}
MEM_freeN(objects_changed);
@@ -2485,7 +2555,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
}
if (changed_multi) {
uv_map_clip_correct_multi(objects, objects_len, op);
uv_map_clip_correct_multi(objects, objects_len, op, true);
}
MEM_freeN(objects);