GPv3: Overlay for Weight Paint mode
This PR implements the viewport overlay for Weight Paint mode in GPv3. In Weight Paint mode the stroke points are colored depending on their weights in the active vertex group. Pull Request: https://projects.blender.org/blender/blender/pulls/118273
This commit is contained in:
committed by
Falk David
parent
7a8e4995c8
commit
7b3e063704
@@ -55,6 +55,7 @@ void OVERLAY_edit_curves_cache_init(OVERLAY_Data *vedata)
|
||||
sh = OVERLAY_shader_edit_particle_point();
|
||||
grp = pd->edit_curves_points_grp[i] = DRW_shgroup_create(sh, psl->edit_curves_points_ps[i]);
|
||||
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
|
||||
DRW_shgroup_uniform_bool_copy(grp, "useWeight", false);
|
||||
}
|
||||
DRW_PASS_CREATE(psl->edit_curves_lines_ps[i], (state | pd->clipping_state));
|
||||
sh = OVERLAY_shader_edit_particle_strand();
|
||||
|
||||
@@ -295,6 +295,14 @@ static bool overlay_object_is_edit_mode(const OVERLAY_PrivateData *pd, const Obj
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool overlay_object_is_paint_mode(const DRWContextState *draw_ctx, const Object *ob)
|
||||
{
|
||||
if (ob->type == OB_GREASE_PENCIL && draw_ctx->object_mode & OB_MODE_WEIGHT_GPENCIL_LEGACY) {
|
||||
return true;
|
||||
}
|
||||
return (ob == draw_ctx->obact) && (draw_ctx->object_mode & OB_MODE_ALL_PAINT);
|
||||
}
|
||||
|
||||
static bool overlay_should_fade_object(Object *ob, Object *active_object)
|
||||
{
|
||||
if (!active_object || !ob) {
|
||||
@@ -337,8 +345,7 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
|
||||
false;
|
||||
const bool in_particle_edit_mode = (ob->mode == OB_MODE_PARTICLE_EDIT) &&
|
||||
(pd->ctx_mode == CTX_MODE_PARTICLE);
|
||||
const bool in_paint_mode = (ob == draw_ctx->obact) &&
|
||||
(draw_ctx->object_mode & OB_MODE_ALL_PAINT);
|
||||
const bool in_paint_mode = overlay_object_is_paint_mode(draw_ctx, ob);
|
||||
const bool in_sculpt_curve_mode = (ob == draw_ctx->obact ||
|
||||
(is_preview && dupli_parent == draw_ctx->obact &&
|
||||
ob->type == OB_CURVES)) &&
|
||||
@@ -465,6 +472,9 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
|
||||
case OB_MODE_TEXTURE_PAINT:
|
||||
OVERLAY_paint_texture_cache_populate(data, ob);
|
||||
break;
|
||||
case OB_MODE_WEIGHT_GPENCIL_LEGACY:
|
||||
OVERLAY_weight_grease_pencil_cache_populate(data, ob);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -751,6 +761,7 @@ static void OVERLAY_draw_scene(void *vedata)
|
||||
OVERLAY_edit_curves_draw(data);
|
||||
break;
|
||||
case CTX_MODE_EDIT_GREASE_PENCIL:
|
||||
case CTX_MODE_WEIGHT_GREASE_PENCIL:
|
||||
OVERLAY_edit_grease_pencil_draw(data);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -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 use_weight = (draw_ctx->object_mode & OB_MODE_WEIGHT_GPENCIL_LEGACY) != 0;
|
||||
|
||||
GPUShader *sh;
|
||||
DRWShadingGroup *grp;
|
||||
@@ -32,19 +33,23 @@ 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) || use_weight;
|
||||
const bool show_lines = (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES) != 0;
|
||||
|
||||
if (show_lines) {
|
||||
sh = OVERLAY_shader_edit_particle_strand();
|
||||
grp = pd->edit_grease_pencil_wires_grp = DRW_shgroup_create(sh, psl->edit_grease_pencil_ps);
|
||||
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
|
||||
DRW_shgroup_uniform_bool_copy(grp, "useWeight", use_weight);
|
||||
DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
|
||||
}
|
||||
|
||||
if (show_points) {
|
||||
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);
|
||||
DRW_shgroup_uniform_bool_copy(grp, "useWeight", use_weight);
|
||||
DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +74,28 @@ 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) {
|
||||
blender::gpu::Batch *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) {
|
||||
blender::gpu::Batch *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;
|
||||
|
||||
@@ -46,6 +46,7 @@ void OVERLAY_edit_particle_cache_init(OVERLAY_Data *vedata)
|
||||
sh = OVERLAY_shader_edit_particle_point();
|
||||
pd->edit_particle_point_grp = grp = DRW_shgroup_create(sh, psl->edit_particle_ps);
|
||||
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
|
||||
DRW_shgroup_uniform_bool_copy(grp, "useWeight", false);
|
||||
}
|
||||
|
||||
void OVERLAY_edit_particle_cache_populate(OVERLAY_Data *vedata, Object *ob)
|
||||
|
||||
@@ -564,6 +564,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);
|
||||
|
||||
@@ -571,6 +571,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_particle_point)
|
||||
.vertex_in(0, Type::VEC3, "pos")
|
||||
.vertex_in(1, Type::FLOAT, "selection")
|
||||
.vertex_out(overlay_edit_flat_color_iface)
|
||||
.sampler(0, ImageType::FLOAT_1D, "weightTex")
|
||||
.push_constant(Type::BOOL, "useWeight")
|
||||
.fragment_out(0, Type::VEC4, "fragColor")
|
||||
.vertex_source("overlay_edit_particle_point_vert.glsl")
|
||||
.fragment_source("overlay_point_varying_color_frag.glsl")
|
||||
|
||||
@@ -5,12 +5,34 @@
|
||||
#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
|
||||
#define no_active_weight 666.0
|
||||
|
||||
vec3 weight_to_rgb(float t)
|
||||
{
|
||||
if (t == no_active_weight) {
|
||||
/* No weight. */
|
||||
return colorWire.rgb;
|
||||
}
|
||||
if (t > 1.0 || t < 0.0) {
|
||||
/* Error color */
|
||||
return vec3(1.0, 0.0, 1.0);
|
||||
}
|
||||
else {
|
||||
return texture(weightTex, t).rgb;
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 world_pos = point_object_to_world(pos);
|
||||
gl_Position = point_world_to_ndc(world_pos);
|
||||
|
||||
finalColor = mix(colorWire, colorVertexSelect, selection);
|
||||
if (useWeight) {
|
||||
finalColor = vec4(weight_to_rgb(selection), 1.0);
|
||||
}
|
||||
else {
|
||||
finalColor = mix(colorWire, colorVertexSelect, selection);
|
||||
}
|
||||
|
||||
gl_PointSize = sizeVertex * 2.0;
|
||||
|
||||
|
||||
@@ -286,4 +286,6 @@ blender::gpu::Batch *DRW_cache_grease_pencil_edit_points_get(const Scene *scene,
|
||||
blender::gpu::Batch *DRW_cache_grease_pencil_edit_lines_get(const Scene *scene, Object *ob);
|
||||
gpu::VertBuf *DRW_cache_grease_pencil_position_buffer_get(const Scene *scene, Object *ob);
|
||||
gpu::VertBuf *DRW_cache_grease_pencil_color_buffer_get(const Scene *scene, Object *ob);
|
||||
blender::gpu::Batch *DRW_cache_grease_pencil_weight_points_get(const Scene *scene, Object *ob);
|
||||
blender::gpu::Batch *DRW_cache_grease_pencil_weight_lines_get(const Scene *scene, Object *ob);
|
||||
} // namespace blender::draw
|
||||
|
||||
@@ -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,189 @@ 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 = 666.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));
|
||||
const char *active_defgroup_name = (active_defgroup == nullptr) ? "" : active_defgroup->name;
|
||||
|
||||
/* Get the visible drawings. */
|
||||
const Vector<ed::greasepencil::DrawingInfo> drawings =
|
||||
ed::greasepencil::retrieve_visible_drawings(scene, grease_pencil, false);
|
||||
|
||||
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) {
|
||||
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 VArray<float> weights = *curves.attributes().lookup_or_default<float>(
|
||||
active_defgroup_name, bke::AttrDomain::Point, no_active_weight);
|
||||
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 visible_strokes = ed::greasepencil::retrieve_visible_strokes(
|
||||
object, info.drawing, memory);
|
||||
|
||||
/* Fill line indices. */
|
||||
visible_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()) {
|
||||
visible_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);
|
||||
GPU_batch_vertbuf_add(cache->edit_lines, cache->edit_points_selection, false);
|
||||
|
||||
/* 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)
|
||||
@@ -752,4 +936,22 @@ gpu::VertBuf *DRW_cache_grease_pencil_color_buffer_get(const Scene *scene, Objec
|
||||
return cache->vbo_col;
|
||||
}
|
||||
|
||||
gpu::Batch *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;
|
||||
}
|
||||
|
||||
gpu::Batch *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
|
||||
|
||||
Reference in New Issue
Block a user