Overlay-Next: Sculpt
Rel #102179 Pull Request: https://projects.blender.org/blender/blender/pulls/127261
This commit is contained in:
committed by
Clément Foucault
parent
eee34de007
commit
adbb732ba2
@@ -311,6 +311,7 @@ set(SRC
|
||||
engines/overlay/overlay_next_prepass.hh
|
||||
engines/overlay/overlay_next_private.hh
|
||||
engines/overlay/overlay_next_relation.hh
|
||||
engines/overlay/overlay_next_sculpt.hh
|
||||
engines/overlay/overlay_next_speaker.hh
|
||||
engines/overlay/overlay_next_wireframe.hh
|
||||
engines/overlay/overlay_next_xray_fade.hh
|
||||
|
||||
@@ -116,6 +116,7 @@ void Instance::begin_sync()
|
||||
layer.prepass.begin_sync(resources, state);
|
||||
layer.relations.begin_sync();
|
||||
layer.speakers.begin_sync();
|
||||
layer.sculpts.begin_sync(resources, state);
|
||||
layer.wireframe.begin_sync(resources, state);
|
||||
};
|
||||
begin_sync_layer(regular);
|
||||
@@ -142,6 +143,10 @@ void Instance::object_sync(ObjectRef &ob_ref, Manager &manager)
|
||||
layer.prepass.object_sync(manager, ob_ref, resources, state);
|
||||
}
|
||||
|
||||
if (in_sculpt_mode) {
|
||||
layer.sculpts.object_sync(manager, ob_ref, state);
|
||||
}
|
||||
|
||||
if (in_edit_mode && !state.hide_overlays) {
|
||||
switch (ob_ref.object->type) {
|
||||
case OB_MESH:
|
||||
@@ -264,6 +269,9 @@ void Instance::draw(Manager &manager)
|
||||
resources.color_overlay_tx.wrap(DRW_viewport_texture_list_get()->color_overlay);
|
||||
resources.color_render_tx.wrap(DRW_viewport_texture_list_get()->color);
|
||||
|
||||
resources.render_fb = DRW_viewport_framebuffer_list_get()->default_fb;
|
||||
resources.render_in_front_fb = DRW_viewport_framebuffer_list_get()->in_front_fb;
|
||||
|
||||
int2 render_size = int2(resources.depth_tx.size());
|
||||
|
||||
const DRWView *view_legacy = DRW_view_default_get();
|
||||
@@ -331,6 +339,9 @@ void Instance::draw(Manager &manager)
|
||||
resources.overlay_output_fb.ensure(GPU_ATTACHMENT_NONE,
|
||||
GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx));
|
||||
|
||||
regular.sculpts.draw_on_render(resources.render_fb, manager, view);
|
||||
infront.sculpts.draw_on_render(resources.render_in_front_fb, manager, view);
|
||||
|
||||
GPU_framebuffer_bind(resources.overlay_line_fb);
|
||||
float4 clear_color(0.0f);
|
||||
if (state.xray_enabled) {
|
||||
@@ -374,6 +385,7 @@ void Instance::draw(Manager &manager)
|
||||
layer.fluids.draw(framebuffer, manager, view);
|
||||
layer.particles.draw(framebuffer, manager, view);
|
||||
layer.armatures.draw(framebuffer, manager, view);
|
||||
layer.sculpts.draw(framebuffer, manager, view);
|
||||
layer.meshes.draw(framebuffer, manager, view);
|
||||
};
|
||||
|
||||
@@ -435,7 +447,13 @@ bool Instance::object_is_sculpt_mode(const ObjectRef &ob_ref)
|
||||
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);
|
||||
};
|
||||
}
|
||||
|
||||
if (state.object_mode == OB_MODE_SCULPT) {
|
||||
const Object *active_object = state.active_base->object;
|
||||
const bool is_active_object = ob_ref.object == active_object;
|
||||
return is_active_object;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "overlay_next_particle.hh"
|
||||
#include "overlay_next_prepass.hh"
|
||||
#include "overlay_next_relation.hh"
|
||||
#include "overlay_next_sculpt.hh"
|
||||
#include "overlay_next_speaker.hh"
|
||||
#include "overlay_next_wireframe.hh"
|
||||
#include "overlay_next_xray_fade.hh"
|
||||
@@ -80,6 +81,7 @@ class Instance {
|
||||
Particles particles;
|
||||
Prepass prepass = {selection_type_};
|
||||
Relations relations = {selection_type_};
|
||||
Sculpts sculpts = {selection_type_};
|
||||
Speakers speakers = {selection_type_};
|
||||
Wireframe wireframe;
|
||||
} regular{selection_type_}, infront{selection_type_};
|
||||
|
||||
@@ -220,6 +220,9 @@ class ShaderModule {
|
||||
ShaderPtr outline_prepass_pointcloud;
|
||||
ShaderPtr outline_prepass_gpencil;
|
||||
ShaderPtr outline_detect = shader("overlay_outline_detect");
|
||||
ShaderPtr sculpt_mesh;
|
||||
ShaderPtr sculpt_curves;
|
||||
ShaderPtr sculpt_curves_cage;
|
||||
ShaderPtr xray_fade;
|
||||
|
||||
/** Selectable Shaders */
|
||||
@@ -298,6 +301,11 @@ struct Resources : public select::SelectMap {
|
||||
/* Output Color. */
|
||||
Framebuffer overlay_output_fb = {"overlay_output_fb"};
|
||||
|
||||
/* Render Framebuffers. Only used for multiplicative blending on top of the render. */
|
||||
/* TODO(fclem): Remove the usage of these somehow. This is against design. */
|
||||
GPUFrameBuffer *render_fb = nullptr;
|
||||
GPUFrameBuffer *render_in_front_fb = nullptr;
|
||||
|
||||
/* Target containing line direction and data for line expansion and anti-aliasing. */
|
||||
TextureFromPool line_tx = {"line_tx"};
|
||||
/* Target containing overlay color before anti-aliasing. */
|
||||
|
||||
260
source/blender/draw/engines/overlay/overlay_next_sculpt.hh
Normal file
260
source/blender/draw/engines/overlay/overlay_next_sculpt.hh
Normal file
@@ -0,0 +1,260 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup overlay
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_paint.hh"
|
||||
#include "BKE_pbvh_api.hh"
|
||||
#include "BKE_subdiv_ccg.hh"
|
||||
|
||||
#include "draw_cache_impl.hh"
|
||||
|
||||
#include "overlay_next_private.hh"
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
class Sculpts {
|
||||
|
||||
private:
|
||||
const SelectionType selection_type_;
|
||||
|
||||
PassSimple sculpt_mask_ = {"SculptMaskAndFaceSet"};
|
||||
PassSimple::Sub *mesh_ps_ = nullptr;
|
||||
PassSimple::Sub *curves_ps_ = nullptr;
|
||||
|
||||
PassSimple sculpt_curve_cage_ = {"SculptCage"};
|
||||
|
||||
bool show_curves_cage_ = false;
|
||||
bool show_face_set_ = false;
|
||||
bool show_mask_ = false;
|
||||
|
||||
bool enabled_ = false;
|
||||
|
||||
public:
|
||||
Sculpts(const SelectionType selection_type_) : selection_type_(selection_type_) {}
|
||||
|
||||
void begin_sync(Resources &res, const State &state)
|
||||
{
|
||||
const int sculpt_overlay_flags = V3D_OVERLAY_SCULPT_SHOW_FACE_SETS |
|
||||
V3D_OVERLAY_SCULPT_SHOW_MASK | V3D_OVERLAY_SCULPT_CURVES_CAGE;
|
||||
|
||||
enabled_ = (state.space_type == SPACE_VIEW3D) && !state.xray_enabled &&
|
||||
(selection_type_ == SelectionType::DISABLED) &&
|
||||
ELEM(state.object_mode, OB_MODE_SCULPT_CURVES, OB_MODE_SCULPT) &&
|
||||
(state.overlay.flag & sculpt_overlay_flags);
|
||||
|
||||
if (!enabled_) {
|
||||
/* Not used. But release the data. */
|
||||
sculpt_mask_.init();
|
||||
sculpt_curve_cage_.init();
|
||||
return;
|
||||
}
|
||||
|
||||
show_curves_cage_ = state.overlay.flag & V3D_OVERLAY_SCULPT_CURVES_CAGE;
|
||||
show_face_set_ = state.overlay.flag & V3D_OVERLAY_SCULPT_SHOW_FACE_SETS;
|
||||
show_mask_ = state.overlay.flag & V3D_OVERLAY_SCULPT_SHOW_MASK;
|
||||
|
||||
float curve_cage_opacity = show_curves_cage_ ? state.overlay.sculpt_curves_cage_opacity : 0.0f;
|
||||
float face_set_opacity = show_face_set_ ? state.overlay.sculpt_mode_face_sets_opacity : 0.0f;
|
||||
float mask_opacity = show_mask_ ? state.overlay.sculpt_mode_mask_opacity : 0.0f;
|
||||
|
||||
{
|
||||
sculpt_mask_.init();
|
||||
sculpt_mask_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL |
|
||||
DRW_STATE_BLEND_MUL,
|
||||
state.clipping_plane_count);
|
||||
{
|
||||
auto &sub = sculpt_mask_.sub("Mesh");
|
||||
sub.shader_set(res.shaders.sculpt_mesh.get());
|
||||
sub.bind_ubo("globalsBlock", &res.globals_buf);
|
||||
sub.push_constant("maskOpacity", mask_opacity);
|
||||
sub.push_constant("faceSetsOpacity", face_set_opacity);
|
||||
mesh_ps_ = ⊂
|
||||
}
|
||||
{
|
||||
auto &sub = sculpt_mask_.sub("Curves");
|
||||
sub.shader_set(res.shaders.sculpt_curves.get());
|
||||
sub.bind_ubo("globalsBlock", &res.globals_buf);
|
||||
sub.push_constant("selection_opacity", mask_opacity);
|
||||
curves_ps_ = ⊂
|
||||
}
|
||||
}
|
||||
{
|
||||
auto &pass = sculpt_curve_cage_;
|
||||
pass.init();
|
||||
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA,
|
||||
state.clipping_plane_count);
|
||||
pass.shader_set(res.shaders.sculpt_curves_cage.get());
|
||||
pass.bind_ubo("globalsBlock", &res.globals_buf);
|
||||
pass.push_constant("opacity", curve_cage_opacity);
|
||||
}
|
||||
}
|
||||
|
||||
void object_sync(Manager &manager, const ObjectRef &ob_ref, const State &state)
|
||||
{
|
||||
if (!enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ob_ref.object->type) {
|
||||
case OB_MESH:
|
||||
mesh_sync(manager, ob_ref, state);
|
||||
break;
|
||||
case OB_CURVES:
|
||||
curves_sync(manager, ob_ref, state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void curves_sync(Manager &manager, const ObjectRef &ob_ref, const State &state)
|
||||
{
|
||||
::Curves *curves = static_cast<::Curves *>(ob_ref.object->data);
|
||||
|
||||
/* As an optimization, draw nothing if everything is selected. */
|
||||
if (show_mask_ && !everything_selected(*curves)) {
|
||||
/* Retrieve the location of the texture. */
|
||||
bool is_point_domain;
|
||||
gpu::VertBuf **select_attr_buf = DRW_curves_texture_for_evaluated_attribute(
|
||||
curves, ".selection", &is_point_domain);
|
||||
if (select_attr_buf) {
|
||||
/* Evaluate curves and their attributes if necessary. */
|
||||
gpu::Batch *geometry = curves_sub_pass_setup(*curves_ps_, state.scene, ob_ref.object);
|
||||
if (*select_attr_buf) {
|
||||
ResourceHandle handle = manager.resource_handle(ob_ref);
|
||||
|
||||
curves_ps_->push_constant("is_point_domain", is_point_domain);
|
||||
curves_ps_->bind_texture("selection_tx", *select_attr_buf);
|
||||
curves_ps_->draw(geometry, handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (show_curves_cage_) {
|
||||
ResourceHandle handle = manager.resource_handle(ob_ref);
|
||||
|
||||
blender::gpu::Batch *geometry = DRW_curves_batch_cache_get_sculpt_curves_cage(curves);
|
||||
sculpt_curve_cage_.draw(geometry, handle);
|
||||
}
|
||||
}
|
||||
|
||||
void mesh_sync(Manager &manager, const ObjectRef &ob_ref, const State &state)
|
||||
{
|
||||
if (!show_face_set_ && !show_mask_) {
|
||||
/* Nothing to display. */
|
||||
return;
|
||||
}
|
||||
|
||||
const SculptSession *sculpt_session = ob_ref.object->sculpt;
|
||||
if (sculpt_session == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
bke::pbvh::Tree *pbvh = bke::object::pbvh_get(*ob_ref.object);
|
||||
if (!pbvh) {
|
||||
/* It is possible to have SculptSession without pbvh::Tree. This happens, for example, when
|
||||
* toggling object mode to sculpt then to edit mode. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Using the original object/geometry is necessary because we skip depsgraph updates in sculpt
|
||||
* mode to improve performance. This means the evaluated mesh doesn't have the latest face set,
|
||||
* visibility, and mask data. */
|
||||
Object *object_orig = reinterpret_cast<Object *>(DEG_get_original_id(&ob_ref.object->id));
|
||||
if (!object_orig) {
|
||||
BLI_assert_unreachable();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (pbvh->type()) {
|
||||
case blender::bke::pbvh::Type::Mesh: {
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(object_orig->data);
|
||||
if (!mesh.attributes().contains(".sculpt_face_set") &&
|
||||
!mesh.attributes().contains(".sculpt_mask"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case blender::bke::pbvh::Type::Grids: {
|
||||
const SubdivCCG &subdiv_ccg = *sculpt_session->subdiv_ccg;
|
||||
const Mesh &base_mesh = *static_cast<const Mesh *>(object_orig->data);
|
||||
if (!BKE_subdiv_ccg_key_top_level(subdiv_ccg).has_mask &&
|
||||
!base_mesh.attributes().contains(".sculpt_face_set"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case blender::bke::pbvh::Type::BMesh: {
|
||||
const BMesh &bm = *sculpt_session->bm;
|
||||
if (!CustomData_has_layer_named(&bm.pdata, CD_PROP_FLOAT, ".sculpt_face_set") &&
|
||||
!CustomData_has_layer_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const bool use_pbvh = BKE_sculptsession_use_pbvh_draw(ob_ref.object, state.rv3d);
|
||||
if (use_pbvh) {
|
||||
/* TODO(fclem): Deduplicate with other engine. */
|
||||
const blender::Bounds<float3> bounds = bke::pbvh::bounds_get(*ob_ref.object->sculpt->pbvh);
|
||||
const float3 center = math::midpoint(bounds.min, bounds.max);
|
||||
const float3 half_extent = bounds.max - center;
|
||||
ResourceHandle handle = manager.resource_handle(ob_ref, nullptr, ¢er, &half_extent);
|
||||
|
||||
SculptBatchFeature sculpt_batch_features_ = (show_face_set_ ? SCULPT_BATCH_FACE_SET :
|
||||
SCULPT_BATCH_DEFAULT) |
|
||||
(show_mask_ ? SCULPT_BATCH_MASK :
|
||||
SCULPT_BATCH_DEFAULT);
|
||||
|
||||
for (SculptBatch &batch : sculpt_batches_get(ob_ref.object, sculpt_batch_features_)) {
|
||||
mesh_ps_->draw(batch.batch, handle);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ResourceHandle handle = manager.resource_handle(ob_ref);
|
||||
|
||||
Mesh &mesh = *static_cast<Mesh *>(ob_ref.object->data);
|
||||
gpu::Batch *sculpt_overlays = DRW_mesh_batch_cache_get_sculpt_overlays(mesh);
|
||||
mesh_ps_->draw(sculpt_overlays, handle);
|
||||
}
|
||||
}
|
||||
|
||||
void draw(GPUFrameBuffer *framebuffer, Manager &manager, View &view)
|
||||
{
|
||||
if (!enabled_) {
|
||||
return;
|
||||
}
|
||||
GPU_framebuffer_bind(framebuffer);
|
||||
manager.submit(sculpt_curve_cage_, view);
|
||||
}
|
||||
|
||||
void draw_on_render(GPUFrameBuffer *framebuffer, Manager &manager, View &view)
|
||||
{
|
||||
if (!enabled_) {
|
||||
return;
|
||||
}
|
||||
GPU_framebuffer_bind(framebuffer);
|
||||
manager.submit(sculpt_mask_, view);
|
||||
}
|
||||
|
||||
private:
|
||||
bool everything_selected(const ::Curves &curves_id)
|
||||
{
|
||||
const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
|
||||
const VArray<bool> selection = *curves.attributes().lookup_or_default<bool>(
|
||||
".selection", bke::AttrDomain::Point, true);
|
||||
return selection.is_single() && selection.get_internal_single();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::draw::overlay
|
||||
@@ -236,6 +236,17 @@ ShaderModule::ShaderModule(const SelectionType selection_type, const bool clippi
|
||||
info.additional_info("draw_gpencil_new", "draw_object_infos_new");
|
||||
});
|
||||
|
||||
sculpt_mesh = shader("overlay_sculpt_mask",
|
||||
[](gpu::shader::ShaderCreateInfo &info) { shader_patch_common(info); });
|
||||
sculpt_curves = shader("overlay_sculpt_curves_selection",
|
||||
[](gpu::shader::ShaderCreateInfo &info) {
|
||||
shader_patch_common(info);
|
||||
info.additional_info("draw_hair_new");
|
||||
});
|
||||
sculpt_curves_cage = shader(
|
||||
"overlay_sculpt_curves_cage",
|
||||
[](gpu::shader::ShaderCreateInfo &info) { shader_patch_common(info); });
|
||||
|
||||
xray_fade = shader("overlay_xray_fade", [](gpu::shader::ShaderCreateInfo &info) {
|
||||
info.sampler(2, ImageType::DEPTH_2D, "xrayDepthTexInfront");
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@ GPU_SHADER_CREATE_INFO(overlay_sculpt_curves_selection)
|
||||
.do_static_compilation(true)
|
||||
.push_constant(Type::BOOL, "is_point_domain")
|
||||
.push_constant(Type::FLOAT, "selection_opacity")
|
||||
.sampler(0, ImageType::FLOAT_BUFFER, "selection_tx")
|
||||
.sampler(1, ImageType::FLOAT_BUFFER, "selection_tx")
|
||||
.vertex_out(overlay_sculpt_curves_selection_iface)
|
||||
.vertex_source("overlay_sculpt_curves_selection_vert.glsl")
|
||||
.fragment_source("overlay_sculpt_curves_selection_frag.glsl")
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
|
||||
void main()
|
||||
{
|
||||
fragColor = vec4(faceset_color * vec3(mask_color), 1.0);
|
||||
fragColor = vec4(faceset_color * mask_color, 1.0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user