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:
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
|
@ -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);
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue