Blender V5.0
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
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
33
34#include "DEG_depsgraph.hh"
35
36#include "UI_resources.hh"
37
39
40/* -------------------------------------------------------------------- */
43
45 Object *ob,
46 const bool is_stroke_order_3d,
48{
49 tObject *tgp_ob = static_cast<tObject *>(BLI_memblock_alloc(inst->gp_object_pool));
50
51 tgp_ob->layers.first = tgp_ob->layers.last = nullptr;
52 tgp_ob->vfx.first = tgp_ob->vfx.last = nullptr;
53 tgp_ob->camera_z = dot_v3v3(inst->camera_z_axis, ob->object_to_world().location());
54 tgp_ob->is_drawmode3d = is_stroke_order_3d;
55
56 /* Check if any material with holdout flag enabled. */
57 tgp_ob->do_mat_holdout = false;
58 const int tot_materials = BKE_object_material_used_with_fallback_eval(*ob);
59 for (int i = 0; i < tot_materials; i++) {
61 if (((gp_style != nullptr) && (gp_style->flag & GP_MATERIAL_IS_STROKE_HOLDOUT)) ||
63 {
64 tgp_ob->do_mat_holdout = true;
65 break;
66 }
67 }
68
69 /* Find the normal most likely to represent the gpObject. */
70 /* TODO: This does not work quite well if you use
71 * strokes not aligned with the object axes. Maybe we could try to
72 * compute the minimum axis of all strokes. But this would be more
73 * computationally heavy and should go into the GPData evaluation. */
74 float3 size = (bounds.max - bounds.min) * 0.5f;
75 float3 center = math::midpoint(bounds.min, bounds.max);
76 /* Convert bbox to matrix */
77 float mat[4][4];
78 unit_m4(mat);
79 copy_v3_v3(mat[3], center);
80 /* Avoid division by 0.0 later. */
81 add_v3_fl(size, 1e-8f);
82 rescale_m4(mat, size);
83 /* BBox space to World. */
84 mul_m4_m4m4(mat, ob->object_to_world().ptr(), mat);
85 if (View::default_get().is_persp()) {
86 /* BBox center to camera vector. */
87 sub_v3_v3v3(tgp_ob->plane_normal, inst->camera_pos, mat[3]);
88 }
89 else {
91 }
92 /* World to BBox space. */
93 invert_m4(mat);
94 /* Normalize the vector in BBox space. */
99 /* mat is now a "normal" matrix which will transform
100 * BBox space normal to world space. */
103
104 /* Define a matrix that will be used to render a triangle to merge the depth of the rendered
105 * gpencil object with the rest of the scene. */
107 copy_v3_v3(tgp_ob->plane_mat[2], tgp_ob->plane_normal);
109 mul_mat3_m4_v3(ob->object_to_world().ptr(), size);
110 float radius = len_v3(size);
111 mul_m4_v3(ob->object_to_world().ptr(), center);
112 rescale_m4(tgp_ob->plane_mat, float3{radius, radius, radius});
113 copy_v3_v3(tgp_ob->plane_mat[3], center);
114
115 /* Add to corresponding list if is in front. */
116 if (ob->dtx & OB_DRAW_IN_FRONT) {
117 BLI_LINKS_APPEND(&inst->tobjects_infront, tgp_ob);
118 }
119 else {
120 BLI_LINKS_APPEND(&inst->tobjects, tgp_ob);
121 }
123 return tgp_ob;
126#define SORT_IMPL_LINKTYPE tObject
127
128#define SORT_IMPL_FUNC gpencil_tobject_sort_fn_r
130#undef SORT_IMPL_FUNC
131
132#undef SORT_IMPL_LINKTYPE
134static int gpencil_tobject_dist_sort(const void *a, const void *b)
136 const tObject *ob_a = (const tObject *)a;
137 const tObject *ob_b = (const tObject *)b;
138 /* Reminder, camera_z is negative in front of the camera. */
139 if (ob_a->camera_z > ob_b->camera_z) {
140 return 1;
142 if (ob_a->camera_z < ob_b->camera_z) {
143 return -1;
145
146 return 0;
151 if (inst->is_sorted) {
152 return;
154 /* Sort object by distance to the camera. */
155 if (inst->tobjects.first) {
156 inst->tobjects.first = gpencil_tobject_sort_fn_r(inst->tobjects.first,
158 /* Relink last pointer. */
159 while (inst->tobjects.last->next) {
160 inst->tobjects.last = inst->tobjects.last->next;
164 inst->tobjects_infront.first = gpencil_tobject_sort_fn_r(inst->tobjects_infront.first,
166 /* Relink last pointer. */
167 while (inst->tobjects_infront.last->next) {
172 /* Join both lists, adding in front. */
173 if (inst->tobjects_infront.first != nullptr) {
174 if (inst->tobjects.last != nullptr) {
175 inst->tobjects.last->next = inst->tobjects_infront.first;
176 inst->tobjects.last = inst->tobjects_infront.last;
177 inst->tobjects_infront.first = inst->tobjects.last = nullptr;
178 }
179 else {
180 /* Only in front objects. */
183 inst->tobjects_infront.first = inst->tobjects.last = nullptr;
185 }
186 inst->is_sorted = true;
190
191/* -------------------------------------------------------------------- */
193
194
196 const Object *ob,
197 const GreasePencil &grease_pencil,
198 const bke::greasepencil::Layer &layer)
199{
200 const bool is_obact = ((inst->obact) && (inst->obact == ob));
201 const bool is_fade = (inst->fade_layer_opacity > -1.0f) && (is_obact) &&
202 !grease_pencil.is_layer_active(&layer);
203
204 /* Defines layer opacity. For active object depends of layer opacity factor, and
205 * for no active object, depends if the fade grease pencil objects option is enabled. */
206 if (!inst->is_render) {
207 if (is_obact && is_fade) {
208 return layer.opacity * inst->fade_layer_opacity;
209 }
210 if (!is_obact && (inst->fade_gp_object_opacity > -1.0f)) {
211 return layer.opacity * inst->fade_gp_object_opacity;
212 }
214 return layer.opacity;
215}
218 const GreasePencil &grease_pencil,
219 const int onion_id,
220 float *r_alpha)
221{
222 const bool use_onion = (onion_id != 0);
223 if (use_onion && inst->do_onion) {
224 const bool use_onion_custom_col = (grease_pencil.onion_skinning_settings.flag &
226 const bool use_onion_fade = (grease_pencil.onion_skinning_settings.flag &
228 const bool use_next_col = onion_id > 0;
229
230 const float onion_factor = grease_pencil.onion_skinning_settings.opacity;
232 float3 color_next, color_prev;
233 if (use_onion_custom_col) {
234 color_next = float3(grease_pencil.onion_skinning_settings.color_after);
235 color_prev = float3(grease_pencil.onion_skinning_settings.color_before);
237 else {
240 }
241
242 const float4 onion_col_custom = use_next_col ? float4(color_next, 1.0f) :
243 float4(color_prev, 1.0f);
244
245 *r_alpha = use_onion_fade ? (1.0f / abs(onion_id)) : 0.5f;
246 *r_alpha *= onion_factor;
247 *r_alpha = (onion_factor > 0.0f) ? clamp_f(*r_alpha, 0.1f, 1.0f) :
248 clamp_f(*r_alpha, 0.01f, 1.0f);
249 *r_alpha *= inst->xray_alpha;
250
251 return onion_col_custom;
252 }
253
254 /* Layer tint is not a property in GPv3 anymore. It's only used for onion skinning. The previous
255 * property is replaced by a tint modifier during conversion. */
256 float4 layer_tint(0.0f);
257 if (GPENCIL_SIMPLIFY_TINT(inst->scene)) {
258 layer_tint[3] = 0.0f;
259 }
260 *r_alpha = 1.0f;
261 *r_alpha *= inst->xray_alpha;
262
263 return layer_tint;
264}
265
266/* Random color by layer. */
269 float r_color[3])
270{
271 const float hsv_saturation = 0.7f;
272 const float hsv_value = 0.6f;
273
275 uint gpl_hash = BLI_ghashutil_strhash_p_murmur(layer.name().c_str());
276 float hue = BLI_hash_int_01(ob_hash * gpl_hash);
277 const float hsv[3] = {hue, hsv_saturation, hsv_value};
278 hsv_to_rgb_v(hsv, r_color);
280}
281
282tLayer *grease_pencil_layer_cache_get(tObject *tgp_ob, int layer_id, const bool skip_onion)
283{
284 BLI_assert(layer_id >= 0);
285 for (tLayer *layer = tgp_ob->layers.first; layer != nullptr; layer = layer->next) {
286 if (skip_onion && layer->is_onion) {
287 continue;
288 }
289 if (layer->layer_id == layer_id) {
290 return layer;
291 }
292 }
293 return nullptr;
294}
295
297 const Object *ob,
298 const bke::greasepencil::Layer &layer,
299 const int onion_id,
300 const bool is_used_as_mask,
301 tObject *tgp_ob)
302
303{
304 using namespace bke::greasepencil;
306
307 const bool is_in_front = (ob->dtx & OB_DRAW_IN_FRONT);
308
309 const bool override_vertcol = (inst->v3d_color_type != -1);
310 /* In draw mode and vertex paint mode it's possible to draw vertex colors so we want to make sure
311 * to render them. Otherwise this can lead to unexpected behavior. */
312 const bool is_vert_col_mode = (inst->v3d_color_type == V3D_SHADING_VERTEX_COLOR) ||
313 (ob->mode & OB_MODE_VERTEX_PAINT) != 0 ||
314 (ob->mode & OB_MODE_PAINT_GREASE_PENCIL) != 0 || inst->is_render;
315 const bool is_viewlayer_render = inst->is_render && !layer.view_layer_name().is_empty() &&
316 STREQ(inst->view_layer->name, layer.view_layer_name().c_str());
317 const bool disable_masks_render = is_viewlayer_render &&
318 (layer.base.flag &
320 bool is_masked = !disable_masks_render && layer.use_masks() &&
322
323 const float vert_col_opacity = (override_vertcol) ?
324 (is_vert_col_mode ? inst->vertex_paint_opacity : 0.0f) :
325 (inst->is_render ? 1.0f : inst->vertex_paint_opacity);
326 /* If the layer is used as a mask (but is otherwise not visible in the render), render it with a
327 * opacity of 0 so that it can still mask other layers. */
328 const float layer_opacity = !is_used_as_mask ? grease_pencil_layer_final_opacity_get(
329 inst, ob, grease_pencil, layer) :
330 0.0f;
331
332 float layer_alpha = inst->xray_alpha;
334 inst, grease_pencil, onion_id, &layer_alpha);
335
336 /* Create the new layer descriptor. */
338 tLayer *tgp_layer = &(*inst->gp_layer_pool)[id];
339 BLI_LINKS_APPEND(&tgp_ob->layers, tgp_layer);
340 tgp_layer->layer_id = *grease_pencil.get_layer_index(layer);
341 tgp_layer->is_onion = onion_id != 0;
342 tgp_layer->mask_bits = nullptr;
343 tgp_layer->mask_invert_bits = nullptr;
344 tgp_layer->blend_ps = nullptr;
345
346 /* Masking: Go through mask list and extract valid masks in a bitmap. */
347 if (is_masked) {
348 bool valid_mask = false;
349 /* WARNING: only #GP_MAX_MASKBITS amount of bits.
350 * TODO(fclem): Find a better system without any limitation. */
351 tgp_layer->mask_bits = static_cast<BLI_bitmap *>(BLI_memblock_alloc(inst->gp_maskbit_pool));
352 tgp_layer->mask_invert_bits = static_cast<BLI_bitmap *>(
354 BLI_bitmap_set_all(tgp_layer->mask_bits, false, GP_MAX_MASKBITS);
355
357 if (mask->flag & GP_LAYER_MASK_HIDE) {
358 continue;
359 }
360 const TreeNode *node = grease_pencil.find_node_by_name(mask->layer_name);
361 if (node == nullptr) {
362 continue;
363 }
364 const Layer &mask_layer = node->as_layer();
365 if ((&mask_layer == &layer) || !mask_layer.is_visible()) {
366 continue;
367 }
368 const int index = *grease_pencil.get_layer_index(mask_layer);
369 if (index < GP_MAX_MASKBITS) {
370 const bool invert = (mask->flag & GP_LAYER_MASK_INVERT) != 0;
371 BLI_BITMAP_SET(tgp_layer->mask_bits, index, true);
372 BLI_BITMAP_SET(tgp_layer->mask_invert_bits, index, invert);
373 valid_mask = true;
374 }
375 }
376
377 if (valid_mask) {
378 inst->use_mask_fb = true;
379 }
380 else {
381 tgp_layer->mask_bits = nullptr;
382 }
383 is_masked = valid_mask;
384 }
385
386 /* Blending: Force blending for masked layer. */
387 if (is_masked || (layer.blend_mode != GP_LAYER_BLEND_NONE) || (layer_opacity < 1.0f)) {
389 switch (layer.blend_mode) {
392 break;
395 break;
398 break;
403 break;
404 }
405
407 /* For these effect to propagate, we need a signed floating point buffer. */
408 inst->use_signed_fb = true;
409 }
410
411 if (tgp_layer->blend_ps == nullptr) {
412 tgp_layer->blend_ps = std::make_unique<PassSimple>("GPencil Blend Layer");
413 }
414 PassSimple &pass = *tgp_layer->blend_ps;
415 pass.init();
416 pass.state_set(state);
417 pass.shader_set(ShaderCache::get().layer_blend.get());
418 pass.push_constant("blend_mode", int(layer.blend_mode));
419 pass.push_constant("blend_opacity", layer_opacity);
420 pass.bind_texture("color_buf", &inst->color_layer_tx);
421 pass.bind_texture("reveal_buf", &inst->reveal_layer_tx);
422 pass.bind_texture("mask_buf", (is_masked) ? &inst->mask_tx : &inst->dummy_tx);
423 pass.state_stencil(0xFF, 0xFF, 0xFF);
424 pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
425
427 /* We cannot do custom blending on Multi-Target frame-buffers.
428 * Workaround by doing 2 passes. */
430 pass.push_constant("blend_mode", 999);
431 pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
432 }
433
434 inst->use_layer_fb = true;
435 }
436
437 /* Geometry pass */
438 {
439 if (tgp_layer->geom_ps == nullptr) {
440 tgp_layer->geom_ps = std::make_unique<PassSimple>("GPencil Layer");
441 }
442
443 PassSimple &pass = *tgp_layer->geom_ps;
444
445 gpu::Texture **depth_tex = (is_in_front) ? &inst->dummy_depth : &inst->scene_depth_tx;
446 gpu::Texture **mask_tex = (is_masked) ? &inst->mask_tx : &inst->dummy_tx;
447
449 /* For 2D mode, we render all strokes with uniform depth (increasing with stroke id). */
451 /* Always write stencil. Only used as optimization for blending. */
453
454 pass.state_set(state);
455 pass.shader_set(ShaderCache::get().geometry.get());
456 pass.bind_texture("gp_scene_depth_tx", depth_tex);
457 pass.bind_texture("gp_mask_tx", mask_tex);
458 pass.push_constant("gp_normal", tgp_ob->plane_normal);
459 pass.push_constant("gp_stroke_order3d", tgp_ob->is_drawmode3d);
460 pass.push_constant("gp_vertex_color_opacity", vert_col_opacity);
461
462 pass.bind_texture("gp_fill_tx", inst->dummy_tx);
463 pass.bind_texture("gp_stroke_tx", inst->dummy_tx);
464
465 /* If random color type, need color by layer. */
466 float4 gpl_color;
467 copy_v4_v4(gpl_color, layer_tint);
469 grease_pencil_layer_random_color_get(ob, layer, gpl_color);
470 gpl_color[3] = 1.0f;
471 }
472 pass.push_constant("gp_layer_tint", gpl_color);
473
474 pass.push_constant("gp_layer_opacity", layer_alpha);
475 pass.state_stencil(0xFF, 0xFF, 0xFF);
476 }
477
478 return tgp_layer;
479}
480
481
482} // 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
T & DRW_object_get_data_for_drawing(const Object &object)
@ GPU_PRIM_TRIS
BLI_INLINE void IMB_colormanagement_rec709_to_scene_linear(float scene_linear[3], const float rec709[3])
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
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[258]
Definition DNA_ID.h:432
char name[64]
struct blender::draw::gpencil::Instance::@236154265015220156065132174366266070164251065066 tobjects
struct blender::draw::gpencil::Instance::@236154265015220156065132174366266070164251065066 tobjects_infront
std::unique_ptr< PassSimple > geom_ps
std::unique_ptr< PassSimple > blend_ps
struct blender::draw::gpencil::tObject::@205301145252027033255155341114207373222070270161 layers
struct blender::draw::gpencil::tObject::@173025115035047336003051253055014360144006015207 vfx
i
Definition text_draw.cc:230