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
This commit is contained in:
Clément Foucault
2024-08-12 15:29:20 +02:00
committed by Clément Foucault
parent 1c70e07af5
commit c42380c633
16 changed files with 579 additions and 21 deletions

View File

@@ -205,6 +205,13 @@ template<typename MatT, typename RotationT>
[[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<typename MatT, int ScaleDim>
[[nodiscard]] MatT from_loc_scale(const typename MatT::loc_type &location,
const VecBase<typename MatT::base_type, ScaleDim> &scale);
/**
* Create a transform matrix with translation, rotation and scale applied in this order.
*/
@@ -1409,6 +1416,15 @@ template<typename MatT, typename RotationT>
return mat;
}
template<typename MatT, int ScaleDim>
[[nodiscard]] MatT from_loc_scale(const typename MatT::loc_type &location,
const VecBase<typename MatT::base_type, ScaleDim> &scale)
{
MatT mat = MatT(from_scale<MatT>(scale));
mat.location() = location;
return mat;
}
template<typename MatT, typename VectorT>
[[nodiscard]] MatT from_orthonormal_axes(const VectorT forward, const VectorT up)
{

View File

@@ -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

View File

@@ -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<DrawingInfo> 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<int> points_by_curve = curves.evaluated_points_by_curve();
const bke::AttributeAccessor attributes = curves.attributes();
const VArray<int> stroke_materials = *attributes.lookup_or_default<int>(
"material_index", bke::AttrDomain::Curve, 0);
const VArray<bool> cyclic = *attributes.lookup_or_default<bool>(
"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<blender::Bounds<float3>> 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<float4x4>(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

View File

@@ -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:

View File

@@ -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

View File

@@ -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_ = &sub;
}
{
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_ = &sub;
}
{
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_ = &sub;
}
{
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_ = &sub;
}
{
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_ = &sub;
}
}
{
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

View File

@@ -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. */

View File

@@ -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(

View File

@@ -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)

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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",