Overlay-Next: Particle Edit #127518

Merged
Clément Foucault merged 1 commits from fclem/blender:overlay-next-part-edit into main 2024-09-13 17:01:09 +02:00
5 changed files with 140 additions and 1 deletions

View File

@ -156,6 +156,7 @@ 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_particle_edit_mode = object_is_particle_edit_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 = object_needs_prepass(ob_ref, in_paint_mode);
@ -166,6 +167,10 @@ void Instance::object_sync(ObjectRef &ob_ref, Manager &manager)
layer.prepass.object_sync(manager, ob_ref, resources, state);
}
if (in_particle_edit_mode) {
layer.particles.edit_object_sync(manager, ob_ref, resources, state);
}
if (in_paint_mode) {
switch (ob_ref.object->type) {
case OB_MESH:
@ -437,6 +442,7 @@ void Instance::draw(Manager &manager)
layer.facing.draw(framebuffer, manager, view);
layer.fade.draw(framebuffer, manager, view);
layer.paints.draw(framebuffer, manager, view);
layer.particles.draw_no_line(framebuffer, manager, view);
};
auto draw_layer = [&](OverlayLayer &layer, Framebuffer &framebuffer) {
@ -537,6 +543,11 @@ bool Instance::object_is_sculpt_mode(const ObjectRef &ob_ref)
return false;
}
bool Instance::object_is_particle_edit_mode(const ObjectRef &ob_ref)
{
return (ob_ref.object->mode == OB_MODE_PARTICLE_EDIT) && (state.ctx_mode == CTX_MODE_PARTICLE);
}
bool Instance::object_is_sculpt_mode(const Object *object)
{
if (object->sculpt && (object->sculpt->mode_type == OB_MODE_SCULPT)) {

View File

@ -119,6 +119,7 @@ class Instance {
bool object_is_selected(const ObjectRef &ob_ref);
bool object_is_edit_mode(const Object *object);
bool object_is_paint_mode(const Object *object);
bool object_is_particle_edit_mode(const ObjectRef &ob_ref);
/* Checks for both curve sculpt and regular sculpt mode. */
bool object_is_sculpt_mode(const ObjectRef &ob_ref);
/* Checks only for sculpt mode. */

View File

@ -13,6 +13,8 @@
#include "BKE_pointcache.h"
#include "ED_particle.hh"
#include "overlay_next_private.hh"
namespace blender::draw::overlay {
@ -24,6 +26,14 @@ class Particles {
PassMain::Sub *shape_ps_ = nullptr;
PassMain::Sub *hair_ps_ = nullptr;
PassSimple edit_particle_ps_ = {"edit_particle_ps_"};
PassSimple::Sub *edit_vert_ps_ = nullptr;
PassSimple::Sub *edit_edge_ps_ = nullptr;
bool show_weight_ = false;
bool show_point_inner_ = false;
bool show_point_tip_ = false;
bool enabled_ = false;
public:
@ -37,6 +47,13 @@ class Particles {
const bool is_transform = (G.moving & G_TRANSFORM_OBJ) != 0;
const ParticleEditSettings *edit_settings = PE_settings(const_cast<Scene *>(state.scene));
if (edit_settings) {
show_weight_ = (edit_settings->brushtype == PE_BRUSH_WEIGHT);
show_point_inner_ = edit_settings->selectmode == SCE_SELECT_POINT;
show_point_tip_ = ELEM(edit_settings->selectmode, SCE_SELECT_POINT, SCE_SELECT_END);
}
{
auto &pass = particle_ps_;
pass.init();
@ -66,6 +83,32 @@ class Particles {
hair_ps_ = &sub;
}
}
{
auto &pass = edit_particle_ps_;
pass.init();
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL,
state.clipping_plane_count);
res.select_bind(pass);
{
auto &sub = pass.sub("Dots");
sub.shader_set(res.shaders.particle_edit_vert.get());
sub.bind_ubo("globalsBlock", &res.globals_buf);
sub.bind_texture("weightTex", res.weight_ramp_tx);
sub.push_constant("useWeight", show_weight_);
sub.push_constant("useGreasePencil", false);
edit_vert_ps_ = &sub;
}
{
auto &sub = pass.sub("Edges");
sub.shader_set(res.shaders.particle_edit_edge.get());
sub.bind_ubo("globalsBlock", &res.globals_buf);
sub.bind_texture("weightTex", res.weight_ramp_tx);
sub.push_constant("useWeight", false);
sub.push_constant("useGreasePencil", false);
edit_edge_ps_ = &sub;
}
}
}
/* Particle data are stored in world space. If an object is instanced, the associated particle
@ -90,6 +133,71 @@ class Particles {
return dupli_mat;
}
void edit_object_sync(Manager &manager,
const ObjectRef &ob_ref,
Resources & /*res*/,
const State &state)
{
if (!enabled_) {
return;
}
/* Usually the edit structure is created by Particle Edit Mode Toggle
* operator, but sometimes it's invoked after tagging hair as outdated
* (for example, when toggling edit mode). That makes it impossible to
* create edit structure for until after next dependency graph evaluation.
*
* Ideally, the edit structure will be created here already via some
* dependency graph callback or so, but currently trying to make it nicer
* only causes bad level calls and breaks design from the past.
*/
Object *object_eval = ob_ref.object;
Object *object_orig = DEG_get_original_object(object_eval);
Scene *scene_orig = (Scene *)DEG_get_original_id(const_cast<ID *>(&state.scene->id));
PTCacheEdit *edit = PE_create_current(state.depsgraph, scene_orig, object_orig);
if (edit == nullptr) {
/* Happens when trying to edit particles in EMITTER mode without having them cached. */
return;
}
auto find_active_evaluated_psys =
[&](ListBaseWrapper<ParticleSystem> particle_systems_orig,
ListBaseWrapper<ParticleSystem> particle_systems_eval) -> ParticleSystem * {
int psys_index = 0;
for (ParticleSystem *psys_orig : particle_systems_orig) {
if (PE_get_current_from_psys(psys_orig) == edit) {
return particle_systems_eval.get(psys_index);
}
psys_index++;
}
return nullptr;
};
ParticleSystem *psys = find_active_evaluated_psys(&object_orig->particlesystem,
&object_eval->particlesystem);
if (psys == nullptr) {
printf("Error getting evaluated particle system for edit.\n");
return;
}
Object *ob = ob_ref.object;
ResourceHandle handle = manager.resource_handle_for_psys(ob_ref, dupli_matrix_get(ob_ref));
{
gpu::Batch *geom = DRW_cache_particles_get_edit_strands(ob, psys, edit, show_weight_);
edit_edge_ps_->draw(geom, handle);
}
if (show_point_inner_) {
gpu::Batch *geom = DRW_cache_particles_get_edit_inner_points(ob, psys, edit);
edit_vert_ps_->draw(geom, handle);
}
if (show_point_tip_) {
gpu::Batch *geom = DRW_cache_particles_get_edit_tip_points(ob, psys, edit);
edit_vert_ps_->draw(geom, handle);
}
}
void object_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res, const State &state)
{
if (!enabled_) {
@ -100,7 +208,7 @@ class Particles {
ResourceHandle handle = {0};
LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
for (ParticleSystem *psys : ListBaseWrapper<ParticleSystem>(&ob->particlesystem)) {
if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
continue;
}
@ -181,5 +289,15 @@ class Particles {
GPU_framebuffer_bind(framebuffer);
manager.submit(particle_ps_, view);
}
void draw_no_line(Framebuffer &framebuffer, Manager &manager, View &view)
{
if (!enabled_) {
return;
}
GPU_framebuffer_bind(framebuffer);
manager.submit(edit_particle_ps_, view);
}
};
} // namespace blender::draw::overlay

View File

@ -231,6 +231,8 @@ class ShaderModule {
ShaderPtr outline_prepass_pointcloud;
ShaderPtr outline_prepass_gpencil;
ShaderPtr outline_detect = shader("overlay_outline_detect");
ShaderPtr particle_edit_vert;
ShaderPtr particle_edit_edge;
ShaderPtr paint_region_edge;
ShaderPtr paint_region_face;
ShaderPtr paint_region_vert;

View File

@ -255,6 +255,13 @@ ShaderModule::ShaderModule(const SelectionType selection_type, const bool clippi
info.additional_info("draw_gpencil_new", "draw_object_infos_new");
});
particle_edit_vert = shader(
"overlay_edit_particle_point",
[](gpu::shader::ShaderCreateInfo &info) { shader_patch_common(info); });
particle_edit_edge = shader(
"overlay_edit_particle_strand",
[](gpu::shader::ShaderCreateInfo &info) { shader_patch_common(info); });
paint_region_edge = shader("overlay_paint_wire", [](gpu::shader::ShaderCreateInfo &info) {
shader_patch_common(info);
});