Fix T101889: Curves editmode points are drawn from evaluated curves

Editmode should display the original (non-evaluated) points unless there
is something like an "On Cage" option of a modifier [which none of the
curves modifiers have].

This was not the case since the introduction in rBe15320568a29.

So we now draw the editpoints from the original curves. This also means
that original and evaluated curves might not have the same number of
points, so we have to get independent of `proc_point_buf` since that
would possibly create vertexbuffers of different sizes (compared to the
original curves) which is not allowed for a single batch.

- remove the "pos" alias from the vertex buffer format of proc_point_buf
- instead, create a new "edit_points_pos" vertex buffer
- fill that with the original (un-evaluated) curves positions
- dont request `proc_point_buf` anymore
- rename the editpoints flags buffer to be more consistent

And since original and evaluated points might also be in completely
different positions, we also need to draw connecting lines between those
editpoints to not have them float in thin air. For drawing these in
editmode, a simple polyline was chosen (instead of drawing lines in a
resolution that is take from the old particle system -- which is not
depending on points even but has a hardcoded resolution that can only be
upped by the hair_subdiv scene render setting)

- create appropriate batch and indexbuffer for this
- positions vertex buffer can be reused
- reuse particle edit shader (instead of curve edi shader) to get
segment highlighting

{F14055436}

NOTE: this also removes the broken depth handling and instead makes it
work (also XRay is properly taken into account) by binding the correct
overlay framebuffer.

NOTE: to further clarify the distinction between curves drawing (that is
based on the old partice system drawing) and drawing in editmode, the
corresponding vertexbuffers have been moved out of CurvesEvalCache into
CurvesBatchCache directly.

NOTE: drawing the lines in editmode could be improved (taking the "real"
resolution of splines into account, but since this should happen on the
GPU in a compute shader, this is for later)

Potentionally fixes T101889.

Maniphest Tasks: T101889

Differential Revision: https://developer.blender.org/D16281
This commit is contained in:
Philipp Oeser 2022-12-06 14:49:44 +01:00
parent 9e47db4f43
commit e5f139e99d
Notes: blender-bot 2023-02-14 05:59:31 +01:00
Referenced by issue #101889, Curves editmode: edit points are drawn from the fully evaluated curves
5 changed files with 130 additions and 51 deletions

View File

@ -22,12 +22,11 @@ void OVERLAY_edit_curves_init(OVERLAY_Data *vedata)
/* Create view with depth offset. */
DRWView *default_view = (DRWView *)DRW_view_default_get();
pd->view_edit_curves_points = default_view;
pd->view_edit_curves = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, 1.0f);
}
void OVERLAY_edit_curves_cache_init(OVERLAY_Data *vedata)
{
OVERLAY_TextureList *txl = vedata->txl;
OVERLAY_PassList *psl = vedata->psl;
OVERLAY_PrivateData *pd = vedata->stl->pd;
@ -35,33 +34,35 @@ void OVERLAY_edit_curves_cache_init(OVERLAY_Data *vedata)
DRWState state = (DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA |
DRW_STATE_WRITE_DEPTH);
/* Common boilerplate for shading groups. */
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
const DRWContextState *draw_ctx = DRW_context_state_get();
const View3D *v3d = draw_ctx->v3d;
GPUTexture **depth_tex = (pd->edit_curves.do_zbufclip) ? &dtxl->depth : &txl->dummy_depth_tx;
const float backwire_opacity = (pd->edit_curves.do_zbufclip) ? v3d->overlay.backwire_opacity :
1.0f;
GPUShader *sh;
DRWShadingGroup *grp;
/* Run Twice for in-front passes. */
for (int i = 0; i < 2; i++) {
DRW_PASS_CREATE(psl->edit_curves_points_ps[i], (state | pd->clipping_state));
GPUShader *sh = OVERLAY_shader_edit_curve_point();
DRWShadingGroup *grp = pd->edit_curves_points_grp[i] = DRW_shgroup_create(
sh, psl->edit_curves_points_ps[i]);
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_float_copy(grp, "alpha", backwire_opacity);
DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tex);
DRW_PASS_CREATE(psl->edit_curves_lines_ps[i], (state | pd->clipping_state));
sh = OVERLAY_shader_edit_particle_strand();
grp = pd->edit_curves_lines_grp[i] = DRW_shgroup_create(sh, psl->edit_curves_lines_ps[i]);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_bool_copy(grp, "useWeight", false);
}
}
static void overlay_edit_curves_add_ob_to_pass(OVERLAY_PrivateData *pd, Object *ob, bool in_front)
{
Curves *curves = static_cast<Curves *>(ob->data);
DRWShadingGroup *point_shgrp = pd->edit_curves_points_grp[in_front];
struct GPUBatch *geom_points = DRW_curves_batch_cache_get_edit_points(curves);
DRW_shgroup_call_no_cull(point_shgrp, geom_points, ob);
DRWShadingGroup *lines_shgrp = pd->edit_curves_lines_grp[in_front];
struct GPUBatch *geom_lines = DRW_curves_batch_cache_get_edit_lines(curves);
DRW_shgroup_call_no_cull(lines_shgrp, geom_lines, ob);
}
void OVERLAY_edit_curves_cache_populate(OVERLAY_Data *vedata, Object *ob)
@ -80,13 +81,20 @@ void OVERLAY_edit_curves_draw(OVERLAY_Data *vedata)
{
OVERLAY_PassList *psl = vedata->psl;
OVERLAY_PrivateData *pd = vedata->stl->pd;
OVERLAY_FramebufferList *fbl = vedata->fbl;
if (DRW_state_is_fbo()) {
GPU_framebuffer_bind(fbl->overlay_default_fb);
}
if (pd->edit_curves.do_zbufclip) {
DRW_view_set_active(pd->view_edit_curves_points);
DRW_view_set_active(pd->view_edit_curves);
DRW_draw_pass(psl->edit_curves_points_ps[NOT_IN_FRONT]);
DRW_draw_pass(psl->edit_curves_lines_ps[NOT_IN_FRONT]);
}
else {
DRW_view_set_active(pd->view_edit_curves_points);
DRW_view_set_active(pd->view_edit_curves);
DRW_draw_pass(psl->edit_curves_points_ps[IN_FRONT]);
DRW_draw_pass(psl->edit_curves_lines_ps[IN_FRONT]);
}
}

View File

@ -76,6 +76,7 @@ typedef struct OVERLAY_PassList {
DRWPass *edit_mesh_faces_ps[2];
DRWPass *edit_mesh_faces_cage_ps[2];
DRWPass *edit_curves_points_ps[2];
DRWPass *edit_curves_lines_ps[2];
DRWPass *edit_mesh_analysis_ps;
DRWPass *edit_mesh_normals_ps;
DRWPass *edit_particle_ps;
@ -264,6 +265,7 @@ typedef struct OVERLAY_PrivateData {
DRWShadingGroup *edit_uv_face_dots_grp;
DRWShadingGroup *edit_uv_stretching_grp;
DRWShadingGroup *edit_curves_points_grp[2];
DRWShadingGroup *edit_curves_lines_grp[2];
DRWShadingGroup *extra_grid_grp;
DRWShadingGroup *facing_grp[2];
DRWShadingGroup *fade_grp[2];
@ -305,7 +307,7 @@ typedef struct OVERLAY_PrivateData {
DRWView *view_edit_verts;
DRWView *view_edit_text;
DRWView *view_reference_images;
DRWView *view_edit_curves_points;
DRWView *view_edit_curves;
/** TODO: get rid of this. */
ListBase bg_movie_clips;

View File

@ -137,6 +137,7 @@ struct GPUVertBuf **DRW_curves_texture_for_evaluated_attribute(struct Curves *cu
bool *r_is_point_domain);
struct GPUBatch *DRW_curves_batch_cache_get_edit_points(struct Curves *curves);
struct GPUBatch *DRW_curves_batch_cache_get_edit_lines(struct Curves *curves);
void DRW_curves_batch_cache_create_requested(struct Object *ob);

View File

@ -23,6 +23,8 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DEG_depsgraph_query.h"
#include "BKE_curves.hh"
#include "BKE_geometry_set.hh"
@ -51,6 +53,15 @@ struct CurvesBatchCache {
CurvesEvalCache curves_cache;
GPUBatch *edit_points;
GPUBatch *edit_lines;
/* Editmode (original) point positions. */
GPUVertBuf *edit_points_pos;
/* Editmode data (such as selection). */
GPUVertBuf *edit_points_data;
GPUIndexBuf *edit_lines_ibo;
/* Whether the cache is invalid. */
bool is_dirty;
@ -99,13 +110,22 @@ static void curves_discard_attributes(CurvesEvalCache &curves_cache)
}
}
static void curves_batch_cache_clear_data(CurvesEvalCache &curves_cache)
static void curves_batch_cache_clear_edit_data(CurvesBatchCache *cache)
{
/* TODO: more granular update tagging. */
GPU_VERTBUF_DISCARD_SAFE(cache->edit_points_pos);
GPU_VERTBUF_DISCARD_SAFE(cache->edit_points_data);
GPU_INDEXBUF_DISCARD_SAFE(cache->edit_lines_ibo);
GPU_BATCH_DISCARD_SAFE(cache->edit_points);
GPU_BATCH_DISCARD_SAFE(cache->edit_lines);
}
static void curves_batch_cache_clear_eval_data(CurvesEvalCache &curves_cache)
{
/* TODO: more granular update tagging. */
GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_point_buf);
GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_length_buf);
GPU_VERTBUF_DISCARD_SAFE(curves_cache.data_edit_points);
GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_strand_buf);
GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_strand_seg_buf);
@ -126,9 +146,8 @@ static void curves_batch_cache_clear(Curves &curves)
return;
}
curves_batch_cache_clear_data(cache->curves_cache);
GPU_BATCH_DISCARD_SAFE(cache->edit_points);
curves_batch_cache_clear_eval_data(cache->curves_cache);
curves_batch_cache_clear_edit_data(cache);
}
void DRW_curves_batch_cache_validate(Curves *curves)
@ -258,7 +277,6 @@ static void curves_batch_cache_ensure_procedural_pos(const Curves &curves,
/* Initialize vertex format. */
GPUVertFormat format = {0};
GPU_vertformat_attr_add(&format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
GPU_vertformat_alias_add(&format, "pos");
cache.proc_point_buf = GPU_vertbuf_create_with_format_ex(
&format, GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
@ -282,47 +300,85 @@ static void curves_batch_cache_ensure_procedural_pos(const Curves &curves,
}
}
static void curves_batch_cache_ensure_data_edit_points(const Curves &curves_id,
CurvesEvalCache &cache)
static void curves_batch_cache_ensure_edit_points_pos(const Curves &curves_id,
CurvesBatchCache &cache)
{
using namespace blender;
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
static GPUVertFormat format_pos = {0};
static uint pos;
if (format_pos.attr_len == 0) {
pos = GPU_vertformat_attr_add(&format_pos, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
}
GPU_vertbuf_init_with_format(cache.edit_points_pos, &format_pos);
GPU_vertbuf_data_alloc(cache.edit_points_pos, curves.points_num());
Span<float3> positions = curves.positions();
GPU_vertbuf_attr_fill(cache.edit_points_pos, pos, positions.data());
}
static void curves_batch_cache_ensure_edit_points_data(const Curves &curves_id,
CurvesBatchCache &cache)
{
using namespace blender;
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
static GPUVertFormat format_data = {0};
static uint data;
static uint color;
if (format_data.attr_len == 0) {
data = GPU_vertformat_attr_add(&format_data, "data", GPU_COMP_U8, 1, GPU_FETCH_INT);
color = GPU_vertformat_attr_add(&format_data, "color", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
}
GPU_vertbuf_init_with_format(cache.data_edit_points, &format_data);
GPU_vertbuf_data_alloc(cache.data_edit_points, curves.points_num());
GPU_vertbuf_init_with_format(cache.edit_points_data, &format_data);
GPU_vertbuf_data_alloc(cache.edit_points_data, curves.points_num());
VArray<float> selection;
switch (curves_id.selection_domain) {
case ATTR_DOMAIN_POINT:
selection = curves.selection_point_float();
for (const int point_i : selection.index_range()) {
uint8_t vflag = 0;
const float point_selection = selection[point_i];
SET_FLAG_FROM_TEST(vflag, (point_selection > 0.0f), VFLAG_VERT_SELECTED);
GPU_vertbuf_attr_set(cache.data_edit_points, data, point_i, &vflag);
const float point_selection = (selection[point_i] > 0.0f) ? 1.0f : 0.0f;
GPU_vertbuf_attr_set(cache.edit_points_data, color, point_i, &point_selection);
}
break;
case ATTR_DOMAIN_CURVE:
selection = curves.selection_curve_float();
for (const int curve_i : curves.curves_range()) {
uint8_t vflag = 0;
const float curve_selection = selection[curve_i];
SET_FLAG_FROM_TEST(vflag, (curve_selection > 0.0f), VFLAG_VERT_SELECTED);
const float curve_selection = (selection[curve_i] > 0.0f) ? 1.0f : 0.0f;
const IndexRange points = curves.points_for_curve(curve_i);
for (const int point_i : points) {
GPU_vertbuf_attr_set(cache.data_edit_points, data, point_i, &vflag);
GPU_vertbuf_attr_set(cache.edit_points_data, color, point_i, &curve_selection);
}
}
break;
}
}
static void curves_batch_cache_ensure_edit_lines(const Curves &curves_id, CurvesBatchCache &cache)
{
using namespace blender;
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
const int vert_len = curves.points_num();
const int curve_len = curves.curves_num();
const int index_len = vert_len + curve_len;
GPUIndexBufBuilder elb;
GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, index_len, vert_len);
for (const int i : curves.curves_range()) {
const IndexRange points = curves.points_for_curve(i);
for (const int i_point : points) {
GPU_indexbuf_add_generic_vert(&elb, i_point);
}
GPU_indexbuf_add_primitive_restart(&elb);
}
GPU_indexbuf_build_in_place(&elb, cache.edit_lines_ibo);
}
void drw_curves_get_attribute_sampler_name(const char *layer_name, char r_sampler_name[32])
{
char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
@ -617,6 +673,12 @@ GPUBatch *DRW_curves_batch_cache_get_edit_points(Curves *curves)
return DRW_batch_request(&cache.edit_points);
}
GPUBatch *DRW_curves_batch_cache_get_edit_lines(Curves *curves)
{
CurvesBatchCache &cache = curves_batch_cache_get(*curves);
return DRW_batch_request(&cache.edit_lines);
}
static void request_attribute(Curves &curves, const char *name)
{
CurvesBatchCache &cache = curves_batch_cache_get(curves);
@ -684,18 +746,27 @@ GPUVertBuf **DRW_curves_texture_for_evaluated_attribute(Curves *curves,
void DRW_curves_batch_cache_create_requested(Object *ob)
{
Curves *curves = static_cast<Curves *>(ob->data);
Object *orig = DEG_get_original_object(ob);
Curves *curves_orig = static_cast<Curves *>(orig->data);
CurvesBatchCache &cache = curves_batch_cache_get(*curves);
if (DRW_batch_requested(cache.edit_points, GPU_PRIM_POINTS)) {
DRW_vbo_request(cache.edit_points, &cache.curves_cache.proc_point_buf);
DRW_vbo_request(cache.edit_points, &cache.curves_cache.data_edit_points);
DRW_vbo_request(cache.edit_points, &cache.edit_points_pos);
DRW_vbo_request(cache.edit_points, &cache.edit_points_data);
}
if (DRW_vbo_requested(cache.curves_cache.proc_point_buf)) {
curves_batch_cache_ensure_procedural_pos(*curves, cache.curves_cache, nullptr);
if (DRW_batch_requested(cache.edit_lines, GPU_PRIM_LINE_STRIP)) {
DRW_ibo_request(cache.edit_lines, &cache.edit_lines_ibo);
DRW_vbo_request(cache.edit_lines, &cache.edit_points_pos);
DRW_vbo_request(cache.edit_lines, &cache.edit_points_data);
}
if (DRW_vbo_requested(cache.curves_cache.data_edit_points)) {
curves_batch_cache_ensure_data_edit_points(*curves, cache.curves_cache);
if (DRW_vbo_requested(cache.edit_points_pos)) {
curves_batch_cache_ensure_edit_points_pos(*curves_orig, cache);
}
if (DRW_vbo_requested(cache.edit_points_data)) {
curves_batch_cache_ensure_edit_points_data(*curves_orig, cache);
}
if (DRW_ibo_requested(cache.edit_lines_ibo)) {
curves_batch_cache_ensure_edit_lines(*curves_orig, cache);
}
}

View File

@ -64,12 +64,9 @@ typedef struct CurvesEvalFinalCache {
/* Curves procedural display: Evaluation is done on the GPU. */
typedef struct CurvesEvalCache {
/* Input control point positions combined with parameter data. */
/* Control point positions on evaluated data-block combined with parameter data. */
GPUVertBuf *proc_point_buf;
/* Editmode data (such as selection flags) used by overlay_edit_curve_point.glsl */
GPUVertBuf *data_edit_points;
/** Info of control points strands (segment count and base index) */
GPUVertBuf *proc_strand_buf;