Blender V4.5
gpencil_cache_utils.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2017 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "DRW_engine.hh"
10#include "DRW_render.hh"
11
12#include "ED_view3d.hh"
13
14#include "DNA_material_types.h"
15
16#include "BKE_gpencil_legacy.h"
17#include "BKE_grease_pencil.hh"
18#include "BKE_material.hh"
19#include "BKE_object.hh"
20
21#include "BLI_ghash.h"
22#include "BLI_hash.h"
26#include "BLI_math_vector.h"
27#include "BLI_math_vector.hh"
28#include "BLI_memblock.h"
29
31
32#include "DEG_depsgraph.hh"
33
34#include "UI_resources.hh"
35
36namespace blender::draw::gpencil {
37
38/* -------------------------------------------------------------------- */
41
43 Object *ob,
44 const bool is_stroke_order_3d,
46{
47 tObject *tgp_ob = static_cast<tObject *>(BLI_memblock_alloc(inst->gp_object_pool));
48
49 tgp_ob->layers.first = tgp_ob->layers.last = nullptr;
50 tgp_ob->vfx.first = tgp_ob->vfx.last = nullptr;
51 tgp_ob->camera_z = dot_v3v3(inst->camera_z_axis, ob->object_to_world().location());
52 tgp_ob->is_drawmode3d = is_stroke_order_3d;
53
54 /* Check if any material with holdout flag enabled. */
55 tgp_ob->do_mat_holdout = false;
56 const int tot_materials = BKE_object_material_used_with_fallback_eval(*ob);
57 for (int i = 0; i < tot_materials; i++) {
59 if (((gp_style != nullptr) && (gp_style->flag & GP_MATERIAL_IS_STROKE_HOLDOUT)) ||
61 {
62 tgp_ob->do_mat_holdout = true;
63 break;
64 }
65 }
67 /* Find the normal most likely to represent the gpObject. */
68 /* TODO: This does not work quite well if you use
69 * strokes not aligned with the object axes. Maybe we could try to
70 * compute the minimum axis of all strokes. But this would be more
71 * computationally heavy and should go into the GPData evaluation. */
72 float3 size = (bounds.max - bounds.min) * 0.5f;
73 float3 center = math::midpoint(bounds.min, bounds.max);
74 /* Convert bbox to matrix */
75 float mat[4][4];
76 unit_m4(mat);
77 copy_v3_v3(mat[3], center);
78 /* Avoid division by 0.0 later. */
79 add_v3_fl(size, 1e-8f);
81 /* BBox space to World. */
82 mul_m4_m4m4(mat, ob->object_to_world().ptr(), mat);
83 if (View::default_get().is_persp()) {
84 /* BBox center to camera vector. */
85 sub_v3_v3v3(tgp_ob->plane_normal, inst->camera_pos, mat[3]);
86 }
87 else {
89 }
90 /* World to BBox space. */
92 /* Normalize the vector in BBox space. */
93 mul_mat3_m4_v3(mat, tgp_ob->plane_normal);
97 /* mat is now a "normal" matrix which will transform
98 * BBox space normal to world space. */
102 /* Define a matrix that will be used to render a triangle to merge the depth of the rendered
103 * gpencil object with the rest of the scene. */
104 unit_m4(tgp_ob->plane_mat);
105 copy_v3_v3(tgp_ob->plane_mat[2], tgp_ob->plane_normal);
107 mul_mat3_m4_v3(ob->object_to_world().ptr(), size);
108 float radius = len_v3(size);
109 mul_m4_v3(ob->object_to_world().ptr(), center);
110 rescale_m4(tgp_ob->plane_mat, float3{radius, radius, radius});
111 copy_v3_v3(tgp_ob->plane_mat[3], center);
113 /* Add to corresponding list if is in front. */
114 if (ob->dtx & OB_DRAW_IN_FRONT) {
115 BLI_LINKS_APPEND(&inst->tobjects_infront, tgp_ob);
116 }
117 else {
118 BLI_LINKS_APPEND(&inst->tobjects, tgp_ob);
121 return tgp_ob;
124#define SORT_IMPL_LINKTYPE tObject
126#define SORT_IMPL_FUNC gpencil_tobject_sort_fn_r
128#undef SORT_IMPL_FUNC
129
130#undef SORT_IMPL_LINKTYPE
131
132static int gpencil_tobject_dist_sort(const void *a, const void *b)
134 const tObject *ob_a = (const tObject *)a;
135 const tObject *ob_b = (const tObject *)b;
136 /* Reminder, camera_z is negative in front of the camera. */
137 if (ob_a->camera_z > ob_b->camera_z) {
138 return 1;
140 if (ob_a->camera_z < ob_b->camera_z) {
141 return -1;
144 return 0;
145}
146
149 if (inst->is_sorted) {
150 return;
152 /* Sort object by distance to the camera. */
153 if (inst->tobjects.first) {
154 inst->tobjects.first = gpencil_tobject_sort_fn_r(inst->tobjects.first,
156 /* Relink last pointer. */
157 while (inst->tobjects.last->next) {
159 }
160 }
162 inst->tobjects_infront.first = gpencil_tobject_sort_fn_r(inst->tobjects_infront.first,
164 /* Relink last pointer. */
165 while (inst->tobjects_infront.last->next) {
170 /* Join both lists, adding in front. */
171 if (inst->tobjects_infront.first != nullptr) {
172 if (inst->tobjects.last != nullptr) {
173 inst->tobjects.last->next = inst->tobjects_infront.first;
174 inst->tobjects.last = inst->tobjects_infront.last;
175 inst->tobjects_infront.first = inst->tobjects.last = nullptr;
176 }
177 else {
178 /* Only in front objects. */
179 inst->tobjects.first = inst->tobjects_infront.first;
181 inst->tobjects_infront.first = inst->tobjects.last = nullptr;
183 }
184 inst->is_sorted = true;
185}
189/* -------------------------------------------------------------------- */
192
194 const Object *ob,
195 const GreasePencil &grease_pencil,
196 const bke::greasepencil::Layer &layer)
198 const bool is_obact = ((inst->obact) && (inst->obact == ob));
199 const bool is_fade = (inst->fade_layer_opacity > -1.0f) && (is_obact) &&
200 !grease_pencil.is_layer_active(&layer);
202 /* Defines layer opacity. For active object depends of layer opacity factor, and
203 * for no active object, depends if the fade grease pencil objects option is enabled. */
204 if (!inst->is_render) {
205 if (is_obact && is_fade) {
206 return layer.opacity * inst->fade_layer_opacity;
208 if (!is_obact && (inst->fade_gp_object_opacity > -1.0f)) {
209 return layer.opacity * inst->fade_gp_object_opacity;
210 }
211 }
212 return layer.opacity;
214
216 const GreasePencil &grease_pencil,
217 const int onion_id,
218 float *r_alpha)
220 const bool use_onion = (onion_id != 0);
221 if (use_onion && inst->do_onion) {
222 const bool use_onion_custom_col = (grease_pencil.onion_skinning_settings.flag &
224 const bool use_onion_fade = (grease_pencil.onion_skinning_settings.flag &
226 const bool use_next_col = onion_id > 0;
227
228 const float onion_factor = grease_pencil.onion_skinning_settings.opacity;
229
230 float3 color_next, color_prev;
231 if (use_onion_custom_col) {
232 color_next = float3(grease_pencil.onion_skinning_settings.color_after);
233 color_prev = float3(grease_pencil.onion_skinning_settings.color_before);
235 else {
240 const float4 onion_col_custom = use_next_col ? float4(color_next, 1.0f) :
241 float4(color_prev, 1.0f);
243 *r_alpha = use_onion_fade ? (1.0f / abs(onion_id)) : 0.5f;
244 *r_alpha *= onion_factor;
245 *r_alpha = (onion_factor > 0.0f) ? clamp_f(*r_alpha, 0.1f, 1.0f) :
246 clamp_f(*r_alpha, 0.01f, 1.0f);
247 *r_alpha *= inst->xray_alpha;
248
249 return onion_col_custom;
250 }
251
252 /* Layer tint is not a property in GPv3 anymore. It's only used for onion skinning. The previous
253 * property is replaced by a tint modifier during conversion. */
254 float4 layer_tint(0.0f);
255 if (GPENCIL_SIMPLIFY_TINT(inst->scene)) {
256 layer_tint[3] = 0.0f;
257 }
258 *r_alpha = 1.0f;
259 *r_alpha *= inst->xray_alpha;
260
261 return layer_tint;
262}
263
264/* Random color by layer. */
266 const bke::greasepencil::Layer &layer,
267 float r_color[3])
269 const float hsv_saturation = 0.7f;
270 const float hsv_value = 0.6f;
271
273 uint gpl_hash = BLI_ghashutil_strhash_p_murmur(layer.name().c_str());
274 float hue = BLI_hash_int_01(ob_hash * gpl_hash);
275 const float hsv[3] = {hue, hsv_saturation, hsv_value};
276 hsv_to_rgb_v(hsv, r_color);
277}
278
279tLayer *grease_pencil_layer_cache_get(tObject *tgp_ob, int layer_id, const bool skip_onion)
280{
281 BLI_assert(layer_id >= 0);
282 for (tLayer *layer = tgp_ob->layers.first; layer != nullptr; layer = layer->next) {
283 if (skip_onion && layer->is_onion) {
284 continue;
285 }
286 if (layer->layer_id == layer_id) {
287 return layer;
288 }
289 }
290 return nullptr;
291}
292
294 const Object *ob,
295 const bke::greasepencil::Layer &layer,
296 const int onion_id,
297 const bool is_used_as_mask,
298 tObject *tgp_ob)
299
300{
301 using namespace bke::greasepencil;
303
304 const bool is_in_front = (ob->dtx & OB_DRAW_IN_FRONT);
305
306 const bool override_vertcol = (inst->v3d_color_type != -1);
307 /* In draw mode and vertex paint mode it's possible to draw vertex colors so we want to make sure
308 * to render them. Otherwise this can lead to unexpected behavior. */
309 const bool is_vert_col_mode = (inst->v3d_color_type == V3D_SHADING_VERTEX_COLOR) ||
310 (ob->mode & OB_MODE_VERTEX_PAINT) != 0 ||
311 (ob->mode & OB_MODE_PAINT_GREASE_PENCIL) != 0 || inst->is_render;
312 const bool is_viewlayer_render = inst->is_render && !layer.view_layer_name().is_empty() &&
313 STREQ(inst->view_layer->name, layer.view_layer_name().c_str());
314 const bool disable_masks_render = is_viewlayer_render &&
315 (layer.base.flag &
317 bool is_masked = !disable_masks_render && layer.use_masks() &&
319
320 const float vert_col_opacity = (override_vertcol) ?
321 (is_vert_col_mode ? inst->vertex_paint_opacity : 0.0f) :
322 (inst->is_render ? 1.0f : inst->vertex_paint_opacity);
323 /* If the layer is used as a mask (but is otherwise not visible in the render), render it with a
324 * opacity of 0 so that it can still mask other layers. */
325 const float layer_opacity = !is_used_as_mask ? grease_pencil_layer_final_opacity_get(
326 inst, ob, grease_pencil, layer) :
327 0.0f;
328
329 float layer_alpha = inst->xray_alpha;
331 inst, grease_pencil, onion_id, &layer_alpha);
332
333 /* Create the new layer descriptor. */
335 tLayer *tgp_layer = &(*inst->gp_layer_pool)[id];
336 BLI_LINKS_APPEND(&tgp_ob->layers, tgp_layer);
337 tgp_layer->layer_id = *grease_pencil.get_layer_index(layer);
338 tgp_layer->is_onion = onion_id != 0;
339 tgp_layer->mask_bits = nullptr;
340 tgp_layer->mask_invert_bits = nullptr;
341 tgp_layer->blend_ps = nullptr;
342
343 /* Masking: Go through mask list and extract valid masks in a bitmap. */
344 if (is_masked) {
345 bool valid_mask = false;
346 /* WARNING: only #GP_MAX_MASKBITS amount of bits.
347 * TODO(fclem): Find a better system without any limitation. */
348 tgp_layer->mask_bits = static_cast<BLI_bitmap *>(BLI_memblock_alloc(inst->gp_maskbit_pool));
349 tgp_layer->mask_invert_bits = static_cast<BLI_bitmap *>(
351 BLI_bitmap_set_all(tgp_layer->mask_bits, false, GP_MAX_MASKBITS);
352
354 if (mask->flag & GP_LAYER_MASK_HIDE) {
355 continue;
356 }
357 const TreeNode *node = grease_pencil.find_node_by_name(mask->layer_name);
358 if (node == nullptr) {
359 continue;
360 }
361 const Layer &mask_layer = node->as_layer();
362 if ((&mask_layer == &layer) || !mask_layer.is_visible()) {
363 continue;
364 }
365 const int index = *grease_pencil.get_layer_index(mask_layer);
366 if (index < GP_MAX_MASKBITS) {
367 const bool invert = (mask->flag & GP_LAYER_MASK_INVERT) != 0;
368 BLI_BITMAP_SET(tgp_layer->mask_bits, index, true);
369 BLI_BITMAP_SET(tgp_layer->mask_invert_bits, index, invert);
370 valid_mask = true;
371 }
372 }
373
374 if (valid_mask) {
375 inst->use_mask_fb = true;
376 }
377 else {
378 tgp_layer->mask_bits = nullptr;
379 }
380 is_masked = valid_mask;
381 }
382
383 /* Blending: Force blending for masked layer. */
384 if (is_masked || (layer.blend_mode != GP_LAYER_BLEND_NONE) || (layer_opacity < 1.0f)) {
386 switch (layer.blend_mode) {
389 break;
392 break;
395 break;
400 break;
401 }
402
404 /* For these effect to propagate, we need a signed floating point buffer. */
405 inst->use_signed_fb = true;
406 }
407
408 if (tgp_layer->blend_ps == nullptr) {
409 tgp_layer->blend_ps = std::make_unique<PassSimple>("GPencil Blend Layer");
410 }
411 PassSimple &pass = *tgp_layer->blend_ps;
412 pass.init();
413 pass.state_set(state);
414 pass.shader_set(ShaderCache::get().layer_blend.get());
415 pass.push_constant("blend_mode", int(layer.blend_mode));
416 pass.push_constant("blend_opacity", layer_opacity);
417 pass.bind_texture("color_buf", &inst->color_layer_tx);
418 pass.bind_texture("reveal_buf", &inst->reveal_layer_tx);
419 pass.bind_texture("mask_buf", (is_masked) ? &inst->mask_tx : &inst->dummy_tx);
420 pass.state_stencil(0xFF, 0xFF, 0xFF);
421 pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
422
424 /* We cannot do custom blending on Multi-Target frame-buffers.
425 * Workaround by doing 2 passes. */
427 pass.push_constant("blend_mode", 999);
428 pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
429 }
430
431 inst->use_layer_fb = true;
432 }
433
434 /* Geometry pass */
435 {
436 if (tgp_layer->geom_ps == nullptr) {
437 tgp_layer->geom_ps = std::make_unique<PassSimple>("GPencil Layer");
438 }
439
440 PassSimple &pass = *tgp_layer->geom_ps;
441
442 GPUTexture **depth_tex = (is_in_front) ? &inst->dummy_depth : &inst->scene_depth_tx;
443 GPUTexture **mask_tex = (is_masked) ? &inst->mask_tx : &inst->dummy_tx;
444
446 /* For 2D mode, we render all strokes with uniform depth (increasing with stroke id). */
448 /* Always write stencil. Only used as optimization for blending. */
450
451 pass.state_set(state);
452 pass.shader_set(ShaderCache::get().geometry.get());
453 pass.bind_texture("gp_scene_depth_tx", depth_tex);
454 pass.bind_texture("gp_mask_tx", mask_tex);
455 pass.push_constant("gp_normal", tgp_ob->plane_normal);
456 pass.push_constant("gp_stroke_order3d", tgp_ob->is_drawmode3d);
457 pass.push_constant("gp_vertex_color_opacity", vert_col_opacity);
458
459 pass.bind_texture("gp_fill_tx", inst->dummy_tx);
460 pass.bind_texture("gp_stroke_tx", inst->dummy_tx);
461
462 /* If random color type, need color by layer. */
463 float4 gpl_color;
464 copy_v4_v4(gpl_color, layer_tint);
466 grease_pencil_layer_random_color_get(ob, layer, gpl_color);
467 gpl_color[3] = 1.0f;
468 }
469 pass.push_constant("gp_layer_tint", gpl_color);
470
471 pass.push_constant("gp_layer_opacity", layer_alpha);
472 pass.state_stencil(0xFF, 0xFF, 0xFF);
473 }
474
475 return tgp_layer;
476}
477
478
479} // namespace blender::draw::gpencil
#define GPENCIL_SIMPLIFY_TINT(scene)
Low-level operations for grease pencil.
General operations, lookup, etc. for materials.
MaterialGPencilStyle * BKE_gpencil_material_settings(Object *ob, short act)
int BKE_object_material_used_with_fallback_eval(const Object &ob)
General operations, lookup, etc. for blender objects.
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_bitmap_set_all(BLI_bitmap *bitmap, bool set, size_t bits)
Definition bitmap.cc:17
#define BLI_BITMAP_SET(_bitmap, _index, _set)
Definition BLI_bitmap.h:99
unsigned int BLI_bitmap
Definition BLI_bitmap.h:13
unsigned int BLI_ghashutil_strhash_p_murmur(const void *ptr)
BLI_INLINE float BLI_hash_int_01(unsigned int k)
Definition BLI_hash.h:92
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
MINLINE float clamp_f(float value, float min, float max)
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
Definition math_color.cc:57
void orthogonalize_m4(float R[4][4], int axis)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void rescale_m4(float mat[4][4], const float scale[3])
void mul_m4_v3(const float M[4][4], float r[3])
bool invert_m4(float mat[4][4])
void transpose_m4(float R[4][4])
void mul_mat3_m4_v3(const float mat[4][4], float r[3])
void unit_m4(float m[4][4])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void add_v3_fl(float r[3], float f)
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float n[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
void * BLI_memblock_alloc(BLI_memblock *mblk) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define ELEM(...)
#define STREQ(a, b)
@ GP_LAYER_BLEND_HARDLIGHT
@ GP_LAYER_BLEND_NONE
@ GP_LAYER_BLEND_MULTIPLY
@ GP_LAYER_BLEND_DIVIDE
@ GP_LAYER_BLEND_SUBTRACT
@ GP_LAYER_MASK_INVERT
@ GP_LAYER_TREE_NODE_DISABLE_MASKS_IN_VIEWLAYER
@ GP_ONION_SKINNING_USE_FADE
@ GP_ONION_SKINNING_USE_CUSTOM_COLORS
@ GP_MATERIAL_IS_STROKE_HOLDOUT
@ GP_MATERIAL_IS_FILL_HOLDOUT
@ OB_MODE_PAINT_GREASE_PENCIL
@ OB_MODE_VERTEX_PAINT
@ OB_DRAW_IN_FRONT
@ V3D_SHADING_VERTEX_COLOR
@ V3D_SHADING_RANDOM_COLOR
@ GPU_PRIM_TRIS
void UI_GetThemeColor3fv(int colorid, float col[3])
@ TH_FRAME_AFTER
@ TH_FRAME_BEFORE
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
const Layer & as_layer() const
constexpr bool is_empty() const
constexpr const char * c_str() const
StringRefNull view_layer_name() const
static View & default_get()
Definition draw_view.cc:317
int64_t append_and_get_index(T &&elem)
Definition draw_pass.hh:98
Mesh & DRW_object_get_data_for_drawing(const Object &object)
DRWState
Definition draw_state.hh:25
@ DRW_STATE_STENCIL_EQUAL
Definition draw_state.hh:47
@ DRW_STATE_STENCIL_ALWAYS
Definition draw_state.hh:46
@ DRW_STATE_BLEND_SUB
Definition draw_state.hh:61
@ DRW_STATE_WRITE_DEPTH
Definition draw_state.hh:29
@ DRW_STATE_BLEND_ADD_FULL
Definition draw_state.hh:53
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_DEPTH_LESS_EQUAL
Definition draw_state.hh:38
@ DRW_STATE_BLEND_ALPHA_PREMUL
Definition draw_state.hh:57
@ DRW_STATE_DEPTH_GREATER
Definition draw_state.hh:40
@ DRW_STATE_BLEND_MUL
Definition draw_state.hh:60
@ DRW_STATE_WRITE_STENCIL
Definition draw_state.hh:32
#define GP_MAX_MASKBITS
#define abs
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static ulong state[N]
static void grease_pencil_layer_random_color_get(const Object *ob, const bke::greasepencil::Layer &layer, float r_color[3])
void gpencil_object_cache_sort(Instance *inst)
static float4 grease_pencil_layer_final_tint_and_alpha_get(const Instance *inst, const GreasePencil &grease_pencil, const int onion_id, float *r_alpha)
static int gpencil_tobject_dist_sort(const void *a, const void *b)
static float grease_pencil_layer_final_opacity_get(const Instance *inst, const Object *ob, const GreasePencil &grease_pencil, const bke::greasepencil::Layer &layer)
tLayer * grease_pencil_layer_cache_add(Instance *inst, const Object *ob, const bke::greasepencil::Layer &layer, const int onion_id, const bool is_used_as_mask, tObject *tgp_ob)
tLayer * grease_pencil_layer_cache_get(tObject *tgp_ob, int layer_id, const bool skip_onion)
tObject * gpencil_object_cache_add(Instance *inst, Object *ob, const bool is_stroke_order_3d, const Bounds< float3 > bounds)
detail::Pass< command::DrawCommandBuf > PassSimple
CartesianBasis invert(const CartesianBasis &basis)
T midpoint(const T &a, const T &b)
VecBase< float, 4 > float4
VecBase< float, 3 > float3
GreasePencilLayerTreeNode base
GreasePencilOnionSkinningSettings onion_skinning_settings
char name[66]
Definition DNA_ID.h:415
char name[64]
struct blender::draw::gpencil::Instance::@025011325033111341345356265074201047356331240361 tobjects
struct blender::draw::gpencil::Instance::@025011325033111341345356265074201047356331240361 tobjects_infront
std::unique_ptr< PassSimple > geom_ps
std::unique_ptr< PassSimple > blend_ps
struct blender::draw::gpencil::tObject::@325031062357010051031354276005356023371347032371 layers
struct blender::draw::gpencil::tObject::@133305170033366341204050017212365211060071363062 vfx
i
Definition text_draw.cc:230