GPv3: Weight Paint tools (Draw, Blur, Average, Smear, Sample weight) #118347

Merged
Falk David merged 48 commits from SietseB/blender:gpv3-weight-paint-tools into main 2024-04-25 15:21:26 +02:00
6 changed files with 252 additions and 3 deletions
Showing only changes of commit cd5ac40c33 - Show all commits

View File

@ -188,8 +188,17 @@ static void OVERLAY_cache_init(void *vedata)
case CTX_MODE_PARTICLE:
OVERLAY_edit_particle_cache_init(data);
break;
case CTX_MODE_PAINT_WEIGHT: {
const DRWContextState *draw_ctx = DRW_context_state_get();
if (draw_ctx->obact != nullptr && draw_ctx->obact->type == OB_GREASE_PENCIL) {
OVERLAY_edit_grease_pencil_cache_init(data);
}
else {
OVERLAY_paint_cache_init(data);
}
break;
}
case CTX_MODE_POSE:
case CTX_MODE_PAINT_WEIGHT:
case CTX_MODE_PAINT_VERTEX:
case CTX_MODE_PAINT_TEXTURE:
OVERLAY_paint_cache_init(data);
@ -750,6 +759,7 @@ static void OVERLAY_draw_scene(void *vedata)
OVERLAY_edit_curves_draw(data);
break;
case CTX_MODE_EDIT_GREASE_PENCIL:
case CTX_MODE_PAINT_WEIGHT:
OVERLAY_edit_grease_pencil_draw(data);
break;
default:

View File

@ -24,6 +24,7 @@ void OVERLAY_edit_grease_pencil_cache_init(OVERLAY_Data *vedata)
const bke::AttrDomain selection_domain = ED_grease_pencil_selection_domain_get(
draw_ctx->scene->toolsettings);
const View3D *v3d = draw_ctx->v3d;
const bool in_weight_paint_mode = (draw_ctx->object_mode == OB_MODE_WEIGHT_PAINT);
GPUShader *sh;
DRWShadingGroup *grp;
@ -32,7 +33,7 @@ void OVERLAY_edit_grease_pencil_cache_init(OVERLAY_Data *vedata)
DRW_STATE_BLEND_ALPHA;
DRW_PASS_CREATE(psl->edit_grease_pencil_ps, (state | pd->clipping_state));
const bool show_points = selection_domain == bke::AttrDomain::Point;
const bool show_points = (selection_domain == bke::AttrDomain::Point) || in_weight_paint_mode;
const bool show_lines = (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES) != 0;
if (show_lines) {
@ -45,6 +46,11 @@ void OVERLAY_edit_grease_pencil_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_edit_particle_point();
grp = pd->edit_grease_pencil_points_grp = DRW_shgroup_create(sh, psl->edit_grease_pencil_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
/* TODO: this naive attempt to show vertex weights using a color ramp does not work yet... */
if (in_weight_paint_mode) {
DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
}
}
}
@ -68,6 +74,26 @@ void OVERLAY_edit_grease_pencil_cache_populate(OVERLAY_Data *vedata, Object *ob)
}
}
void OVERLAY_weight_grease_pencil_cache_populate(OVERLAY_Data *vedata, Object *ob)
{
using namespace blender::draw;
OVERLAY_PrivateData *pd = vedata->stl->pd;
const DRWContextState *draw_ctx = DRW_context_state_get();
DRWShadingGroup *lines_grp = pd->edit_grease_pencil_wires_grp;
if (lines_grp) {
GPUBatch *geom_lines = DRW_cache_grease_pencil_weight_lines_get(draw_ctx->scene, ob);
DRW_shgroup_call_no_cull(lines_grp, geom_lines, ob);
}
DRWShadingGroup *points_grp = pd->edit_grease_pencil_points_grp;
if (points_grp) {
GPUBatch *geom_points = DRW_cache_grease_pencil_weight_points_get(draw_ctx->scene, ob);
DRW_shgroup_call_no_cull(points_grp, geom_points, ob);
}
}
void OVERLAY_edit_grease_pencil_draw(OVERLAY_Data *vedata)
{
OVERLAY_PassList *psl = vedata->psl;

View File

@ -254,7 +254,7 @@ void OVERLAY_paint_weight_cache_populate(OVERLAY_Data *vedata, Object *ob)
OVERLAY_paint_vertex_cache_populate(vedata, ob);
break;
case OB_GREASE_PENCIL:
/* TODO */
OVERLAY_weight_grease_pencil_cache_populate(vedata, ob);
break;
default:
BLI_assert_unreachable();

View File

@ -560,6 +560,7 @@ void OVERLAY_edit_gpencil_legacy_draw(OVERLAY_Data *vedata);
void OVERLAY_edit_grease_pencil_cache_init(OVERLAY_Data *vedata);
void OVERLAY_edit_grease_pencil_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_weight_grease_pencil_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_edit_grease_pencil_draw(OVERLAY_Data *vedata);
void OVERLAY_edit_lattice_cache_init(OVERLAY_Data *vedata);

View File

@ -280,4 +280,6 @@ GPUBatch *DRW_cache_grease_pencil_edit_points_get(const Scene *scene, Object *ob
GPUBatch *DRW_cache_grease_pencil_edit_lines_get(const Scene *scene, Object *ob);
GPUVertBuf *DRW_cache_grease_pencil_position_buffer_get(const Scene *scene, Object *ob);
GPUVertBuf *DRW_cache_grease_pencil_color_buffer_get(const Scene *scene, Object *ob);
GPUBatch *DRW_cache_grease_pencil_weight_points_get(const Scene *scene, Object *ob);
GPUBatch *DRW_cache_grease_pencil_weight_lines_get(const Scene *scene, Object *ob);
} // namespace blender::draw

View File

@ -10,6 +10,7 @@
#include "BKE_attribute.hh"
#include "BKE_curves.hh"
#include "BKE_deform.hh"
#include "BKE_grease_pencil.h"
#include "BKE_grease_pencil.hh"
@ -209,6 +210,197 @@ static void copy_transformed_positions(const Span<float3> src_positions,
}
}
static void grease_pencil_weight_batch_ensure(Object &object,
const GreasePencil &grease_pencil,
const Scene &scene)
{
using namespace blender::bke::greasepencil;
constexpr float no_active_weight = -1.0f;
BLI_assert(grease_pencil.runtime != nullptr);
GreasePencilBatchCache *cache = static_cast<GreasePencilBatchCache *>(
grease_pencil.runtime->batch_cache);
if (cache->edit_points_pos != nullptr) {
return;
}
/* Should be discarded together. */
BLI_assert(cache->edit_points_pos == nullptr && cache->edit_line_indices == nullptr &&
cache->edit_points_indices == nullptr);
BLI_assert(cache->edit_points == nullptr && cache->edit_lines == nullptr);
/* Get active vertex group. */
const bDeformGroup *active_defgroup = static_cast<bDeformGroup *>(BLI_findlink(
&grease_pencil.vertex_group_names, grease_pencil.vertex_group_active_index - 1));
if (active_defgroup == nullptr) {
return;
}
const char *active_defgroup_name = active_defgroup->name;
/* Get the visible drawings. */
const Array<ed::greasepencil::DrawingInfo> drawings =
ed::greasepencil::retrieve_visible_drawings(scene, grease_pencil);
const Span<const Layer *> layers = grease_pencil.layers();
static GPUVertFormat format_points_pos = {0};
if (format_points_pos.attr_len == 0) {
GPU_vertformat_attr_add(&format_points_pos, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
}
static GPUVertFormat format_points_weight = {0};
if (format_points_weight.attr_len == 0) {
/* TODO: use something like "weight" as attribute name. */
GPU_vertformat_attr_add(&format_points_weight, "selection", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
}
GPUUsageType vbo_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY;
cache->edit_points_pos = GPU_vertbuf_create_with_format_ex(&format_points_pos, vbo_flag);
cache->edit_points_selection = GPU_vertbuf_create_with_format_ex(&format_points_weight,
vbo_flag);
int visible_points_num = 0;
int total_line_ids_num = 0;
int total_points_num = 0;
for (const ed::greasepencil::DrawingInfo &info : drawings) {
const bke::CurvesGeometry &curves = info.drawing.strokes();
total_points_num += curves.points_num();
}
GPU_vertbuf_data_alloc(cache->edit_points_pos, total_points_num);
GPU_vertbuf_data_alloc(cache->edit_points_selection, total_points_num);
MutableSpan<float3> points_pos = {
static_cast<float3 *>(GPU_vertbuf_get_data(cache->edit_points_pos)),
GPU_vertbuf_get_vertex_len(cache->edit_points_pos)};
MutableSpan<float> points_weight = {
static_cast<float *>(GPU_vertbuf_get_data(cache->edit_points_selection)),
GPU_vertbuf_get_vertex_len(cache->edit_points_selection)};
int drawing_start_offset = 0;
for (const ed::greasepencil::DrawingInfo &info : drawings) {
const Layer &layer = *layers[info.layer_index];
const float4x4 layer_space_to_object_space = layer.to_object_space(object);
const bke::CurvesGeometry &curves = info.drawing.strokes();
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
const VArray<bool> cyclic = curves.cyclic();
IndexMaskMemory memory;
const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes(
object, info.drawing, memory);
const IndexRange points(drawing_start_offset, curves.points_num());
const Span<float3> positions = curves.positions();
MutableSpan<float3> positions_slice = points_pos.slice(points);
threading::parallel_for(curves.points_range(), 1024, [&](const IndexRange range) {
copy_transformed_positions(positions, range, layer_space_to_object_space, positions_slice);
});
/* Get vertex weights of the active vertex group in this drawing. */
const int def_nr = BLI_findstringindex(
&curves.vertex_group_names, active_defgroup_name, offsetof(bDeformGroup, name));
const Span<MDeformVert> dverts = curves.deform_verts();
const VArray<float> weights = (def_nr < 0 || layer.is_locked()) ?
VArray<float>::ForSingle(no_active_weight,
curves.points_num()) :
bke::varray_for_deform_verts(dverts, def_nr);
MutableSpan<float> weights_slice = points_weight.slice(points);
weights.materialize(weights_slice);
drawing_start_offset += curves.points_num();
/* Add one id for the restart after every curve. */
total_line_ids_num += visible_strokes.size();
Array<int> size_per_editable_stroke(visible_strokes.size());
offset_indices::gather_group_sizes(points_by_curve, visible_strokes, size_per_editable_stroke);
/* Add one id for every non-cyclic segment. */
total_line_ids_num += std::accumulate(
size_per_editable_stroke.begin(), size_per_editable_stroke.end(), 0);
/* Add one id for the last segment of every cyclic curve. */
total_line_ids_num += array_utils::count_booleans(curves.cyclic(), visible_strokes);
/* Do not show weights for locked layers. */
if (layer.is_locked()) {
continue;
}
visible_strokes.foreach_index([&](const int curve_i) {
const IndexRange points = points_by_curve[curve_i];
visible_points_num += points.size();
});
}
GPUIndexBufBuilder elb;
GPU_indexbuf_init_ex(&elb,
GPU_PRIM_LINE_STRIP,
total_line_ids_num,
GPU_vertbuf_get_vertex_len(cache->edit_points_pos));
GPUIndexBufBuilder epb;
GPU_indexbuf_init_ex(&epb,
GPU_PRIM_POINTS,
visible_points_num,
GPU_vertbuf_get_vertex_len(cache->edit_points_pos));
/* Fill point index buffer with data. */
drawing_start_offset = 0;
for (const ed::greasepencil::DrawingInfo &info : drawings) {
const Layer *layer = layers[info.layer_index];
const bke::CurvesGeometry &curves = info.drawing.strokes();
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
const VArray<bool> cyclic = curves.cyclic();
IndexMaskMemory memory;
const IndexMask editable_strokes = ed::greasepencil::retrieve_editable_strokes(
object, info.drawing, memory);
/* Fill line indices. */
editable_strokes.foreach_index([&](const int curve_i) {
const IndexRange points = points_by_curve[curve_i];
const bool is_cyclic = cyclic[curve_i];
for (const int point_i : points) {
GPU_indexbuf_add_generic_vert(&elb, point_i + drawing_start_offset);
}
if (is_cyclic) {
GPU_indexbuf_add_generic_vert(&elb, points.first() + drawing_start_offset);
}
GPU_indexbuf_add_primitive_restart(&elb);
});
/* Fill point indices. */
if (!layer->is_locked()) {
editable_strokes.foreach_index([&](const int curve_i) {
const IndexRange points = points_by_curve[curve_i];
for (const int point : points) {
GPU_indexbuf_add_generic_vert(&epb, point + drawing_start_offset);
}
});
}
drawing_start_offset += curves.points_num();
}
cache->edit_line_indices = GPU_indexbuf_build(&elb);
cache->edit_points_indices = GPU_indexbuf_build(&epb);
/* Create the batches. */
cache->edit_points = GPU_batch_create(
GPU_PRIM_POINTS, cache->edit_points_pos, cache->edit_points_indices);
GPU_batch_vertbuf_add(cache->edit_points, cache->edit_points_selection, false);
cache->edit_lines = GPU_batch_create(
GPU_PRIM_LINE_STRIP, cache->edit_points_pos, cache->edit_line_indices);
/* Allow creation of buffer texture. */
GPU_vertbuf_use(cache->edit_points_pos);
GPU_vertbuf_use(cache->edit_points_selection);
cache->is_dirty = false;
}
static void grease_pencil_edit_batch_ensure(Object &object,
const GreasePencil &grease_pencil,
const Scene &scene)
@ -736,4 +928,22 @@ GPUVertBuf *DRW_cache_grease_pencil_color_buffer_get(const Scene *scene, Object
return cache->vbo_col;
}
GPUBatch *DRW_cache_grease_pencil_weight_points_get(const Scene *scene, Object *ob)
{
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob->data);
GreasePencilBatchCache *cache = grease_pencil_batch_cache_get(grease_pencil);
grease_pencil_weight_batch_ensure(*ob, grease_pencil, *scene);
return cache->edit_points;
}
GPUBatch *DRW_cache_grease_pencil_weight_lines_get(const Scene *scene, Object *ob)
{
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob->data);
GreasePencilBatchCache *cache = grease_pencil_batch_cache_get(grease_pencil);
grease_pencil_weight_batch_ensure(*ob, grease_pencil, *scene);
return cache->edit_lines;
}
} // namespace blender::draw