From c42380c633f4bd4847b1ee42d0a234f781cb891d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 12 Aug 2024 15:29:20 +0200 Subject: [PATCH] Overlay-Next: Outline Straightforward port. Only the dupli object optimization and the resource handle deduplication are left as todos. Marked areas that are against design to be fixed. Rel #102179 Pull Request: https://projects.blender.org/blender/blender/pulls/126152 --- source/blender/blenlib/BLI_math_matrix.hh | 16 ++ source/blender/draw/CMakeLists.txt | 2 + .../overlay/overlay_next_grease_pencil.hh | 173 ++++++++++++++ .../engines/overlay/overlay_next_instance.cc | 73 +++++- .../engines/overlay/overlay_next_instance.hh | 12 +- .../engines/overlay/overlay_next_outline.hh | 211 ++++++++++++++++++ .../engines/overlay/overlay_next_private.hh | 19 +- .../engines/overlay/overlay_next_shader.cc | 27 +++ .../shaders/infos/overlay_outline_info.hh | 25 ++- .../overlay_outline_prepass_curves_vert.glsl | 6 + .../overlay_outline_prepass_gpencil_vert.glsl | 5 + ...erlay_outline_prepass_pointcloud_vert.glsl | 6 + .../shaders/overlay_outline_prepass_vert.glsl | 6 + .../overlay_outline_prepass_vert_no_geom.glsl | 6 + .../shaders/overlay_wireframe_vert.glsl | 8 + .../draw/intern/shaders/draw_view_info.hh | 5 +- 16 files changed, 579 insertions(+), 21 deletions(-) create mode 100644 source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh create mode 100644 source/blender/draw/engines/overlay/overlay_next_outline.hh diff --git a/source/blender/blenlib/BLI_math_matrix.hh b/source/blender/blenlib/BLI_math_matrix.hh index 48c21000cb2..a11eec6f7f2 100644 --- a/source/blender/blenlib/BLI_math_matrix.hh +++ b/source/blender/blenlib/BLI_math_matrix.hh @@ -205,6 +205,13 @@ template [[nodiscard]] MatT from_loc_rot(const typename MatT::loc_type &location, const RotationT &rotation); +/** + * Create a transform matrix with translation and scale applied in this order. + */ +template +[[nodiscard]] MatT from_loc_scale(const typename MatT::loc_type &location, + const VecBase &scale); + /** * Create a transform matrix with translation, rotation and scale applied in this order. */ @@ -1409,6 +1416,15 @@ template return mat; } +template +[[nodiscard]] MatT from_loc_scale(const typename MatT::loc_type &location, + const VecBase &scale) +{ + MatT mat = MatT(from_scale(scale)); + mat.location() = location; + return mat; +} + template [[nodiscard]] MatT from_orthonormal_axes(const VectorT forward, const VectorT up) { diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 57cb398aee7..988f6d789fe 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -296,6 +296,7 @@ set(SRC engines/overlay/overlay_next_camera.hh engines/overlay/overlay_next_facing.hh engines/overlay/overlay_next_force_field.hh + engines/overlay/overlay_next_grease_pencil.hh engines/overlay/overlay_next_grid.hh engines/overlay/overlay_next_instance.hh engines/overlay/overlay_next_lattice.hh @@ -303,6 +304,7 @@ set(SRC engines/overlay/overlay_next_lightprobe.hh engines/overlay/overlay_next_mesh.hh engines/overlay/overlay_next_metaball.hh + engines/overlay/overlay_next_outline.hh engines/overlay/overlay_next_prepass.hh engines/overlay/overlay_next_private.hh engines/overlay/overlay_next_relation.hh diff --git a/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh b/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh new file mode 100644 index 00000000000..45573c07e51 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_next_grease_pencil.hh @@ -0,0 +1,173 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup overlay + */ + +#pragma once + +#include "BLI_bounds.hh" +#include "BLI_math_matrix.hh" + +#include "BKE_curves.hh" +#include "BKE_grease_pencil.hh" +#include "BKE_object.hh" + +#include "ED_grease_pencil.hh" + +#include "overlay_next_private.hh" + +namespace blender::draw::overlay { + +class GreasePencil { + public: + struct ViewParameters { + bool is_perspective; + union { + /* Z axis if ortho or position if perspective. */ + float3 z_axis; + float3 location; + }; + + ViewParameters() = default; + + ViewParameters(bool is_perspective, const float4x4 &viewinv) + { + if (is_perspective) { + location = viewinv.location(); + } + else { + z_axis = viewinv.z_axis(); + } + } + }; + + public: + static void draw_grease_pencil(PassMain::Sub &pass, + const ViewParameters &view, + const Scene *scene, + Object *ob, + ResourceHandle res_handle) + { + using namespace blender; + using namespace blender::ed::greasepencil; + ::GreasePencil &grease_pencil = *static_cast<::GreasePencil *>(ob->data); + + float4 plane = (grease_pencil.flag & GREASE_PENCIL_STROKE_ORDER_3D) ? + float4(0.0f) : + depth_plane_get(ob, view); + pass.push_constant("gpDepthPlane", plane); + + int t_offset = 0; + const Vector drawings = retrieve_visible_drawings(*scene, grease_pencil, true); + for (const DrawingInfo info : drawings) { + const bool is_stroke_order_3d = (grease_pencil.flag & GREASE_PENCIL_STROKE_ORDER_3D) != 0; + + const float object_scale = mat4_to_scale(ob->object_to_world().ptr()); + const float thickness_scale = bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR; + + gpu::VertBuf *position_tx = draw::DRW_cache_grease_pencil_position_buffer_get(scene, ob); + gpu::VertBuf *color_tx = draw::DRW_cache_grease_pencil_color_buffer_get(scene, ob); + + pass.push_constant("gpStrokeOrder3d", is_stroke_order_3d); + pass.push_constant("gpThicknessScale", object_scale); + pass.push_constant("gpThicknessOffset", 0.0f); + pass.push_constant("gpThicknessWorldScale", thickness_scale); + pass.bind_texture("gp_pos_tx", position_tx); + pass.bind_texture("gp_col_tx", color_tx); + + const bke::CurvesGeometry &curves = info.drawing.strokes(); + const OffsetIndices points_by_curve = curves.evaluated_points_by_curve(); + const bke::AttributeAccessor attributes = curves.attributes(); + const VArray stroke_materials = *attributes.lookup_or_default( + "material_index", bke::AttrDomain::Curve, 0); + const VArray cyclic = *attributes.lookup_or_default( + "cyclic", bke::AttrDomain::Curve, false); + + IndexMaskMemory memory; + const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( + *ob, info.drawing, memory); + + visible_strokes.foreach_index([&](const int stroke_i) { + const IndexRange points = points_by_curve[stroke_i]; + const int material_index = stroke_materials[stroke_i]; + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, material_index + 1); + + const bool hide_onion = info.onion_id != 0; + const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; + + const int num_stroke_triangles = (points.size() >= 3) ? (points.size() - 2) : 0; + const int num_stroke_vertices = (points.size() + + int(cyclic[stroke_i] && (points.size() >= 3))); + + if (hide_material || hide_onion) { + t_offset += num_stroke_triangles; + t_offset += num_stroke_vertices * 2; + return; + } + + blender::gpu::Batch *geom = draw::DRW_cache_grease_pencil_get(scene, ob); + + const bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0; + const bool show_fill = (points.size() >= 3) && + (gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0; + + if (show_fill) { + int v_first = t_offset * 3; + int v_count = num_stroke_triangles * 3; + pass.draw(geom, 1, v_count, v_first, res_handle); + } + + t_offset += num_stroke_triangles; + + if (show_stroke) { + int v_first = t_offset * 3; + int v_count = num_stroke_vertices * 2 * 3; + pass.draw(geom, 1, v_count, v_first, res_handle); + } + t_offset += num_stroke_vertices * 2; + }); + } + } + + private: + /* Returns the normal plane in NDC space. */ + static float4 depth_plane_get(const Object *ob, const ViewParameters &view) + { + using namespace blender::math; + + /* Find the normal most likely to represent the grease pencil object. */ + /* TODO: This does not work quite well if you use + * strokes not aligned with the object axes. Maybe we could try to + * compute the minimum axis of all strokes. But this would be more + * computationally heavy and should go into the GPData evaluation. */ + const std::optional> bounds = BKE_object_boundbox_get(ob).value_or( + blender::Bounds(float3(0))); + + float3 center = midpoint(bounds->min, bounds->max); + float3 size = (bounds->max - bounds->min) * 0.5f; + /* Avoid division by 0.0 later. */ + size += 1e-8f; + /* Convert Bbox unit space to object space. */ + float4x4 bbox_to_object = from_loc_scale(center, size); + float4x4 bbox_to_world = ob->object_to_world() * bbox_to_object; + + float3 bbox_center = bbox_to_world.location(); + float3 view_vector = (view.is_perspective) ? view.location - bbox_center : view.z_axis; + + float3x3 world_to_bbox = invert(float3x3(bbox_to_world)); + + /* Normalize the vector in BBox space. */ + float3 local_plane_direction = normalize(transform_direction(world_to_bbox, view_vector)); + /* `bbox_to_world_normal` is a "normal" matrix. It transforms BBox space normals to world. */ + float3x3 bbox_to_world_normal = transpose(world_to_bbox); + float3 plane_direction = normalize( + transform_direction(bbox_to_world_normal, local_plane_direction)); + + return float4(plane_direction, -dot(plane_direction, bbox_center)); + } +}; + +} // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_next_instance.cc b/source/blender/draw/engines/overlay/overlay_next_instance.cc index b8c34d73dfc..0742d7d1d7c 100644 --- a/source/blender/draw/engines/overlay/overlay_next_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_next_instance.cc @@ -10,6 +10,8 @@ #include "ED_view3d.hh" +#include "BKE_paint.hh" + #include "draw_debug.hh" #include "overlay_next_instance.hh" @@ -85,6 +87,7 @@ void Instance::begin_sync() resources.begin_sync(); background.begin_sync(resources, state); + outline.begin_sync(resources, state); auto begin_sync_layer = [&](OverlayLayer &layer) { layer.bounds.begin_sync(); @@ -112,7 +115,9 @@ void Instance::begin_sync() void Instance::object_sync(ObjectRef &ob_ref, Manager &manager) { const bool in_edit_mode = object_is_edit_mode(ob_ref.object); - const bool needs_prepass = true; /* TODO */ + const bool in_paint_mode = object_is_paint_mode(ob_ref.object); + const bool in_sculpt_mode = object_is_sculpt_mode(ob_ref); + const bool needs_prepass = !state.xray_enabled; /* TODO */ OverlayLayer &layer = (state.use_in_front && ob_ref.object->dtx & OB_DRAW_IN_FRONT) ? infront : regular; @@ -189,6 +194,22 @@ void Instance::object_sync(ObjectRef &ob_ref, Manager &manager) layer.force_fields.object_sync(ob_ref, resources, state); layer.bounds.object_sync(ob_ref, resources, state); layer.relations.object_sync(ob_ref, resources, state); + + if (object_is_selected(ob_ref)) { + if (in_edit_mode || in_paint_mode || in_sculpt_mode) { + /* Disable outlines for objects in sculpt, paint or edit mode. */ + } + else if ((ob_ref.object->base_flag & BASE_FROM_DUPLI) && + (object_is_edit_mode(ob_ref.dupli_parent) || + object_is_sculpt_mode(ob_ref.dupli_parent) || + object_is_paint_mode(ob_ref.dupli_parent))) + { + /* Disable outlines for objects instanced by an object in sculpt, paint or edit mode. */ + } + else { + outline.object_sync(manager, ob_ref, state); + } + } } } @@ -273,12 +294,15 @@ void Instance::draw(Manager &manager) GPU_ATTACHMENT_TEXTURE(resources.overlay_tx), GPU_ATTACHMENT_TEXTURE(resources.line_tx)); resources.overlay_in_front_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_in_front_tx), - GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx)); + GPU_ATTACHMENT_TEXTURE(resources.overlay_tx)); resources.overlay_line_in_front_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_in_front_tx), - GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx), + GPU_ATTACHMENT_TEXTURE(resources.overlay_tx), GPU_ATTACHMENT_TEXTURE(resources.line_tx)); } + resources.overlay_line_only_fb.ensure(GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(resources.overlay_tx), + GPU_ATTACHMENT_TEXTURE(resources.line_tx)); resources.overlay_color_only_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(resources.overlay_tx)); resources.overlay_output_fb.ensure(GPU_ATTACHMENT_NONE, @@ -291,6 +315,8 @@ void Instance::draw(Manager &manager) regular.prepass.draw(resources.overlay_line_fb, manager, view); infront.prepass.draw(resources.overlay_line_in_front_fb, manager, view); + outline.draw(resources, manager, view); + auto overlay_fb_draw = [&](OverlayLayer &layer, Framebuffer &framebuffer) { regular.facing.draw(framebuffer, manager, view); }; @@ -338,11 +364,46 @@ void Instance::draw(Manager &manager) resources.read_result(); } -bool Instance::object_is_edit_mode(const Object *ob) +bool Instance::object_is_selected(const ObjectRef &ob_ref) { - if (DRW_object_is_in_edit_mode(ob)) { + return (ob_ref.object->base_flag & BASE_SELECTED); +} + +bool Instance::object_is_paint_mode(const Object *object) +{ + if (object->type == OB_GREASE_PENCIL && state.object_mode & OB_MODE_WEIGHT_GPENCIL_LEGACY) { + return true; + } + return (object == state.active_base->object) && (state.object_mode & OB_MODE_ALL_PAINT); +} + +bool Instance::object_is_sculpt_mode(const ObjectRef &ob_ref) +{ + if (state.object_mode == OB_MODE_SCULPT_CURVES) { + const Object *active_object = state.active_base->object; + const bool is_active_object = ob_ref.object == active_object; + + bool is_geonode_preview = ob_ref.dupli_object && ob_ref.dupli_object->preview_base_geometry; + bool is_active_dupli_parent = ob_ref.dupli_parent == active_object; + return is_active_object || (is_active_dupli_parent && is_geonode_preview); + }; + + return false; +} + +bool Instance::object_is_sculpt_mode(const Object *object) +{ + if (object->sculpt && (object->sculpt->mode_type == OB_MODE_SCULPT)) { + return object == state.active_base->object; + } + return false; +} + +bool Instance::object_is_edit_mode(const Object *object) +{ + if (DRW_object_is_in_edit_mode(object)) { /* Also check for context mode as the object mode is not 100% reliable. (see T72490) */ - switch (ob->type) { + switch (object->type) { case OB_MESH: return state.ctx_mode == CTX_MODE_EDIT_MESH; case OB_ARMATURE: diff --git a/source/blender/draw/engines/overlay/overlay_next_instance.hh b/source/blender/draw/engines/overlay/overlay_next_instance.hh index 6ce8839c24b..592cd622fd5 100644 --- a/source/blender/draw/engines/overlay/overlay_next_instance.hh +++ b/source/blender/draw/engines/overlay/overlay_next_instance.hh @@ -17,12 +17,14 @@ #include "overlay_next_empty.hh" #include "overlay_next_facing.hh" #include "overlay_next_force_field.hh" +#include "overlay_next_grease_pencil.hh" #include "overlay_next_grid.hh" #include "overlay_next_lattice.hh" #include "overlay_next_light.hh" #include "overlay_next_lightprobe.hh" #include "overlay_next_mesh.hh" #include "overlay_next_metaball.hh" +#include "overlay_next_outline.hh" #include "overlay_next_prepass.hh" #include "overlay_next_relation.hh" #include "overlay_next_speaker.hh" @@ -49,6 +51,7 @@ class Instance { /** Overlay types. */ Background background; + Outline outline; struct OverlayLayer { const SelectionType selection_type_; @@ -57,6 +60,7 @@ class Instance { Empties empties = {selection_type_}; Facing facing = {selection_type_}; ForceFields force_fields = {selection_type_}; + GreasePencil grease_pencil; Lattices lattices; Lights lights = {selection_type_}; LightProbes light_probes = {selection_type_}; @@ -85,7 +89,13 @@ class Instance { void draw(Manager &manager); private: - bool object_is_edit_mode(const Object *ob); + bool object_is_selected(const ObjectRef &ob_ref); + bool object_is_edit_mode(const Object *object); + bool object_is_paint_mode(const Object *object); + /* Checks for both curve sculpt and regular sculpt mode. */ + bool object_is_sculpt_mode(const ObjectRef &ob_ref); + /* Checks only for sculpt mode. */ + bool object_is_sculpt_mode(const Object *object); }; } // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_next_outline.hh b/source/blender/draw/engines/overlay/overlay_next_outline.hh new file mode 100644 index 00000000000..b782139e760 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_next_outline.hh @@ -0,0 +1,211 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup overlay + */ + +#pragma once + +#include "overlay_next_private.hh" + +#include "draw_common.hh" + +namespace blender::draw::overlay { + +class Outline { + private: + /* Simple render pass that renders an object ID pass. */ + PassMain outline_prepass_ps_ = {"Prepass"}; + PassMain::Sub *prepass_curves_ps_ = nullptr; + PassMain::Sub *prepass_pointcloud_ps_ = nullptr; + PassMain::Sub *prepass_gpencil_ps_ = nullptr; + PassMain::Sub *prepass_mesh_ps_ = nullptr; + PassMain::Sub *prepass_wire_ps_ = nullptr; + /* Detect edges inside the ID pass and output color for each of them. */ + PassSimple outline_resolve_ps_ = {"Resolve"}; + + TextureFromPool object_id_tx_ = {"outline_ob_id_tx"}; + TextureFromPool tmp_depth_tx_ = {"outline_depth_tx"}; + + Framebuffer prepass_fb_ = {"outline.prepass_fb"}; + + bool enabled = false; + + overlay::GreasePencil::ViewParameters grease_pencil_view; + + public: + void begin_sync(Resources &res, const State &state) + { + enabled = (state.v3d_flag & V3D_SELECT_OUTLINE); + if (!enabled) { + return; + } + + { + /* TODO(fclem): This is against design. We should not sync depending on view position. + * Eventually, we should do this in a compute shader prepass. */ + float4x4 viewinv; + DRW_view_viewmat_get(nullptr, viewinv.ptr(), true); + grease_pencil_view = {DRW_view_is_persp_get(nullptr), viewinv}; + } + + const float outline_width = UI_GetThemeValuef(TH_OUTLINE_WIDTH); + const bool do_smooth_lines = (U.gpu_flag & USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE) != 0; + const bool do_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f); + const bool is_transform = (G.moving & G_TRANSFORM_OBJ) != 0; + + { + auto &pass = outline_prepass_ps_; + pass.init(); + pass.framebuffer_set(&prepass_fb_); + pass.clear_color_depth_stencil(float4(0.0f), 1.0f, 0x0); + pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | + state.clipping_state); + { + auto &sub = pass.sub("Curves"); + sub.shader_set(res.shaders.outline_prepass_curves.get()); + sub.push_constant("isTransform", is_transform); + sub.bind_ubo("globalsBlock", &res.globals_buf); + prepass_curves_ps_ = ⊂ + } + { + auto &sub = pass.sub("PointCloud"); + sub.shader_set(res.shaders.outline_prepass_pointcloud.get()); + sub.push_constant("isTransform", is_transform); + sub.bind_ubo("globalsBlock", &res.globals_buf); + prepass_pointcloud_ps_ = ⊂ + } + { + auto &sub = pass.sub("GreasePencil"); + sub.shader_set(res.shaders.outline_prepass_gpencil.get()); + sub.push_constant("isTransform", is_transform); + sub.bind_ubo("globalsBlock", &res.globals_buf); + prepass_gpencil_ps_ = ⊂ + } + { + auto &sub = pass.sub("Mesh"); + sub.shader_set(res.shaders.outline_prepass_mesh.get()); + sub.push_constant("isTransform", is_transform); + sub.bind_ubo("globalsBlock", &res.globals_buf); + prepass_mesh_ps_ = ⊂ + } + { + auto &sub = pass.sub("Wire"); + sub.shader_set(res.shaders.outline_prepass_wire.get()); + sub.push_constant("isTransform", is_transform); + sub.bind_ubo("globalsBlock", &res.globals_buf); + prepass_wire_ps_ = ⊂ + } + } + { + auto &pass = outline_resolve_ps_; + pass.init(); + pass.framebuffer_set(&res.overlay_line_only_fb); + pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL); + pass.shader_set(res.shaders.outline_detect.get()); + /* Don't occlude the outline if in xray mode as it causes too much flickering. */ + pass.push_constant("alphaOcclu", state.xray_enabled ? 1.0f : 0.35f); + pass.push_constant("doThickOutlines", do_expand); + pass.push_constant("doAntiAliasing", do_smooth_lines); + pass.bind_texture("outlineId", &object_id_tx_); + pass.bind_texture("sceneDepth", &res.depth_tx); + pass.bind_texture("outlineDepth", &tmp_depth_tx_); + pass.bind_ubo("globalsBlock", &res.globals_buf); + pass.draw_procedural(GPU_PRIM_TRIS, 1, 3); + } + } + + void object_sync(Manager &manager, const ObjectRef &ob_ref, const State &state) + { + if (!enabled) { + return; + } + + /* Outlines of bounding boxes are not drawn. */ + if (ob_ref.object->dt == OB_BOUNDBOX) { + return; + } + + /* TODO(fclem): Non-mandatory handle creation and reuse with other overlays. */ + ResourceHandle res_handle = manager.resource_handle(ob_ref); + + gpu::Batch *geom; + switch (ob_ref.object->type) { + case OB_GPENCIL_LEGACY: + /* TODO ? */ + break; + case OB_CURVES: + geom = curves_sub_pass_setup(*prepass_curves_ps_, state.scene, ob_ref.object); + prepass_curves_ps_->draw(geom, res_handle); + break; + case OB_GREASE_PENCIL: + GreasePencil::draw_grease_pencil( + *prepass_gpencil_ps_, grease_pencil_view, state.scene, ob_ref.object, res_handle); + break; + case OB_MESH: + geom = DRW_cache_mesh_surface_get(ob_ref.object); + prepass_mesh_ps_->draw(geom, res_handle); + { + /* TODO(fclem): This is against design. We should not sync depending on view position. + * Eventually, add a bounding box display pass with some special culling phase. */ + + /* Display flat object as a line when view is orthogonal to them. + * This fixes only the biggest case which is a plane in ortho view. */ + int flat_axis = 0; + bool is_flat_object_viewed_from_side = ((state.rv3d->persp == RV3D_ORTHO) && + DRW_object_is_flat(ob_ref.object, &flat_axis) && + DRW_object_axis_orthogonal_to_view(ob_ref.object, + flat_axis)); + if (is_flat_object_viewed_from_side) { + geom = DRW_cache_mesh_edge_detection_get(ob_ref.object, nullptr); + prepass_wire_ps_->draw(geom, res_handle); + } + } + break; + case OB_POINTCLOUD: + /* Looks bad in wireframe mode. Could be relaxed if we draw a wireframe of some sort in + * the future. */ + if (!state.is_wireframe_mode) { + geom = point_cloud_sub_pass_setup(*prepass_pointcloud_ps_, ob_ref.object); + prepass_pointcloud_ps_->draw(geom, res_handle); + } + break; + case OB_VOLUME: + geom = DRW_cache_volume_selection_surface_get(ob_ref.object); + outline_prepass_ps_.draw(geom, res_handle); + break; + default: + break; + } + } + + void draw(Resources &res, Manager &manager, View &view) + { + if (!enabled) { + return; + } + + GPU_debug_group_begin("Outline"); + + int2 render_size = int2(res.depth_tx.size()); + + eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT; + tmp_depth_tx_.acquire(render_size, GPU_DEPTH24_STENCIL8, usage); + object_id_tx_.acquire(render_size, GPU_R16UI, usage); + + prepass_fb_.ensure(GPU_ATTACHMENT_TEXTURE(tmp_depth_tx_), + GPU_ATTACHMENT_TEXTURE(object_id_tx_)); + + manager.submit(outline_prepass_ps_, view); + manager.submit(outline_resolve_ps_, view); + + tmp_depth_tx_.release(); + object_id_tx_.release(); + + GPU_debug_group_end(); + } +}; + +} // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_next_private.hh b/source/blender/draw/engines/overlay/overlay_next_private.hh index bc290b4dfb9..56804ffa550 100644 --- a/source/blender/draw/engines/overlay/overlay_next_private.hh +++ b/source/blender/draw/engines/overlay/overlay_next_private.hh @@ -181,6 +181,12 @@ class ShaderModule { ShaderPtr mesh_face_normal, mesh_face_normal_subdiv; ShaderPtr mesh_loop_normal, mesh_loop_normal_subdiv; ShaderPtr mesh_vert_normal; + ShaderPtr outline_prepass_mesh; + ShaderPtr outline_prepass_wire; + ShaderPtr outline_prepass_curves; + ShaderPtr outline_prepass_pointcloud; + ShaderPtr outline_prepass_gpencil; + ShaderPtr outline_detect = shader("overlay_outline_detect"); /** Selectable Shaders */ ShaderPtr armature_sphere_outline; @@ -217,11 +223,20 @@ class ShaderModule { struct Resources : public select::SelectMap { ShaderModule &shaders; - Framebuffer overlay_fb = {"overlay_fb"}; - Framebuffer overlay_in_front_fb = {"overlay_in_front_fb"}; + /* Overlay Color. */ Framebuffer overlay_color_only_fb = {"overlay_color_only_fb"}; + /* Overlay Color, Line Data. */ + Framebuffer overlay_line_only_fb = {"overlay_line_only_fb"}; + /* Depth, Overlay Color. */ + Framebuffer overlay_fb = {"overlay_fb"}; + /* Depth, Overlay Color, Line Data. */ Framebuffer overlay_line_fb = {"overlay_line_fb"}; + /* Depth In-Front, Overlay Color. */ + Framebuffer overlay_in_front_fb = {"overlay_in_front_fb"}; + /* Depth In-Front, Overlay Color, Line Data. */ Framebuffer overlay_line_in_front_fb = {"overlay_line_in_front_fb"}; + + /* Output Color. */ Framebuffer overlay_output_fb = {"overlay_output_fb"}; /* Target containing line direction and data for line expansion and anti-aliasing. */ diff --git a/source/blender/draw/engines/overlay/overlay_next_shader.cc b/source/blender/draw/engines/overlay/overlay_next_shader.cc index cfc3130e703..645b45d4e18 100644 --- a/source/blender/draw/engines/overlay/overlay_next_shader.cc +++ b/source/blender/draw/engines/overlay/overlay_next_shader.cc @@ -162,6 +162,33 @@ ShaderModule::ShaderModule(const SelectionType selection_type, const bool clippi info.storage_buf(0, Qualifier::READ, "uint", "vnor[]", Frequency::GEOMETRY); }); + outline_prepass_mesh = shader( + "overlay_outline_prepass_mesh", [](gpu::shader::ShaderCreateInfo &info) { + shader_patch_common(info); + info.additional_info("draw_object_infos_new", "overlay_outline_prepass"); + }); + outline_prepass_wire = shader( + "overlay_outline_prepass_wire", [](gpu::shader::ShaderCreateInfo &info) { + shader_patch_common(info); + info.additional_info("draw_object_infos_new", "overlay_outline_prepass"); + }); + outline_prepass_curves = shader( + "overlay_outline_prepass_curves", [](gpu::shader::ShaderCreateInfo &info) { + shader_patch_common(info); + info.additional_info("draw_hair_new", "draw_object_infos_new", "overlay_outline_prepass"); + }); + outline_prepass_pointcloud = shader( + "overlay_outline_prepass_pointcloud", [](gpu::shader::ShaderCreateInfo &info) { + shader_patch_common(info); + info.additional_info( + "draw_pointcloud_new", "draw_object_infos_new", "overlay_outline_prepass"); + }); + outline_prepass_gpencil = shader( + "overlay_outline_prepass_gpencil", [](gpu::shader::ShaderCreateInfo &info) { + shader_patch_common(info); + info.additional_info("draw_gpencil_new", "draw_object_infos_new"); + }); + /** Selectable Shaders */ armature_sphere_outline = selectable_shader( diff --git a/source/blender/draw/engines/overlay/shaders/infos/overlay_outline_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_outline_info.hh index 5d6fa806aec..ae05234f152 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/overlay_outline_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_outline_info.hh @@ -16,13 +16,13 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass) /* Using uint because 16bit uint can contain more ids than int. */ .fragment_out(0, Type::UINT, "out_object_id") .fragment_source("overlay_outline_prepass_frag.glsl") - .additional_info("draw_resource_handle", "draw_globals"); + .additional_info("draw_globals"); GPU_SHADER_CREATE_INFO(overlay_outline_prepass_mesh) .do_static_compilation(true) .vertex_in(0, Type::VEC3, "pos") .vertex_source("overlay_outline_prepass_vert.glsl") - .additional_info("draw_mesh", "overlay_outline_prepass") + .additional_info("draw_mesh", "draw_resource_handle", "overlay_outline_prepass") .additional_info("draw_object_infos"); GPU_SHADER_CREATE_INFO(overlay_outline_prepass_mesh_clipped) @@ -34,21 +34,20 @@ GPU_SHADER_INTERFACE_INFO(overlay_outline_prepass_wire_iface, "vert").flat(Type: GPU_SHADER_CREATE_INFO(overlay_outline_prepass_curves) .do_static_compilation(true) .vertex_source("overlay_outline_prepass_curves_vert.glsl") - .additional_info("draw_hair", "overlay_outline_prepass") + .additional_info("draw_hair", "draw_resource_handle", "overlay_outline_prepass") .additional_info("draw_object_infos"); GPU_SHADER_CREATE_INFO(overlay_outline_prepass_curves_clipped) .do_static_compilation(true) .additional_info("overlay_outline_prepass_curves", "drw_clipped"); -GPU_SHADER_CREATE_INFO(overlay_outline_prepass_wire_common) - .vertex_in(0, Type::VEC3, "pos") - .additional_info("draw_mesh", "overlay_outline_prepass") - .additional_info("draw_object_infos"); - GPU_SHADER_CREATE_INFO(overlay_outline_prepass_wire) .do_static_compilation(true) - .additional_info("overlay_outline_prepass_wire_common") + .additional_info("overlay_outline_prepass", + "draw_object_infos", + "draw_mesh", + "draw_resource_handle") + .vertex_in(0, Type::VEC3, "pos") .define("USE_GEOM") .vertex_out(overlay_outline_prepass_wire_iface) .geometry_layout(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::LINE_STRIP, 2) @@ -59,7 +58,11 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass_wire) GPU_SHADER_CREATE_INFO(overlay_outline_prepass_wire_no_geom) .metal_backend_only(true) .do_static_compilation(true) - .additional_info("overlay_outline_prepass_wire_common") + .vertex_in(0, Type::VEC3, "pos") + .additional_info("overlay_outline_prepass", + "draw_object_infos", + "draw_mesh", + "draw_resource_handle") .vertex_source("overlay_outline_prepass_vert_no_geom.glsl"); GPU_SHADER_CREATE_INFO(overlay_outline_prepass_wire_clipped) @@ -96,7 +99,7 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass_gpencil_clipped) GPU_SHADER_CREATE_INFO(overlay_outline_prepass_pointcloud) .do_static_compilation(true) .vertex_source("overlay_outline_prepass_pointcloud_vert.glsl") - .additional_info("draw_pointcloud", "overlay_outline_prepass") + .additional_info("draw_pointcloud", "draw_resource_handle", "overlay_outline_prepass") .additional_info("draw_object_infos"); GPU_SHADER_CREATE_INFO(overlay_outline_prepass_pointcloud_clipped) diff --git a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_curves_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_curves_vert.glsl index 0fae40bcb45..24a794983f9 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_curves_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_curves_vert.glsl @@ -5,11 +5,17 @@ #pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) #pragma BLENDER_REQUIRE(common_hair_lib.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl) uint outline_colorid_get(void) { +#ifdef OBINFO_NEW + eObjectInfoFlag ob_flag = eObjectInfoFlag(floatBitsToUint(drw_infos[resource_id].infos.w)); + bool is_active = flag_test(ob_flag, OBJECT_ACTIVE); +#else int flag = int(abs(ObjectInfo.w)); bool is_active = (flag & DRW_BASE_ACTIVE) != 0; +#endif if (isTransform) { return 0u; /* colorTransform */ diff --git a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl index 213fd22cb20..7dfa2fb232b 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl @@ -8,8 +8,13 @@ uint outline_colorid_get(void) { +#ifdef OBINFO_NEW + eObjectInfoFlag ob_flag = eObjectInfoFlag(floatBitsToUint(drw_infos[resource_id].infos.w)); + bool is_active = flag_test(ob_flag, OBJECT_ACTIVE); +#else int flag = int(abs(ObjectInfo.w)); bool is_active = (flag & DRW_BASE_ACTIVE) != 0; +#endif if (isTransform) { return 0u; /* colorTransform */ diff --git a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl index 8d1e4ae0bfb..9aef65805ea 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl @@ -5,11 +5,17 @@ #pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) #pragma BLENDER_REQUIRE(common_pointcloud_lib.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl) uint outline_colorid_get(void) { +#ifdef OBINFO_NEW + eObjectInfoFlag ob_flag = eObjectInfoFlag(floatBitsToUint(drw_infos[resource_id].infos.w)); + bool is_active = flag_test(ob_flag, OBJECT_ACTIVE); +#else int flag = int(abs(ObjectInfo.w)); bool is_active = (flag & DRW_BASE_ACTIVE) != 0; +#endif if (isTransform) { return 0u; /* colorTransform */ diff --git a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert.glsl index 86460b851fa..fc199b90549 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert.glsl @@ -4,11 +4,17 @@ #pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl) uint outline_colorid_get(void) { +#ifdef OBINFO_NEW + eObjectInfoFlag ob_flag = eObjectInfoFlag(floatBitsToUint(drw_infos[resource_id].infos.w)); + bool is_active = flag_test(ob_flag, OBJECT_ACTIVE); +#else int flag = int(abs(ObjectInfo.w)); bool is_active = (flag & DRW_BASE_ACTIVE) != 0; +#endif if (isTransform) { return 0u; /* colorTransform */ diff --git a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert_no_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert_no_geom.glsl index 2c8b1f53d4b..ef087fcf4a8 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert_no_geom.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert_no_geom.glsl @@ -5,6 +5,7 @@ #pragma USE_SSBO_VERTEX_FETCH(LineList, 2) #pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl) #define DISCARD_VERTEX \ gl_Position = vec4(0.0); \ @@ -12,8 +13,13 @@ uint outline_colorid_get(void) { +#ifdef OBINFO_NEW + eObjectInfoFlag ob_flag = eObjectInfoFlag(floatBitsToUint(drw_infos[resource_id].infos.w)); + bool is_active = flag_test(ob_flag, OBJECT_ACTIVE); +#else int flag = int(abs(ObjectInfo.w)); bool is_active = (flag & DRW_BASE_ACTIVE) != 0; +#endif if (isTransform) { return 0u; /* colorTransform */ diff --git a/source/blender/draw/engines/overlay/shaders/overlay_wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_vert.glsl index 88628f0c7ad..4b05b8bbac7 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_wireframe_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_vert.glsl @@ -4,6 +4,7 @@ #pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl) bool is_edge_sharpness_visible(float wd) { @@ -12,10 +13,17 @@ bool is_edge_sharpness_visible(float wd) void wire_color_get(out vec3 rim_col, out vec3 wire_col) { +#ifdef OBINFO_NEW + eObjectInfoFlag ob_flag = eObjectInfoFlag(floatBitsToUint(drw_infos[resource_id].infos.w)); + bool is_selected = flag_test(ob_flag, OBJECT_SELECTED); + bool is_from_set = flag_test(ob_flag, OBJECT_FROM_SET); + bool is_active = flag_test(ob_flag, OBJECT_ACTIVE); +#else int flag = int(abs(ObjectInfo.w)); bool is_selected = (flag & DRW_BASE_SELECTED) != 0; bool is_from_set = (flag & DRW_BASE_FROM_SET) != 0; bool is_active = (flag & DRW_BASE_ACTIVE) != 0; +#endif if (is_from_set) { rim_col = colorWire.rgb; diff --git a/source/blender/draw/intern/shaders/draw_view_info.hh b/source/blender/draw/intern/shaders/draw_view_info.hh index d3c4e11c019..d26d0655105 100644 --- a/source/blender/draw/intern/shaders/draw_view_info.hh +++ b/source/blender/draw/intern/shaders/draw_view_info.hh @@ -171,8 +171,11 @@ GPU_SHADER_CREATE_INFO(draw_gpencil_new) .sampler(0, ImageType::FLOAT_BUFFER, "gp_pos_tx") .sampler(1, ImageType::FLOAT_BUFFER, "gp_col_tx") /* Per Object */ - .define("gpThicknessScale", "1.0") /* TODO(fclem): Replace with object info. */ + .push_constant(Type::FLOAT, "gpThicknessScale") /* TODO(fclem): Replace with object info. */ + .push_constant(Type::FLOAT, "gpThicknessWorldScale") /* TODO(fclem): Same as above. */ + .define("gpThicknessIsScreenSpace", "(gpThicknessWorldScale < 0.0)") /* Per Layer */ + .push_constant(Type::FLOAT, "gpThicknessOffset") .additional_info("draw_modelmat_new", "draw_resource_id_varying", "draw_view",