From 24d08e0bae1ff8bdd707e5d47f41a3b8950651b4 Mon Sep 17 00:00:00 2001 From: T0MIS0N Date: Fri, 4 Apr 2025 21:30:05 +0200 Subject: [PATCH] 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 Pull Request: https://projects.blender.org/blender/blender/pulls/135102 --- scripts/startup/bl_ui/space_image.py | 10 +-- .../blender/blenkernel/BKE_blender_version.h | 2 +- .../blenloader/intern/versioning_400.cc | 42 ++++++++++ .../blenloader/intern/versioning_defaults.cc | 5 ++ .../engines/overlay/overlay_next_instance.cc | 21 ++++- .../draw/engines/overlay/overlay_next_mesh.hh | 76 ++++++++++++++----- .../shaders/infos/overlay_edit_mode_info.hh | 4 + .../shaders/infos/overlay_wireframe_info.hh | 2 + .../shaders/overlay_edit_uv_edges_frag.glsl | 7 +- .../shaders/overlay_edit_uv_edges_vert.glsl | 2 + .../shaders/overlay_edit_uv_faces_vert.glsl | 6 +- .../blender/draw/intern/draw_cache_extract.hh | 8 +- .../draw/intern/draw_cache_extract_mesh.cc | 11 ++- source/blender/draw/intern/draw_cache_impl.hh | 4 +- .../draw/intern/draw_cache_impl_mesh.cc | 42 +++++++++- .../intern/mesh_extractors/extract_mesh.hh | 5 +- .../extract_mesh_ibo_edituv.cc | 9 ++- .../editors/space_image/space_image.cc | 13 +++- source/blender/makesdna/DNA_space_types.h | 8 +- source/blender/makesrna/intern/rna_space.cc | 13 +++- 20 files changed, 239 insertions(+), 51 deletions(-) diff --git a/scripts/startup/bl_ui/space_image.py b/scripts/startup/bl_ui/space_image.py index 1343c8c5f26..43d7b21dd02 100644 --- a/scripts/startup/bl_ui/space_image.py +++ b/scripts/startup/bl_ui/space_image.py @@ -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, ) diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index c67e4efa105..c51547af1b5 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -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 diff --git a/source/blender/blenloader/intern/versioning_400.cc b/source/blender/blenloader/intern/versioning_400.cc index cd3c7b9e544..aedc2ab9e4b 100644 --- a/source/blender/blenloader/intern/versioning_400.cc +++ b/source/blender/blenloader/intern/versioning_400.cc @@ -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(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(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. */ diff --git a/source/blender/blenloader/intern/versioning_defaults.cc b/source/blender/blenloader/intern/versioning_defaults.cc index 334156ea421..c27f5a8d43b 100644 --- a/source/blender/blenloader/intern/versioning_defaults.cc +++ b/source/blender/blenloader/intern/versioning_defaults.cc @@ -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(area->spacedata.first); + sima->uv_face_opacity = 0.0f; } } else if (area->spacetype == SPACE_ACTION) { diff --git a/source/blender/draw/engines/overlay/overlay_next_instance.cc b/source/blender/draw/engines/overlay/overlay_next_instance.cc index 8a44803e218..9034cd27e1a 100644 --- a/source/blender/draw/engines/overlay/overlay_next_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_next_instance.cc @@ -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); diff --git a/source/blender/draw/engines/overlay/overlay_next_mesh.hh b/source/blender/draw/engines/overlay/overlay_next_mesh.hh index 14a48f6055b..890538488c8 100644 --- a/source/blender/draw/engines/overlay/overlay_next_mesh.hh +++ b/source/blender/draw/engines/overlay/overlay_next_mesh.hh @@ -552,12 +552,10 @@ class MeshUVs : Overlay { const SpaceImage *space_image = reinterpret_cast(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(*ob); + + const SpaceImage *space_image = reinterpret_cast(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(ob); + const SpaceImage *space_image = reinterpret_cast(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); + } } } diff --git a/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh index 6626d58a238..54c5daf4185 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh @@ -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() diff --git a/source/blender/draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh index f3e7b7b9b83..b8af1d15173 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh @@ -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() diff --git a/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl index f3209d41936..ed9909b8adc 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl @@ -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; } diff --git a/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl index 91ef96393c6..7cfef8eeb0d 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl @@ -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); diff --git a/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl index cad6c138cf3..d6ad679f496 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl @@ -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); } diff --git a/source/blender/draw/intern/draw_cache_extract.hh b/source/blender/draw/intern/draw_cache_extract.hh index 6da5ec6bca1..e9c1eb8a573 100644 --- a/source/blender/draw/intern/draw_cache_extract.hh +++ b/source/blender/draw/intern/draw_cache_extract.hh @@ -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, diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc index ebaa432393f..5a6c145225d 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc @@ -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)); diff --git a/source/blender/draw/intern/draw_cache_impl.hh b/source/blender/draw/intern/draw_cache_impl.hh index afd47f4fcda..138c5e3e2b7 100644 --- a/source/blender/draw/intern/draw_cache_impl.hh +++ b/source/blender/draw/intern/draw_cache_impl.hh @@ -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); /** \} */ diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.cc b/source/blender/draw/intern/draw_cache_impl_mesh.cc index a463595f481..edb1ff6317b 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.cc +++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc @@ -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); } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh index 97925930ead..9134eb44a21 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh @@ -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); diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc index 97e542a6d98..9772eaa36c9 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc @@ -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); diff --git a/source/blender/editors/space_image/space_image.cc b/source/blender/editors/space_image/space_image.cc index 4db95765424..1d385215ed9 100644 --- a/source/blender/editors/space_image/space_image.cc +++ b/source/blender/editors/space_image/space_image.cc @@ -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(¶ms->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; } } diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index d645f4ae788..bd0d087b923 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -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 { diff --git a/source/blender/makesrna/intern/rna_space.cc b/source/blender/makesrna/intern/rna_space.cc index a7145d3a98e..f6129deffea 100644 --- a/source/blender/makesrna/intern/rna_space.cc +++ b/source/blender/makesrna/intern/rna_space.cc @@ -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);