Overlay: Allow drawing UVs in Image Editor in any mode

**Problem**
When using Texture Paint mode, the Image Editor will show a UV Wireframe
to display the active object's UVs. In every other mode, this wireframe
is absent. This is currently a big problem for Sculpt Mode since the
Experimental Texture Paint system is a part of that mode, meaning that
the user can't see their UVs while they paint in Sculpt Mode. This is
also troublesome for users that would like to quickly view an object's
UVs without using Texture Paint Mode.

**Solution**
Since it's useful to be able to view an object's UVs at all times, the
Image Editor should display UV Wireframes in all Object Modes regardless
of the Image Editor's mode. This is the best solution since it means
that future Blender features, that would benefit from having a preview
of an object's UV Wireframes, will automatically have that option since
UV Wireframes are supported in all modes. Also, if a user doesn't want
to see UV Wireframes for any reason, it can be disabled with an Overlay
option.

Additionally, when multiple objects are selected, each object should
have its UV Wireframe drawn in the Image Editor. The selected objects
that aren't active should have less opaque wireframes to indicate which
wireframe belongs to the active object. This is the best approach for
having multiple objects selected since it allows the user to quickly
view the UV layout for all selected objects to troubleshoot UV problems,
like texture mapping. This is especially helpful when using a material
for multiple different objects.

An alternative solution would be to only show the UV Wireframe for the
active object, but this would be undesirable because it would make
troubleshooting UV positions tedious when working with multiple objects
since the user would need to select objects individually.

Co-authored-by: T0MIS0N <50230774+T0MIS0N@users.noreply.github.com>
Co-authored-by: Sean Kim <SeanCTKim@protonmail.com>
Pull Request: https://projects.blender.org/blender/blender/pulls/135102
This commit is contained in:
T0MIS0N
2025-04-04 21:30:05 +02:00
committed by Sean Kim
parent f60c528c48
commit 24d08e0bae
20 changed files with 239 additions and 51 deletions

View File

@@ -109,7 +109,6 @@ class IMAGE_MT_view(Menu):
layout.separator()
if paint.brush and (context.image_paint_object or sima.mode == 'PAINT'):
layout.prop(uv, "show_texpaint")
layout.prop(tool_settings, "show_uv_local_view", text="Show Same Material")
layout.menu("INFO_MT_area")
@@ -1682,7 +1681,7 @@ class IMAGE_PT_overlay_uv_edit_geometry(Panel):
row.prop(uvedit, "show_faces", text="Faces")
class IMAGE_PT_overlay_texture_paint(Panel):
class IMAGE_PT_overlay_uv_display(Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'HEADER'
bl_label = "Geometry"
@@ -1691,7 +1690,7 @@ class IMAGE_PT_overlay_texture_paint(Panel):
@classmethod
def poll(cls, context):
sima = context.space_data
return (sima and (sima.show_paint))
return (sima and not (sima.show_uvedit))
def draw(self, context):
layout = self.layout
@@ -1701,7 +1700,8 @@ class IMAGE_PT_overlay_texture_paint(Panel):
overlay = sima.overlay
layout.active = overlay.show_overlays
layout.prop(uvedit, "show_texpaint")
layout.prop(uvedit, "show_uv")
layout.prop(uvedit, "uv_face_opacity")
class IMAGE_PT_overlay_image(Panel):
@@ -1814,7 +1814,7 @@ classes = (
IMAGE_PT_overlay_guides,
IMAGE_PT_overlay_uv_stretch,
IMAGE_PT_overlay_uv_edit_geometry,
IMAGE_PT_overlay_texture_paint,
IMAGE_PT_overlay_uv_display,
IMAGE_PT_overlay_image,
IMAGE_AST_brush_paint,
)

View File

@@ -27,7 +27,7 @@
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 16
#define BLENDER_FILE_SUBVERSION 17
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@@ -4431,6 +4431,43 @@ static void asset_browser_add_list_view(Main *bmain)
}
}
static void version_show_texpaint_to_show_uv(Main *bmain)
{
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = reinterpret_cast<SpaceImage *>(sl);
if (sima->flag & SI_NO_DRAW_TEXPAINT) {
sima->flag |= SI_NO_DRAW_UV_GUIDE;
}
}
}
}
}
}
static void version_set_uv_face_overlay_defaults(Main *bmain)
{
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = reinterpret_cast<SpaceImage *>(sl);
/* Remove ID Code from screen name */
const char *workspace_name = screen->id.name + 2;
/* Don't set uv_face_opacity for Texture Paint or Shading since these are workspaces
* where it's important to have unobstructed view of the Image Editor to see Image
* Textures. UV Editing is the only other default workspace with an Image Editor.*/
if (STREQ(workspace_name, "UV Editing")) {
sima->uv_face_opacity = 1.0f;
}
}
}
}
}
}
void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
{
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 1)) {
@@ -6642,6 +6679,11 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 17)) {
version_show_texpaint_to_show_uv(bmain);
version_set_uv_face_overlay_defaults(bmain);
}
/* Always run this versioning; meshes are written with the legacy format which always needs to
* be converted to the new format on file load. Can be moved to a subversion check in a larger
* breaking release. */

View File

@@ -132,6 +132,11 @@ static void blo_update_defaults_screen(bScreen *screen,
if (sima->mode == SI_MODE_VIEW) {
sima->mode = SI_MODE_UV;
}
sima->uv_face_opacity = 1.0f;
}
else if (STREQ(workspace_name, "Texture Paint") || STREQ(workspace_name, "Shading")) {
SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
sima->uv_face_opacity = 0.0f;
}
}
else if (area->spacetype == SPACE_ACTION) {

View File

@@ -467,6 +467,7 @@ void Instance::begin_sync()
void Instance::object_sync(ObjectRef &ob_ref, Manager &manager)
{
const bool in_object_mode = ob_ref.object->mode == OB_MODE_OBJECT;
const bool in_edit_mode = ob_ref.object->mode == OB_MODE_EDIT;
const bool in_paint_mode = object_is_paint_mode(ob_ref.object);
const bool in_sculpt_mode = object_is_sculpt_mode(ob_ref);
@@ -487,13 +488,27 @@ void Instance::object_sync(ObjectRef &ob_ref, Manager &manager)
layer.particles.edit_object_sync(manager, ob_ref, resources, state);
}
/* For 2D UV overlays. */
if (!state.hide_overlays && state.is_space_image()) {
switch (ob_ref.object->type) {
case OB_MESH:
if (in_edit_paint_mode) {
/* TODO(fclem): Find a better place / condition. */
layer.mesh_uvs.edit_object_sync(manager, ob_ref, resources, state);
}
else if (in_object_mode) {
layer.mesh_uvs.object_sync(manager, ob_ref, resources, state);
}
default:
break;
}
}
if (in_paint_mode && !state.hide_overlays) {
switch (ob_ref.object->type) {
case OB_MESH:
/* TODO(fclem): Make it part of a #Meshes. */
layer.paints.object_sync(manager, ob_ref, resources, state);
/* For wire-frames. */
layer.mesh_uvs.edit_object_sync(manager, ob_ref, resources, state);
break;
case OB_GREASE_PENCIL:
layer.grease_pencil.paint_object_sync(manager, ob_ref, resources, state);
@@ -522,8 +537,6 @@ void Instance::object_sync(ObjectRef &ob_ref, Manager &manager)
switch (ob_ref.object->type) {
case OB_MESH:
layer.meshes.edit_object_sync(manager, ob_ref, resources, state);
/* TODO(fclem): Find a better place / condition. */
layer.mesh_uvs.edit_object_sync(manager, ob_ref, resources, state);
break;
case OB_ARMATURE:
layer.armatures.edit_object_sync(manager, ob_ref, resources, state);

View File

@@ -552,12 +552,10 @@ class MeshUVs : Overlay {
const SpaceImage *space_image = reinterpret_cast<const SpaceImage *>(state.space_data);
::Image *image = space_image->image;
const bool space_mode_is_paint = space_image->mode == SI_MODE_PAINT;
const bool space_mode_is_view = space_image->mode == SI_MODE_VIEW;
const bool space_mode_is_mask = space_image->mode == SI_MODE_MASK;
const bool space_mode_is_uv = space_image->mode == SI_MODE_UV;
const bool object_mode_is_edit = state.object_mode & OB_MODE_EDIT;
const bool object_mode_is_paint = state.object_mode & OB_MODE_TEXTURE_PAINT;
const bool is_viewer = image && ELEM(image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE);
const bool is_tiled_image = image && (image->source == IMA_SRC_TILED);
@@ -618,22 +616,16 @@ class MeshUVs : Overlay {
{
/* Wireframe UV Overlay. */
const bool show_wireframe_uv_edit = space_image->flag & SI_DRAWSHADOW;
const bool show_wireframe_tex_paint = !(space_image->flag & SI_NO_DRAW_TEXPAINT);
const bool show_wireframe_uv_guide = !(space_image->flag & SI_NO_DRAW_UV_GUIDE);
if (space_mode_is_uv && object_mode_is_edit) {
show_wireframe_ = show_wireframe_uv_edit;
}
else if (space_mode_is_uv && object_mode_is_paint) {
show_wireframe_ = show_wireframe_tex_paint;
}
else if (space_mode_is_paint && (object_mode_is_paint || object_mode_is_edit)) {
show_wireframe_ = show_wireframe_tex_paint;
}
else if (space_mode_is_view && object_mode_is_paint) {
show_wireframe_ = show_wireframe_tex_paint;
}
else {
show_wireframe_ = false;
show_wireframe_ = show_wireframe_uv_guide;
if (!show_face_) {
show_face_ = show_wireframe_;
}
}
}
{
@@ -716,13 +708,17 @@ class MeshUVs : Overlay {
}
if (show_face_) {
const float opacity = (object_mode_is_edit && space_mode_is_uv) ?
space_image->uv_opacity :
space_image->uv_face_opacity;
auto &pass = faces_ps_;
pass.init();
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ALPHA);
pass.shader_set(res.shaders->uv_edit_face.get());
pass.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
pass.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
pass.push_constant("uvOpacity", space_image->uv_opacity);
pass.push_constant("uvOpacity", opacity);
}
if (show_mesh_analysis_) {
@@ -743,10 +739,40 @@ class MeshUVs : Overlay {
per_mesh_area_2d_.clear();
}
void object_sync(Manager &manager,
const ObjectRef &ob_ref,
Resources & /*res*/,
const State &state) final
{
if (!enabled_ || ob_ref.object->type != OB_MESH ||
!((ob_ref.object->base_flag & BASE_SELECTED) || (ob_ref.object == state.object_active)))
{
return;
}
Object *ob = ob_ref.object;
Mesh &mesh = DRW_object_get_data_for_drawing<Mesh>(*ob);
const SpaceImage *space_image = reinterpret_cast<const SpaceImage *>(state.space_data);
const bool has_active_object_uvmap = CustomData_get_active_layer(&mesh.corner_data,
CD_PROP_FLOAT2) != -1;
ResourceHandle res_handle = manager.unique_handle(ob_ref);
if (show_wireframe_ && has_active_object_uvmap) {
gpu::Batch *geom = DRW_mesh_batch_cache_get_uv_wireframe(*ob, mesh);
wireframe_ps_.draw_expand(geom, GPU_PRIM_TRIS, 2, 1, res_handle);
}
if (show_face_ && has_active_object_uvmap && space_image->uv_face_opacity > 0.0f) {
gpu::Batch *geom = DRW_mesh_batch_cache_get_uv_faces(*ob, mesh);
faces_ps_.draw(geom, res_handle);
}
}
void edit_object_sync(Manager &manager,
const ObjectRef &ob_ref,
Resources & /*res*/,
const State & /*state*/) final
const State &state) final
{
if (!enabled_ || ob_ref.object->type != OB_MESH) {
return;
@@ -755,7 +781,9 @@ class MeshUVs : Overlay {
Object &ob = *ob_ref.object;
Mesh &mesh = DRW_object_get_data_for_drawing<Mesh>(ob);
const SpaceImage *space_image = reinterpret_cast<const SpaceImage *>(state.space_data);
const bool is_edit_object = DRW_object_is_in_edit_mode(&ob);
const bool is_uv_editable = is_edit_object && space_image->mode == SI_MODE_UV;
const bool has_active_object_uvmap = CustomData_get_active_layer(&mesh.corner_data,
CD_PROP_FLOAT2) != -1;
const bool has_active_edit_uvmap = is_edit_object && (CustomData_get_active_layer(
@@ -764,7 +792,7 @@ class MeshUVs : Overlay {
ResourceHandle res_handle = manager.unique_handle(ob_ref);
if (has_active_edit_uvmap) {
if (has_active_edit_uvmap && is_uv_editable) {
if (show_uv_edit) {
gpu::Batch *geom = DRW_mesh_batch_cache_get_edituv_edges(ob, mesh);
edges_ps_.draw_expand(geom, GPU_PRIM_TRIS, 2, 1, res_handle);
@@ -781,6 +809,10 @@ class MeshUVs : Overlay {
gpu::Batch *geom = DRW_mesh_batch_cache_get_edituv_faces(ob, mesh);
faces_ps_.draw(geom, res_handle);
}
if (show_wireframe_) {
gpu::Batch *geom = DRW_mesh_batch_cache_get_edituv_wireframe(ob, mesh);
wireframe_ps_.draw_expand(geom, GPU_PRIM_TRIS, 2, 1, res_handle);
}
if (show_mesh_analysis_) {
int index_3d, index_2d;
@@ -799,9 +831,15 @@ class MeshUVs : Overlay {
}
}
if (show_wireframe_ && (has_active_object_uvmap || has_active_edit_uvmap)) {
gpu::Batch *geom = DRW_mesh_batch_cache_get_uv_edges(ob, mesh);
wireframe_ps_.draw_expand(geom, GPU_PRIM_TRIS, 2, 1, res_handle);
if ((has_active_object_uvmap || has_active_edit_uvmap) && !is_uv_editable) {
if (show_wireframe_) {
gpu::Batch *geom = DRW_mesh_batch_cache_get_uv_wireframe(ob, mesh);
wireframe_ps_.draw_expand(geom, GPU_PRIM_TRIS, 2, 1, res_handle);
}
if (show_face_ && space_image->uv_face_opacity > 0.0f) {
gpu::Batch *geom = DRW_mesh_batch_cache_get_uv_faces(ob, mesh);
faces_ps_.draw(geom, res_handle);
}
}
}

View File

@@ -331,6 +331,8 @@ VERTEX_SOURCE("overlay_edit_uv_edges_vert.glsl")
FRAGMENT_SOURCE("overlay_edit_uv_edges_frag.glsl")
ADDITIONAL_INFO(draw_view)
ADDITIONAL_INFO(draw_modelmat)
ADDITIONAL_INFO(draw_object_infos)
ADDITIONAL_INFO(draw_resource_id_varying)
ADDITIONAL_INFO(gpu_index_buffer_load)
ADDITIONAL_INFO(draw_globals)
GPU_SHADER_CREATE_END()
@@ -346,6 +348,8 @@ VERTEX_SOURCE("overlay_edit_uv_faces_vert.glsl")
FRAGMENT_SOURCE("overlay_varying_color.glsl")
ADDITIONAL_INFO(draw_view)
ADDITIONAL_INFO(draw_modelmat)
ADDITIONAL_INFO(draw_object_infos)
ADDITIONAL_INFO(draw_resource_id_varying)
ADDITIONAL_INFO(draw_globals)
GPU_SHADER_CREATE_END()

View File

@@ -119,6 +119,8 @@ VERTEX_SOURCE("overlay_edit_uv_edges_vert.glsl")
FRAGMENT_SOURCE("overlay_edit_uv_edges_frag.glsl")
ADDITIONAL_INFO(draw_view)
ADDITIONAL_INFO(draw_modelmat)
ADDITIONAL_INFO(draw_object_infos)
ADDITIONAL_INFO(draw_resource_id_varying)
ADDITIONAL_INFO(gpu_index_buffer_load)
ADDITIONAL_INFO(draw_globals)
GPU_SHADER_CREATE_END()

View File

@@ -18,6 +18,8 @@ FRAGMENT_SHADER_CREATE_INFO(overlay_edit_uv_edges)
#define GRID_LINE_SMOOTH_START (0.5 - DISC_RADIUS)
#define GRID_LINE_SMOOTH_END (0.5 + DISC_RADIUS)
#include "draw_object_infos_lib.glsl"
#include "gpu_shader_utildefines_lib.glsl"
#include "overlay_common_lib.glsl"
void main()
@@ -73,7 +75,10 @@ void main()
vec4 final_color = mix(outer_color, inner_color, 1.0 - mix_w * outer_color.a);
final_color.a *= 1.0 - (outer_color.a > 0.0 ? mix_w_outer : mix_w);
final_color.a *= alpha;
eObjectInfoFlag ob_flag = drw_object_infos().flag;
bool is_active = flag_test(ob_flag, OBJECT_ACTIVE);
final_color.a *= is_active ? alpha : (alpha * 0.25);
fragColor = final_color;
}

View File

@@ -184,6 +184,8 @@ void main()
vert_out[0] = vertex_main(vert_in[0]);
vert_out[1] = vertex_main(vert_in[1]);
drw_ResourceID_iface.resource_index = drw_resource_id();
/* Discard by default. */
gl_Position = vec4(NAN_FLT);
geometry_main(vert_out, out_vertex_id, out_primitive_id, out_invocation_id);

View File

@@ -7,7 +7,9 @@
VERTEX_SHADER_CREATE_INFO(overlay_edit_uv_faces)
#include "draw_model_lib.glsl"
#include "draw_object_infos_lib.glsl"
#include "draw_view_lib.glsl"
#include "gpu_shader_utildefines_lib.glsl"
void main()
{
@@ -16,8 +18,10 @@ void main()
bool is_selected = (flag & FACE_UV_SELECT) != 0u;
bool is_active = (flag & FACE_UV_ACTIVE) != 0u;
eObjectInfoFlag ob_flag = drw_object_infos().flag;
bool is_object_active = flag_test(ob_flag, OBJECT_ACTIVE);
finalColor = (is_selected) ? colorFaceSelect : colorFace;
finalColor = (is_active) ? colorEditMeshActive : finalColor;
finalColor.a *= uvOpacity;
finalColor.a *= is_object_active ? uvOpacity : (uvOpacity * 0.25);
}

View File

@@ -126,6 +126,7 @@ enum class IBOType : int8_t {
FaceDots,
LinesPaintMask,
LinesAdjacency,
UVLines,
EditUVTris,
EditUVLines,
EditUVPoints,
@@ -168,6 +169,7 @@ struct MeshBatchList {
gpu::Batch *edit_selection_faces;
gpu::Batch *edit_selection_fdots;
/* Common display / Other */
gpu::Batch *uv_faces;
gpu::Batch *all_verts;
gpu::Batch *all_edges;
gpu::Batch *loose_edges;
@@ -178,6 +180,7 @@ struct MeshBatchList {
gpu::Batch *wire_loops;
/* Same as wire_loops but only has uvs. */
gpu::Batch *wire_loops_uvs;
gpu::Batch *wire_loops_edituvs;
gpu::Batch *sculpt_overlays;
gpu::Batch *surface_viewer_attribute;
};
@@ -197,6 +200,7 @@ enum DRWBatchFlag {
MBC_EDIT_FACEDOTS = (1u << MBC_BATCH_INDEX(edit_fdots)),
MBC_EDIT_MESH_ANALYSIS = (1u << MBC_BATCH_INDEX(edit_mesh_analysis)),
MBC_SKIN_ROOTS = (1u << MBC_BATCH_INDEX(edit_skin_roots)),
MBC_UV_FACES = (1u << MBC_BATCH_INDEX(uv_faces)),
MBC_EDITUV_FACES_STRETCH_AREA = (1u << MBC_BATCH_INDEX(edituv_faces_stretch_area)),
MBC_EDITUV_FACES_STRETCH_ANGLE = (1u << MBC_BATCH_INDEX(edituv_faces_stretch_angle)),
MBC_EDITUV_FACES = (1u << MBC_BATCH_INDEX(edituv_faces)),
@@ -214,6 +218,7 @@ enum DRWBatchFlag {
MBC_WIRE_EDGES = (1u << MBC_BATCH_INDEX(wire_edges)),
MBC_WIRE_LOOPS = (1u << MBC_BATCH_INDEX(wire_loops)),
MBC_WIRE_LOOPS_UVS = (1u << MBC_BATCH_INDEX(wire_loops_uvs)),
MBC_WIRE_LOOPS_EDITUVS = (1u << MBC_BATCH_INDEX(wire_loops_edituvs)),
MBC_SCULPT_OVERLAYS = (1u << MBC_BATCH_INDEX(sculpt_overlays)),
MBC_VIEWER_ATTRIBUTE_OVERLAY = (1u << MBC_BATCH_INDEX(surface_viewer_attribute)),
MBC_SURFACE_PER_MAT = (1u << MBC_BATCH_LEN),
@@ -310,7 +315,8 @@ struct MeshBatchCache {
#define MBC_EDITUV \
(MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | \
MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS | MBC_WIRE_LOOPS_UVS)
MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS | MBC_UV_FACES | \
MBC_WIRE_LOOPS_UVS | MBC_WIRE_LOOPS_EDITUVS)
void mesh_buffer_cache_create_requested(TaskGraph &task_graph,
const Scene &scene,

View File

@@ -158,11 +158,14 @@ void mesh_buffer_cache_create_requested(TaskGraph & /*task_graph*/,
case IBOType::LinesAdjacency:
created_ibos[i] = extract_lines_adjacency(mr, cache.is_manifold);
break;
case IBOType::UVLines:
created_ibos[i] = extract_edituv_lines(mr, false);
break;
case IBOType::EditUVTris:
created_ibos[i] = extract_edituv_tris(mr);
break;
case IBOType::EditUVLines:
created_ibos[i] = extract_edituv_lines(mr);
created_ibos[i] = extract_edituv_lines(mr, true);
break;
case IBOType::EditUVPoints:
created_ibos[i] = extract_edituv_points(mr);
@@ -418,6 +421,9 @@ void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache &cache,
/* Make sure UVs are computed before edituv stuffs. */
buffers.vbos.add_new(VBOType::UVs, extract_uv_maps_subdiv(subdiv_cache, cache));
}
if (ibos_to_create.contains(IBOType::UVLines)) {
buffers.ibos.add_new(IBOType::UVLines, extract_edituv_lines_subdiv(mr, subdiv_cache, false));
}
if (vbos_to_create.contains(VBOType::EditUVStretchArea)) {
buffers.vbos.add_new(
VBOType::EditUVStretchArea,
@@ -434,7 +440,8 @@ void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache &cache,
buffers.ibos.add_new(IBOType::EditUVTris, extract_edituv_tris_subdiv(mr, subdiv_cache));
}
if (ibos_to_create.contains(IBOType::EditUVLines)) {
buffers.ibos.add_new(IBOType::EditUVLines, extract_edituv_lines_subdiv(mr, subdiv_cache));
buffers.ibos.add_new(IBOType::EditUVLines,
extract_edituv_lines_subdiv(mr, subdiv_cache, true));
}
if (ibos_to_create.contains(IBOType::EditUVPoints)) {
buffers.ibos.add_new(IBOType::EditUVPoints, extract_edituv_points_subdiv(mr, subdiv_cache));

View File

@@ -255,6 +255,7 @@ blender::gpu::Batch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Object &
blender::gpu::Batch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(Object &object,
Mesh &mesh);
blender::gpu::Batch *DRW_mesh_batch_cache_get_edituv_faces(Object &object, Mesh &mesh);
blender::gpu::Batch *DRW_mesh_batch_cache_get_edituv_wireframe(Object &object, Mesh &mesh);
blender::gpu::Batch *DRW_mesh_batch_cache_get_edituv_edges(Object &object, Mesh &mesh);
blender::gpu::Batch *DRW_mesh_batch_cache_get_edituv_verts(Object &object, Mesh &mesh);
blender::gpu::Batch *DRW_mesh_batch_cache_get_edituv_facedots(Object &object, Mesh &mesh);
@@ -265,7 +266,8 @@ blender::gpu::Batch *DRW_mesh_batch_cache_get_edituv_facedots(Object &object, Me
/** \name For Image UV Editor
* \{ */
blender::gpu::Batch *DRW_mesh_batch_cache_get_uv_edges(Object &object, Mesh &mesh);
blender::gpu::Batch *DRW_mesh_batch_cache_get_uv_faces(Object &object, Mesh &mesh);
blender::gpu::Batch *DRW_mesh_batch_cache_get_uv_wireframe(Object &object, Mesh &mesh);
blender::gpu::Batch *DRW_mesh_batch_cache_get_edit_mesh_analysis(Mesh &mesh);
/** \} */

View File

@@ -1042,7 +1042,15 @@ gpu::Batch *DRW_mesh_batch_cache_get_edituv_facedots(Object &object, Mesh &mesh)
return DRW_batch_request(&cache.batch.edituv_fdots);
}
gpu::Batch *DRW_mesh_batch_cache_get_uv_edges(Object &object, Mesh &mesh)
gpu::Batch *DRW_mesh_batch_cache_get_uv_faces(Object &object, Mesh &mesh)
{
MeshBatchCache &cache = *mesh_batch_cache_get(mesh);
edituv_request_active_uv(cache, object, mesh);
mesh_batch_cache_add_request(cache, MBC_UV_FACES);
return DRW_batch_request(&cache.batch.uv_faces);
}
gpu::Batch *DRW_mesh_batch_cache_get_uv_wireframe(Object &object, Mesh &mesh)
{
MeshBatchCache &cache = *mesh_batch_cache_get(mesh);
edituv_request_active_uv(cache, object, mesh);
@@ -1050,6 +1058,14 @@ gpu::Batch *DRW_mesh_batch_cache_get_uv_edges(Object &object, Mesh &mesh)
return DRW_batch_request(&cache.batch.wire_loops_uvs);
}
gpu::Batch *DRW_mesh_batch_cache_get_edituv_wireframe(Object &object, Mesh &mesh)
{
MeshBatchCache &cache = *mesh_batch_cache_get(mesh);
edituv_request_active_uv(cache, object, mesh);
mesh_batch_cache_add_request(cache, MBC_WIRE_LOOPS_EDITUVS);
return DRW_batch_request(&cache.batch.wire_loops_edituvs);
}
gpu::Batch *DRW_mesh_batch_cache_get_surface_edges(Mesh &mesh)
{
MeshBatchCache &cache = *mesh_batch_cache_get(mesh);
@@ -1141,8 +1157,9 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph &task_graph,
}
if (batch_requested &
(MBC_SURFACE | MBC_SURFACE_PER_MAT | MBC_WIRE_LOOPS_UVS | MBC_EDITUV_FACES_STRETCH_AREA |
MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS))
(MBC_SURFACE | MBC_SURFACE_PER_MAT | MBC_WIRE_LOOPS_UVS | MBC_WIRE_LOOPS_EDITUVS |
MBC_UV_FACES | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE |
MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS))
{
/* Modifiers will only generate an orco layer if the mesh is deformed. */
if (cache.cd_needed.orco != 0) {
@@ -1219,7 +1236,9 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph &task_graph,
}
/* We only clear the batches as they may already have been
* referenced. */
GPU_BATCH_CLEAR_SAFE(cache.batch.uv_faces);
GPU_BATCH_CLEAR_SAFE(cache.batch.wire_loops_uvs);
GPU_BATCH_CLEAR_SAFE(cache.batch.wire_loops_edituvs);
GPU_BATCH_CLEAR_SAFE(cache.batch.edituv_faces_stretch_area);
GPU_BATCH_CLEAR_SAFE(cache.batch.edituv_faces_stretch_angle);
GPU_BATCH_CLEAR_SAFE(cache.batch.edituv_faces);
@@ -1365,7 +1384,22 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph &task_graph,
}
if (batches_to_create & MBC_WIRE_LOOPS_UVS) {
BatchCreateData batch{
*cache.batch.wire_loops_uvs, GPU_PRIM_LINES, list, IBOType::EditUVLines, {}};
*cache.batch.wire_loops_uvs, GPU_PRIM_LINES, list, IBOType::UVLines, {}};
if (cache.cd_used.uv != 0) {
batch.vbos.append(VBOType::UVs);
}
batch_info.append(std::move(batch));
}
if (batches_to_create & MBC_WIRE_LOOPS_EDITUVS) {
BatchCreateData batch{
*cache.batch.wire_loops_edituvs, GPU_PRIM_LINES, list, IBOType::EditUVLines, {}};
if (cache.cd_used.uv != 0) {
batch.vbos.append(VBOType::UVs);
}
batch_info.append(std::move(batch));
}
if (batches_to_create & MBC_UV_FACES) {
BatchCreateData batch{*cache.batch.uv_faces, GPU_PRIM_TRIS, list, IBOType::Tris, {}};
if (cache.cd_used.uv != 0) {
batch.vbos.append(VBOType::UVs);
}

View File

@@ -352,9 +352,10 @@ gpu::VertBufPtr extract_edituv_data_subdiv(const MeshRenderData &mr,
gpu::IndexBufPtr extract_edituv_tris(const MeshRenderData &mr);
gpu::IndexBufPtr extract_edituv_tris_subdiv(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache);
gpu::IndexBufPtr extract_edituv_lines(const MeshRenderData &mr);
gpu::IndexBufPtr extract_edituv_lines(const MeshRenderData &mr, bool edit_uvs);
gpu::IndexBufPtr extract_edituv_lines_subdiv(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache);
const DRWSubdivCache &subdiv_cache,
bool edit_uvs);
gpu::IndexBufPtr extract_edituv_points(const MeshRenderData &mr);
gpu::IndexBufPtr extract_edituv_points_subdiv(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache);

View File

@@ -239,9 +239,9 @@ static gpu::IndexBufPtr extract_edituv_lines_mesh(const MeshRenderData &mr,
return gpu::IndexBufPtr(GPU_indexbuf_build_ex(&builder, 0, mr.corners_num, false));
}
gpu::IndexBufPtr extract_edituv_lines(const MeshRenderData &mr)
gpu::IndexBufPtr extract_edituv_lines(const MeshRenderData &mr, bool edit_uvs)
{
const bool sync_selection = (mr.toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
const bool sync_selection = ((mr.toolsettings->uv_flag & UV_SYNC_SELECTION) != 0) || !edit_uvs;
if (mr.extract_type == MeshExtractType::BMesh) {
return extract_edituv_lines_bm(mr, sync_selection);
@@ -334,9 +334,10 @@ static gpu::IndexBufPtr extract_edituv_lines_subdiv_mesh(const MeshRenderData &m
}
gpu::IndexBufPtr extract_edituv_lines_subdiv(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache)
const DRWSubdivCache &subdiv_cache,
bool edit_uvs)
{
const bool sync_selection = (mr.toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
const bool sync_selection = ((mr.toolsettings->uv_flag & UV_SYNC_SELECTION) != 0) || !edit_uvs;
if (mr.extract_type == MeshExtractType::BMesh) {
return extract_edituv_lines_subdiv_bm(mr, subdiv_cache, sync_selection);

View File

@@ -102,6 +102,7 @@ static SpaceLink *image_create(const ScrArea * /*area*/, const Scene * /*scene*/
simage->lock = true;
simage->flag = SI_SHOW_GPENCIL | SI_USE_ALPHA | SI_COORDFLOATS;
simage->uv_opacity = 1.0f;
simage->uv_face_opacity = 1.0f;
simage->stretch_opacity = 1.0f;
simage->overlay.flag = SI_OVERLAY_SHOW_OVERLAYS | SI_OVERLAY_SHOW_GRID_BACKGROUND;
@@ -310,6 +311,10 @@ static void image_listener(const wmSpaceTypeListenerParams *params)
ED_area_tag_refresh(area);
ED_area_tag_redraw(area);
break;
case ND_OB_ACTIVE:
case ND_OB_SELECT:
ED_area_tag_redraw(area);
break;
case ND_MODE:
ED_paint_cursor_start(&params->scene->toolsettings->imapaint.paint,
ED_image_tools_paint_poll);
@@ -397,12 +402,18 @@ static void image_listener(const wmSpaceTypeListenerParams *params)
/* \note With a geometry nodes modifier, the UVs on `ob` can change in response to
* any change on `wmn->reference`. If we could track the upstream dependencies,
* unnecessary redraws could be reduced. Until then, just redraw. See #98594. */
if (ob && (ob->mode & OB_MODE_EDIT)) {
if (ob && (ob->mode & OB_MODE_EDIT) && sima->mode == SI_MODE_UV) {
if (sima->lock && (sima->flag & SI_DRAWSHADOW)) {
ED_area_tag_refresh(area);
ED_area_tag_redraw(area);
}
}
else if (ob) {
if (sima->lock && !(sima->flag & SI_NO_DRAW_UV_GUIDE)) {
ED_area_tag_refresh(area);
ED_area_tag_redraw(area);
}
}
break;
}
}

View File

@@ -1297,6 +1297,8 @@ typedef struct SpaceImage {
int flag;
float uv_opacity;
float uv_face_opacity;
char _pad2[4];
float stretch_opacity;
@@ -1378,7 +1380,9 @@ typedef enum eSpaceImage_Flag {
SI_FLAG_UNUSED_24 = (1 << 24),
SI_NO_DRAW_TEXPAINT = (1 << 25),
#ifdef DNA_DEPRECATED_ALLOW
SI_NO_DRAW_TEXPAINT = (1 << 25), /* deprecated - use SI_NO_DRAW_UV_GUIDE instead, see #135102 */
#endif
SI_DRAW_METADATA = (1 << 26),
SI_SHOW_R = (1 << 27),
@@ -1386,6 +1390,8 @@ typedef enum eSpaceImage_Flag {
SI_SHOW_B = (1 << 29),
SI_GRID_OVER_IMAGE = (1 << 30),
SI_NO_DRAW_UV_GUIDE = (1 << 31),
} eSpaceImage_Flag;
typedef enum eSpaceImageOverlay_Flag {

View File

@@ -3860,10 +3860,9 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Metadata", "Display metadata properties of the image");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, nullptr);
prop = RNA_def_property(srna, "show_texpaint", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, nullptr, "flag", SI_NO_DRAW_TEXPAINT);
RNA_def_property_ui_text(
prop, "Display Texture Paint UVs", "Display overlay of texture paint UV layer");
prop = RNA_def_property(srna, "show_uv", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, nullptr, "flag", SI_NO_DRAW_UV_GUIDE);
RNA_def_property_ui_text(prop, "Display UVs", "Display overlay of UV layer");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, nullptr);
prop = RNA_def_property(srna, "show_pixel_coords", PROP_BOOLEAN, PROP_NONE);
@@ -3914,6 +3913,12 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "UV Opacity", "Opacity of UV overlays");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, nullptr);
prop = RNA_def_property(srna, "uv_face_opacity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, nullptr, "uv_face_opacity");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "UV Face Opacity", "Opacity of faces in UV overlays");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, nullptr);
prop = RNA_def_property(srna, "stretch_opacity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, nullptr, "stretch_opacity");
RNA_def_property_range(prop, 0.0f, 1.0f);