Sculpt: Refactor draw manager sculpt drawing mechanism

Workbench/Eevee now displays multiple multi-materials correctly.

Iterate over pbvh nodes when doing object iteration. This makes the
rendering process more streamlined and allow for using different materials.

This change will make possible to:
- Add culling pass of each pbvh leaf node. (speedup if zoomed on a small
area)
- Reduce number of lead node iteration.
- Reduce code complexity
This commit is contained in:
Clément Foucault 2019-05-04 01:39:35 +02:00
parent 1d8ed6dcd7
commit b2f1a65874
Notes: blender-bot 2024-04-29 13:07:32 +02:00
Referenced by issue #62282, Multires: normals not updating when using smooth shading
9 changed files with 314 additions and 278 deletions

View File

@ -40,6 +40,7 @@ struct MPoly;
struct MVert;
struct PBVH;
struct PBVHNode;
struct GPU_PBVH_Buffers;
typedef struct PBVH PBVH;
typedef struct PBVHNode PBVHNode;
@ -48,6 +49,21 @@ typedef struct {
float (*co)[3];
} PBVHProxyNode;
typedef enum {
PBVH_Leaf = 1,
PBVH_UpdateNormals = 2,
PBVH_UpdateBB = 4,
PBVH_UpdateOriginalBB = 8,
PBVH_UpdateDrawBuffers = 16,
PBVH_UpdateRedraw = 32,
PBVH_RebuildDrawBuffers = 64,
PBVH_FullyHidden = 128,
PBVH_UpdateTopology = 256,
} PBVHNodeFlags;
/* Callbacks */
/* returns 1 if the search should continue from this node, 0 otherwise */
@ -151,13 +167,15 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh,
void BKE_pbvh_draw_cb(PBVH *bvh,
float (*planes)[4],
float (*fnors)[3],
bool fast,
bool wires,
bool only_mask,
bool show_vcol,
void (*draw_fn)(void *user_data, struct GPUBatch *batch),
void (*draw_fn)(void *user_data, struct GPU_PBVH_Buffers *buffers),
void *user_data);
void BKE_pbvh_draw_debug_cb(
PBVH *bvh,
void (*draw_fn)(void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag),
void *user_data);
/* PBVH Access */
typedef enum {
PBVH_FACES,
@ -202,21 +220,6 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
/* Node Access */
typedef enum {
PBVH_Leaf = 1,
PBVH_UpdateNormals = 2,
PBVH_UpdateBB = 4,
PBVH_UpdateOriginalBB = 8,
PBVH_UpdateDrawBuffers = 16,
PBVH_UpdateRedraw = 32,
PBVH_RebuildDrawBuffers = 64,
PBVH_FullyHidden = 128,
PBVH_UpdateTopology = 256,
} PBVHNodeFlags;
void BKE_pbvh_node_mark_update(PBVHNode *node);
void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node);
void BKE_pbvh_node_mark_redraw(PBVHNode *node);

View File

@ -2202,26 +2202,17 @@ bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data)
return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE;
}
struct PBVHNodeDrawCallbackData {
void (*draw_fn)(void *user_data, GPUBatch *batch);
typedef struct PBVHNodeDrawCallbackData {
void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers);
void *user_data;
bool fast;
bool only_mask; /* Only draw nodes that have mask data. */
bool wires;
};
} PBVHNodeDrawCallbackData;
static void pbvh_node_draw_cb(PBVHNode *node, void *data_v)
{
struct PBVHNodeDrawCallbackData *data = data_v;
PBVHNodeDrawCallbackData *data = data_v;
if (!(node->flag & PBVH_FullyHidden)) {
GPUBatch *batch = GPU_pbvh_buffers_batch_get(node->draw_buffers, data->fast, data->wires);
bool show_mask = GPU_pbvh_buffers_has_mask(node->draw_buffers);
if (!data->only_mask || show_mask) {
if (batch != NULL) {
data->draw_fn(data->user_data, batch);
}
}
data->draw_fn(data->user_data, node->draw_buffers);
}
}
@ -2231,20 +2222,10 @@ static void pbvh_node_draw_cb(PBVHNode *node, void *data_v)
void BKE_pbvh_draw_cb(PBVH *bvh,
float (*planes)[4],
float (*fnors)[3],
bool fast,
bool wires,
bool only_mask,
bool show_vcol,
void (*draw_fn)(void *user_data, GPUBatch *batch),
void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers),
void *user_data)
{
struct PBVHNodeDrawCallbackData draw_data = {
.only_mask = only_mask,
.fast = fast,
.wires = wires,
.draw_fn = draw_fn,
.user_data = user_data,
};
PBVHNode **nodes;
int totnode;
@ -2261,6 +2242,11 @@ void BKE_pbvh_draw_cb(PBVH *bvh,
MEM_freeN(nodes);
}
PBVHNodeDrawCallbackData draw_data = {
.draw_fn = draw_fn,
.user_data = user_data,
};
if (planes) {
BKE_pbvh_search_callback(
bvh, BKE_pbvh_node_planes_contain_AABB, planes, pbvh_node_draw_cb, &draw_data);
@ -2268,10 +2254,18 @@ void BKE_pbvh_draw_cb(PBVH *bvh,
else {
BKE_pbvh_search_callback(bvh, NULL, NULL, pbvh_node_draw_cb, &draw_data);
}
#if 0
if (G.debug_value == 14)
pbvh_draw_BB(bvh);
#endif
}
void BKE_pbvh_draw_debug_cb(
PBVH *bvh,
void (*draw_fn)(void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag),
void *user_data)
{
for (int a = 0; a < bvh->totnode; a++) {
PBVHNode *node = &bvh->nodes[a];
draw_fn(user_data, node->vb.bmin, node->vb.bmax, node->flag);
}
}
void BKE_pbvh_grids_update(

View File

@ -1190,17 +1190,12 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
#define ADD_SHGROUP_CALL(shgrp, ob, ma, geom, oedata) \
do { \
if (is_sculpt_mode_draw) { \
DRW_shgroup_call_sculpt_add(shgrp, ob, ob->obmat); \
if (oedata) { \
DRW_shgroup_call_object_add_with_callback( \
shgrp, geom, ob, ma, EEVEE_lightprobes_obj_visibility_cb, oedata); \
} \
else { \
if (oedata) { \
DRW_shgroup_call_object_add_with_callback( \
shgrp, geom, ob, ma, EEVEE_lightprobes_obj_visibility_cb, oedata); \
} \
else { \
DRW_shgroup_call_object_add_ex(shgrp, geom, ob, ma, false); \
} \
DRW_shgroup_call_object_add_ex(shgrp, geom, ob, ma, false); \
} \
} while (0)
@ -1604,6 +1599,16 @@ static void material_transparent(Material *ma,
}
}
/* Return correct material or &defmaterial if slot is empty. */
BLI_INLINE Material *eevee_object_material_get(Object *ob, int slot)
{
Material *ma = give_current_material(ob, slot + 1);
if (ma == NULL) {
ma = &defmaterial;
}
return ma;
}
void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata,
Object *ob,
@ -1617,15 +1622,14 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
const bool do_cull = (draw_ctx->v3d &&
(draw_ctx->v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING));
const bool is_sculpt_mode = DRW_object_use_pbvh_drawing(ob);
bool is_sculpt_mode = DRW_object_use_pbvh_drawing(ob);
/* For now just force fully shaded with eevee when supported. */
const bool is_sculpt_mode_draw = ob->sculpt && ob->sculpt->pbvh &&
BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_FACES;
const bool is_default_mode_shader = is_sculpt_mode;
is_sculpt_mode = is_sculpt_mode &&
!(ob->sculpt->pbvh && BKE_pbvh_type(ob->sculpt->pbvh) == PBVH_FACES);
/* First get materials for this mesh. */
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
const int materials_len = MAX2(1, (is_sculpt_mode_draw ? 1 : ob->totcol));
const int materials_len = MAX2(1, ob->totcol);
struct DRWShadingGroup **shgrp_array = BLI_array_alloca(shgrp_array, materials_len);
struct DRWShadingGroup **shgrp_depth_array = BLI_array_alloca(shgrp_depth_array,
@ -1635,40 +1639,22 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
struct GPUMaterial **gpumat_depth_array = BLI_array_alloca(gpumat_array, materials_len);
struct Material **ma_array = BLI_array_alloca(ma_array, materials_len);
bool use_flat_nor = false;
if (is_default_mode_shader) {
if (is_sculpt_mode_draw) {
use_flat_nor = DRW_object_is_flat_normal(ob);
}
}
for (int i = 0; i < materials_len; ++i) {
Material *ma;
if (is_sculpt_mode_draw) {
ma = NULL;
}
else {
ma = give_current_material(ob, i + 1);
}
ma_array[i] = eevee_object_material_get(ob, i);
gpumat_array[i] = NULL;
gpumat_depth_array[i] = NULL;
shgrp_array[i] = NULL;
shgrp_depth_array[i] = NULL;
shgrp_depth_clip_array[i] = NULL;
if (ma == NULL) {
ma = &defmaterial;
}
switch (ma->blend_method) {
switch (ma_array[i]->blend_method) {
case MA_BM_SOLID:
case MA_BM_CLIP:
case MA_BM_HASHED:
material_opaque(ma,
material_opaque(ma_array[i],
material_hash,
sldata,
vedata,
@ -1683,7 +1669,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
case MA_BM_ADD:
case MA_BM_MULTIPLY:
case MA_BM_BLEND:
material_transparent(ma,
material_transparent(ma_array[i],
sldata,
vedata,
do_cull,
@ -1725,17 +1711,18 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
&auto_layer_count);
}
if (is_sculpt_mode_draw || mat_geom) {
if (is_sculpt_mode) {
/* TODO(fclem): Support Vcol. */
DRW_shgroup_call_sculpt_with_materials_add(shgrp_array, ma_array, ob, false);
DRW_shgroup_call_sculpt_with_materials_add(shgrp_depth_array, ma_array, ob, false);
DRW_shgroup_call_sculpt_with_materials_add(shgrp_depth_clip_array, ma_array, ob, false);
/* TODO(fclem): Support shadows in sculpt mode. */
}
else if (mat_geom) {
for (int i = 0; i < materials_len; ++i) {
if (!is_sculpt_mode_draw && mat_geom[i] == NULL) {
if (mat_geom[i] == NULL) {
continue;
}
EEVEE_ObjectEngineData *oedata = NULL;
Material *ma = give_current_material(ob, i + 1);
if (ma == NULL) {
ma = &defmaterial;
}
/* Do not render surface if we are rendering a volume object
* and do not have a surface closure. */
@ -1746,23 +1733,16 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
/* XXX TODO rewrite this to include the dupli objects.
* This means we cannot exclude dupli objects from reflections!!! */
EEVEE_ObjectEngineData *oedata = NULL;
if ((ob->base_flag & BASE_FROM_DUPLI) == 0) {
oedata = EEVEE_object_data_ensure(ob);
oedata->ob = ob;
oedata->test_data = &sldata->probes->vis_data;
}
/* Shading pass */
ADD_SHGROUP_CALL(shgrp_array[i], ob, ma, mat_geom[i], oedata);
/* Depth Prepass */
ADD_SHGROUP_CALL_SAFE(shgrp_depth_array[i], ob, ma, mat_geom[i], oedata);
ADD_SHGROUP_CALL_SAFE(shgrp_depth_clip_array[i], ob, ma, mat_geom[i], oedata);
/* TODO(fclem): Don't support shadows in sculpt mode. */
if (is_sculpt_mode_draw) {
break;
}
ADD_SHGROUP_CALL(shgrp_array[i], ob, ma_array[i], mat_geom[i], oedata);
ADD_SHGROUP_CALL_SAFE(shgrp_depth_array[i], ob, ma_array[i], mat_geom[i], oedata);
ADD_SHGROUP_CALL_SAFE(shgrp_depth_clip_array[i], ob, ma_array[i], mat_geom[i], oedata);
char *name = auto_layer_names;
for (int j = 0; j < auto_layer_count; ++j) {
@ -1785,19 +1765,19 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
/* Shadow Pass */
struct GPUMaterial *gpumat;
switch (ma->blend_shadow) {
switch (ma_array[i]->blend_shadow) {
case MA_BS_SOLID:
EEVEE_lights_cache_shcaster_add(sldata, stl, mat_geom[i], ob);
*cast_shadow = true;
break;
case MA_BS_CLIP:
gpumat = EEVEE_material_mesh_depth_get(scene, ma, false, true);
gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], false, true);
EEVEE_lights_cache_shcaster_material_add(
sldata, psl, gpumat, mat_geom[i], ob, &ma->alpha_threshold);
sldata, psl, gpumat, mat_geom[i], ob, &ma_array[i]->alpha_threshold);
*cast_shadow = true;
break;
case MA_BS_HASHED:
gpumat = EEVEE_material_mesh_depth_get(scene, ma, true, true);
gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], true, true);
EEVEE_lights_cache_shcaster_material_add(sldata, psl, gpumat, mat_geom[i], ob, NULL);
*cast_shadow = true;
break;
@ -1845,11 +1825,7 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata,
}
DRWShadingGroup *shgrp = NULL;
Material *ma = give_current_material(ob, part->omat);
if (ma == NULL) {
ma = &defmaterial;
}
Material *ma = eevee_object_material_get(ob, part->omat - 1);
float *color_p = &ma->r;
float *metal_p = &ma->metallic;

View File

@ -937,7 +937,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
const bool is_active = (ob == draw_ctx->obact);
const bool is_sculpt_mode = DRW_object_use_pbvh_drawing(ob);
const bool use_hide = is_active && DRW_object_use_hide_faces(ob);
const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol));
const int materials_len = MAX2(1, ob->totcol);
const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
bool has_transp_mat = false;
@ -983,8 +983,10 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
/* Draw solid color */
material = get_or_create_material_data(vedata, ob, NULL, NULL, NULL, color_type, 0);
}
if (is_sculpt_mode) {
DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat);
bool use_vcol = (color_type == V3D_SHADING_VERTEX_COLOR);
DRW_shgroup_call_sculpt_add(material->shgrp, ob, false, false, use_vcol);
}
else {
struct GPUBatch *geom;
@ -1003,11 +1005,25 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
else {
/* Draw material color */
if (is_sculpt_mode) {
/* Multiple materials are not supported in sculpt mode yet. */
Material *mat = give_current_material(ob, 1);
material = get_or_create_material_data(
vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat);
struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len);
struct Material **mats = BLI_array_alloca(mats, materials_len);
for (int i = 0; i < materials_len; ++i) {
mats[i] = give_current_material(ob, i + 1);
if (mats[i] != NULL && mats[i]->a < 1.0f) {
/* Hack */
wpd->shading.xray_alpha = mats[i]->a;
material = workbench_forward_get_or_create_material_data(
vedata, ob, mats[i], NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0, is_sculpt_mode);
has_transp_mat = true;
}
else {
material = get_or_create_material_data(
vedata, ob, mats[i], NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
}
shgrps[i] = material->shgrp;
}
DRW_shgroup_call_sculpt_with_materials_add(shgrps, mats, ob, false);
}
else {
struct GPUBatch **geoms;

View File

@ -566,69 +566,78 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
WORKBENCH_MaterialData *material;
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
const bool is_sculpt_mode = DRW_object_use_pbvh_drawing(ob);
bool is_drawn = false;
const int materials_len = MAX2(1, ob->totcol);
const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
if (!is_sculpt_mode && TEXTURE_DRAWING_ENABLED(wpd) && ELEM(ob->type, OB_MESH)) {
const Mesh *me = ob->data;
if (me->mloopuv) {
const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol));
struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
for (int i = 0; i < materials_len; i++) {
Material *mat;
Image *image;
ImageUser *iuser;
int interp;
workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat);
int color_type = workbench_material_determine_color_type(wpd, image, ob, is_sculpt_mode);
material = workbench_forward_get_or_create_material_data(
vedata, ob, mat, image, iuser, color_type, interp, is_sculpt_mode);
DRW_shgroup_call_object_add(material->shgrp_object_outline, geom_array[i], ob);
DRW_shgroup_call_object_add(material->shgrp, geom_array[i], ob);
}
is_drawn = true;
if (!is_sculpt_mode && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) {
struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
for (int i = 0; i < materials_len; i++) {
Material *mat;
Image *image;
ImageUser *iuser;
int interp;
workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat);
int color_type = workbench_material_determine_color_type(wpd, image, ob, is_sculpt_mode);
material = workbench_forward_get_or_create_material_data(
vedata, ob, mat, image, iuser, color_type, interp, is_sculpt_mode);
DRW_shgroup_call_object_add(material->shgrp_object_outline, geom_array[i], ob);
DRW_shgroup_call_object_add(material->shgrp, geom_array[i], ob);
}
}
else if (ELEM(wpd->shading.color_type,
V3D_SHADING_SINGLE_COLOR,
V3D_SHADING_OBJECT_COLOR,
V3D_SHADING_RANDOM_COLOR,
V3D_SHADING_VERTEX_COLOR)) {
/* No material split needed */
int color_type = workbench_material_determine_color_type(wpd, NULL, ob, is_sculpt_mode);
/* Fallback from not drawn OB_TEXTURE mode or just OB_SOLID mode */
if (!is_drawn) {
if (ELEM(wpd->shading.color_type,
V3D_SHADING_SINGLE_COLOR,
V3D_SHADING_OBJECT_COLOR,
V3D_SHADING_RANDOM_COLOR,
V3D_SHADING_VERTEX_COLOR)) {
/* No material split needed */
int color_type = workbench_material_determine_color_type(wpd, NULL, ob, is_sculpt_mode);
struct GPUBatch *geom;
if (color_type == V3D_SHADING_VERTEX_COLOR) {
geom = DRW_cache_mesh_surface_vertpaint_get(ob);
}
else {
geom = DRW_cache_object_surface_get(ob);
}
if (geom) {
material = workbench_forward_get_or_create_material_data(
vedata, ob, NULL, NULL, NULL, color_type, 0, is_sculpt_mode);
if (is_sculpt_mode) {
DRW_shgroup_call_sculpt_add(material->shgrp_object_outline, ob, ob->obmat);
if (!is_wire) {
DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat);
}
}
else {
DRW_shgroup_call_object_add(material->shgrp_object_outline, geom, ob);
if (!is_wire) {
DRW_shgroup_call_object_add(material->shgrp, geom, ob);
}
}
if (is_sculpt_mode) {
material = workbench_forward_get_or_create_material_data(
vedata, ob, NULL, NULL, NULL, color_type, 0, is_sculpt_mode);
bool use_vcol = (color_type == V3D_SHADING_VERTEX_COLOR);
/* TODO(fclem) make this call optional */
DRW_shgroup_call_sculpt_add(material->shgrp_object_outline, ob, false, false, false);
if (!is_wire) {
DRW_shgroup_call_sculpt_add(material->shgrp, ob, false, false, use_vcol);
}
}
else {
const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol));
struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
for (int i = 0; i < materials_len; i++) {
gpumat_array[i] = NULL;
struct GPUBatch *geom = (color_type == V3D_SHADING_VERTEX_COLOR) ?
DRW_cache_mesh_surface_vertpaint_get(ob) :
DRW_cache_object_surface_get(ob);
if (geom) {
material = workbench_forward_get_or_create_material_data(
vedata, ob, NULL, NULL, NULL, color_type, 0, is_sculpt_mode);
/* TODO(fclem) make this call optional */
DRW_shgroup_call_object_add(material->shgrp_object_outline, geom, ob);
if (!is_wire) {
DRW_shgroup_call_object_add(material->shgrp, geom, ob);
}
}
}
}
else {
/* Draw material color */
if (is_sculpt_mode) {
struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len);
struct Material **mats = BLI_array_alloca(mats, materials_len);
for (int i = 0; i < materials_len; ++i) {
mats[i] = give_current_material(ob, i + 1);
material = workbench_forward_get_or_create_material_data(
vedata, ob, mats[i], NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0, is_sculpt_mode);
shgrps[i] = material->shgrp;
}
/* TODO(fclem) make this call optional */
DRW_shgroup_call_sculpt_add(material->shgrp_object_outline, ob, false, false, false);
if (!is_wire) {
DRW_shgroup_call_sculpt_with_materials_add(shgrps, mats, ob, false);
}
}
else {
struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len);
struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get(
ob, gpumat_array, materials_len, NULL, NULL, NULL);
@ -641,17 +650,10 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
Material *mat = give_current_material(ob, i + 1);
material = workbench_forward_get_or_create_material_data(
vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0, is_sculpt_mode);
if (is_sculpt_mode) {
DRW_shgroup_call_sculpt_add(material->shgrp_object_outline, ob, ob->obmat);
if (!is_wire) {
DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat);
}
}
else {
DRW_shgroup_call_object_add(material->shgrp_object_outline, mat_geom[i], ob);
if (!is_wire) {
DRW_shgroup_call_object_add(material->shgrp, mat_geom[i], ob);
}
/* TODO(fclem) make this call optional */
DRW_shgroup_call_object_add(material->shgrp_object_outline, mat_geom[i], ob);
if (!is_wire) {
DRW_shgroup_call_object_add(material->shgrp, mat_geom[i], ob);
}
}
}

View File

@ -440,6 +440,17 @@ void DRW_shgroup_call_object_add_with_callback(DRWShadingGroup *shgroup,
struct Material *ma,
DRWCallVisibilityFn *callback,
void *user_data);
void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shading_group,
Object *object,
bool use_wire,
bool use_mask,
bool use_vert_color);
void DRW_shgroup_call_sculpt_with_materials_add(DRWShadingGroup **shgroups,
Material **materials,
Object *ob,
bool use_vcol);
/* Used for drawing a batch with instancing without instance attributes. */
void DRW_shgroup_call_instances_add(DRWShadingGroup *shgroup,
struct GPUBatch *geom,
@ -449,14 +460,6 @@ void DRW_shgroup_call_object_instances_add(DRWShadingGroup *shgroup,
struct GPUBatch *geom,
struct Object *ob,
uint *count);
void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shgroup, struct Object *ob, float (*obmat)[4]);
void DRW_shgroup_call_sculpt_wires_add(DRWShadingGroup *shgroup,
struct Object *ob,
float (*obmat)[4]);
void DRW_shgroup_call_generate_add(DRWShadingGroup *shgroup,
DRWCallGenerateFn *geometry_fn,
void *user_data,
float (*obmat)[4]);
void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup,
const void *attr[],
uint attr_len);

View File

@ -38,6 +38,8 @@
#include "BLI_link_utils.h"
#include "BLI_mempool.h"
#include "GPU_buffers.h"
#include "intern/gpu_codegen.h"
struct GPUVertFormat *g_pos_format = NULL;
@ -616,110 +618,150 @@ void DRW_shgroup_call_object_instances_add(DRWShadingGroup *shgroup,
BLI_LINKS_APPEND(&shgroup->calls, call);
}
void DRW_shgroup_call_generate_add(DRWShadingGroup *shgroup,
DRWCallGenerateFn *geometry_fn,
void *user_data,
float (*obmat)[4])
{
BLI_assert(geometry_fn != NULL);
BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
// #define SCULPT_DEBUG_BUFFERS
DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
call->state = drw_call_state_create(shgroup, obmat, NULL);
call->type = DRW_CALL_GENERATE;
call->generate.geometry_fn = geometry_fn;
call->generate.user_data = user_data;
#ifdef USE_GPU_SELECT
call->select_id = DST.select_id;
typedef struct DRWSculptCallbackData {
Object *ob;
DRWShadingGroup **shading_groups;
Material **materials;
bool use_wire;
bool use_mats;
bool use_mask;
bool fast_mode; /* Set by draw manager. Do not init. */
#ifdef SCULPT_DEBUG_BUFFERS
int node_nr;
#endif
} DRWSculptCallbackData;
#ifdef SCULPT_DEBUG_BUFFERS
# define SCULPT_DEBUG_COLOR(id) (sculpt_debug_colors[id % 9])
static float sculpt_debug_colors[9][4] = {
{1.0f, 0.2f, 0.2f, 1.0f},
{0.2f, 1.0f, 0.2f, 1.0f},
{0.2f, 0.2f, 1.0f, 1.0f},
{1.0f, 1.0f, 0.2f, 1.0f},
{0.2f, 1.0f, 1.0f, 1.0f},
{1.0f, 0.2f, 1.0f, 1.0f},
{1.0f, 0.7f, 0.2f, 1.0f},
{0.2f, 1.0f, 0.7f, 1.0f},
{0.7f, 0.2f, 1.0f, 1.0f},
};
#endif
BLI_LINKS_APPEND(&shgroup->calls, call);
static void sculpt_draw_cb(DRWSculptCallbackData *scd, GPU_PBVH_Buffers *buffers)
{
GPUBatch *geom = GPU_pbvh_buffers_batch_get(buffers, scd->fast_mode, scd->use_wire);
Material *ma = NULL;
short index = 0;
/* Meh... use_mask is a bit misleading here. */
if (scd->use_mask && !GPU_pbvh_buffers_has_mask(buffers)) {
return;
}
if (scd->use_mats) {
index = GPU_pbvh_buffers_material_index_get(buffers);
ma = scd->materials[index];
}
DRWShadingGroup *shgrp = scd->shading_groups[index];
if (geom != NULL && shgrp != NULL) {
#ifdef SCULPT_DEBUG_BUFFERS
/* Color each buffers in different colors. Only work in solid/Xray mode. */
shgrp = DRW_shgroup_create_sub(shgrp);
DRW_shgroup_uniform_vec3(shgrp, "materialDiffuseColor", SCULPT_DEBUG_COLOR(scd->node_nr++), 1);
#endif
/* DRW_shgroup_call_object_add_ex reuses matrices calculations for all the drawcalls of this
* object. */
DRW_shgroup_call_object_add_ex(shgrp, geom, scd->ob, ma, true);
}
}
/* This function tests if the current draw engine draws the vertex colors
* It is used when drawing sculpts
*
* XXX: should we use a callback to a the draw engine to retrieve this
* setting, this makes the draw manager more clean? */
static bool DRW_draw_vertex_color_active(const DRWContextState *draw_ctx)
#ifdef SCULPT_DEBUG_BUFFERS
static void sculpt_debug_cb(void *user_data,
const float bmin[3],
const float bmax[3],
PBVHNodeFlags flag)
{
View3D *v3d = draw_ctx->v3d;
return v3d->shading.type == OB_SOLID && v3d->shading.color_type == V3D_SHADING_VERTEX_COLOR;
int *node_nr = (int *)user_data;
BoundBox bb;
BKE_boundbox_init_from_minmax(&bb, bmin, bmax);
# if 0 /* Nodes hierarchy. */
if (flag & PBVH_Leaf) {
DRW_debug_bbox(&bb, (float[4]){0.0f, 1.0f, 0.0f, 1.0f});
}
else {
DRW_debug_bbox(&bb, (float[4]){0.5f, 0.5f, 0.5f, 0.6f});
}
# else /* Color coded leaf bounds. */
if (flag & PBVH_Leaf) {
DRW_debug_bbox(&bb, SCULPT_DEBUG_COLOR((*node_nr)++));
}
# endif
}
#endif
static void sculpt_draw_cb(DRWShadingGroup *shgroup,
void (*draw_fn)(DRWShadingGroup *shgroup, GPUBatch *geom),
void *user_data)
static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd, bool use_vcol)
{
Object *ob = user_data;
/* XXX should be ensured before but sometime it's not... go figure (see T57040). */
PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(DST.draw_ctx.depsgraph, ob);
PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(DST.draw_ctx.depsgraph, scd->ob);
if (!pbvh) {
return;
}
float(*planes)[4] = NULL; /* TODO proper culling. */
scd->fast_mode = false;
const DRWContextState *drwctx = DRW_context_state_get();
int fast_mode = 0;
if (drwctx->evil_C != NULL) {
Paint *p = BKE_paint_get_active_from_context(drwctx->evil_C);
if (p && (p->flags & PAINT_FAST_NAVIGATE)) {
fast_mode = drwctx->rv3d->rflag & RV3D_NAVIGATING;
scd->fast_mode = (drwctx->rv3d->rflag & RV3D_NAVIGATING) != 0;
}
}
if (pbvh) {
const bool show_vcol = DRW_draw_vertex_color_active(drwctx);
BKE_pbvh_draw_cb(pbvh,
NULL,
NULL,
fast_mode,
false,
false,
show_vcol,
(void (*)(void *, GPUBatch *))draw_fn,
shgroup);
}
BKE_pbvh_draw_cb(
pbvh, planes, NULL, use_vcol, (void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb, scd);
#ifdef SCULPT_DEBUG_BUFFERS
int node_nr = 0;
DRW_debug_modelmat(scd->ob->obmat);
BKE_pbvh_draw_debug_cb(
pbvh,
(void (*)(void *d, const float min[3], const float max[3], PBVHNodeFlags f))sculpt_debug_cb,
&node_nr);
#endif
}
static void sculpt_draw_wires_cb(DRWShadingGroup *shgroup,
void (*draw_fn)(DRWShadingGroup *shgroup, GPUBatch *geom),
void *user_data)
void DRW_shgroup_call_sculpt_add(
DRWShadingGroup *shgroup, Object *ob, bool use_wire, bool use_mask, bool use_vcol)
{
Object *ob = user_data;
/* XXX should be ensured before but sometime it's not... go figure (see T57040). */
PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(DST.draw_ctx.depsgraph, ob);
const DRWContextState *drwctx = DRW_context_state_get();
int fast_mode = 0;
if (drwctx->evil_C != NULL) {
Paint *p = BKE_paint_get_active_from_context(drwctx->evil_C);
if (p && (p->flags & PAINT_FAST_NAVIGATE)) {
fast_mode = drwctx->rv3d->rflag & RV3D_NAVIGATING;
}
}
if (pbvh) {
BKE_pbvh_draw_cb(pbvh,
NULL,
NULL,
fast_mode,
true,
false,
false,
(void (*)(void *, GPUBatch *))draw_fn,
shgroup);
}
DRWSculptCallbackData scd = {
.ob = ob,
.shading_groups = &shgroup,
.materials = NULL,
.use_wire = use_wire,
.use_mats = false,
.use_mask = use_mask,
};
drw_sculpt_generate_calls(&scd, use_vcol);
}
void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shgroup, Object *ob, float (*obmat)[4])
void DRW_shgroup_call_sculpt_with_materials_add(DRWShadingGroup **shgroups,
Material **materials,
Object *ob,
bool use_vcol)
{
DRW_shgroup_call_generate_add(shgroup, sculpt_draw_cb, ob, obmat);
}
void DRW_shgroup_call_sculpt_wires_add(DRWShadingGroup *shgroup, Object *ob, float (*obmat)[4])
{
DRW_shgroup_call_generate_add(shgroup, sculpt_draw_wires_cb, ob, obmat);
DRWSculptCallbackData scd = {
.ob = ob,
.shading_groups = shgroups,
.materials = materials,
.use_wire = false,
.use_mats = true,
.use_mask = false,
};
drw_sculpt_generate_calls(&scd, use_vcol);
}
void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup,

View File

@ -389,7 +389,7 @@ static void overlay_cache_populate(void *vedata, Object *ob)
}
if (is_sculpt_mode) {
DRW_shgroup_call_sculpt_wires_add(shgrp, ob, ob->obmat);
DRW_shgroup_call_sculpt_add(shgrp, ob, true, false, false);
}
else {
DRW_shgroup_call_add(shgrp, geom, ob->obmat);

View File

@ -98,6 +98,7 @@ static struct {
} e_data = {NULL}; /* Engine data */
typedef struct SCULPT_PrivateData {
DRWShadingGroup *mask_overlay_grp;
/* This keeps the references of the shading groups for
* easy access in SCULPT_cache_populate() */
DRWShadingGroup *group_flat;
@ -143,7 +144,7 @@ static void SCULPT_cache_init(void *vedata)
DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.shader_smooth, psl->pass);
DRW_shgroup_uniform_float(shgrp, "maskOpacity", &v3d->overlay.sculpt_mode_mask_opacity, 1);
stl->g_data->group_smooth = shgrp;
stl->g_data->mask_overlay_grp = shgrp;
}
}
@ -213,8 +214,7 @@ static void SCULPT_cache_populate(void *vedata, Object *ob)
PBVH *pbvh = ob->sculpt->pbvh;
if (pbvh && pbvh_has_mask(pbvh)) {
DRW_shgroup_call_generate_add(
stl->g_data->group_smooth, sculpt_draw_mask_cb, ob, ob->obmat);
DRW_shgroup_call_sculpt_add(stl->g_data->mask_overlay_grp, ob, false, true, false);
}
}
}