Overlay-Next: Wireframe
Straightforward port. Left out particle hair to a separate patch for consistency and simplicity. Grease Pencil is also missing but that's also missing in main. Rel #102179 Pull Request: https://projects.blender.org/blender/blender/pulls/126242
This commit is contained in:
committed by
Clément Foucault
parent
51461d0561
commit
86e9254a63
@@ -309,6 +309,7 @@ set(SRC
|
||||
engines/overlay/overlay_next_private.hh
|
||||
engines/overlay/overlay_next_relation.hh
|
||||
engines/overlay/overlay_next_speaker.hh
|
||||
engines/overlay/overlay_next_wireframe.hh
|
||||
engines/overlay/overlay_private.hh
|
||||
engines/select/select_defines.hh
|
||||
engines/select/select_engine.hh
|
||||
|
||||
@@ -103,6 +103,7 @@ void Instance::begin_sync()
|
||||
layer.prepass.begin_sync(resources, state);
|
||||
layer.relations.begin_sync();
|
||||
layer.speakers.begin_sync();
|
||||
layer.wireframe.begin_sync(resources, state);
|
||||
};
|
||||
begin_sync_layer(regular);
|
||||
begin_sync_layer(infront);
|
||||
@@ -117,6 +118,8 @@ void Instance::object_sync(ObjectRef &ob_ref, Manager &manager)
|
||||
const bool in_edit_mode = object_is_edit_mode(ob_ref.object);
|
||||
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 in_edit_paint_mode = object_is_edit_paint_mode(
|
||||
ob_ref, in_edit_mode, in_paint_mode, in_sculpt_mode);
|
||||
const bool needs_prepass = !state.xray_enabled; /* TODO */
|
||||
|
||||
OverlayLayer &layer = (state.use_in_front && ob_ref.object->dtx & OB_DRAW_IN_FRONT) ? infront :
|
||||
@@ -158,6 +161,10 @@ void Instance::object_sync(ObjectRef &ob_ref, Manager &manager)
|
||||
}
|
||||
}
|
||||
|
||||
if (state.is_wireframe_mode || !state.hide_overlays) {
|
||||
layer.wireframe.object_sync(manager, ob_ref, resources, in_edit_paint_mode);
|
||||
}
|
||||
|
||||
if (!state.hide_overlays) {
|
||||
switch (ob_ref.object->type) {
|
||||
case OB_EMPTY:
|
||||
@@ -195,20 +202,8 @@ void Instance::object_sync(ObjectRef &ob_ref, Manager &manager)
|
||||
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);
|
||||
}
|
||||
if (object_is_selected(ob_ref) && !in_edit_paint_mode) {
|
||||
outline.object_sync(manager, ob_ref, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -259,6 +254,15 @@ void Instance::draw(Manager &manager)
|
||||
const DRWView *view_legacy = DRW_view_default_get();
|
||||
View view("OverlayView", view_legacy);
|
||||
|
||||
if (state.xray_enabled) {
|
||||
/* For Xray we render the scene to a separate depth buffer. */
|
||||
resources.xray_depth_tx.acquire(render_size, GPU_DEPTH_COMPONENT24);
|
||||
resources.depth_target_tx.wrap(resources.xray_depth_tx);
|
||||
}
|
||||
else {
|
||||
resources.depth_target_tx.wrap(resources.depth_tx);
|
||||
}
|
||||
|
||||
/* TODO(fclem): Remove mandatory allocation. */
|
||||
if (!resources.depth_in_front_tx.is_valid()) {
|
||||
resources.depth_in_front_alloc_tx.acquire(render_size, GPU_DEPTH_COMPONENT24);
|
||||
@@ -277,10 +281,10 @@ void Instance::draw(Manager &manager)
|
||||
resources.line_tx.acquire(int2(1, 1), GPU_RGBA8);
|
||||
resources.overlay_tx.acquire(int2(1, 1), GPU_SRGB8_A8);
|
||||
|
||||
resources.overlay_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx));
|
||||
resources.overlay_line_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx));
|
||||
resources.overlay_in_front_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx));
|
||||
resources.overlay_line_in_front_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx));
|
||||
resources.overlay_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_target_tx));
|
||||
resources.overlay_line_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_target_tx));
|
||||
resources.overlay_in_front_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_target_tx));
|
||||
resources.overlay_line_in_front_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_target_tx));
|
||||
}
|
||||
else {
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE |
|
||||
@@ -288,9 +292,9 @@ void Instance::draw(Manager &manager)
|
||||
resources.line_tx.acquire(render_size, GPU_RGBA8, usage);
|
||||
resources.overlay_tx.acquire(render_size, GPU_SRGB8_A8, usage);
|
||||
|
||||
resources.overlay_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx),
|
||||
resources.overlay_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_target_tx),
|
||||
GPU_ATTACHMENT_TEXTURE(resources.overlay_tx));
|
||||
resources.overlay_line_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx),
|
||||
resources.overlay_line_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_target_tx),
|
||||
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),
|
||||
@@ -308,9 +312,15 @@ void Instance::draw(Manager &manager)
|
||||
resources.overlay_output_fb.ensure(GPU_ATTACHMENT_NONE,
|
||||
GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx));
|
||||
|
||||
float4 clear_color(0.0f);
|
||||
GPU_framebuffer_bind(resources.overlay_line_fb);
|
||||
GPU_framebuffer_clear_color(resources.overlay_line_fb, clear_color);
|
||||
float4 clear_color(0.0f);
|
||||
if (state.xray_enabled) {
|
||||
/* Rendering to a new depth buffer that needs to be cleared. */
|
||||
GPU_framebuffer_clear_color_depth(resources.overlay_line_fb, clear_color, 1.0f);
|
||||
}
|
||||
else {
|
||||
GPU_framebuffer_clear_color(resources.overlay_line_fb, clear_color);
|
||||
}
|
||||
|
||||
regular.prepass.draw(resources.overlay_line_fb, manager, view);
|
||||
infront.prepass.draw(resources.overlay_line_in_front_fb, manager, view);
|
||||
@@ -325,6 +335,7 @@ void Instance::draw(Manager &manager)
|
||||
|
||||
auto draw_layer = [&](OverlayLayer &layer, Framebuffer &framebuffer) {
|
||||
layer.bounds.draw(framebuffer, manager, view);
|
||||
layer.wireframe.draw(framebuffer, manager, view);
|
||||
layer.cameras.draw(framebuffer, manager, view);
|
||||
layer.empties.draw(framebuffer, manager, view);
|
||||
layer.force_fields.draw(framebuffer, manager, view);
|
||||
@@ -357,6 +368,7 @@ void Instance::draw(Manager &manager)
|
||||
|
||||
resources.line_tx.release();
|
||||
resources.overlay_tx.release();
|
||||
resources.xray_depth_tx.release();
|
||||
resources.depth_in_front_alloc_tx.release();
|
||||
resources.color_overlay_alloc_tx.release();
|
||||
resources.color_render_alloc_tx.release();
|
||||
@@ -400,6 +412,21 @@ bool Instance::object_is_sculpt_mode(const Object *object)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Instance::object_is_edit_paint_mode(const ObjectRef &ob_ref,
|
||||
bool in_edit_mode,
|
||||
bool in_paint_mode,
|
||||
bool in_sculpt_mode)
|
||||
{
|
||||
bool in_edit_paint_mode = in_edit_mode || in_paint_mode || in_sculpt_mode;
|
||||
if (ob_ref.object->base_flag & BASE_FROM_DUPLI) {
|
||||
/* Disable outlines for objects instanced by an object in sculpt, paint or edit mode. */
|
||||
in_edit_paint_mode |= object_is_edit_mode(ob_ref.dupli_parent) ||
|
||||
object_is_sculpt_mode(ob_ref.dupli_parent) ||
|
||||
object_is_paint_mode(ob_ref.dupli_parent);
|
||||
}
|
||||
return in_edit_paint_mode;
|
||||
}
|
||||
|
||||
bool Instance::object_is_edit_mode(const Object *object)
|
||||
{
|
||||
if (DRW_object_is_in_edit_mode(object)) {
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "overlay_next_prepass.hh"
|
||||
#include "overlay_next_relation.hh"
|
||||
#include "overlay_next_speaker.hh"
|
||||
#include "overlay_next_wireframe.hh"
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
@@ -69,6 +70,7 @@ class Instance {
|
||||
Prepass prepass = {selection_type_};
|
||||
Relations relations;
|
||||
Speakers speakers = {selection_type_};
|
||||
Wireframe wireframe;
|
||||
} regular{selection_type_}, infront{selection_type_};
|
||||
|
||||
Grid grid;
|
||||
@@ -96,6 +98,11 @@ class Instance {
|
||||
bool object_is_sculpt_mode(const ObjectRef &ob_ref);
|
||||
/* Checks only for sculpt mode. */
|
||||
bool object_is_sculpt_mode(const Object *object);
|
||||
/* Any mode that requires to view the object without distraction. */
|
||||
bool object_is_edit_paint_mode(const ObjectRef &ob_ref,
|
||||
bool in_edit_mode,
|
||||
bool in_paint_mode,
|
||||
bool in_sculpt_mode);
|
||||
};
|
||||
|
||||
} // namespace blender::draw::overlay
|
||||
|
||||
@@ -338,6 +338,18 @@ class Meshes {
|
||||
GPU_debug_group_end();
|
||||
}
|
||||
|
||||
static bool mesh_has_edit_cage(const Object *ob)
|
||||
{
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(ob->data);
|
||||
if (mesh.runtime->edit_mesh.get() != nullptr) {
|
||||
const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
|
||||
const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);
|
||||
|
||||
return (editmesh_eval_cage != nullptr) && (editmesh_eval_cage != editmesh_eval_final);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
uint4 data_mask_get(const int flag)
|
||||
{
|
||||
@@ -360,18 +372,6 @@ class Meshes {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool mesh_has_edit_cage(const Object *ob)
|
||||
{
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(ob->data);
|
||||
if (mesh.runtime->edit_mesh.get() != nullptr) {
|
||||
const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
|
||||
const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);
|
||||
|
||||
return (editmesh_eval_cage != nullptr) && (editmesh_eval_cage != editmesh_eval_final);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::draw::overlay
|
||||
|
||||
@@ -200,6 +200,9 @@ class ShaderModule {
|
||||
ShaderPtr facing;
|
||||
ShaderPtr lattice_points;
|
||||
ShaderPtr lattice_wire;
|
||||
ShaderPtr wireframe_mesh;
|
||||
ShaderPtr wireframe_curve;
|
||||
ShaderPtr wireframe_points; /* Draw objects without edges for the wireframe overlay. */
|
||||
|
||||
ShaderModule(const SelectionType selection_type, const bool clipping_enabled);
|
||||
|
||||
@@ -243,6 +246,8 @@ struct Resources : public select::SelectMap {
|
||||
TextureFromPool line_tx = {"line_tx"};
|
||||
/* Target containing overlay color before anti-aliasing. */
|
||||
TextureFromPool overlay_tx = {"overlay_tx"};
|
||||
/* Target containing depth of overlays when xray is enabled. */
|
||||
TextureFromPool xray_depth_tx = {"xray_depth_tx"};
|
||||
|
||||
/* Texture that are usually allocated inside. These are fallback when they aren't.
|
||||
* They are then wrapped inside the #TextureRefs below. */
|
||||
@@ -259,10 +264,23 @@ struct Resources : public select::SelectMap {
|
||||
GPUUniformBuf *globals_buf;
|
||||
TextureRef weight_ramp_tx;
|
||||
/* Wrappers around #DefaultTextureList members. */
|
||||
TextureRef depth_tx;
|
||||
TextureRef depth_in_front_tx;
|
||||
TextureRef color_overlay_tx;
|
||||
TextureRef color_render_tx;
|
||||
/**
|
||||
* Scene depth buffer that can also be used as render target for overlays.
|
||||
*
|
||||
* Can only be bound as a texture if either:
|
||||
* - the current frame-buffer has no depth buffer attached.
|
||||
* - `state.xray_enabled` is true.
|
||||
*/
|
||||
TextureRef depth_tx;
|
||||
/**
|
||||
* Depth target.
|
||||
* Can either be default depth buffer texture from #DefaultTextureList
|
||||
* or `xray_depth_tx` if Xray is enabled.
|
||||
*/
|
||||
TextureRef depth_target_tx;
|
||||
|
||||
Resources(const SelectionType selection_type_, ShaderModule &shader_module)
|
||||
: select::SelectMap(selection_type_), shaders(shader_module){};
|
||||
|
||||
@@ -66,6 +66,7 @@ ShaderModule::ShaderPtr ShaderModule::selectable_shader(
|
||||
|
||||
if (selection_type_ != SelectionType::DISABLED) {
|
||||
info.define("SELECT_ENABLE");
|
||||
info.depth_write(gpu::shader::DepthWrite::UNCHANGED);
|
||||
/* Replace additional info. */
|
||||
for (StringRefNull &str : info.additional_infos_) {
|
||||
if (str == "draw_modelmat_new") {
|
||||
@@ -277,6 +278,23 @@ ShaderModule::ShaderModule(const SelectionType selection_type, const bool clippi
|
||||
info.define("inst_pos", "data_buf[gl_InstanceID].xyz");
|
||||
info.vertex_inputs_.pop_last();
|
||||
});
|
||||
|
||||
wireframe_mesh = selectable_shader("overlay_wireframe", [](gpu::shader::ShaderCreateInfo &info) {
|
||||
info.additional_infos_.clear();
|
||||
info.define("CUSTOM_DEPTH_BIAS_CONST");
|
||||
info.specialization_constant(gpu::shader::Type::BOOL, "use_custom_depth_bias", true);
|
||||
info.additional_info("draw_view",
|
||||
"draw_modelmat_new",
|
||||
"draw_resource_handle_new",
|
||||
"draw_object_infos_new",
|
||||
"draw_globals");
|
||||
});
|
||||
|
||||
wireframe_points = selectable_shader("overlay_wireframe_points",
|
||||
[](gpu::shader::ShaderCreateInfo &info) {});
|
||||
|
||||
wireframe_curve = selectable_shader("overlay_wireframe_curve",
|
||||
[](gpu::shader::ShaderCreateInfo &info) {});
|
||||
}
|
||||
|
||||
ShaderModule &ShaderModule::module_get(SelectionType selection_type, bool clipping_enabled)
|
||||
|
||||
180
source/blender/draw/engines/overlay/overlay_next_wireframe.hh
Normal file
180
source/blender/draw/engines/overlay/overlay_next_wireframe.hh
Normal file
@@ -0,0 +1,180 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup overlay
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DNA_volume_types.h"
|
||||
|
||||
#include "draw_common.hh"
|
||||
|
||||
#include "overlay_next_mesh.hh"
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
class Wireframe {
|
||||
private:
|
||||
PassMain wireframe_ps_ = {"Wireframe"};
|
||||
struct ColoringPass {
|
||||
PassMain::Sub *curves_ps_ = nullptr;
|
||||
PassMain::Sub *gpencil_ps_ = nullptr;
|
||||
PassMain::Sub *mesh_ps_ = nullptr;
|
||||
PassMain::Sub *pointcloud_ps_ = nullptr;
|
||||
/* Variant for meshes that force drawing all edges. */
|
||||
PassMain::Sub *mesh_all_edges_ps_ = nullptr;
|
||||
} colored, non_colored;
|
||||
|
||||
bool enabled = false;
|
||||
|
||||
public:
|
||||
void begin_sync(Resources &res, const State &state)
|
||||
{
|
||||
enabled = state.is_wireframe_mode || (state.overlay.flag & V3D_OVERLAY_WIREFRAMES);
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool do_smooth_lines = (U.gpu_flag & USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE) != 0;
|
||||
const bool is_transform = (G.moving & G_TRANSFORM_OBJ) != 0;
|
||||
const float wire_threshold = wire_discard_threshold_get(state.overlay.wireframe_threshold);
|
||||
|
||||
GPUTexture **depth_tex = (state.xray_enabled) ? &res.depth_tx : &res.dummy_depth_tx;
|
||||
|
||||
{
|
||||
auto &pass = wireframe_ps_;
|
||||
pass.init();
|
||||
pass.state_set(DRW_STATE_FIRST_VERTEX_CONVENTION | DRW_STATE_WRITE_COLOR |
|
||||
DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | state.clipping_state);
|
||||
res.select_bind(pass);
|
||||
|
||||
auto shader_pass =
|
||||
[&](GPUShader *shader, const char *name, bool use_coloring, float wire_threshold) {
|
||||
auto &sub = pass.sub(name);
|
||||
if (res.shaders.wireframe_mesh.get() == shader) {
|
||||
sub.specialize_constant(shader, "use_custom_depth_bias", do_smooth_lines);
|
||||
}
|
||||
sub.shader_set(shader);
|
||||
sub.bind_ubo("globalsBlock", &res.globals_buf);
|
||||
sub.bind_texture("depthTex", depth_tex);
|
||||
sub.push_constant("wireOpacity", state.overlay.wireframe_opacity);
|
||||
sub.push_constant("isTransform", is_transform);
|
||||
sub.push_constant("colorType", state.v3d->shading.wire_color_type);
|
||||
sub.push_constant("useColoring", use_coloring);
|
||||
sub.push_constant("wireStepParam", wire_threshold);
|
||||
sub.push_constant("isHair", false);
|
||||
return ⊂
|
||||
};
|
||||
|
||||
auto coloring_pass = [&](ColoringPass &ps, bool use_color) {
|
||||
overlay::ShaderModule &sh = res.shaders;
|
||||
ps.mesh_ps_ = shader_pass(sh.wireframe_mesh.get(), "Mesh", use_color, wire_threshold);
|
||||
ps.mesh_all_edges_ps_ = shader_pass(sh.wireframe_mesh.get(), "Wire", use_color, 1.0f);
|
||||
ps.pointcloud_ps_ = shader_pass(sh.wireframe_points.get(), "PtCloud", use_color, 1.0f);
|
||||
ps.curves_ps_ = shader_pass(sh.wireframe_curve.get(), "Curve", use_color, 1.0f);
|
||||
};
|
||||
|
||||
coloring_pass(non_colored, false);
|
||||
coloring_pass(colored, true);
|
||||
}
|
||||
}
|
||||
|
||||
void object_sync(Manager &manager,
|
||||
const ObjectRef &ob_ref,
|
||||
Resources &res,
|
||||
const bool in_edit_paint_mode)
|
||||
{
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool all_edges = (ob_ref.object->dtx & OB_DRAW_ALL_EDGES) != 0;
|
||||
|
||||
/* TODO(fclem): Non-mandatory handle creation and reuse with other overlays. */
|
||||
ResourceHandle res_handle = manager.resource_handle(ob_ref);
|
||||
|
||||
ColoringPass &coloring = in_edit_paint_mode ? non_colored : colored;
|
||||
gpu::Batch *geom;
|
||||
switch (ob_ref.object->type) {
|
||||
case OB_CURVES_LEGACY:
|
||||
geom = DRW_cache_curve_edge_wire_get(ob_ref.object);
|
||||
coloring.curves_ps_->draw(geom, res_handle, res.select_id(ob_ref).get());
|
||||
break;
|
||||
case OB_FONT:
|
||||
geom = DRW_cache_text_edge_wire_get(ob_ref.object);
|
||||
coloring.curves_ps_->draw(geom, res_handle, res.select_id(ob_ref).get());
|
||||
break;
|
||||
case OB_SURF:
|
||||
geom = DRW_cache_surf_edge_wire_get(ob_ref.object);
|
||||
coloring.curves_ps_->draw(geom, res_handle, res.select_id(ob_ref).get());
|
||||
break;
|
||||
case OB_CURVES:
|
||||
/* TODO(fclem): Not yet implemented. */
|
||||
break;
|
||||
case OB_GREASE_PENCIL:
|
||||
/* TODO(fclem): Not yet implemented. */
|
||||
break;
|
||||
case OB_MESH:
|
||||
geom = DRW_cache_mesh_face_wireframe_get(ob_ref.object);
|
||||
(all_edges ? coloring.mesh_all_edges_ps_ : coloring.mesh_ps_)
|
||||
->draw(geom, res_handle, res.select_id(ob_ref).get());
|
||||
|
||||
/* Draw loose geometry. */
|
||||
if (!in_edit_paint_mode || Meshes::mesh_has_edit_cage(ob_ref.object)) {
|
||||
const Mesh *mesh = static_cast<const Mesh *>(ob_ref.object->data);
|
||||
if ((mesh->edges_num == 0) && (mesh->verts_num > 0)) {
|
||||
geom = DRW_cache_mesh_all_verts_get(ob_ref.object);
|
||||
coloring.pointcloud_ps_->draw(geom, res_handle, res.select_id(ob_ref).get());
|
||||
}
|
||||
else if ((geom = DRW_cache_mesh_loose_edges_get(ob_ref.object))) {
|
||||
coloring.mesh_all_edges_ps_->draw(geom, res_handle, res.select_id(ob_ref).get());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OB_POINTCLOUD:
|
||||
geom = DRW_pointcloud_batch_cache_get_dots(ob_ref.object);
|
||||
coloring.pointcloud_ps_->draw(geom, res_handle, res.select_id(ob_ref).get());
|
||||
break;
|
||||
case OB_VOLUME:
|
||||
geom = DRW_cache_volume_face_wireframe_get(ob_ref.object);
|
||||
if (static_cast<Volume *>(ob_ref.object->data)->display.wireframe_type ==
|
||||
VOLUME_WIREFRAME_POINTS)
|
||||
{
|
||||
coloring.pointcloud_ps_->draw(geom, res_handle, res.select_id(ob_ref).get());
|
||||
}
|
||||
else {
|
||||
coloring.mesh_ps_->draw(geom, res_handle, res.select_id(ob_ref).get());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Would be good to have. */
|
||||
// BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void draw(Framebuffer &framebuffer, Manager &manager, View &view)
|
||||
{
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
GPU_framebuffer_bind(framebuffer);
|
||||
manager.submit(wireframe_ps_, view);
|
||||
}
|
||||
|
||||
private:
|
||||
float wire_discard_threshold_get(float threshold)
|
||||
{
|
||||
/* Use `sqrt` since the value stored in the edge is a variation of the cosine, so its square
|
||||
* becomes more proportional with a variation of angle. */
|
||||
threshold = sqrt(abs(threshold));
|
||||
/* The maximum value (255 in the VBO) is used to force hide the edge. */
|
||||
return math::interpolate(0.0f, 1.0f - (1.0f / 255.0f), threshold);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::draw::overlay
|
||||
@@ -5,8 +5,8 @@
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
GPU_SHADER_INTERFACE_INFO(overlay_wireframe_iface, "")
|
||||
.flat(Type::VEC2, "edgeStart")
|
||||
.smooth(Type::VEC4, "finalColor")
|
||||
.flat(Type::VEC2, "edgeStart")
|
||||
.no_perspective(Type::VEC2, "edgePos");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(overlay_wireframe)
|
||||
@@ -31,6 +31,47 @@ GPU_SHADER_CREATE_INFO(overlay_wireframe)
|
||||
.depth_write(DepthWrite::ANY)
|
||||
.additional_info("draw_mesh", "draw_object_infos", "draw_globals");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(overlay_wireframe_curve)
|
||||
.do_static_compilation(true)
|
||||
.define("CURVES")
|
||||
.push_constant(Type::FLOAT, "wireOpacity")
|
||||
.push_constant(Type::BOOL, "useColoring")
|
||||
.push_constant(Type::BOOL, "isTransform")
|
||||
.push_constant(Type::INT, "colorType")
|
||||
.vertex_in(0, Type::VEC3, "pos")
|
||||
.vertex_out(overlay_wireframe_iface)
|
||||
.vertex_source("overlay_wireframe_vert.glsl")
|
||||
.fragment_source("overlay_wireframe_frag.glsl")
|
||||
.fragment_out(0, Type::VEC4, "fragColor")
|
||||
.fragment_out(1, Type::VEC4, "lineOutput")
|
||||
.additional_info("draw_view",
|
||||
"draw_modelmat_new",
|
||||
"draw_resource_handle_new",
|
||||
"draw_object_infos_new",
|
||||
"draw_globals");
|
||||
|
||||
GPU_SHADER_INTERFACE_INFO(overlay_wireframe_points_iface, "")
|
||||
.flat(Type::VEC4, "finalColor")
|
||||
.flat(Type::VEC4, "finalColorInner");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(overlay_wireframe_points)
|
||||
.do_static_compilation(true)
|
||||
.define("POINTS")
|
||||
.push_constant(Type::BOOL, "useColoring")
|
||||
.push_constant(Type::BOOL, "isTransform")
|
||||
.push_constant(Type::INT, "colorType")
|
||||
.vertex_in(0, Type::VEC3, "pos")
|
||||
.vertex_out(overlay_wireframe_points_iface)
|
||||
.vertex_source("overlay_wireframe_vert.glsl")
|
||||
.fragment_source("overlay_wireframe_frag.glsl")
|
||||
.fragment_out(0, Type::VEC4, "fragColor")
|
||||
.fragment_out(1, Type::VEC4, "lineOutput")
|
||||
.additional_info("draw_view",
|
||||
"draw_modelmat_new",
|
||||
"draw_resource_handle_new",
|
||||
"draw_object_infos_new",
|
||||
"draw_globals");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(overlay_wireframe_clipped)
|
||||
.do_static_compilation(true)
|
||||
.additional_info("overlay_wireframe", "drw_clipped");
|
||||
|
||||
@@ -2,47 +2,81 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(select_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
#if !defined(POINTS) && !defined(CURVES)
|
||||
/* Needed only because of wireframe slider.
|
||||
* If we could get rid of it would be nice because of performance drain of discard. */
|
||||
if (edgeStart.r == -1.0) {
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SELECT_EDGES
|
||||
lineOutput = vec4(0.0);
|
||||
|
||||
#if defined(POINTS)
|
||||
vec2 centered = abs(gl_PointCoord - vec2(0.5));
|
||||
float dist = max(centered.x, centered.y);
|
||||
|
||||
float fac = dist * dist * 4.0;
|
||||
/* Create a small gradient so that dense objects have a small fresnel effect. */
|
||||
/* Non linear blend. */
|
||||
vec3 rim_col = sqrt(finalColorInner.rgb);
|
||||
vec3 wire_col = sqrt(finalColor.rgb);
|
||||
vec3 final_front_col = mix(rim_col, wire_col, 0.35);
|
||||
fragColor = vec4(mix(final_front_col, rim_col, saturate(fac)), 1.0);
|
||||
fragColor *= fragColor;
|
||||
|
||||
#elif !defined(SELECT_EDGES)
|
||||
lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos);
|
||||
fragColor = finalColor;
|
||||
|
||||
# ifdef CUSTOM_DEPTH_BIAS
|
||||
vec2 dir = lineOutput.xy * 2.0 - 1.0;
|
||||
bool dir_horiz = abs(dir.x) > abs(dir.y);
|
||||
# ifndef CUSTOM_DEPTH_BIAS_CONST
|
||||
/* TODO(fclem): Cleanup after overlay next. */
|
||||
# ifdef CUSTOM_DEPTH_BIAS
|
||||
const bool use_custom_depth_bias = true;
|
||||
# else
|
||||
const bool use_custom_depth_bias = false;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
vec2 uv = gl_FragCoord.xy * sizeViewportInv;
|
||||
float depth_occluder = texture(depthTex, uv).r;
|
||||
float depth_min = depth_occluder;
|
||||
vec2 texel_uv_size = sizeViewportInv;
|
||||
# if !defined(CURVES)
|
||||
if (use_custom_depth_bias) {
|
||||
vec2 dir = lineOutput.xy * 2.0 - 1.0;
|
||||
bool dir_horiz = abs(dir.x) > abs(dir.y);
|
||||
|
||||
if (dir_horiz) {
|
||||
depth_min = min(depth_min, texture(depthTex, uv + vec2(-texel_uv_size.x, 0.0)).r);
|
||||
depth_min = min(depth_min, texture(depthTex, uv + vec2(texel_uv_size.x, 0.0)).r);
|
||||
}
|
||||
else {
|
||||
depth_min = min(depth_min, texture(depthTex, uv + vec2(0, -texel_uv_size.y)).r);
|
||||
depth_min = min(depth_min, texture(depthTex, uv + vec2(0, texel_uv_size.y)).r);
|
||||
}
|
||||
vec2 uv = gl_FragCoord.xy * sizeViewportInv;
|
||||
float depth_occluder = texture(depthTex, uv).r;
|
||||
float depth_min = depth_occluder;
|
||||
vec2 texel_uv_size = sizeViewportInv;
|
||||
|
||||
float delta = abs(depth_occluder - depth_min);
|
||||
if (dir_horiz) {
|
||||
depth_min = min(depth_min, texture(depthTex, uv + vec2(-texel_uv_size.x, 0.0)).r);
|
||||
depth_min = min(depth_min, texture(depthTex, uv + vec2(texel_uv_size.x, 0.0)).r);
|
||||
}
|
||||
else {
|
||||
depth_min = min(depth_min, texture(depthTex, uv + vec2(0, -texel_uv_size.y)).r);
|
||||
depth_min = min(depth_min, texture(depthTex, uv + vec2(0, texel_uv_size.y)).r);
|
||||
}
|
||||
|
||||
if (gl_FragCoord.z < (depth_occluder + delta) && gl_FragCoord.z > depth_occluder) {
|
||||
gl_FragDepth = depth_occluder;
|
||||
}
|
||||
else {
|
||||
gl_FragDepth = gl_FragCoord.z;
|
||||
float delta = abs(depth_occluder - depth_min);
|
||||
|
||||
# ifndef SELECT_ENABLE
|
||||
if (gl_FragCoord.z < (depth_occluder + delta) && gl_FragCoord.z > depth_occluder) {
|
||||
gl_FragDepth = depth_occluder;
|
||||
}
|
||||
else {
|
||||
gl_FragDepth = gl_FragCoord.z;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
select_id_output(select_id);
|
||||
}
|
||||
|
||||
@@ -5,11 +5,14 @@
|
||||
#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(select_lib.glsl)
|
||||
|
||||
bool is_edge_sharpness_visible(float wd)
|
||||
#if !defined(POINTS) && !defined(CURVES)
|
||||
bool is_edge_sharpness_visible(float wire_data)
|
||||
{
|
||||
return wd <= wireStepParam;
|
||||
return wire_data <= wireStepParam;
|
||||
}
|
||||
#endif
|
||||
|
||||
void wire_color_get(out vec3 rim_col, out vec3 wire_col)
|
||||
{
|
||||
@@ -83,9 +86,16 @@ void wire_object_color_get(out vec3 rim_col, out vec3 wire_col)
|
||||
|
||||
void main()
|
||||
{
|
||||
select_id_set(drw_CustomID);
|
||||
|
||||
vec3 wpos = point_object_to_world(pos);
|
||||
#if defined(POINTS)
|
||||
gl_PointSize = sizeVertex * 2.0;
|
||||
#elif defined(CURVES)
|
||||
/* Noop */
|
||||
#else
|
||||
bool no_attr = all(equal(nor, vec3(0)));
|
||||
vec3 wnor = no_attr ? drw_view.viewinv[2].xyz : normalize(normal_object_to_world(nor));
|
||||
vec3 wpos = point_object_to_world(pos);
|
||||
|
||||
if (isHair) {
|
||||
mat4 obmat = hairDupliMatrix;
|
||||
@@ -97,28 +107,34 @@ void main()
|
||||
vec3 V = (is_persp) ? normalize(drw_view.viewinv[3].xyz - wpos) : drw_view.viewinv[2].xyz;
|
||||
|
||||
float facing = dot(wnor, V);
|
||||
#endif
|
||||
|
||||
gl_Position = point_world_to_ndc(wpos);
|
||||
|
||||
#ifndef CUSTOM_DEPTH_BIAS
|
||||
float facing_ratio = clamp(1.0 - facing * facing, 0.0, 1.0);
|
||||
float flip = sign(facing); /* Flip when not facing the normal (i.e.: back-facing). */
|
||||
float curvature = (1.0 - wd * 0.75); /* Avoid making things worse for curvy areas. */
|
||||
vec3 wofs = wnor * (facing_ratio * curvature * flip);
|
||||
wofs = normal_world_to_view(wofs);
|
||||
|
||||
/* Push vertex half a pixel (maximum) in normal direction. */
|
||||
gl_Position.xy += wofs.xy * sizeViewportInv * gl_Position.w;
|
||||
|
||||
/* Push the vertex towards the camera. Helps a bit. */
|
||||
gl_Position.z -= facing_ratio * curvature * 1.0e-6 * gl_Position.w;
|
||||
#ifndef CUSTOM_DEPTH_BIAS_CONST
|
||||
/* TODO(fclem): Cleanup after overlay next. */
|
||||
# ifdef CUSTOM_DEPTH_BIAS
|
||||
const bool use_custom_depth_bias = true;
|
||||
# else
|
||||
const bool use_custom_depth_bias = false;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Convert to screen position [0..sizeVp]. */
|
||||
edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
|
||||
#if !defined(POINTS) && !defined(CURVES)
|
||||
if (!use_custom_depth_bias) {
|
||||
float facing_ratio = clamp(1.0 - facing * facing, 0.0, 1.0);
|
||||
float flip = sign(facing); /* Flip when not facing the normal (i.e.: back-facing). */
|
||||
float curvature = (1.0 - wd * 0.75); /* Avoid making things worse for curvy areas. */
|
||||
vec3 wofs = wnor * (facing_ratio * curvature * flip);
|
||||
wofs = normal_world_to_view(wofs);
|
||||
|
||||
#ifndef SELECT_EDGES
|
||||
edgePos = edgeStart;
|
||||
/* Push vertex half a pixel (maximum) in normal direction. */
|
||||
gl_Position.xy += wofs.xy * sizeViewportInv * gl_Position.w;
|
||||
|
||||
/* Push the vertex towards the camera. Helps a bit. */
|
||||
gl_Position.z -= facing_ratio * curvature * 1.0e-6 * gl_Position.w;
|
||||
}
|
||||
#endif
|
||||
|
||||
vec3 rim_col, wire_col;
|
||||
if (colorType == V3D_SHADING_OBJECT_COLOR || colorType == V3D_SHADING_RANDOM_COLOR) {
|
||||
@@ -128,27 +144,42 @@ void main()
|
||||
wire_color_get(rim_col, wire_col);
|
||||
}
|
||||
|
||||
facing = clamp(abs(facing), 0.0, 1.0);
|
||||
#if defined(POINTS)
|
||||
finalColor = wire_col.rgbb;
|
||||
finalColorInner = rim_col.rgbb;
|
||||
|
||||
#else
|
||||
/* Convert to screen position [0..sizeVp]. */
|
||||
edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
|
||||
edgePos = edgeStart;
|
||||
|
||||
# if defined(CURVES)
|
||||
finalColor.rgb = rim_col;
|
||||
# elif !defined(SELECT_EDGES)
|
||||
facing = clamp(abs(facing), 0.0, 1.0);
|
||||
/* Do interpolation in a non-linear space to have a better visual result. */
|
||||
rim_col = pow(rim_col, vec3(1.0 / 2.2));
|
||||
wire_col = pow(wire_col, vec3(1.0 / 2.2));
|
||||
vec3 final_front_col = mix(rim_col, wire_col, 0.35);
|
||||
finalColor.rgb = mix(rim_col, final_front_col, facing);
|
||||
finalColor.rgb = pow(finalColor.rgb, vec3(2.2));
|
||||
# endif
|
||||
|
||||
finalColor.a = wireOpacity;
|
||||
finalColor.rgb *= wireOpacity;
|
||||
#endif
|
||||
|
||||
# if !defined(CURVES)
|
||||
/* Cull flat edges below threshold. */
|
||||
if (!no_attr && !is_edge_sharpness_visible(wd)) {
|
||||
edgeStart = vec2(-1.0);
|
||||
}
|
||||
# endif
|
||||
|
||||
#ifdef SELECT_EDGES
|
||||
# ifdef SELECT_EDGES
|
||||
/* HACK: to avoid losing sub-pixel object in selections, we add a bit of randomness to the
|
||||
* wire to at least create one fragment that will pass the occlusion query. */
|
||||
gl_Position.xy += sizeViewportInv * gl_Position.w * ((gl_VertexID % 2 == 0) ? -1.0 : 1.0);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
view_clipping_distances(wpos);
|
||||
|
||||
Reference in New Issue
Block a user