Blender V4.5
gpencil_engine_c.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#include "DRW_engine.hh"
9#include "DRW_render.hh"
10
11#include "BKE_context.hh"
12#include "BKE_curves.hh"
14#include "BKE_gpencil_legacy.h"
15#include "BKE_grease_pencil.hh"
16#include "BKE_material.hh"
17#include "BKE_object.hh"
18#include "BKE_paint.hh"
19#include "BKE_shader_fx.h"
20
21#include "BKE_camera.h"
22
23#include "BLI_listbase.h"
24#include "BLI_memblock.h"
25#include "BLI_virtual_array.hh"
26
27#include "BLT_translation.hh"
28
29#include "DNA_camera_types.h"
30#include "DNA_material_types.h"
31#include "DNA_screen_types.h"
32#include "DNA_view3d_types.h"
33#include "DNA_world_types.h"
34
35#include "GPU_texture.hh"
36#include "GPU_uniform_buffer.hh"
37
38#include "draw_cache.hh"
39#include "draw_manager.hh"
40#include "draw_view.hh"
41
42#include "gpencil_engine.hh"
44
46
47#include "ED_grease_pencil.hh"
48#include "ED_screen.hh"
49#include "ED_view3d.hh"
50
51#include "GPU_debug.hh"
52
53namespace blender::draw::gpencil {
54
56{
57 this->draw_ctx = DRW_context_get();
58
59 const View3D *v3d = draw_ctx->v3d;
60
61 if (!dummy_texture.is_valid()) {
62 const float pixels[1][4] = {{1.0f, 0.0f, 1.0f, 1.0f}};
63 dummy_texture.ensure_2d(GPU_RGBA8, int2(1), GPU_TEXTURE_USAGE_SHADER_READ, &pixels[0][0]);
64 }
65 if (!dummy_depth.is_valid()) {
66 const float pixels[1] = {1.0f};
67 dummy_depth.ensure_2d(
69 }
70
71 /* Resize and reset memory-blocks. */
72 BLI_memblock_clear(this->gp_light_pool, light_pool_free);
73 BLI_memblock_clear(this->gp_material_pool, material_pool_free);
74 BLI_memblock_clear(this->gp_object_pool, nullptr);
75 this->gp_layer_pool->clear();
76 this->gp_vfx_pool->clear();
77 BLI_memblock_clear(this->gp_maskbit_pool, nullptr);
78
79 this->view_layer = draw_ctx->view_layer;
80 this->scene = draw_ctx->scene;
81 this->v3d = draw_ctx->v3d;
82 this->last_light_pool = nullptr;
83 this->last_material_pool = nullptr;
84 this->tobjects.first = nullptr;
85 this->tobjects.last = nullptr;
86 this->tobjects_infront.first = nullptr;
87 this->tobjects_infront.last = nullptr;
88 this->sbuffer_tobjects.first = nullptr;
89 this->sbuffer_tobjects.last = nullptr;
90 this->dummy_tx = this->dummy_texture;
91 this->draw_wireframe = (v3d && v3d->shading.type == OB_WIRE);
92 this->scene_depth_tx = nullptr;
93 this->scene_fb = nullptr;
94 this->is_render = this->render_depth_tx.is_valid() || (v3d && v3d->shading.type == OB_RENDER);
95 this->is_viewport = (v3d != nullptr);
98 /* Small HACK: we don't want the global pool to be reused,
99 * so we set the last light pool to nullptr. */
100 this->last_light_pool = nullptr;
101 this->is_sorted = false;
102
103 bool use_scene_lights = false;
104 bool use_scene_world = false;
105
106 if (v3d) {
107 use_scene_lights = V3D_USES_SCENE_LIGHTS(v3d);
108
109 use_scene_world = V3D_USES_SCENE_WORLD(v3d);
110
111 this->v3d_color_type = (v3d->shading.type == OB_SOLID) ? v3d->shading.color_type : -1;
112 /* Special case: If we're in Vertex Paint mode, enforce #V3D_SHADING_VERTEX_COLOR setting. */
113 if (v3d->shading.type == OB_SOLID && draw_ctx->obact &&
114 (draw_ctx->obact->mode & OB_MODE_VERTEX_GREASE_PENCIL) != 0)
115 {
117 }
118
119 copy_v3_v3(this->v3d_single_color, v3d->shading.single_color);
120
121 /* For non active frame, use only lines in multiedit mode. */
122 const bool overlays_on = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0;
123 this->use_multiedit_lines_only = overlays_on &&
124 (v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) != 0;
125
126 const bool shmode_xray_support = v3d->shading.type <= OB_SOLID;
127 this->xray_alpha = (shmode_xray_support && XRAY_ENABLED(v3d)) ? XRAY_ALPHA(v3d) : 1.0f;
129 }
130 else if (this->is_render) {
131 use_scene_lights = true;
132 use_scene_world = true;
133 this->use_multiedit_lines_only = false;
134 this->xray_alpha = 1.0f;
135 this->v3d_color_type = -1;
136 this->force_stroke_order_3d = false;
137 }
138
139 this->use_lighting = (v3d && v3d->shading.type > OB_SOLID) || this->is_render;
140 this->use_lights = use_scene_lights;
141
142 gpencil_light_ambient_add(this->shadeless_light_pool, float3{1.0f, 1.0f, 1.0f});
143
144 World *world = draw_ctx->scene->world;
145 if (world != nullptr && use_scene_world) {
146 gpencil_light_ambient_add(this->global_light_pool, &world->horr);
147 }
148 else if (v3d) {
149 float world_light[3];
150 copy_v3_fl(world_light, v3d->shading.studiolight_intensity);
152 }
153
154 float4x4 viewmatinv = View::default_get().viewinv();
155 copy_v3_v3(this->camera_z_axis, viewmatinv[2]);
156 copy_v3_v3(this->camera_pos, viewmatinv[3]);
157 this->camera_z_offset = dot_v3v3(viewmatinv[3], viewmatinv[2]);
158
159 if (draw_ctx && draw_ctx->rv3d && v3d) {
160 this->camera = (draw_ctx->rv3d->persp == RV3D_CAMOB) ? v3d->camera : nullptr;
161 }
162 else {
163 this->camera = nullptr;
164 }
165}
166
168{
169 this->cfra = int(DEG_get_ctime(draw_ctx->depsgraph));
171 this->use_layer_fb = false;
172 this->use_object_fb = false;
173 this->use_mask_fb = false;
174 /* Always use high precision for render. */
175 this->use_signed_fb = !this->is_viewport;
176
177 if (draw_ctx->v3d) {
178 const bool hide_overlay = ((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) != 0);
179 const bool show_onion = ((draw_ctx->v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) != 0);
180 const bool playing = (draw_ctx->evil_C != nullptr) ?
182 nullptr :
183 false;
184 this->do_onion = show_onion && !hide_overlay && !playing;
185 this->do_onion_only_active_object = ((draw_ctx->v3d->gp_flag &
187 this->playing = playing;
188 /* Save simplify flags (can change while drawing, so it's better to save). */
189 Scene *scene = draw_ctx->scene;
192 (draw_ctx->v3d->shading.type < OB_RENDER);
193
194 /* Fade Layer. */
195 const bool is_fade_layer = ((!hide_overlay) && (!this->is_render) &&
196 (draw_ctx->v3d->gp_flag & V3D_GP_FADE_NOACTIVE_LAYERS));
197 this->fade_layer_opacity = (is_fade_layer) ? draw_ctx->v3d->overlay.gpencil_fade_layer : -1.0f;
198 this->vertex_paint_opacity = draw_ctx->v3d->overlay.gpencil_vertex_paint_opacity;
199 /* Fade GPencil Objects. */
200 const bool is_fade_object = ((!hide_overlay) && (!this->is_render) &&
201 (draw_ctx->v3d->gp_flag & V3D_GP_FADE_OBJECTS) &&
202 (draw_ctx->v3d->gp_flag & V3D_GP_FADE_NOACTIVE_GPENCIL));
203 this->fade_gp_object_opacity = (is_fade_object) ?
204 draw_ctx->v3d->overlay.gpencil_paper_opacity :
205 -1.0f;
206 this->fade_3d_object_opacity = ((!hide_overlay) && (!this->is_render) &&
207 (draw_ctx->v3d->gp_flag & V3D_GP_FADE_OBJECTS)) ?
208 draw_ctx->v3d->overlay.gpencil_paper_opacity :
209 -1.0f;
210 }
211 else {
212 this->do_onion = true;
213 Scene *scene = draw_ctx->scene;
215 this->simplify_fx = GPENCIL_SIMPLIFY_FX(scene, false);
216 this->fade_layer_opacity = -1.0f;
217 this->playing = false;
218 }
219
220 {
221 this->stroke_batch = nullptr;
222 this->fill_batch = nullptr;
223 this->do_fast_drawing = false;
224
225 this->obact = draw_ctx->obact;
226 }
227
228 if (this->do_fast_drawing) {
229 this->snapshot_buffer_dirty = !this->snapshot_depth_tx.is_valid();
230 const float2 size = draw_ctx->viewport_size_get();
231
233 this->snapshot_depth_tx.ensure_2d(GPU_DEPTH24_STENCIL8, int2(size), usage);
234 this->snapshot_color_tx.ensure_2d(GPU_R11F_G11F_B10F, int2(size), usage);
235 this->snapshot_reveal_tx.ensure_2d(GPU_R11F_G11F_B10F, int2(size), usage);
236
240 }
241 else {
242 /* Free unneeded buffers. */
243 this->snapshot_depth_tx.free();
244 this->snapshot_color_tx.free();
245 this->snapshot_reveal_tx.free();
246 }
247
248 {
249 PassSimple &pass = this->merge_depth_ps;
250 pass.init();
252 pass.shader_set(ShaderCache::get().depth_merge.get());
253 pass.bind_texture("depth_buf", &this->depth_tx);
254 pass.push_constant("stroke_order3d", &this->is_stroke_order_3d);
255 pass.push_constant("gp_model_matrix", &this->object_bound_mat);
256 pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
257 }
258 {
259 PassSimple &pass = this->mask_invert_ps;
260 pass.init();
263 pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
264 }
265
266 Camera *cam = static_cast<Camera *>(
267 (this->camera != nullptr && this->camera->type == OB_CAMERA) ? this->camera->data : nullptr);
268
269 /* Pseudo DOF setup. */
270 if (cam && (cam->dof.flag & CAM_DOF_ENABLED)) {
271 const float2 vp_size = draw_ctx->viewport_size_get();
272 float fstop = cam->dof.aperture_fstop;
273 float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
274 float focus_dist = BKE_camera_object_dof_distance(this->camera);
275 float focal_len = cam->lens;
276
277 const float scale_camera = 0.001f;
278 /* We want radius here for the aperture number. */
279 float aperture = 0.5f * scale_camera * focal_len / fstop;
280 float focal_len_scaled = scale_camera * focal_len;
281 float sensor_scaled = scale_camera * sensor;
282
283 if (draw_ctx->rv3d != nullptr) {
284 sensor_scaled *= draw_ctx->rv3d->viewcamtexcofac[0];
285 }
286
287 this->dof_params[1] = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled));
288 this->dof_params[1] *= vp_size[0] / sensor_scaled;
289 this->dof_params[0] = -focus_dist * this->dof_params[1];
290 }
291 else {
292 /* Disable DoF blur scaling. */
293 this->camera = nullptr;
294 }
295}
296
297#define DISABLE_BATCHING 0
298
299bool Instance::is_used_as_layer_mask_in_viewlayer(const GreasePencil &grease_pencil,
300 const bke::greasepencil::Layer &mask_layer,
301 const ViewLayer &view_layer)
302{
303 using namespace bke::greasepencil;
304 for (const Layer *layer : grease_pencil.layers()) {
305 if (layer->view_layer_name().is_empty() ||
306 !STREQ(view_layer.name, layer->view_layer_name().c_str()))
307 {
308 continue;
309 }
310
311 if ((layer->base.flag & GP_LAYER_TREE_NODE_DISABLE_MASKS_IN_VIEWLAYER) != 0) {
312 continue;
313 }
314
315 LISTBASE_FOREACH (GreasePencilLayerMask *, mask, &layer->masks) {
316 if (STREQ(mask->layer_name, mask_layer.name().c_str())) {
317 return true;
318 }
319 }
320 }
321 return false;
322}
323
324bool Instance::use_layer_in_render(const GreasePencil &grease_pencil,
325 const bke::greasepencil::Layer &layer,
326 const ViewLayer &view_layer,
327 bool &r_is_used_as_mask)
328{
329 if (!layer.view_layer_name().is_empty() &&
330 !STREQ(view_layer.name, layer.view_layer_name().c_str()))
331 {
332 /* Do not skip layers that are masks when rendering the viewlayer so that it can still be used
333 * to clip/mask other layers. */
334 if (is_used_as_layer_mask_in_viewlayer(grease_pencil, layer, view_layer)) {
335 r_is_used_as_mask = true;
336 }
337 else {
338 return false;
339 }
340 }
341 return true;
342}
343
344tObject *Instance::object_sync_do(Object *ob, ResourceHandle res_handle)
345{
346 using namespace ed::greasepencil;
347 using namespace bke::greasepencil;
349 const bool is_vertex_mode = (ob->mode & OB_MODE_VERTEX_PAINT) != 0;
350 const Bounds<float3> bounds = grease_pencil.bounds_min_max_eval().value_or(Bounds(float3(0)));
351
352 const bool do_onion = !this->is_render && this->do_onion &&
353 (this->do_onion_only_active_object ? this->obact == ob : true);
354 const bool do_multi_frame = (((this->scene->toolsettings->gpencil_flags &
356 (ob->mode != OB_MODE_OBJECT));
357 const bool use_stroke_order_3d = this->force_stroke_order_3d ||
358 ((grease_pencil.flag & GREASE_PENCIL_STROKE_ORDER_3D) != 0);
359 tObject *tgp_ob = gpencil_object_cache_add(this, ob, use_stroke_order_3d, bounds);
360
361 int mat_ofs = 0;
362 MaterialPool *matpool = gpencil_material_pool_create(this, ob, &mat_ofs, is_vertex_mode);
363
364 GPUTexture *tex_fill = this->dummy_tx;
365 GPUTexture *tex_stroke = this->dummy_tx;
366
367 gpu::Batch *iter_geom = nullptr;
368 PassSimple *last_pass = nullptr;
369 int vfirst = 0;
370 int vcount = 0;
371
372 const auto drawcall_flush = [&](PassSimple &pass) {
373#if !DISABLE_BATCHING
374 if (iter_geom != nullptr) {
375 pass.draw(iter_geom, 1, vcount, vfirst, res_handle);
376 }
377#endif
378 iter_geom = nullptr;
379 vfirst = -1;
380 vcount = 0;
381 };
382
383 const auto drawcall_add =
384 [&](PassSimple &pass, gpu::Batch *draw_geom, const int v_first, const int v_count) {
385#if DISABLE_BATCHING
386 pass.draw(iter_geom, 1, vcount, vfirst, res_handle);
387 return;
388#endif
389 int last = vfirst + vcount;
390 /* Interrupt draw-call grouping if the sequence is not consecutive. */
391 if ((draw_geom != iter_geom) || (v_first - last > 0)) {
392 drawcall_flush(pass);
393 }
394 iter_geom = draw_geom;
395 if (vfirst == -1) {
396 vfirst = v_first;
397 }
398 vcount = v_first + v_count - vfirst;
399 };
400
401 int t_offset = 0;
402 /* Note that we loop over all the drawings (including the onion skinned ones) to make sure we
403 * match the offsets of the batch cache. */
405 *this->scene, grease_pencil, true);
406 const Span<const Layer *> layers = grease_pencil.layers();
407 for (const DrawingInfo info : drawings) {
408 const Layer &layer = *layers[info.layer_index];
409
410 const bke::CurvesGeometry &curves = info.drawing.strokes();
411 const OffsetIndices<int> points_by_curve = curves.evaluated_points_by_curve();
412 const bke::AttributeAccessor attributes = curves.attributes();
413 const VArray<bool> cyclic = *attributes.lookup_or_default<bool>(
414 "cyclic", bke::AttrDomain::Curve, false);
415
416 IndexMaskMemory memory;
417 const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes(
418 *ob, info.drawing, memory);
419
420 /* Precompute all the triangle and vertex counts.
421 * In case the drawing should not be rendered, we need to compute the offset where the next
422 * drawing begins. */
423 Array<int> num_triangles_per_stroke(visible_strokes.size());
424 Array<int> num_vertices_per_stroke(visible_strokes.size());
425 int total_num_triangles = 0;
426 int total_num_vertices = 0;
427 visible_strokes.foreach_index([&](const int stroke_i, const int pos) {
428 const IndexRange points = points_by_curve[stroke_i];
429 const int num_stroke_triangles = (points.size() >= 3) ? (points.size() - 2) : 0;
430 const int num_stroke_vertices = (points.size() +
431 int(cyclic[stroke_i] && (points.size() >= 3)));
432 num_triangles_per_stroke[pos] = num_stroke_triangles;
433 num_vertices_per_stroke[pos] = num_stroke_vertices;
434 total_num_triangles += num_stroke_triangles;
435 total_num_vertices += num_stroke_vertices;
436 });
437
438 bool is_layer_used_as_mask = false;
439 const bool show_drawing_in_render = use_layer_in_render(
440 grease_pencil, layer, *this->view_layer, is_layer_used_as_mask);
441 if (!show_drawing_in_render) {
442 /* Skip over the entire drawing. */
443 t_offset += total_num_triangles;
444 t_offset += total_num_vertices * 2;
445 continue;
446 }
447
448 if (last_pass) {
449 drawcall_flush(*last_pass);
450 }
451
452 tLayer *tgp_layer = grease_pencil_layer_cache_add(
453 this, ob, layer, info.onion_id, is_layer_used_as_mask, tgp_ob);
454 PassSimple &pass = *tgp_layer->geom_ps;
455 last_pass = &pass;
456
457 const bool use_lights = this->use_lighting &&
458 ((layer.base.flag & GP_LAYER_TREE_NODE_USE_LIGHTS) != 0) &&
460
461 GPUUniformBuf *lights_ubo = (use_lights) ? this->global_light_pool->ubo :
463
464 GPUUniformBuf *ubo_mat;
465 gpencil_material_resources_get(matpool, 0, nullptr, nullptr, &ubo_mat);
466
467 pass.bind_ubo("gp_lights", lights_ubo);
468 pass.bind_ubo("gp_materials", ubo_mat);
469 pass.bind_texture("gp_fill_tx", tex_fill);
470 pass.bind_texture("gp_stroke_tx", tex_stroke);
471 pass.push_constant("gp_material_offset", mat_ofs);
472 /* Since we don't use the sbuffer in GPv3, this is always 0. */
473 pass.push_constant("gp_stroke_index_offset", 0.0f);
474 pass.push_constant("viewport_size", float2(draw_ctx->viewport_size_get()));
475
476 const VArray<int> stroke_materials = *attributes.lookup_or_default<int>(
477 "material_index", bke::AttrDomain::Curve, 0);
478 const VArray<bool> is_fill_guide = *attributes.lookup_or_default<bool>(
479 ".is_fill_guide", bke::AttrDomain::Curve, false);
480
481 const bool only_lines = !ELEM(ob->mode,
485 info.frame_number != this->cfra && this->use_multiedit_lines_only &&
486 do_multi_frame;
487 const bool is_onion = info.onion_id != 0;
488
489 visible_strokes.foreach_index([&](const int stroke_i, const int pos) {
490 const IndexRange points = points_by_curve[stroke_i];
491 /* The material index is allowed to be negative as it's stored as a generic attribute. We
492 * clamp it here to avoid crashing in the rendering code. Any stroke with a material < 0 will
493 * use the first material in the first material slot. */
494 const int material_index = std::max(stroke_materials[stroke_i], 0);
495 const MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, material_index + 1);
496
497 const bool is_fill_guide_stroke = is_fill_guide[stroke_i];
498
499 const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0;
500 const bool show_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0) ||
501 is_fill_guide_stroke;
502 const bool show_fill = (points.size() >= 3) &&
503 ((gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0) &&
504 (!this->simplify_fill) && !is_fill_guide_stroke;
505 const bool hide_onion = is_onion && ((gp_style->flag & GP_MATERIAL_HIDE_ONIONSKIN) != 0 ||
506 (!do_onion && !do_multi_frame));
507 const bool skip_stroke = hide_material || (!show_stroke && !show_fill) ||
508 (only_lines && !do_onion && is_onion) || hide_onion;
509
510 if (skip_stroke) {
511 t_offset += num_triangles_per_stroke[pos];
512 t_offset += num_vertices_per_stroke[pos] * 2;
513 return;
514 }
515
516 GPUUniformBuf *new_ubo_mat;
517 GPUTexture *new_tex_fill = nullptr;
518 GPUTexture *new_tex_stroke = nullptr;
520 matpool, mat_ofs + material_index, &new_tex_stroke, &new_tex_fill, &new_ubo_mat);
521
522 const bool resource_changed = (ubo_mat != new_ubo_mat) ||
523 (new_tex_fill && (new_tex_fill != tex_fill)) ||
524 (new_tex_stroke && (new_tex_stroke != tex_stroke));
525
526 if (resource_changed) {
527 drawcall_flush(pass);
528
529 if (new_ubo_mat != ubo_mat) {
530 pass.bind_ubo("gp_materials", new_ubo_mat);
531 ubo_mat = new_ubo_mat;
532 }
533 if (new_tex_fill) {
534 pass.bind_texture("gp_fill_tx", new_tex_fill);
535 tex_fill = new_tex_fill;
536 }
537 if (new_tex_stroke) {
538 pass.bind_texture("gp_stroke_tx", new_tex_stroke);
539 tex_stroke = new_tex_stroke;
540 }
541 }
542
543 gpu::Batch *geom = DRW_cache_grease_pencil_get(this->scene, ob);
544 if (iter_geom != geom) {
545 drawcall_flush(pass);
546
547 gpu::VertBuf *position_tx = DRW_cache_grease_pencil_position_buffer_get(this->scene, ob);
549 pass.bind_texture("gp_pos_tx", position_tx);
550 pass.bind_texture("gp_col_tx", color_tx);
551 }
552
553 if (show_fill) {
554 const int v_first = t_offset * 3;
555 const int v_count = num_triangles_per_stroke[pos] * 3;
556 drawcall_add(pass, geom, v_first, v_count);
557 }
558
559 t_offset += num_triangles_per_stroke[pos];
560
561 if (show_stroke) {
562 const int v_first = t_offset * 3;
563 const int v_count = num_vertices_per_stroke[pos] * 2 * 3;
564 drawcall_add(pass, geom, v_first, v_count);
565 }
566
567 t_offset += num_vertices_per_stroke[pos] * 2;
568 });
569 }
570
571 if (last_pass) {
572 drawcall_flush(*last_pass);
573 }
574
575 return tgp_ob;
576}
577
579{
580 Object *ob = ob_ref.object;
581
582 /* object must be visible */
584 return;
585 }
586
587 if (ob->data && (ob->type == OB_GREASE_PENCIL) && (ob->dt >= OB_SOLID)) {
588 ResourceHandle res_handle = manager.unique_handle(ob_ref);
589
590 tObject *tgp_ob = object_sync_do(ob, res_handle);
591 vfx_sync(ob, tgp_ob);
592 }
593
594 if (ob->type == OB_LAMP && this->use_lights) {
596 }
597}
598
600{
601 /* Upload UBO data. */
604 MaterialPool *pool;
605 while ((pool = (MaterialPool *)BLI_memblock_iterstep(&iter))) {
606 GPU_uniformbuf_update(pool->ubo, pool->mat_data);
607 }
608
610 LightPool *lpool;
611 while ((lpool = (LightPool *)BLI_memblock_iterstep(&iter))) {
612 GPU_uniformbuf_update(lpool->ubo, lpool->light_data);
613 }
614}
615
617{
618 /* Create frame-buffers only if needed. */
619 if (this->tobjects.first == nullptr) {
620 return;
621 }
622
623 const int2 size = int2(draw_ctx->viewport_size_get());
624
625 const eGPUTextureFormat format_color = GPU_RGBA16F;
626 const eGPUTextureFormat format_reveal = this->use_signed_fb ? GPU_RGBA16F : GPU_RGB10_A2;
627
628 this->depth_tx.acquire(size, GPU_DEPTH24_STENCIL8);
629 this->color_tx.acquire(size, format_color);
630 this->reveal_tx.acquire(size, format_reveal);
631
632 this->gpencil_fb.ensure(GPU_ATTACHMENT_TEXTURE(this->depth_tx),
633 GPU_ATTACHMENT_TEXTURE(this->color_tx),
635
636 if (this->use_layer_fb) {
637 this->color_layer_tx.acquire(size, format_color);
638 this->reveal_layer_tx.acquire(size, format_reveal);
639
640 this->layer_fb.ensure(GPU_ATTACHMENT_TEXTURE(this->depth_tx),
643 }
644
645 if (this->use_object_fb) {
646 this->color_object_tx.acquire(size, format_color);
647 this->reveal_object_tx.acquire(size, format_reveal);
648
649 this->object_fb.ensure(GPU_ATTACHMENT_TEXTURE(this->depth_tx),
652 }
653
654 if (this->use_mask_fb) {
655 /* Use high quality format for render. */
656 const eGPUTextureFormat mask_format = this->is_render ? GPU_R16 : GPU_R8;
657 /* We need an extra depth to not disturb the normal drawing. */
659 /* The mask_color_tx is needed for frame-buffer completeness. */
660 this->mask_color_tx.acquire(size, GPU_R8);
661 this->mask_tx.acquire(size, mask_format);
662
663 this->mask_fb.ensure(GPU_ATTACHMENT_TEXTURE(this->mask_depth_tx),
666 }
667}
668
670{
671 this->depth_tx.release();
672 this->color_tx.release();
673 this->reveal_tx.release();
674 this->color_layer_tx.release();
675 this->reveal_layer_tx.release();
676 this->color_object_tx.release();
677 this->reveal_object_tx.release();
678 this->mask_depth_tx.release();
679 this->mask_color_tx.release();
680 this->mask_tx.release();
681 this->smaa_edge_tx.release();
682 this->smaa_weight_tx.release();
683}
684
685void Instance::draw_mask(View &view, tObject *ob, tLayer *layer)
686{
687 Manager *manager = DRW_manager_get();
688
689 const float clear_col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
690 float clear_depth = ob->is_drawmode3d ? 1.0f : 0.0f;
691 bool inverted = false;
692 /* OPTI(@fclem): we could optimize by only clearing if the new mask_bits does not contain all
693 * the masks already rendered in the buffer, and drawing only the layers not already drawn. */
694 bool cleared = false;
695
696 GPU_debug_group_begin("GPencil Mask");
697
699
700 for (int i = 0; i < GP_MAX_MASKBITS; i++) {
701 if (!BLI_BITMAP_TEST(layer->mask_bits, i)) {
702 continue;
703 }
704
705 if (BLI_BITMAP_TEST_BOOL(layer->mask_invert_bits, i) != inverted) {
706 if (cleared) {
707 manager->submit(this->mask_invert_ps);
708 }
709 inverted = !inverted;
710 }
711
712 if (!cleared) {
713 cleared = true;
714 GPU_framebuffer_clear_color_depth(this->mask_fb, clear_col, clear_depth);
715 }
716
717 tLayer *mask_layer = grease_pencil_layer_cache_get(ob, i, true);
718 /* When filtering by view-layer, the mask could be null and must be ignored. */
719 if (mask_layer == nullptr) {
720 continue;
721 }
722
723 manager->submit(*mask_layer->geom_ps, view);
724 }
725
726 if (!inverted) {
727 /* Blend shader expect an opacity mask not a reavealage buffer. */
728 manager->submit(this->mask_invert_ps);
729 }
730
732}
733
734void Instance::draw_object(View &view, tObject *ob)
735{
736 Manager *manager = DRW_manager_get();
737
738 const float clear_cols[2][4] = {{0.0f, 0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}};
739
740 GPU_debug_group_begin("GPencil Object");
741
742 GPUFrameBuffer *fb_object = (ob->vfx.first) ? this->object_fb : this->gpencil_fb;
743
744 GPU_framebuffer_bind(fb_object);
745 GPU_framebuffer_clear_depth_stencil(fb_object, ob->is_drawmode3d ? 1.0f : 0.0f, 0x00);
746
747 if (ob->vfx.first) {
748 GPU_framebuffer_multi_clear(fb_object, clear_cols);
749 }
750
751 LISTBASE_FOREACH (tLayer *, layer, &ob->layers) {
752 if (layer->mask_bits) {
753 draw_mask(view, ob, layer);
754 }
755
756 if (layer->blend_ps) {
758 GPU_framebuffer_multi_clear(this->layer_fb, clear_cols);
759 }
760 else {
761 GPU_framebuffer_bind(fb_object);
762 }
763
764 manager->submit(*layer->geom_ps, view);
765
766 if (layer->blend_ps) {
767 GPU_framebuffer_bind(fb_object);
768 manager->submit(*layer->blend_ps);
769 }
770 }
771
772 LISTBASE_FOREACH (tVfx *, vfx, &ob->vfx) {
773 GPU_framebuffer_bind(*(vfx->target_fb));
774 manager->submit(*vfx->vfx_ps);
775 }
776
777 this->object_bound_mat = float4x4(ob->plane_mat);
778 this->is_stroke_order_3d = ob->is_drawmode3d;
779
780 if (this->scene_fb) {
782 manager->submit(this->merge_depth_ps, view);
783 }
784
786}
787
788void Instance::fast_draw_start()
789{
790 DefaultFramebufferList *dfbl = this->draw_ctx->viewport_framebuffer_list_get();
791
792 if (!this->snapshot_buffer_dirty) {
793 /* Copy back cached render. */
797 /* Bypass drawing. */
798 this->tobjects.first = this->tobjects.last = nullptr;
799 }
800}
801
802void Instance::fast_draw_end(View &view)
803{
804 DefaultFramebufferList *dfbl = this->draw_ctx->viewport_framebuffer_list_get();
805
806 if (this->snapshot_buffer_dirty) {
807 /* Save to snapshot buffer. */
808 GPU_framebuffer_blit(dfbl->default_fb, 0, this->snapshot_fb, 0, GPU_DEPTH_BIT);
811 this->snapshot_buffer_dirty = false;
812 }
813 /* Draw the sbuffer stroke(s). */
814 LISTBASE_FOREACH (tObject *, ob, &this->sbuffer_tobjects) {
815 draw_object(view, ob);
816 }
817}
818
820{
821 DefaultTextureList *dtxl = draw_ctx->viewport_texture_list_get();
822 DefaultFramebufferList *dfbl = draw_ctx->viewport_framebuffer_list_get();
823
824 if (this->render_depth_tx.is_valid()) {
825 this->scene_depth_tx = this->render_depth_tx;
826 this->scene_fb = this->render_fb;
827 }
828 else {
829 this->scene_fb = dfbl->default_fb;
830 this->scene_depth_tx = dtxl->depth;
831 }
833
834 float clear_cols[2][4] = {{0.0f, 0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}};
835
836 /* Fade 3D objects. */
837 if ((!this->is_render) && (this->fade_3d_object_opacity > -1.0f) && (this->obact != nullptr) &&
838 ELEM(this->obact->type, OB_GREASE_PENCIL))
839 {
840 float background_color[3];
841 ED_view3d_background_color_get(this->scene, this->v3d, background_color);
842 /* Blend color. */
843 interp_v3_v3v3(clear_cols[0], background_color, clear_cols[0], this->fade_3d_object_opacity);
844
845 mul_v4_fl(clear_cols[1], this->fade_3d_object_opacity);
846 }
847
848 /* Sort object by decreasing Z to avoid most of alpha ordering issues. */
850
851 if (this->tobjects.first == nullptr) {
852 return;
853 }
854
856
857 antialiasing_init();
858
859 this->acquire_resources();
860
861 if (this->do_fast_drawing) {
862 fast_draw_start();
863 }
864
865 if (this->tobjects.first) {
867 GPU_framebuffer_multi_clear(this->gpencil_fb, clear_cols);
868 }
869
871
872 LISTBASE_FOREACH (tObject *, ob, &this->tobjects) {
873 draw_object(view, ob);
874 }
875
876 if (this->do_fast_drawing) {
877 fast_draw_end(view);
878 }
879
880 if (this->scene_fb) {
881 antialiasing_draw(manager);
882 }
883
884 this->release_resources();
885
887}
888
890{
891 return new Instance();
892}
893
898
899} // namespace blender::draw::gpencil
Camera data-block and utility functions.
float BKE_camera_sensor_size(int sensor_fit, float sensor_x, float sensor_y)
float BKE_camera_object_dof_distance(const struct Object *ob)
wmWindowManager * CTX_wm_manager(const bContext *C)
Low-level operations for curves.
#define GPENCIL_SIMPLIFY_AA(scene)
#define GPENCIL_SIMPLIFY_FILL(scene, playing)
#define GPENCIL_SIMPLIFY_FX(scene, playing)
Low-level operations for grease pencil.
General operations, lookup, etc. for materials.
MaterialGPencilStyle * BKE_gpencil_material_settings(Object *ob, short act)
General operations, lookup, etc. for blender objects.
@ OB_VISIBLE_SELF
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition BLI_bitmap.h:61
#define BLI_BITMAP_TEST_BOOL(_bitmap, _index)
Definition BLI_bitmap.h:71
#define LISTBASE_FOREACH(type, var, list)
MINLINE void mul_v4_fl(float r[4], float f)
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
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
MINLINE void copy_v3_fl(float r[3], float f)
void BLI_memblock_iternew(BLI_memblock *mblk, BLI_memblock_iter *iter) ATTR_NONNULL()
void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP free_callback) ATTR_NONNULL(1)
void * BLI_memblock_iterstep(BLI_memblock_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define ELEM(...)
#define STREQ(a, b)
float[3] Vector
float DEG_get_ctime(const Depsgraph *graph)
@ CAM_DOF_ENABLED
struct GreasePencil GreasePencil
@ GP_LAYER_TREE_NODE_USE_LIGHTS
@ GP_LAYER_TREE_NODE_DISABLE_MASKS_IN_VIEWLAYER
@ GREASE_PENCIL_STROKE_ORDER_3D
struct ViewLayer ViewLayer
struct MaterialGPencilStyle MaterialGPencilStyle
@ GP_MATERIAL_HIDE_ONIONSKIN
@ GP_MATERIAL_HIDE
@ GP_MATERIAL_STROKE_SHOW
@ GP_MATERIAL_FILL_SHOW
@ OB_WIRE
@ OB_SOLID
@ OB_RENDER
@ OB_MODE_VERTEX_GREASE_PENCIL
@ OB_MODE_PAINT_GREASE_PENCIL
@ OB_MODE_OBJECT
@ OB_MODE_WEIGHT_GREASE_PENCIL
@ OB_MODE_VERTEX_PAINT
@ OB_CAMERA
@ OB_GREASE_PENCIL
@ OB_LAMP
struct Object Object
@ OB_USE_GPENCIL_LIGHTS
@ GP_USE_MULTI_FRAME_EDITING
@ V3D_SHADING_VERTEX_COLOR
@ V3D_GP_FORCE_STROKE_ORDER_3D
@ V3D_GP_FADE_OBJECTS
@ V3D_GP_SHOW_MULTIEDIT_LINES
@ V3D_GP_ONION_SKIN_ACTIVE_OBJECT
@ V3D_GP_FADE_NOACTIVE_GPENCIL
@ V3D_GP_FADE_NOACTIVE_LAYERS
@ V3D_GP_SHOW_ONION_SKIN
#define V3D_USES_SCENE_WORLD(v3d)
@ V3D_HIDE_OVERLAYS
@ RV3D_CAMOB
#define V3D_USES_SCENE_LIGHTS(v3d)
void DRW_submission_end()
void DRW_submission_start()
bScreen * ED_screen_animation_playing(const wmWindowManager *wm)
#define XRAY_ENABLED(v3d)
void ED_view3d_background_color_get(const Scene *scene, const View3D *v3d, float r_color[3])
#define XRAY_ALPHA(v3d)
static AppView * view
static void View(GHOST_IWindow *window, bool stereo, int eye=0)
void GPU_debug_group_end()
Definition gpu_debug.cc:33
void GPU_debug_group_begin(const char *name)
Definition gpu_debug.cc:22
#define GPU_ATTACHMENT_TEXTURE(_texture)
@ GPU_DEPTH_BIT
@ GPU_COLOR_BIT
void GPU_framebuffer_clear_depth_stencil(GPUFrameBuffer *fb, float clear_depth, uint clear_stencil)
void GPU_framebuffer_clear_color_depth(GPUFrameBuffer *fb, const float clear_col[4], float clear_depth)
void GPU_framebuffer_bind(GPUFrameBuffer *fb)
void GPU_framebuffer_multi_clear(GPUFrameBuffer *fb, const float(*clear_colors)[4])
void GPU_framebuffer_blit(GPUFrameBuffer *fb_read, int read_slot, GPUFrameBuffer *fb_write, int write_slot, eGPUFrameBufferBits blit_buffers)
@ GPU_PRIM_TRIS
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_ATTACHMENT
eGPUTextureFormat
@ GPU_DEPTH24_STENCIL8
@ GPU_RGB10_A2
@ GPU_RGBA16F
@ GPU_R16
@ GPU_R8
@ GPU_DEPTH_COMPONENT24
@ GPU_R11F_G11F_B10F
@ GPU_RGBA8
void GPU_uniformbuf_update(GPUUniformBuf *ubo, const void *data)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
int64_t size() const
void foreach_index(Fn &&fn) const
constexpr int64_t size() const
ResourceHandleRange unique_handle(const ObjectRef &ref)
void submit(PassSimple &pass, View &view)
static View & default_get()
Definition draw_view.cc:317
const float4x4 & viewinv(int view_id=0) const
Definition draw_view.hh:142
void bind_texture(const char *name, GPUTexture *texture, GPUSamplerState state=sampler_auto)
void state_set(DRWState state, int clip_plane_count=0)
void push_constant(const char *name, const float &data)
void draw_procedural(GPUPrimType primitive, uint instance_len, uint vertex_len, uint vertex_first=-1, ResourceHandleRange handle={0}, uint custom_id=0)
Definition draw_pass.hh:953
void shader_set(GPUShader *shader)
#define fabsf(x)
const DRWContext * DRW_context_get()
int DRW_object_visibility_in_active_context(const Object *ob)
Mesh & DRW_object_get_data_for_drawing(const Object &object)
blender::draw::Manager * DRW_manager_get()
@ DRW_STATE_DEPTH_LESS
Definition draw_state.hh:37
@ DRW_STATE_WRITE_DEPTH
Definition draw_state.hh:29
@ DRW_STATE_LOGIC_INVERT
Definition draw_state.hh:64
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
#define GP_MAX_MASKBITS
uint pos
#define this
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
void gpencil_light_ambient_add(LightPool *lightpool, const float color[3])
void gpencil_object_cache_sort(Instance *inst)
void gpencil_material_resources_get(MaterialPool *first_pool, int mat_id, GPUTexture **r_tex_stroke, GPUTexture **r_tex_fill, GPUUniformBuf **r_ubo_mat)
void gpencil_light_pool_populate(LightPool *lightpool, Object *ob)
LightPool * gpencil_light_pool_add(Instance *inst)
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)
MaterialPool * gpencil_material_pool_create(Instance *inst, Object *ob, int *ofs, const bool is_vertex_mode)
tObject * gpencil_object_cache_add(Instance *inst, Object *ob, const bool is_stroke_order_3d, const Bounds< float3 > bounds)
gpu::Batch * DRW_cache_grease_pencil_get(const Scene *scene, Object *ob)
detail::Pass< command::DrawCommandBuf > PassSimple
gpu::VertBuf * DRW_cache_grease_pencil_position_buffer_get(const Scene *scene, Object *ob)
gpu::VertBuf * DRW_cache_grease_pencil_color_buffer_get(const Scene *scene, Object *ob)
Vector< DrawingInfo > retrieve_visible_drawings(const Scene &scene, const GreasePencil &grease_pencil, const bool do_onion_skinning)
IndexMask retrieve_visible_strokes(Object &object, const bke::greasepencil::Drawing &drawing, IndexMaskMemory &memory)
MatBase< float, 4, 4 > float4x4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< float, 3 > float3
GPUFrameBuffer * default_fb
char info[GPU_INFO_SIZE]
Definition DRW_render.hh:70
GreasePencilLayerTreeNode base
char name[64]
DrawEngine * create_instance() final
struct blender::draw::gpencil::Instance::@347154071322053171023237172044324150040312176346 sbuffer_tobjects
void draw(Manager &manager) final
struct blender::draw::gpencil::Instance::@152377213014026372203341216150255134366273024311 tobjects_infront
void object_sync(ObjectRef &ob_ref, Manager &manager) final
struct blender::draw::gpencil::Instance::@152377213014026372203341216150255134366273024311 tobjects
gpLight light_data[GPENCIL_LIGHT_BUFFER_LEN]
gpMaterial mat_data[GPENCIL_MATERIAL_BUFFER_LEN]
std::unique_ptr< PassSimple > geom_ps
std::unique_ptr< PassSimple > blend_ps
i
Definition text_draw.cc:230