diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 32bfba97f8a..5da847a09d1 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -182,10 +182,8 @@ set(SRC engines/gpencil/gpencil_antialiasing.cc engines/gpencil/gpencil_cache_utils.cc engines/gpencil/gpencil_draw_data.cc - engines/gpencil/gpencil_engine.cc engines/gpencil/gpencil_engine_c.cc engines/gpencil/gpencil_render.cc - engines/gpencil/gpencil_shader.cc engines/gpencil/gpencil_shader_c.cc engines/gpencil/gpencil_shader_fx.cc engines/select/select_draw_utils.cc @@ -306,14 +304,7 @@ set(SRC engines/eevee_next/eevee_volume.hh engines/eevee_next/eevee_world.hh engines/external/external_engine.h - engines/gpencil/gpencil_antialiasing.hh engines/gpencil/gpencil_engine.h - engines/gpencil/gpencil_layer.hh - engines/gpencil/gpencil_light.hh - engines/gpencil/gpencil_material.hh - engines/gpencil/gpencil_object.hh - engines/gpencil/gpencil_shader.hh - engines/gpencil/gpencil_vfx.hh engines/image/image_batches.hh engines/image/image_buffer_cache.hh engines/image/image_drawing_mode.hh @@ -717,9 +708,7 @@ set(GLSL_SRC intern/draw_shader_shared.h engines/gpencil/shaders/gpencil_frag.glsl - engines/gpencil/shaders/grease_pencil_frag.glsl engines/gpencil/shaders/gpencil_vert.glsl - engines/gpencil/shaders/grease_pencil_vert.glsl engines/gpencil/shaders/gpencil_antialiasing_frag.glsl engines/gpencil/shaders/gpencil_antialiasing_vert.glsl engines/gpencil/shaders/gpencil_common_lib.glsl @@ -727,7 +716,6 @@ set(GLSL_SRC engines/gpencil/shaders/gpencil_mask_invert_frag.glsl engines/gpencil/shaders/gpencil_depth_merge_frag.glsl engines/gpencil/shaders/gpencil_depth_merge_vert.glsl - engines/gpencil/shaders/grease_pencil_depth_merge_vert.glsl engines/gpencil/shaders/gpencil_vfx_frag.glsl engines/gpencil/gpencil_defines.h diff --git a/source/blender/draw/engines/gpencil/gpencil_antialiasing.hh b/source/blender/draw/engines/gpencil/gpencil_antialiasing.hh deleted file mode 100644 index cdcd2282a3d..00000000000 --- a/source/blender/draw/engines/gpencil/gpencil_antialiasing.hh +++ /dev/null @@ -1,154 +0,0 @@ -/* SPDX-FileCopyrightText: 2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup draw - */ - -#pragma once - -#include "BKE_gpencil_legacy.h" -#include "BKE_image.h" -#include "DRW_gpu_wrapper.hh" -#include "DRW_render.hh" - -#include "draw_manager.hh" -#include "draw_pass.hh" - -#include "gpencil_shader.hh" - -#include "BLI_smaa_textures.h" - -namespace blender::draw::greasepencil { - -using namespace draw; - -/** Final anti-aliasing post processing and compositing on top of render. */ -class AntiAliasing { - private: - ShaderModule &shaders_; - - Texture smaa_search_tx_ = {"smaa_search", - GPU_R8, - GPU_TEXTURE_USAGE_SHADER_READ, - int2(SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT)}; - Texture smaa_area_tx_ = { - "smaa_area", GPU_RG8, GPU_TEXTURE_USAGE_SHADER_READ, int2(AREATEX_WIDTH, AREATEX_HEIGHT)}; - - TextureFromPool edge_detect_tx_ = {"edge_detect_tx"}; - Framebuffer edge_detect_fb_ = {"edge_detect_fb"}; - PassSimple edge_detect_ps_ = {"edge_detect_ps"}; - - TextureFromPool blend_weight_tx_ = {"blend_weight_tx"}; - Framebuffer blend_weight_fb_ = {"blend_weight_fb"}; - PassSimple blend_weight_ps_ = {"blend_weight_ps"}; - - PassSimple resolve_ps_ = {"resolve_ps"}; - - bool draw_wireframe_ = false; - float luma_weight_ = 1.0f; - bool anti_aliasing_enabled_ = true; - - public: - AntiAliasing(ShaderModule &shaders) : shaders_(shaders) - { - GPU_texture_update(smaa_search_tx_, GPU_DATA_UBYTE, searchTexBytes); - GPU_texture_update(smaa_area_tx_, GPU_DATA_UBYTE, areaTexBytes); - - GPU_texture_filter_mode(smaa_search_tx_, true); - GPU_texture_filter_mode(smaa_area_tx_, true); - } - - void init(const View3D *v3d, const Scene *scene) - { - if (v3d) { - draw_wireframe_ = (v3d->shading.type == OB_WIRE); - } - - luma_weight_ = scene->grease_pencil_settings.smaa_threshold; - anti_aliasing_enabled_ = true; // GPENCIL_SIMPLIFY_AA(scene); - } - - void begin_sync(TextureFromPool &color_tx, Framebuffer &scene_fb, TextureFromPool &reveal_tx) - { - /* TODO(fclem): No global access. */ - const float *size = DRW_viewport_size_get(); - const float *sizeinv = DRW_viewport_invert_size_get(); - const float4 metrics = {sizeinv[0], sizeinv[1], size[0], size[1]}; - - anti_aliasing_pass(color_tx, reveal_tx, metrics); - - /* Resolve pass. */ - PassSimple &pass = resolve_ps_; - pass.init(); - pass.framebuffer_set(&scene_fb); - pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM); - pass.shader_set(shaders_.static_shader_get(ANTIALIASING_RESOLVE)); - /** \note use color_tx as dummy if AA is disabled. */ - pass.bind_texture("blendTex", anti_aliasing_enabled_ ? &blend_weight_tx_ : &color_tx); - pass.bind_texture("colorTex", &color_tx); - pass.bind_texture("revealTex", &reveal_tx); - pass.push_constant("doAntiAliasing", anti_aliasing_enabled_); - pass.push_constant("onlyAlpha", draw_wireframe_); - pass.push_constant("viewportMetrics", metrics); - pass.draw_procedural(GPU_PRIM_TRIS, 1, 3); - } - - void draw(Manager &manager, const int2 render_resolution) - { - DRW_stats_group_start("Anti-Aliasing"); - - if (anti_aliasing_enabled_) { - edge_detect_tx_.acquire(render_resolution, GPU_RG8); - edge_detect_fb_.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(edge_detect_tx_)); - manager.submit(edge_detect_ps_); - - blend_weight_tx_.acquire(render_resolution, GPU_RGBA8); - blend_weight_fb_.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(blend_weight_tx_)); - manager.submit(blend_weight_ps_); - edge_detect_tx_.release(); - } - - manager.submit(resolve_ps_); - blend_weight_tx_.release(); - - DRW_stats_group_end(); - } - - private: - void anti_aliasing_pass(TextureFromPool &color_tx, - TextureFromPool &reveal_tx, - const float4 metrics) - { - if (!anti_aliasing_enabled_) { - return; - } - - /* Stage 1: Edge detection. */ - edge_detect_ps_.init(); - edge_detect_ps_.framebuffer_set(&edge_detect_fb_); - edge_detect_ps_.state_set(DRW_STATE_WRITE_COLOR); - edge_detect_ps_.shader_set(shaders_.static_shader_get(ANTIALIASING_EDGE_DETECT)); - edge_detect_ps_.bind_texture("colorTex", &color_tx); - edge_detect_ps_.bind_texture("revealTex", &reveal_tx); - edge_detect_ps_.push_constant("viewportMetrics", metrics); - edge_detect_ps_.push_constant("lumaWeight", luma_weight_); - edge_detect_ps_.clear_color(float4(0.0f)); - edge_detect_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); - - /* Stage 2: Blend Weight/Coord. */ - blend_weight_ps_.init(); - blend_weight_ps_.framebuffer_set(&blend_weight_fb_); - blend_weight_ps_.state_set(DRW_STATE_WRITE_COLOR); - blend_weight_ps_.shader_set(shaders_.static_shader_get(ANTIALIASING_BLEND_WEIGHT)); - blend_weight_ps_.bind_texture("edgesTex", &edge_detect_tx_); - blend_weight_ps_.bind_texture("areaTex", smaa_area_tx_); - blend_weight_ps_.bind_texture("searchTex", smaa_search_tx_); - blend_weight_ps_.push_constant("viewportMetrics", metrics); - blend_weight_ps_.clear_color(float4(0.0f)); - blend_weight_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); - } -}; - -} // namespace blender::draw::greasepencil diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.cc b/source/blender/draw/engines/gpencil/gpencil_cache_utils.cc index dd7c151b93e..af09f6c9971 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.cc +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.cc @@ -17,6 +17,7 @@ #include "BKE_gpencil_geom_legacy.h" #include "BKE_gpencil_legacy.h" +#include "BKE_grease_pencil.hh" #include "BKE_lib_id.hh" #include "BKE_object.hh" @@ -36,16 +37,18 @@ /** \name Object * \{ */ -GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob) +GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, + Object *ob, + const bool is_stroke_order_3d, + const std::optional> bounds) { using namespace blender; - bGPdata *gpd = (bGPdata *)ob->data; GPENCIL_tObject *tgp_ob = static_cast(BLI_memblock_alloc(pd->gp_object_pool)); tgp_ob->layers.first = tgp_ob->layers.last = nullptr; tgp_ob->vfx.first = tgp_ob->vfx.last = nullptr; tgp_ob->camera_z = dot_v3v3(pd->camera_z_axis, ob->object_to_world().location()); - tgp_ob->is_drawmode3d = (gpd->draw_mode == GP_DRAWMODE_3D) || pd->draw_depth_only; + tgp_ob->is_drawmode3d = is_stroke_order_3d || pd->draw_depth_only; tgp_ob->object_scale = mat4_to_scale(ob->object_to_world().ptr()); /* Check if any material with holdout flag enabled. */ @@ -66,8 +69,6 @@ GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob) * strokes not aligned with the object axes. Maybe we could try to * compute the minimum axis of all strokes. But this would be more * computationally heavy and should go into the GPData evaluation. */ - const std::optional> bounds = BKE_gpencil_data_minmax(gpd).value_or( - Bounds(float3(0))); float3 size = (bounds->max - bounds->min) * 0.5f; float3 center = math::midpoint(bounds->min, bounds->max); /* Convert bbox to matrix */ @@ -203,6 +204,28 @@ static float gpencil_layer_final_opacity_get(const GPENCIL_PrivateData *pd, return gpl->opacity; } +static float grease_pencil_layer_final_opacity_get(const GPENCIL_PrivateData *pd, + const Object *ob, + const GreasePencil &grease_pencil, + const blender::bke::greasepencil::Layer &layer) +{ + const bool is_obact = ((pd->obact) && (pd->obact == ob)); + const bool is_fade = (pd->fade_layer_opacity > -1.0f) && (is_obact) && + grease_pencil.is_layer_active(&layer); + + /* Defines layer opacity. For active object depends of layer opacity factor, and + * for no active object, depends if the fade grease pencil objects option is enabled. */ + if (!pd->is_render) { + if (is_obact && is_fade) { + return layer.opacity * pd->fade_layer_opacity; + } + if (!is_obact && (pd->fade_gp_object_opacity > -1.0f)) { + return layer.opacity * pd->fade_gp_object_opacity; + } + } + return layer.opacity; +} + static void gpencil_layer_final_tint_and_alpha_get(const GPENCIL_PrivateData *pd, const bGPdata *gpd, const bGPDlayer *gpl, @@ -253,6 +276,20 @@ static void gpencil_layer_random_color_get(const Object *ob, hsv_to_rgb_v(hsv, r_color); } +static void grease_pencil_layer_random_color_get(const Object *ob, + const blender::bke::greasepencil::Layer &layer, + float r_color[3]) +{ + const float hsv_saturation = 0.7f; + const float hsv_value = 0.6f; + + uint ob_hash = BLI_ghashutil_strhash_p_murmur(ob->id.name); + uint gpl_hash = BLI_ghashutil_strhash_p_murmur(layer.name().c_str()); + float hue = BLI_hash_int_01(ob_hash * gpl_hash); + const float hsv[3] = {hue, hsv_saturation, hsv_value}; + hsv_to_rgb_v(hsv, r_color); +} + GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd, const Object *ob, const bGPDlayer *gpl, @@ -433,4 +470,179 @@ GPENCIL_tLayer *gpencil_layer_cache_get(GPENCIL_tObject *tgp_ob, int number) return nullptr; } +GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_PrivateData *pd, + const Object *ob, + const blender::bke::greasepencil::Layer &layer, + std::optional /*onion_id*/, + GPENCIL_tObject *tgp_ob) + +{ + using namespace blender::bke::greasepencil; + const GreasePencil &grease_pencil = *static_cast(ob->data); + + const bool is_in_front = (ob->dtx & OB_DRAW_IN_FRONT); + /* Grease Pencil 3 doesn't have this. */ + const bool is_screenspace = false; + const bool override_vertcol = (pd->v3d_color_type != -1); + const bool is_vert_col_mode = (pd->v3d_color_type == V3D_SHADING_VERTEX_COLOR) || + (ob->mode == OB_MODE_VERTEX_PAINT) || pd->is_render; + const bool is_viewlayer_render = pd->is_render && !layer.view_layer_name().is_empty() && + STREQ(pd->view_layer->name, layer.view_layer_name().c_str()); + const bool disable_masks_render = is_viewlayer_render && + (layer.base.flag & GP_LAYER_DISABLE_MASKS_IN_VIEWLAYER) != 0; + bool is_masked = !disable_masks_render && layer.use_masks() && + !BLI_listbase_is_empty(&layer.masks); + + float vert_col_opacity = (override_vertcol) ? + (is_vert_col_mode ? pd->vertex_paint_opacity : 0.0f) : + pd->vertex_paint_opacity; + /* Negate thickness sign to tag that strokes are in screen space. + * Convert to world units (by default, 1 meter = 1000 pixels). */ + float thickness_scale = (is_screenspace) ? -1.0f : 1.0f / 1000.0f; + float layer_opacity = grease_pencil_layer_final_opacity_get(pd, ob, grease_pencil, layer); + + float4 layer_tint(0.0f); + float layer_alpha = pd->xray_alpha; + /* TODO: Onion skinning! */ + // gpencil_layer_final_tint_and_alpha_get(pd, gpd, gpl, gpf, layer_tint, &layer_alpha); + + /* Create the new layer descriptor. */ + GPENCIL_tLayer *tgp_layer = static_cast(BLI_memblock_alloc(pd->gp_layer_pool)); + BLI_LINKS_APPEND(&tgp_ob->layers, tgp_layer); + tgp_layer->layer_id = *grease_pencil.get_layer_index(layer); + tgp_layer->mask_bits = nullptr; + tgp_layer->mask_invert_bits = nullptr; + tgp_layer->blend_ps = nullptr; + + /* Masking: Go through mask list and extract valid masks in a bitmap. */ + if (is_masked) { + bool valid_mask = false; + /* WARNING: only #GP_MAX_MASKBITS amount of bits. + * TODO(fclem): Find a better system without any limitation. */ + tgp_layer->mask_bits = static_cast(BLI_memblock_alloc(pd->gp_maskbit_pool)); + tgp_layer->mask_invert_bits = static_cast( + BLI_memblock_alloc(pd->gp_maskbit_pool)); + BLI_bitmap_set_all(tgp_layer->mask_bits, false, GP_MAX_MASKBITS); + + LISTBASE_FOREACH (GreasePencilLayerMask *, mask, &layer.masks) { + if (mask->flag & GP_LAYER_MASK_HIDE) { + continue; + } + const TreeNode *node = grease_pencil.find_node_by_name(mask->layer_name); + if (node == nullptr) { + continue; + } + const Layer &mask_layer = node->as_layer(); + if ((&mask_layer == &layer) || !mask_layer.is_visible()) { + continue; + } + const int index = *grease_pencil.get_layer_index(mask_layer); + if (index < GP_MAX_MASKBITS) { + const bool invert = (mask->flag & GP_LAYER_MASK_INVERT) != 0; + BLI_BITMAP_SET(tgp_layer->mask_bits, index, true); + BLI_BITMAP_SET(tgp_layer->mask_invert_bits, index, invert); + valid_mask = true; + } + } + + if (valid_mask) { + pd->use_mask_fb = true; + } + else { + tgp_layer->mask_bits = nullptr; + } + is_masked = valid_mask; + } + + /* Blending: Force blending for masked layer. */ + if (is_masked || (layer.blend_mode != GP_LAYER_BLEND_NONE) || (layer_opacity < 1.0f)) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL; + switch (layer.blend_mode) { + case GP_LAYER_BLEND_NONE: + state |= DRW_STATE_BLEND_ALPHA_PREMUL; + break; + case GP_LAYER_BLEND_ADD: + state |= DRW_STATE_BLEND_ADD_FULL; + break; + case GP_LAYER_BLEND_SUBTRACT: + state |= DRW_STATE_BLEND_SUB; + break; + case GP_LAYER_BLEND_MULTIPLY: + case GP_LAYER_BLEND_DIVIDE: + case GP_LAYER_BLEND_HARDLIGHT: + state |= DRW_STATE_BLEND_MUL; + break; + } + + if (ELEM(layer.blend_mode, GP_LAYER_BLEND_SUBTRACT, GP_LAYER_BLEND_HARDLIGHT)) { + /* For these effect to propagate, we need a signed floating point buffer. */ + pd->use_signed_fb = true; + } + + tgp_layer->blend_ps = DRW_pass_create("GPencil Blend Layer", state); + + GPUShader *sh = GPENCIL_shader_layer_blend_get(); + DRWShadingGroup *grp = DRW_shgroup_create(sh, tgp_layer->blend_ps); + DRW_shgroup_uniform_int_copy(grp, "blendMode", layer.blend_mode); + DRW_shgroup_uniform_float_copy(grp, "blendOpacity", layer_opacity); + DRW_shgroup_uniform_texture_ref(grp, "colorBuf", &pd->color_layer_tx); + DRW_shgroup_uniform_texture_ref(grp, "revealBuf", &pd->reveal_layer_tx); + DRW_shgroup_uniform_texture_ref(grp, "maskBuf", (is_masked) ? &pd->mask_tx : &pd->dummy_tx); + DRW_shgroup_stencil_mask(grp, 0xFF); + DRW_shgroup_call_procedural_triangles(grp, nullptr, 1); + + if (layer.blend_mode == GP_LAYER_BLEND_HARDLIGHT) { + /* We cannot do custom blending on Multi-Target frame-buffers. + * Workaround by doing 2 passes. */ + grp = DRW_shgroup_create(sh, tgp_layer->blend_ps); + DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_MUL); + DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ADD_FULL); + DRW_shgroup_uniform_int_copy(grp, "blendMode", 999); + DRW_shgroup_call_procedural_triangles(grp, nullptr, 1); + } + + pd->use_layer_fb = true; + } + + /* Geometry pass */ + { + GPUTexture *depth_tex = (is_in_front) ? pd->dummy_tx : pd->scene_depth_tx; + GPUTexture **mask_tex = (is_masked) ? &pd->mask_tx : &pd->dummy_tx; + + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_BLEND_ALPHA_PREMUL; + /* For 2D mode, we render all strokes with uniform depth (increasing with stroke id). */ + state |= tgp_ob->is_drawmode3d ? DRW_STATE_DEPTH_LESS_EQUAL : DRW_STATE_DEPTH_GREATER; + /* Always write stencil. Only used as optimization for blending. */ + state |= DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; + + tgp_layer->geom_ps = DRW_pass_create("GPencil Layer", state); + + GPUShader *sh = GPENCIL_shader_geometry_get(); + DRWShadingGroup *grp = tgp_layer->base_shgrp = DRW_shgroup_create(sh, tgp_layer->geom_ps); + + DRW_shgroup_uniform_texture(grp, "gpSceneDepthTexture", depth_tex); + DRW_shgroup_uniform_texture_ref(grp, "gpMaskTexture", mask_tex); + DRW_shgroup_uniform_vec3_copy(grp, "gpNormal", tgp_ob->plane_normal); + DRW_shgroup_uniform_bool_copy(grp, "gpStrokeOrder3d", tgp_ob->is_drawmode3d); + DRW_shgroup_uniform_float_copy(grp, "gpThicknessScale", tgp_ob->object_scale); + /* Replaced by a modifier in GPv3. */ + DRW_shgroup_uniform_float_copy(grp, "gpThicknessOffset", 0.0f); + DRW_shgroup_uniform_float_copy(grp, "gpThicknessWorldScale", thickness_scale); + DRW_shgroup_uniform_float_copy(grp, "gpVertexColorOpacity", vert_col_opacity); + + /* If random color type, need color by layer. */ + float gpl_color[4]; + copy_v4_v4(gpl_color, layer_tint); + if (pd->v3d_color_type == V3D_SHADING_RANDOM_COLOR) { + grease_pencil_layer_random_color_get(ob, layer, gpl_color); + gpl_color[3] = 1.0f; + } + DRW_shgroup_uniform_vec4_copy(grp, "gpLayerTint", gpl_color); + + DRW_shgroup_uniform_float_copy(grp, "gpLayerOpacity", layer_alpha); + DRW_shgroup_stencil_mask(grp, 0xFF); + } + + return tgp_layer; +} /** \} */ diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.cc b/source/blender/draw/engines/gpencil/gpencil_draw_data.cc index d762f6ca533..97e80c65bdb 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_data.cc +++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.cc @@ -157,7 +157,10 @@ static MaterialGPencilStyle *gpencil_viewport_material_overrides( return gp_style; } -GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Object *ob, int *ofs) +GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, + Object *ob, + int *ofs, + const bool is_vertex_mode) { GPENCIL_MaterialPool *matpool = pd->last_material_pool; @@ -175,10 +178,8 @@ GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Obje } /* Force vertex color in solid mode with vertex paint mode. Same behavior as meshes. */ - bGPdata *gpd = (bGPdata *)ob->data; - int color_type = (pd->v3d_color_type != -1 && GPENCIL_VERTEX_MODE(gpd)) ? - V3D_SHADING_VERTEX_COLOR : - pd->v3d_color_type; + int color_type = (pd->v3d_color_type != -1 && is_vertex_mode) ? V3D_SHADING_VERTEX_COLOR : + pd->v3d_color_type; const eV3DShadingLightingMode lighting_mode = eV3DShadingLightingMode( (pd->v3d != nullptr) ? eV3DShadingLightingMode(pd->v3d->shading.light) : V3D_LIGHTING_STUDIO); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.cc b/source/blender/draw/engines/gpencil/gpencil_engine.cc deleted file mode 100644 index 6b8350d7253..00000000000 --- a/source/blender/draw/engines/gpencil/gpencil_engine.cc +++ /dev/null @@ -1,449 +0,0 @@ -/* SPDX-FileCopyrightText: 2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup draw - */ - -#include "BKE_gpencil_modifier_legacy.h" - -#include "BLI_listbase_wrapper.hh" - -#include "DEG_depsgraph_query.hh" - -#include "DNA_shader_fx_types.h" - -#include "DRW_engine.hh" -#include "DRW_render.hh" - -#include "ED_screen.hh" -#include "ED_view3d.hh" - -#include "GPU_capabilities.h" - -#include "IMB_imbuf_types.hh" - -#include "RE_pipeline.h" - -#include "draw_manager.hh" -#include "draw_pass.hh" - -#define GP_LIGHT -#include "gpencil_antialiasing.hh" -#include "gpencil_defines.h" -#include "gpencil_engine.h" -#include "gpencil_layer.hh" -#include "gpencil_light.hh" -#include "gpencil_material.hh" -#include "gpencil_object.hh" -#include "gpencil_shader.hh" -#include "gpencil_shader_shared.h" -#include "gpencil_vfx.hh" - -namespace blender::draw::greasepencil { - -using namespace draw; - -class Instance { - private: - ShaderModule &shaders; - LayerModule layers; - MaterialModule materials; - ObjectModule objects; - LightModule lights; - VfxModule vfx; - AntiAliasing anti_aliasing; - - /** Contains all gpencil objects in the scene as well as their effect sub-passes. */ - PassSortable main_ps_ = {"gp_main_ps"}; - - /** Contains all composited GPencil object. */ - TextureFromPool depth_tx_ = {"gp_depth_tx"}; - TextureFromPool color_tx_ = {"gp_color_tx"}; - TextureFromPool reveal_tx_ = {"gp_reveal_tx"}; - Framebuffer main_fb_ = {"gp_main_fb"}; - - /** Underlying scene pixel. Used to composite the output of the grease pencil render onto the - * scene (including merging the depth buffers). */ - Framebuffer scene_fb_ = {"gp_scene_fb"}; - - /** Texture format for all intermediate buffers. */ - eGPUTextureFormat texture_format_ = GPU_RGBA16F; - - UniformBuffer scene_buf_; - - /** Dummy textures. */ - static constexpr float dummy_px_[4] = {1.0f, 0.0f, 1.0f, 1.0f}; - Texture dummy_depth_tx_ = {"dummy_depth", - GPU_DEPTH_COMPONENT32F, - GPU_TEXTURE_USAGE_SHADER_READ, - int2(1), - (float *)dummy_px_}; - Texture dummy_color_tx_ = { - "dummy_color", GPU_RGBA16F, GPU_TEXTURE_USAGE_SHADER_READ, int2(1), (float *)dummy_px_}; - - /** Scene depth used for manual depth testing. Default to dummy depth to skip depth test. */ - GPUTexture *scene_depth_tx_ = dummy_depth_tx_; - - /** Context. */ - Depsgraph *depsgraph_ = nullptr; - Object *camera_ = nullptr; - Manager *manager_ = nullptr; - draw::View view_ = {"MainView"}; - - /** \note Needs not to be temporary variable since it is dereferenced later. */ - std::array clear_colors_ = {float4(0.0f, 0.0f, 0.0f, 0.0f), - float4(1.0f, 1.0f, 1.0f, 1.0f)}; - - public: - Instance() - : shaders(*ShaderModule::module_get()), - objects(layers, materials, shaders), - vfx(shaders), - anti_aliasing(shaders){}; - - void init(Depsgraph *depsgraph, - Manager *manager, - const DRWView *viewport_draw_view, - const View3D *v3d, - const RegionView3D *rv3d) - { - depsgraph_ = depsgraph; - manager_ = manager; - if (viewport_draw_view != nullptr) { - view_.sync(viewport_draw_view); - } - - const Scene *scene = DEG_get_evaluated_scene(depsgraph_); - - const bool is_viewport = (v3d != nullptr); - - if (is_viewport) { - /* Use lower precision for viewport. */ - texture_format_ = GPU_R11F_G11F_B10F; - camera_ = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : nullptr; - } - - objects.init(v3d, scene); - lights.init(v3d); - /* TODO(@fclem): VFX. */ - // vfx.init(use_vfx_, camera_, rv3d); - anti_aliasing.init(v3d, scene); - } - - void begin_sync() - { - objects.begin_sync(depsgraph_, view_); - layers.begin_sync(); - materials.begin_sync(); - lights.begin_sync(depsgraph_); - - main_ps_.init(); - PassMain::Sub &sub = main_ps_.sub("InitSubpass", -FLT_MAX); - sub.framebuffer_set(&main_fb_); - sub.clear_multi(clear_colors_); - /* TODO(fclem): Textures. */ - sub.bind_texture(GPENCIL_SCENE_DEPTH_TEX_SLOT, &dummy_depth_tx_); - sub.bind_texture(GPENCIL_MASK_TEX_SLOT, &dummy_color_tx_); - sub.bind_texture(GPENCIL_FILL_TEX_SLOT, &dummy_color_tx_); - sub.bind_texture(GPENCIL_STROKE_TEX_SLOT, &dummy_color_tx_); - sub.bind_ubo(GPENCIL_SCENE_SLOT, &scene_buf_); - objects.bind_resources(sub); - layers.bind_resources(sub); - materials.bind_resources(sub); - lights.bind_resources(sub); - - anti_aliasing.begin_sync(color_tx_, scene_fb_, reveal_tx_); - } - - void object_sync(ObjectRef &object_ref) - { - switch (object_ref.object->type) { - case OB_GREASE_PENCIL: - objects.sync_grease_pencil( - *manager_, object_ref, main_fb_, scene_fb_, depth_tx_, main_ps_); - break; - case OB_LAMP: - lights.sync(object_ref); - break; - default: - break; - } - } - - void end_sync() - { - objects.end_sync(); - layers.end_sync(); - materials.end_sync(); - lights.end_sync(); - } - - void render_sync(RenderEngine *engine, Depsgraph *depsgraph) - { - /* TODO: Remove old draw manager calls. */ - DRW_cache_restart(); - - manager_->begin_sync(); - - begin_sync(); - - auto object_sync_render = - [](void *vedata, Object *ob, RenderEngine * /*engine*/, Depsgraph * /*depsgraph*/) { - Instance &inst = *reinterpret_cast(vedata); - ObjectRef ob_ref = DRW_object_ref_get(ob); - inst.object_sync(ob_ref); - }; - - /* HACK: We pass `this` here so we have access to the `Instance` in `object_sync_render`. */ - DRW_render_object_iter(this, engine, depsgraph, object_sync_render); - - end_sync(); - - manager_->end_sync(); - - /* TODO: Remove old draw manager calls. */ - DRW_render_instance_buffer_finish(); - } - - void draw(GPUTexture *dst_color_tx, GPUTexture *dst_depth_tx, const int2 render_resolution) - { - if (!objects.scene_has_visible_gpencil_object()) { - return; - } - - scene_fb_.ensure(GPU_ATTACHMENT_TEXTURE(dst_depth_tx), GPU_ATTACHMENT_TEXTURE(dst_color_tx)); - - depth_tx_.acquire(render_resolution, GPU_DEPTH24_STENCIL8); - color_tx_.acquire(render_resolution, texture_format_); - reveal_tx_.acquire(render_resolution, texture_format_); - main_fb_.ensure(GPU_ATTACHMENT_TEXTURE(depth_tx_), - GPU_ATTACHMENT_TEXTURE(color_tx_), - GPU_ATTACHMENT_TEXTURE(reveal_tx_)); - - scene_buf_.render_size = float2(render_resolution); - scene_buf_.push_update(); - - objects.acquire_temporary_buffers(render_resolution, texture_format_); - - manager_->submit(main_ps_, view_); - - objects.release_temporary_buffers(); - - anti_aliasing.draw(*manager_, render_resolution); - - depth_tx_.release(); - color_tx_.release(); - reveal_tx_.release(); - } - - draw::View &view() - { - return view_; - } -}; - -} // namespace blender::draw::greasepencil - -/* -------------------------------------------------------------------- */ -/** \name Interface with legacy C DRW manager - * \{ */ - -using namespace blender; - -struct GPENCIL_NEXT_Data { - DrawEngineType *engine_type; - DRWViewportEmptyList *fbl; - DRWViewportEmptyList *txl; - DRWViewportEmptyList *psl; - DRWViewportEmptyList *stl; - draw::greasepencil::Instance *instance; - - char info[GPU_INFO_SIZE]; -}; - -static void gpencil_engine_init(void *vedata) -{ - GPENCIL_NEXT_Data *ved = reinterpret_cast(vedata); - if (ved->instance == nullptr) { - ved->instance = new draw::greasepencil::Instance(); - } - - draw::Manager *manager = DRW_manager_get(); - const DRWContextState *ctx_state = DRW_context_state_get(); - const DRWView *default_view = DRW_view_default_get(); - - ved->instance->init( - ctx_state->depsgraph, manager, default_view, ctx_state->v3d, ctx_state->rv3d); -} - -static void gpencil_draw_scene(void *vedata) -{ - GPENCIL_NEXT_Data *ved = reinterpret_cast(vedata); - if (DRW_state_is_select() || DRW_state_is_depth()) { - return; - } - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - const DRWView *default_view = DRW_view_default_get(); - const float2 viewport_size = DRW_viewport_size_get(); - ved->instance->view().sync(default_view); - ved->instance->draw(dtxl->color, dtxl->depth, int2(viewport_size)); -} - -static void gpencil_cache_init(void *vedata) -{ - reinterpret_cast(vedata)->instance->begin_sync(); -} - -static void gpencil_cache_populate(void *vedata, Object *object) -{ - draw::ObjectRef ref; - ref.object = object; - ref.dupli_object = DRW_object_get_dupli(object); - ref.dupli_parent = DRW_object_get_dupli_parent(object); - - reinterpret_cast(vedata)->instance->object_sync(ref); -} - -static void gpencil_cache_finish(void *vedata) -{ - reinterpret_cast(vedata)->instance->end_sync(); -} - -static void gpencil_instance_free(void *instance) -{ - delete reinterpret_cast(instance); -} - -static void gpencil_engine_free() -{ - blender::draw::greasepencil::ShaderModule::module_free(); -} - -/** Get the color and depth textures of the render result in the render layer. */ -static void get_render_result_textures(RenderEngine *engine, - RenderLayer *render_layer, - const draw::View &view, - const int2 render_resolution, - draw::Texture &r_color_tx, - draw::Texture &r_depth_tx) -{ - /* Create depth texture & color texture from render result. */ - const char *viewname = RE_GetActiveRenderView(engine->re); - RenderPass *rpass_z_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname); - RenderPass *rpass_col_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname); - - float *pix_z = (rpass_z_src) ? rpass_z_src->ibuf->float_buffer.data : nullptr; - float *pix_col = (rpass_col_src) ? rpass_col_src->ibuf->float_buffer.data : nullptr; - - if (!pix_z || !pix_col) { - RE_engine_set_error_message(engine, - "Warning: To render grease pencil, enable Combined and Z passes."); - } - - if (pix_z) { - /* Depth need to be remapped to [0..1] range. */ - pix_z = static_cast(MEM_dupallocN(pix_z)); - - int pix_num = rpass_z_src->rectx * rpass_z_src->recty; - - if (view.is_persp()) { - for (int i = 0; i < pix_num; i++) { - pix_z[i] = (-view.winmat()[3][2] / -pix_z[i]) - view.winmat()[2][2]; - pix_z[i] = clamp_f(pix_z[i] * 0.5f + 0.5f, 0.0f, 1.0f); - } - } - else { - /* Keep in mind, near and far distance are negatives. */ - float near = view.near_clip(); - float far = view.far_clip(); - float range_inv = 1.0f / fabsf(far - near); - for (int i = 0; i < pix_num; i++) { - pix_z[i] = (pix_z[i] + near) * range_inv; - pix_z[i] = clamp_f(pix_z[i], 0.0f, 1.0f); - } - } - } - - /* FIXME(fclem): we have a precision loss in the depth buffer because of this re-upload. - * Find where it comes from! */ - const eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ; - r_depth_tx.ensure_2d(GPU_DEPTH_COMPONENT24, render_resolution, usage, pix_z); - r_color_tx.ensure_2d(GPU_RGBA16F, render_resolution, usage, pix_col); -} - -static void gpencil_render_to_image(void * /*vedata*/, - RenderEngine *engine, - RenderLayer *render_layer, - const rcti * /*rect*/) -{ - draw::greasepencil::Instance instance; - draw::Manager &manager = *DRW_manager_get(); - - Render *render = engine->re; - Depsgraph *depsgraph = DRW_context_state_get()->depsgraph; - Object *camera_original_ob = RE_GetCamera(render); - const char *viewname = RE_GetActiveRenderView(render); - const int2 render_resolution = int2(engine->resolution_x, engine->resolution_y); - - instance.init(depsgraph, &manager, nullptr, nullptr, nullptr); - - float4x4 viewinv, winmat; - Object *camera_eval = DEG_get_evaluated_object(depsgraph, camera_original_ob); - RE_GetCameraModelMatrix(render, camera_eval, viewinv.ptr()); - float4x4 viewmat = math::invert(viewinv); - RE_GetCameraWindow(render, camera_eval, winmat.ptr()); - - instance.view().sync(viewmat, winmat); - instance.render_sync(engine, depsgraph); - - draw::Texture color_tx; - draw::Texture depth_tx; - /* TODO: Support `R_BORDER` render mode. */ - get_render_result_textures( - engine, render_layer, instance.view(), render_resolution, color_tx, depth_tx); - - instance.draw(color_tx, depth_tx, render_resolution); - - RenderPass *rp = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname); - if (!rp) { - return; - } - float *result = reinterpret_cast(color_tx.read(GPU_DATA_FLOAT)); - - if (result) { - BLI_mutex_lock(&engine->update_render_passes_mutex); - /* WORKAROUND: We use texture read to avoid using a frame-buffer to get the render result. - * However, on some implementation, we need a buffer with a few extra bytes for the read to - * happen correctly (see #GLTexture::read()). So we need a custom memory allocation. */ - /* Avoid `memcpy()`, replace the pointer directly. */ - RE_pass_set_buffer_data(rp, result); - BLI_mutex_unlock(&engine->update_render_passes_mutex); - } -} - -extern "C" { - -static const DrawEngineDataSize gpencil_data_size = DRW_VIEWPORT_DATA_SIZE(GPENCIL_NEXT_Data); - -DrawEngineType draw_engine_gpencil_next_type = { - /*next*/ nullptr, - /*prev*/ nullptr, - /*idname*/ N_("Gpencil"), - /*vedata_size*/ &gpencil_data_size, - /*engine_init*/ &gpencil_engine_init, - /*engine_free*/ &gpencil_engine_free, - /*instance_free*/ &gpencil_instance_free, - /*cache_init*/ &gpencil_cache_init, - /*cache_populate*/ &gpencil_cache_populate, - /*cache_finish*/ &gpencil_cache_finish, - /*draw_scene*/ &gpencil_draw_scene, - /*view_update*/ nullptr, - /*id_update*/ nullptr, - /*render_to_image*/ &gpencil_render_to_image, - /*store_metadata*/ nullptr, -}; -} - -/** \} */ diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index ab4d9ea4309..5f8501033c6 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -13,6 +13,9 @@ #include "DRW_render.hh" #include "BLI_bitmap.h" +#include "BLI_bounds.hh" + +#include "BKE_grease_pencil.hh" #include "GPU_batch.h" @@ -26,7 +29,6 @@ extern "C" { #include "gpencil_shader_shared.h" extern DrawEngineType draw_engine_gpencil_type; -extern DrawEngineType draw_engine_gpencil_next_type; struct GPENCIL_Data; struct GPENCIL_StorageList; @@ -322,7 +324,10 @@ typedef struct GPENCIL_PrivateData { /* geometry batch cache functions */ struct GpencilBatchCache *gpencil_batch_cache_get(struct Object *ob, int cfra); -GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob); +GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, + Object *ob, + bool is_stroke_order_3d, + std::optional> bounds); void gpencil_object_cache_sort(GPENCIL_PrivateData *pd); GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd, @@ -332,12 +337,20 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd, GPENCIL_tObject *tgp_ob); GPENCIL_tLayer *gpencil_layer_cache_get(GPENCIL_tObject *tgp_ob, int number); +GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_PrivateData *pd, + const Object *ob, + const blender::bke::greasepencil::Layer &layer, + std::optional onion_id, + GPENCIL_tObject *tgp_ob); /** * Creates a linked list of material pool containing all materials assigned for a given object. * We merge the material pools together if object does not contain a huge amount of materials. * Also return an offset to the first material of the object in the UBO. */ -GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Object *ob, int *ofs); +GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, + Object *ob, + int *ofs, + bool is_vertex_mode); void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool, int mat_id, struct GPUTexture **r_tex_stroke, @@ -353,7 +366,10 @@ GPENCIL_LightPool *gpencil_light_pool_add(GPENCIL_PrivateData *pd); GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_PrivateData *pd, Object *ob); /* effects */ -void gpencil_vfx_cache_populate(GPENCIL_Data *vedata, Object *ob, GPENCIL_tObject *tgp_ob); +void gpencil_vfx_cache_populate(GPENCIL_Data *vedata, + Object *ob, + GPENCIL_tObject *tgp_ob, + const bool is_edit_mode); /* Shaders */ struct GPUShader *GPENCIL_shader_antialiasing(int stage); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine_c.cc b/source/blender/draw/engines/gpencil/gpencil_engine_c.cc index b1f0ff32e8a..de48df2161f 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine_c.cc +++ b/source/blender/draw/engines/gpencil/gpencil_engine_c.cc @@ -8,8 +8,12 @@ #include "DRW_engine.hh" #include "DRW_render.hh" +#include "BKE_curves.hh" +#include "BKE_gpencil_geom_legacy.h" #include "BKE_gpencil_legacy.h" #include "BKE_gpencil_modifier_legacy.h" +#include "BKE_grease_pencil.h" +#include "BKE_grease_pencil.hh" #include "BKE_lib_id.hh" #include "BKE_main.hh" #include "BKE_object.hh" @@ -22,6 +26,7 @@ #include "BLI_link_utils.h" #include "BLI_listbase.h" #include "BLI_memblock.h" +#include "BLI_virtual_array.hh" #include "DNA_camera_types.h" #include "DNA_gpencil_legacy_types.h" @@ -35,6 +40,7 @@ #include "DEG_depsgraph_query.hh" +#include "ED_grease_pencil.hh" #include "ED_screen.hh" #include "ED_view3d.hh" @@ -113,8 +119,10 @@ void GPENCIL_engine_init(void *ved) stl->pd->v3d_color_type = (v3d->shading.type == OB_SOLID) ? v3d->shading.color_type : -1; /* Special case: If Vertex Paint mode, use always Vertex mode. */ - if (v3d->shading.type == OB_SOLID && ctx->obact && ctx->obact->type == OB_GPENCIL_LEGACY && - ctx->obact->mode == OB_MODE_VERTEX_GPENCIL_LEGACY) + if (v3d->shading.type == OB_SOLID && ctx->obact && + ((ctx->obact->type == OB_GPENCIL_LEGACY && + ctx->obact->mode == OB_MODE_VERTEX_GPENCIL_LEGACY) || + (ctx->obact->type == OB_GREASE_PENCIL && ctx->obact->mode == OB_MODE_VERTEX_PAINT))) { stl->pd->v3d_color_type = V3D_SHADING_VERTEX_COLOR; } @@ -559,7 +567,10 @@ static void gpencil_sbuffer_cache_populate_fast(GPENCIL_Data *vedata, gpIterPopu GPUTexture *depth_texture = iter->pd->scene_depth_tx; GPENCIL_tObject *last_tgp_ob = iter->pd->tobjects.last; /* Create another temp object that only contain the stroke. */ - iter->tgp_ob = gpencil_object_cache_add(iter->pd, iter->ob); + const std::optional> bounds = BKE_gpencil_data_minmax(gpd).value_or( + blender::Bounds(float3(0))); + iter->tgp_ob = gpencil_object_cache_add( + iter->pd, iter->ob, (gpd->draw_mode == GP_DRAWMODE_3D), bounds); /* Remove from the main list. */ iter->pd->tobjects.last = last_tgp_ob; last_tgp_ob->next = nullptr; @@ -582,13 +593,202 @@ static void gpencil_sbuffer_cache_populate_fast(GPENCIL_Data *vedata, gpIterPopu gpencil_stroke_cache_populate(nullptr, nullptr, iter->pd->sbuffer_stroke, iter); gpencil_drawcall_flush(iter); - gpencil_vfx_cache_populate(vedata, iter->ob, iter->tgp_ob); + gpencil_vfx_cache_populate( + vedata, iter->ob, iter->tgp_ob, (gpd != nullptr && GPENCIL_ANY_EDIT_MODE(gpd))); /* Restore state. */ iter->do_sbuffer_call = 0; iter->pd->scene_depth_tx = depth_texture; } +static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData *pd, + GPENCIL_TextureList *txl, + Object *ob) +{ + using namespace blender; + using namespace blender::ed::greasepencil; + using namespace blender::bke::greasepencil; + GreasePencil &grease_pencil = *static_cast(ob->data); + const bool is_vertex_mode = (ob->mode & OB_MODE_VERTEX_PAINT) != 0; + const std::optional> bounds = grease_pencil.bounds_min_max_eval(); + + const bool use_stroke_order_3d = (grease_pencil.flag & GREASE_PENCIL_STROKE_ORDER_3D) != 0; + GPENCIL_tObject *tgp_ob = gpencil_object_cache_add(pd, ob, use_stroke_order_3d, bounds); + + int mat_ofs = 0; + GPENCIL_MaterialPool *matpool = gpencil_material_pool_create(pd, ob, &mat_ofs, is_vertex_mode); + + GPUTexture *tex_fill = txl->dummy_texture; + GPUTexture *tex_stroke = txl->dummy_texture; + + GPUBatch *iter_geom = nullptr; + DRWShadingGroup *grp; + int vfirst = 0; + int vcount = 0; + + const auto drawcall_flush = [&]() { +#if !DISABLE_BATCHING + if (iter_geom != nullptr) { + DRW_shgroup_call_range(grp, ob, iter_geom, vfirst, vcount); + } +#endif + iter_geom = nullptr; + vfirst = -1; + vcount = 0; + }; + + const auto drawcall_add = [&](GPUBatch *draw_geom, int v_first, int v_count) { +#if DISABLE_BATCHING + DRW_shgroup_call_range(grp, ob, geom, v_first, v_count); + return; +#endif + int last = vfirst + vcount; + /* Interrupt draw-call grouping if the sequence is not consecutive. */ + if ((draw_geom != iter_geom) || (v_first - last > 0)) { + drawcall_flush(); + } + iter_geom = draw_geom; + if (vfirst == -1) { + vfirst = v_first; + } + vcount = v_first + v_count - vfirst; + }; + + int t_offset = 0; + const Vector drawings = retrieve_visible_drawings(*pd->scene, grease_pencil); + const Span layers = grease_pencil.layers(); + for (const DrawingInfo info : drawings) { + const Layer &layer = *layers[info.layer_index]; + + drawcall_flush(); + + GPENCIL_tLayer *tgp_layer = grease_pencil_layer_cache_add(pd, ob, layer, {}, tgp_ob); + + const bool use_lights = pd->use_lighting && + ((layer.base.flag & GP_LAYER_TREE_NODE_USE_LIGHTS) != 0) && + (ob->dtx & OB_USE_GPENCIL_LIGHTS); + + GPUUniformBuf *lights_ubo = (use_lights) ? pd->global_light_pool->ubo : + pd->shadeless_light_pool->ubo; + + GPUUniformBuf *ubo_mat; + gpencil_material_resources_get(matpool, 0, nullptr, nullptr, &ubo_mat); + + grp = tgp_layer->base_shgrp; + DRW_shgroup_uniform_block(grp, "gp_lights", lights_ubo); + DRW_shgroup_uniform_block(grp, "gp_materials", ubo_mat); + DRW_shgroup_uniform_texture(grp, "gpFillTexture", tex_fill); + DRW_shgroup_uniform_texture(grp, "gpStrokeTexture", tex_stroke); + DRW_shgroup_uniform_int_copy(grp, "gpMaterialOffset", mat_ofs); + /* Since we don't use the sbuffer in GPv3, this is always 0. */ + DRW_shgroup_uniform_float_copy(grp, "gpStrokeIndexOffset", 0.0f); + DRW_shgroup_uniform_vec2_copy(grp, "viewportSize", DRW_viewport_size_get()); + + const bke::CurvesGeometry &curves = info.drawing.strokes(); + const OffsetIndices points_by_curve = curves.points_by_curve(); + const bke::AttributeAccessor attributes = curves.attributes(); + const VArray stroke_materials = *attributes.lookup_or_default( + "material_index", bke::AttrDomain::Curve, 0); + const VArray cyclic = *attributes.lookup_or_default( + "cyclic", bke::AttrDomain::Curve, false); + + IndexMaskMemory memory; + const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( + *ob, info.drawing, memory); + + visible_strokes.foreach_index([&](const int stroke_i) { + const IndexRange points = points_by_curve[stroke_i]; + const int material_index = stroke_materials[stroke_i]; + MaterialGPencilStyle *gp_style = BKE_object_material_get(ob, material_index + 1)->gp_style; + + const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; + const bool show_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0); + const bool show_fill = (points.size() >= 3) && + ((gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0) && + (!pd->simplify_fill); + const bool only_lines = !ELEM(ob->mode, + OB_MODE_PAINT_GREASE_PENCIL, + OB_MODE_WEIGHT_PAINT, + OB_MODE_VERTEX_PAINT) && + info.frame_number != pd->cfra && pd->use_multiedit_lines_only; + /* bool is_onion = gpl && gpf && gpf->runtime.onion_id != 0; */ + const bool is_onion = false; + const bool hide_onion = is_onion && ((gp_style->flag & GP_MATERIAL_HIDE_ONIONSKIN) != 0); + + const int num_stroke_triangles = (points.size() >= 3) ? (points.size() - 2) : 0; + const int num_stroke_vertices = (points.size() + + int(cyclic[stroke_i] && (points.size() >= 3))); + + const bool skip_stroke = hide_material || (!show_stroke && !show_fill) || + (only_lines && !is_onion) || hide_onion; + + if (skip_stroke) { + t_offset += num_stroke_triangles; + t_offset += num_stroke_vertices * 2; + return; + } + + GPUUniformBuf *new_ubo_mat; + GPUTexture *new_tex_fill = nullptr; + GPUTexture *new_tex_stroke = nullptr; + gpencil_material_resources_get( + matpool, mat_ofs + material_index, &new_tex_stroke, &new_tex_fill, &new_ubo_mat); + + bool resource_changed = (ubo_mat != new_ubo_mat) || + (new_tex_fill && (new_tex_fill != tex_fill)) || + (new_tex_stroke && (new_tex_stroke != tex_stroke)); + + if (resource_changed) { + drawcall_flush(); + + grp = DRW_shgroup_create_sub(grp); + if (new_ubo_mat != ubo_mat) { + DRW_shgroup_uniform_block(grp, "gp_materials", new_ubo_mat); + ubo_mat = new_ubo_mat; + } + if (new_tex_fill) { + DRW_shgroup_uniform_texture(grp, "gpFillTexture", new_tex_fill); + tex_fill = new_tex_fill; + } + if (new_tex_stroke) { + DRW_shgroup_uniform_texture(grp, "gpStrokeTexture", new_tex_stroke); + tex_stroke = new_tex_stroke; + } + } + + GPUBatch *geom = draw::DRW_cache_grease_pencil_get(pd->scene, ob); + if (iter_geom != geom) { + drawcall_flush(); + + GPUVertBuf *position_tx = draw::DRW_cache_grease_pencil_position_buffer_get(pd->scene, ob); + GPUVertBuf *color_tx = draw::DRW_cache_grease_pencil_color_buffer_get(pd->scene, ob); + DRW_shgroup_buffer_texture(grp, "gp_pos_tx", position_tx); + DRW_shgroup_buffer_texture(grp, "gp_col_tx", color_tx); + } + + if (show_fill) { + int v_first = t_offset * 3; + int v_count = num_stroke_triangles * 3; + drawcall_add(geom, v_first, v_count); + } + + t_offset += num_stroke_triangles; + + if (show_stroke) { + int v_first = t_offset * 3; + int v_count = num_stroke_vertices * 2 * 3; + drawcall_add(geom, v_first, v_count); + } + + t_offset += num_stroke_vertices * 2; + }); + } + + drawcall_flush(); + + return tgp_ob; +} + void GPENCIL_cache_populate(void *ved, Object *ob) { GPENCIL_Data *vedata = (GPENCIL_Data *)ved; @@ -602,16 +802,18 @@ void GPENCIL_cache_populate(void *ved, Object *ob) } if (ob->data && (ob->type == OB_GPENCIL_LEGACY) && (ob->dt >= OB_SOLID)) { + bGPdata *gpd = (bGPdata *)ob->data; + const std::optional> bounds = BKE_gpencil_data_minmax(gpd).value_or( + blender::Bounds(float3(0))); gpIterPopulateData iter = {nullptr}; iter.ob = ob; iter.pd = pd; - iter.tgp_ob = gpencil_object_cache_add(pd, ob); - iter.matpool = gpencil_material_pool_create(pd, ob, &iter.mat_ofs); + iter.tgp_ob = gpencil_object_cache_add(pd, ob, (gpd->draw_mode == GP_DRAWMODE_3D), bounds); + iter.matpool = gpencil_material_pool_create(pd, ob, &iter.mat_ofs, GPENCIL_VERTEX_MODE(gpd)); iter.tex_fill = txl->dummy_texture; iter.tex_stroke = txl->dummy_texture; /* Special case for rendering onion skin. */ - bGPdata *gpd = (bGPdata *)ob->data; bool do_onion = (!pd->is_render) ? pd->do_onion : (gpd->onion_flag & GP_ONION_GHOST_ALWAYS); gpd->runtime.playing = short(pd->playing); @@ -646,12 +848,18 @@ void GPENCIL_cache_populate(void *ved, Object *ob) gpencil_sbuffer_cache_populate(&iter); } - gpencil_vfx_cache_populate(vedata, ob, iter.tgp_ob); + gpencil_vfx_cache_populate( + vedata, ob, iter.tgp_ob, (gpd != nullptr && GPENCIL_ANY_EDIT_MODE(gpd))); if (pd->do_fast_drawing) { gpencil_sbuffer_cache_populate_fast(vedata, &iter); } } + else if (ob->data && (ob->type == OB_GREASE_PENCIL) && (ob->dt >= OB_SOLID)) { + GPENCIL_tObject *tgp_ob = grease_pencil_object_cache_populate(pd, txl, ob); + gpencil_vfx_cache_populate( + vedata, ob, tgp_ob, ELEM(ob->mode, OB_MODE_EDIT, OB_MODE_SCULPT, OB_MODE_WEIGHT_PAINT)); + } if (ob->type == OB_LAMP && pd->use_lights) { gpencil_light_pool_populate(pd->global_light_pool, ob); @@ -928,7 +1136,7 @@ void GPENCIL_draw_scene(void *ved) /* Fade 3D objects. */ if ((!pd->is_render) && (pd->fade_3d_object_opacity > -1.0f) && (pd->obact != nullptr) && - (pd->obact->type == OB_GPENCIL_LEGACY)) + (ELEM(pd->obact->type, OB_GPENCIL_LEGACY, OB_GREASE_PENCIL))) { float background_color[3]; ED_view3d_background_color_get(pd->scene, pd->v3d, background_color); diff --git a/source/blender/draw/engines/gpencil/gpencil_layer.hh b/source/blender/draw/engines/gpencil/gpencil_layer.hh deleted file mode 100644 index f9fe3e06e7d..00000000000 --- a/source/blender/draw/engines/gpencil/gpencil_layer.hh +++ /dev/null @@ -1,69 +0,0 @@ -/* SPDX-FileCopyrightText: 2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup draw - */ - -#pragma once - -#include "BKE_grease_pencil.hh" -#include "DRW_gpu_wrapper.hh" -#include "DRW_render.hh" - -#include "draw_manager.hh" -#include "draw_pass.hh" - -namespace blender::draw::greasepencil { - -using namespace draw; - -class LayerModule { - private: - /** Contains all Objects in the scene. Indexed by gpObject.layer_offset + layer_id. */ - StorageVectorBuffer layers_buf_ = "gp_layers_buf"; - - public: - void begin_sync() - { - layers_buf_.clear(); - } - - void sync(const Object * /*object*/, - const bke::greasepencil::Layer &layer, - bool &do_layer_blending) - { - /* TODO(fclem): All of this is placeholder. */ - gpLayer gp_layer; - // gp_layer.vertex_color_opacity = 0.0f; unused - gp_layer.thickness_offset = 0.0f; - gp_layer.tint = float4(1.0f, 1.0f, 1.0f, 0.0f); - gp_layer.stroke_index_offset = 0.0f; - - gp_layer.opacity = layer.opacity; - - if (layer.opacity != 1.0f) { - do_layer_blending = true; - } - - layers_buf_.append(gp_layer); - } - - void end_sync() - { - layers_buf_.push_update(); - } - - void bind_resources(PassMain::Sub &sub) - { - sub.bind_ssbo(GPENCIL_LAYER_SLOT, &layers_buf_); - } - - uint object_offset_get() const - { - return layers_buf_.size(); - } -}; - -} // namespace blender::draw::greasepencil diff --git a/source/blender/draw/engines/gpencil/gpencil_light.hh b/source/blender/draw/engines/gpencil/gpencil_light.hh deleted file mode 100644 index 45eb0434513..00000000000 --- a/source/blender/draw/engines/gpencil/gpencil_light.hh +++ /dev/null @@ -1,131 +0,0 @@ -/* SPDX-FileCopyrightText: 2022 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup draw - */ - -#pragma once - -#include "BKE_gpencil_legacy.h" -#include "BKE_image.h" -#include "DRW_gpu_wrapper.hh" -#include "DRW_render.hh" - -#include "draw_manager.hh" -#include "draw_pass.hh" - -namespace blender::draw::greasepencil { - -using namespace draw; - -class LightModule { - private: - /** Contains all lights in the scene. */ - StorageVectorBuffer lights_buf_ = "gp_lights_buf"; - - float studiolight_intensity_ = 1.0f; - bool use_scene_lights_ = true; - bool use_scene_world_ = true; - - public: - void init(const View3D *v3d) - { - if (v3d != nullptr) { - use_scene_lights_ = V3D_USES_SCENE_LIGHTS(v3d); - use_scene_world_ = V3D_USES_SCENE_WORLD(v3d); - studiolight_intensity_ = v3d->shading.studiolight_intensity; - } - } - - void begin_sync(Depsgraph *depsgraph) - { - lights_buf_.clear(); - - World *world = DEG_get_evaluated_scene(depsgraph)->world; - if (world != nullptr && use_scene_world_) { - ambient_sync(float3(world->horr, world->horg, world->horb)); - } - else { - ambient_sync(float3(studiolight_intensity_)); - } - } - - void sync(ObjectRef &object_ref) - { - if (!use_scene_lights_) { - return; - } - const Object *ob = object_ref.object; - const Light *la = static_cast(ob->data); - - float light_power; - if (la->type == LA_AREA) { - light_power = 1.0f / (4.0f * M_PI); - } - else if (ELEM(la->type, LA_SPOT, LA_LOCAL)) { - light_power = 1.0f / (4.0f * M_PI * M_PI); - } - else { - light_power = 1.0f / M_PI; - } - - gpLight light; - float4x4 &mat = *reinterpret_cast(&light.right); - switch (la->type) { - case LA_SPOT: - light.type = GP_LIGHT_TYPE_SPOT; - light.spot_size = cosf(la->spotsize * 0.5f); - light.spot_blend = (1.0f - light.spot_size) * la->spotblend; - mat = ob->world_to_object(); - break; - case LA_AREA: - /* Simulate area lights using a spot light. */ - light.type = GP_LIGHT_TYPE_SPOT; - light.spot_size = cosf(M_PI_2); - light.spot_blend = (1.0f - light.spot_size) * 1.0f; - normalize_m4_m4(mat.ptr(), ob->object_to_world().ptr()); - invert_m4(mat.ptr()); - break; - case LA_SUN: - light.forward = math::normalize(float3(ob->object_to_world().ptr()[2])); - light.type = GP_LIGHT_TYPE_SUN; - break; - default: - light.type = GP_LIGHT_TYPE_POINT; - break; - } - light.position = float3(object_ref.object->object_to_world().location()); - light.color = float3(la->r, la->g, la->b) * (la->energy * light_power); - - lights_buf_.append(light); - } - - void end_sync() - { - /* Tag light list end. */ - gpLight light; - light.color[0] = -1.0f; - lights_buf_.append(light); - - lights_buf_.push_update(); - } - - void bind_resources(PassMain::Sub &sub) - { - sub.bind_ssbo(GPENCIL_LIGHT_SLOT, &lights_buf_); - } - - private: - void ambient_sync(float3 color) - { - gpLight light; - light.type = GP_LIGHT_TYPE_AMBIENT; - light.color = color; - - lights_buf_.append(light); - } -}; - -} // namespace blender::draw::greasepencil diff --git a/source/blender/draw/engines/gpencil/gpencil_material.hh b/source/blender/draw/engines/gpencil/gpencil_material.hh deleted file mode 100644 index 8b6e4c0336a..00000000000 --- a/source/blender/draw/engines/gpencil/gpencil_material.hh +++ /dev/null @@ -1,319 +0,0 @@ -/* SPDX-FileCopyrightText: 2022 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup draw - */ - -#pragma once - -#include "BKE_gpencil_legacy.h" -#include "BKE_image.h" -#include "DRW_gpu_wrapper.hh" -#include "DRW_render.hh" - -#include "draw_manager.hh" -#include "draw_pass.hh" - -namespace blender::draw::greasepencil { - -using namespace draw; - -class MaterialModule { - private: - /** Contains all materials in the scene. Indexed by gpObject.material_offset + mat_id. */ - StorageVectorBuffer materials_buf_ = "gp_materials_buf"; - /** List of all the texture used. */ - Vector texture_pool_; - - int v3d_color_type_ = -1; - int v3d_lighting_mode_ = V3D_LIGHTING_STUDIO; - float v3d_xray_alpha_ = 1.0f; - float3 v3d_single_color_ = {1.0f, 1.0f, 1.0f}; - - public: - void init(const View3D *v3d) - { - if (v3d != nullptr) { - const bool shading_mode_supports_xray = (v3d->shading.type <= OB_SOLID); - v3d_color_type_ = (v3d->shading.type == OB_SOLID) ? v3d->shading.color_type : -1; - v3d_lighting_mode_ = v3d->shading.light; - v3d_xray_alpha_ = (shading_mode_supports_xray && XRAY_ENABLED(v3d)) ? XRAY_ALPHA(v3d) : 1.0f; - v3d_single_color_ = float3(v3d->shading.single_color); - } - } - - void begin_sync() - { - materials_buf_.clear(); - texture_pool_.clear(); - } - - void sync(const Object *object, const int mat_slot, bool &do_mat_holdout) - { - const MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings((Object *)object, - mat_slot + 1); - - MaterialGPencilStyle gp_style_override; - - gp_style = material_override(object, &gp_style_override, gp_style); - - /* Material with holdout. */ - if (gp_style->flag & GP_MATERIAL_IS_STROKE_HOLDOUT) { - do_mat_holdout = true; - } - if (gp_style->flag & GP_MATERIAL_IS_FILL_HOLDOUT) { - do_mat_holdout = true; - } - - materials_buf_.append(material_sync(gp_style)); - } - - void end_sync() - { - materials_buf_.push_update(); - } - - void bind_resources(PassMain::Sub &sub) - { - sub.bind_ssbo(GPENCIL_MATERIAL_SLOT, &materials_buf_); - } - - uint object_offset_get() const - { - return materials_buf_.size(); - } - - private: - /* Returns the correct flag for this texture. */ - gpMaterialFlag texture_sync(::Image *image, gpMaterialFlag use_flag, gpMaterialFlag premul_flag) - { - ImageUser iuser = {nullptr}; - GPUTexture *gpu_tex = nullptr; - bool premul = false; - - if (image == nullptr) { - texture_pool_.append(nullptr); - return GP_FLAG_NONE; - } - - gpu_tex = BKE_image_get_gpu_texture(image, &iuser); - if (gpu_tex) { - premul = (image->alpha_mode == IMA_ALPHA_PREMUL) != 0; - } - - texture_pool_.append(gpu_tex); - - return gpMaterialFlag(use_flag | (premul ? premul_flag : GP_FLAG_NONE)); - } - - void uv_transform_sync(const float ofs[2], - const float scale[2], - const float rotation, - float r_rot_scale[2][2], - float r_offset[2]) - { - /* OPTI this could use 3x2 matrices and reduce the number of operations drastically. */ - float mat[4][4]; - unit_m4(mat); - /* Offset to center. */ - translate_m4(mat, 0.5f, 0.5f, 0.0f); - /* Reversed order. */ - float3 tmp = {1.0f / scale[0], 1.0f / scale[1], 0.0}; - rescale_m4(mat, tmp); - rotate_m4(mat, 'Z', -rotation); - translate_m4(mat, ofs[0], ofs[1], 0.0f); - /* Convert to 3x2 */ - copy_v2_v2(r_rot_scale[0], mat[0]); - copy_v2_v2(r_rot_scale[1], mat[1]); - copy_v2_v2(r_offset, mat[3]); - } - - /* Amend object fill color in order to avoid completely flat look. */ - void material_shade_color(float color[3]) - { - if (v3d_lighting_mode_ == V3D_LIGHTING_FLAT) { - return; - } - /* This is scene referred color, not gamma corrected and not per perceptual. - * So we lower the threshold a bit. (1.0 / 3.0) */ - if (color[0] + color[1] + color[2] > 1.1) { - add_v3_fl(color, -0.25f); - } - else { - add_v3_fl(color, 0.15f); - } - CLAMP3(color, 0.0f, 1.0f); - } - - const MaterialGPencilStyle *material_override(const Object *object, - MaterialGPencilStyle *gp_style_override, - const MaterialGPencilStyle *gp_style) - { - switch (v3d_color_type_) { - case V3D_SHADING_MATERIAL_COLOR: - case V3D_SHADING_RANDOM_COLOR: - /* Random uses a random color per layer and this is done using the layer tint. - * A simple color by object, like meshes, is not practical in grease pencil. */ - copy_v4_v4(gp_style_override->stroke_rgba, gp_style->stroke_rgba); - copy_v4_v4(gp_style_override->fill_rgba, gp_style->fill_rgba); - gp_style = gp_style_override; - gp_style_override->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID; - gp_style_override->fill_style = GP_MATERIAL_FILL_STYLE_SOLID; - break; - case V3D_SHADING_TEXTURE_COLOR: - *gp_style_override = blender::dna::shallow_copy(*gp_style); - gp_style = gp_style_override; - if ((gp_style_override->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) && - (gp_style_override->sima)) - { - copy_v4_fl(gp_style_override->stroke_rgba, 1.0f); - gp_style_override->mix_stroke_factor = 0.0f; - } - - if ((gp_style_override->fill_style == GP_MATERIAL_FILL_STYLE_TEXTURE) && - (gp_style_override->ima)) - { - copy_v4_fl(gp_style_override->fill_rgba, 1.0f); - gp_style_override->mix_factor = 0.0f; - } - else if (gp_style_override->fill_style == GP_MATERIAL_FILL_STYLE_GRADIENT) { - /* gp_style_override->fill_rgba is needed for correct gradient. */ - gp_style_override->mix_factor = 0.0f; - } - break; - case V3D_SHADING_SINGLE_COLOR: - gp_style = gp_style_override; - gp_style_override->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID; - gp_style_override->fill_style = GP_MATERIAL_FILL_STYLE_SOLID; - copy_v3_v3(gp_style_override->fill_rgba, v3d_single_color_); - gp_style_override->fill_rgba[3] = 1.0f; - copy_v4_v4(gp_style_override->stroke_rgba, gp_style_override->fill_rgba); - material_shade_color(gp_style_override->fill_rgba); - break; - case V3D_SHADING_OBJECT_COLOR: - gp_style = gp_style_override; - gp_style_override->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID; - gp_style_override->fill_style = GP_MATERIAL_FILL_STYLE_SOLID; - copy_v4_v4(gp_style_override->fill_rgba, object->color); - copy_v4_v4(gp_style_override->stroke_rgba, object->color); - material_shade_color(gp_style_override->fill_rgba); - break; - case V3D_SHADING_VERTEX_COLOR: - gp_style = gp_style_override; - gp_style_override->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID; - gp_style_override->fill_style = GP_MATERIAL_FILL_STYLE_SOLID; - copy_v4_fl(gp_style_override->fill_rgba, 1.0f); - copy_v4_fl(gp_style_override->stroke_rgba, 1.0f); - break; - default: - break; - } - return gp_style; - } - - gpMaterial material_sync(const MaterialGPencilStyle *gp_style) - { - gpMaterial material; - material.flag = 0; - - /* Dots/Square alignment. */ - if (gp_style->mode != GP_MATERIAL_MODE_LINE) { - switch (gp_style->alignment_mode) { - case GP_MATERIAL_FOLLOW_PATH: - material.flag = GP_STROKE_ALIGNMENT_STROKE; - break; - case GP_MATERIAL_FOLLOW_OBJ: - material.flag = GP_STROKE_ALIGNMENT_OBJECT; - break; - case GP_MATERIAL_FOLLOW_FIXED: - default: - material.flag = GP_STROKE_ALIGNMENT_FIXED; - break; - } - if (gp_style->mode == GP_MATERIAL_MODE_DOT) { - material.flag |= GP_STROKE_DOTS; - } - } - - /* Overlap. */ - if ((gp_style->mode != GP_MATERIAL_MODE_LINE) || - (gp_style->flag & GP_MATERIAL_DISABLE_STENCIL)) - { - material.flag |= GP_STROKE_OVERLAP; - } - - /* Material with holdout. */ - if (gp_style->flag & GP_MATERIAL_IS_STROKE_HOLDOUT) { - material.flag |= GP_STROKE_HOLDOUT; - } - if (gp_style->flag & GP_MATERIAL_IS_FILL_HOLDOUT) { - material.flag |= GP_FILL_HOLDOUT; - } - - /* Dots or Squares rotation. */ - material.alignment_rot[0] = cosf(gp_style->alignment_rotation); - material.alignment_rot[1] = sinf(gp_style->alignment_rotation); - - if (gp_style->flag & GP_MATERIAL_STROKE_SHOW) { - material.flag |= GP_SHOW_STROKE; - } - if (gp_style->flag & GP_MATERIAL_FILL_SHOW) { - material.flag |= GP_SHOW_FILL; - } - - /* Stroke Style */ - if ((gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) && (gp_style->sima)) { - material.flag |= texture_sync( - gp_style->sima, GP_STROKE_TEXTURE_USE, GP_STROKE_TEXTURE_PREMUL); - copy_v4_v4(material.stroke_color, gp_style->stroke_rgba); - material.stroke_texture_mix = 1.0f - gp_style->mix_stroke_factor; - material.stroke_u_scale = 500.0f / gp_style->texture_pixsize; - } - else /* if (gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_SOLID) */ { - texture_sync(nullptr, GP_FLAG_NONE, GP_FLAG_NONE); - material.flag &= ~GP_STROKE_TEXTURE_USE; - copy_v4_v4(material.stroke_color, gp_style->stroke_rgba); - material.stroke_texture_mix = 0.0f; - } - - /* Fill Style */ - if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_TEXTURE) && (gp_style->ima)) { - material.flag |= texture_sync(gp_style->ima, GP_FILL_TEXTURE_USE, GP_FILL_TEXTURE_PREMUL); - material.flag |= (gp_style->flag & GP_MATERIAL_TEX_CLAMP) ? GP_FILL_TEXTURE_CLIP : 0; - uv_transform_sync(gp_style->texture_offset, - gp_style->texture_scale, - gp_style->texture_angle, - (float(*)[2]) & material.fill_uv_rot_scale[0], - material.fill_uv_offset); - copy_v4_v4(material.fill_color, gp_style->fill_rgba); - material.fill_texture_mix = 1.0f - gp_style->mix_factor; - } - else if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_GRADIENT) { - texture_sync(nullptr, GP_FLAG_NONE, GP_FLAG_NONE); - bool use_radial = (gp_style->gradient_type == GP_MATERIAL_GRADIENT_RADIAL); - material.flag |= GP_FILL_GRADIENT_USE; - material.flag |= use_radial ? GP_FILL_GRADIENT_RADIAL : 0; - uv_transform_sync(gp_style->texture_offset, - gp_style->texture_scale, - gp_style->texture_angle, - (float(*)[2]) & material.fill_uv_rot_scale[0], - material.fill_uv_offset); - copy_v4_v4(material.fill_color, gp_style->fill_rgba); - copy_v4_v4(material.fill_mix_color, gp_style->mix_rgba); - material.fill_texture_mix = 1.0f - gp_style->mix_factor; - if (gp_style->flag & GP_MATERIAL_FLIP_FILL) { - swap_v4_v4(material.fill_color, material.fill_mix_color); - } - } - else /* if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID) */ { - texture_sync(nullptr, GP_FLAG_NONE, GP_FLAG_NONE); - copy_v4_v4(material.fill_color, gp_style->fill_rgba); - material.fill_texture_mix = 0.0f; - } - return material; - } -}; - -} // namespace blender::draw::greasepencil diff --git a/source/blender/draw/engines/gpencil/gpencil_object.hh b/source/blender/draw/engines/gpencil/gpencil_object.hh deleted file mode 100644 index d7709e7869c..00000000000 --- a/source/blender/draw/engines/gpencil/gpencil_object.hh +++ /dev/null @@ -1,324 +0,0 @@ -/* SPDX-FileCopyrightText: 2022 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup draw - */ - -#pragma once - -#include "BLI_math_quaternion_types.hh" - -#include "BKE_grease_pencil.hh" -#include "BKE_image.h" -#include "DRW_gpu_wrapper.hh" -#include "DRW_render.hh" - -#include "draw_manager.hh" -#include "draw_pass.hh" - -#include "gpencil_layer.hh" -#include "gpencil_material.hh" -#include "gpencil_shader.hh" - -namespace blender::draw::greasepencil { - -using namespace draw; - -class ObjectModule { - private: - LayerModule &layers_; - MaterialModule &materials_; - ShaderModule &shaders_; - - /** Contains all Objects in the scene. Indexed by drw_ResourceID. */ - StorageArrayBuffer objects_buf_ = "gp_objects_buf"; - - /** Contains all gpencil objects in the scene as well as their effect sub-passes. */ - PassSortable main_ps_ = {"gp_main_ps"}; - - /** Contains all composited GPencil layers from one object if is uses VFX. */ - TextureFromPool object_color_tx_ = {"gp_color_object_tx"}; - TextureFromPool object_reveal_tx_ = {"gp_reveal_object_tx"}; - Framebuffer object_fb_ = {"gp_object_fb"}; - bool is_object_fb_needed_ = false; - - /** Contains all strokes from one layer if is uses blending. (also used as target for VFX) */ - TextureFromPool layer_color_tx_ = {"gp_color_layer_tx"}; - TextureFromPool layer_reveal_tx_ = {"gp_reveal_layer_tx"}; - Framebuffer layer_fb_ = {"gp_layer_fb"}; - bool is_layer_fb_needed_ = false; - - bool use_onion_ = true; - bool use_stroke_fill_ = true; - bool use_vfx_ = true; - bool is_render_ = true; - bool is_persp_ = true; - - /** Forward vector used to sort gpencil objects. */ - float3 camera_forward_; - float3 camera_pos_; - - const Scene *scene_ = nullptr; - - /** \note Needs not to be temporary variable since it is dereferenced later. */ - std::array clear_colors_ = {float4(0.0f, 0.0f, 0.0f, 0.0f), - float4(1.0f, 1.0f, 1.0f, 1.0f)}; - - public: - ObjectModule(LayerModule &layers, MaterialModule &materials, ShaderModule &shaders) - : layers_(layers), materials_(materials), shaders_(shaders){}; - - void init(const View3D *v3d, const Scene *scene) - { - const bool is_viewport = (v3d != nullptr); - scene_ = scene; - - if (is_viewport) { - /* TODO(fclem): Avoid access to global DRW. */ - const bContext *evil_C = DRW_context_state_get()->evil_C; - const bool playing = (evil_C != nullptr) ? - ED_screen_animation_playing(CTX_wm_manager(evil_C)) != nullptr : - false; - const bool hide_overlay = ((v3d->flag2 & V3D_HIDE_OVERLAYS) != 0); - const bool show_onion = ((v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) != 0); - use_onion_ = show_onion && !hide_overlay && !playing; - use_stroke_fill_ = GPENCIL_SIMPLIFY_FILL(scene, playing); - use_vfx_ = GPENCIL_SIMPLIFY_FX(scene, playing); - is_render_ = false; - } - else { - use_stroke_fill_ = GPENCIL_SIMPLIFY_FILL(scene, false); - use_vfx_ = GPENCIL_SIMPLIFY_FX(scene, false); - } - } - - void begin_sync(Depsgraph * /*depsgraph*/, const View &main_view) - { - camera_forward_ = main_view.forward(); - camera_pos_ = main_view.location(); - - is_object_fb_needed_ = false; - is_layer_fb_needed_ = false; - - is_persp_ = main_view.is_persp(); - /* TODO(fclem): Shrink buffer. */ - // objects_buf_.shrink(); - } - - void sync_grease_pencil(Manager &manager, - ObjectRef &object_ref, - Framebuffer &main_fb, - Framebuffer &scene_fb, - TextureFromPool &depth_tx, - PassSortable &main_ps) - { - using namespace blender::bke::greasepencil; - - Object *object = object_ref.object; - const GreasePencil &grease_pencil = *static_cast(object->data); - - if (grease_pencil.drawings().is_empty()) { - return; - } - - const bool is_stroke_order_3d = false; /* TODO */ - bool do_material_holdout = false; - bool do_layer_blending = false; - bool object_has_vfx = false; /* TODO: `vfx.object_has_vfx(gpd);`. */ - - uint material_offset = materials_.object_offset_get(); - for (const int i : IndexRange(BKE_object_material_count_eval(object))) { - materials_.sync(object, i, do_material_holdout); - } - - uint layer_offset = layers_.object_offset_get(); - for (const Layer *layer : grease_pencil.layers()) { - layers_.sync(object, *layer, do_layer_blending); - } - - /* Order rendering using camera Z distance. */ - float3 position = float3(object->object_to_world().location()); - float camera_z = math::dot(position, camera_forward_); - - PassMain::Sub &object_subpass = main_ps.sub("GPObject", camera_z); - object_subpass.framebuffer_set((object_has_vfx) ? &object_fb_ : &main_fb); - object_subpass.clear_depth(is_stroke_order_3d ? 1.0f : 0.0f); - if (object_has_vfx) { - object_subpass.clear_multi(clear_colors_); - } - - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_BLEND_ALPHA_PREMUL; - /* For 2D mode, we render all strokes with uniform depth (increasing with stroke id). */ - state |= (is_stroke_order_3d) ? DRW_STATE_DEPTH_LESS_EQUAL : DRW_STATE_DEPTH_GREATER; - /* Always write stencil. Only used as optimization for blending. */ - state |= DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; - - object_subpass.state_set(state); - object_subpass.shader_set(shaders_.static_shader_get(GREASE_PENCIL)); - - GPUVertBuf *position_tx = DRW_cache_grease_pencil_position_buffer_get(scene_, object); - GPUVertBuf *color_tx = DRW_cache_grease_pencil_color_buffer_get(scene_, object); - GPUBatch *geom = DRW_cache_grease_pencil_get(scene_, object); - - /* TODO(fclem): Pass per frame object matrix here. */ - ResourceHandle handle = manager.resource_handle(object_ref); - gpObject &ob = objects_buf_.get_or_resize(handle.resource_index()); - ob.is_shadeless = false; - ob.stroke_order3d = false; - ob.tint = float4(1.0); // frame_tint_get(gpd, frame.gpf, current_frame_); - ob.layer_offset = layer_offset; - ob.material_offset = material_offset; - - if (do_layer_blending) { - /* TODO: Do layer blending. */ - // for (const LayerData &layer : frame.layers) { - // UNUSED_VARS(layer); - // if (has_blending(layer)) { - // object_subpass.framebuffer_set(*vfx_fb.current()); - // } - - /* TODO(fclem): Only draw subrange of geometry for this layer. */ - object_subpass.bind_texture("gp_pos_tx", position_tx); - object_subpass.bind_texture("gp_col_tx", color_tx); - object_subpass.draw(geom, handle); - - /* TODO: Do layer blending. */ - // if (has_blending(layer)) { - // layer_blend_sync(object_ref, object_subpass); - // } - // } - } - else { - /* Fast path. */ - object_subpass.bind_texture("gp_pos_tx", position_tx); - object_subpass.bind_texture("gp_col_tx", color_tx); - object_subpass.draw(geom, handle); - } - - /** Merging the object depth buffer into the scene depth buffer. */ - float4x4 plane_mat = get_object_plane_mat(*object); - ResourceHandle handle_plane_mat = manager.resource_handle(plane_mat); - object_subpass.framebuffer_set(&scene_fb); - object_subpass.state_set(DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_DEPTH); - object_subpass.shader_set(shaders_.static_shader_get(DEPTH_MERGE)); - object_subpass.bind_texture("depthBuf", (object_has_vfx) ? nullptr : &depth_tx); - object_subpass.draw(DRW_cache_quad_get(), handle_plane_mat); - - /* TODO: Do object VFX. */ -#if 0 - if (object_has_vfx) { - VfxContext vfx_ctx(object_subpass, - layer_fb_, - object_fb_, - object_color_tx_, - layer_color_tx_, - object_reveal_tx_, - layer_reveal_tx_, - is_render_); - - /* \note Update this boolean as the actual number of vfx drawn might differ. */ - object_has_vfx = vfx.object_sync(main_fb_, object_ref, vfx_ctx, do_material_holdout); - - if (object_has_vfx || do_layer_blending) { - is_layer_fb_needed_ = true; - } - } -#endif - } - - void end_sync() - { - objects_buf_.push_update(); - } - - void bind_resources(PassMain::Sub &sub) - { - sub.bind_ssbo(GPENCIL_OBJECT_SLOT, &objects_buf_); - } - - void acquire_temporary_buffers(int2 render_size, eGPUTextureFormat format) - { - object_color_tx_.acquire(render_size, format); - object_reveal_tx_.acquire(render_size, format); - object_fb_.ensure(GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(object_color_tx_), - GPU_ATTACHMENT_TEXTURE(object_reveal_tx_)); - if (is_layer_fb_needed_) { - layer_color_tx_.acquire(render_size, format); - layer_reveal_tx_.acquire(render_size, format); - layer_fb_.ensure(GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(layer_color_tx_), - GPU_ATTACHMENT_TEXTURE(layer_reveal_tx_)); - } - } - - void release_temporary_buffers() - { - object_color_tx_.release(); - object_reveal_tx_.release(); - - layer_color_tx_.release(); - layer_reveal_tx_.release(); - } - - bool scene_has_visible_gpencil_object() const - { - return objects_buf_.size() > 0; - } - - /** - * Define a matrix that will be used to render a triangle to merge the depth of the rendered - * gpencil object with the rest of the scene. - */ - float4x4 get_object_plane_mat(const Object &object) - { - using namespace math; - /* Find the normal most likely to represent the gpObject. */ - /* TODO: This does not work quite well if you use - * strokes not aligned with the object axes. Maybe we could try to - * compute the minimum axis of all strokes. But this would be more - * computationally heavy and should go into the GPData evaluation. */ - BLI_assert(object.type == OB_GREASE_PENCIL); - const GreasePencil &grease_pencil = *static_cast(object.data); - const std::optional> bounds = grease_pencil.bounds_min_max_eval(); - if (!bounds) { - return float4x4::identity(); - } - - /* Convert bbox to matrix */ - const float3 size = float3(bounds->max - bounds->min) + 1e-8f; - const float3 center = midpoint(bounds->min, bounds->max); - - /* BBox space to World. */ - const float4x4 &object_to_world = object.object_to_world(); - float4x4 bbox_mat = object_to_world * - from_loc_rot_scale(center, Quaternion::identity(), size); - float3 plane_normal; - if (is_persp_) { - /* BBox center to camera vector. */ - plane_normal = camera_pos_ - bbox_mat.location(); - } - else { - plane_normal = camera_forward_; - } - /* World to BBox space. */ - float4x4 bbox_mat_inv = invert(bbox_mat); - /* mat_inv_t is a "normal" matrix which will transform - * BBox normal space to world space. */ - float4x4 bbox_mat_inv_t = transpose(bbox_mat_inv); - - /* Normalize the vector in BBox space. */ - plane_normal = normalize(transform_direction(bbox_mat_inv, plane_normal)); - plane_normal = normalize(transform_direction(bbox_mat_inv_t, plane_normal)); - - float4x4 plane_mat = from_up_axis(plane_normal); - float radius = length(transform_direction(object_to_world, size)); - plane_mat = scale(plane_mat, float3(radius)); - plane_mat.location() = transform_point(object_to_world, center); - return plane_mat; - } -}; - -} // namespace blender::draw::greasepencil diff --git a/source/blender/draw/engines/gpencil/gpencil_render.cc b/source/blender/draw/engines/gpencil/gpencil_render.cc index faf3cb3f681..1d59557c47d 100644 --- a/source/blender/draw/engines/gpencil/gpencil_render.cc +++ b/source/blender/draw/engines/gpencil/gpencil_render.cc @@ -146,7 +146,7 @@ static void GPENCIL_render_cache(void *vedata, RenderEngine * /*engine*/, Depsgraph * /*depsgraph*/) { - if (ob && ELEM(ob->type, OB_GPENCIL_LEGACY, OB_LAMP)) { + if (ob && ELEM(ob->type, OB_GPENCIL_LEGACY, OB_GREASE_PENCIL, OB_LAMP)) { if (DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF) { GPENCIL_cache_populate(vedata, ob); } diff --git a/source/blender/draw/engines/gpencil/gpencil_shader.cc b/source/blender/draw/engines/gpencil/gpencil_shader.cc deleted file mode 100644 index c8e9724489d..00000000000 --- a/source/blender/draw/engines/gpencil/gpencil_shader.cc +++ /dev/null @@ -1,119 +0,0 @@ -/* SPDX-FileCopyrightText: 2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup draw - */ - -#include "gpencil_shader.hh" - -#include - -namespace blender::draw::greasepencil { - -ShaderModule *ShaderModule::g_shader_module = nullptr; - -ShaderModule *ShaderModule::module_get() -{ - if (g_shader_module == nullptr) { - /* TODO(@fclem) thread-safety. */ - g_shader_module = new ShaderModule(); - } - return g_shader_module; -} - -void ShaderModule::module_free() -{ - if (g_shader_module != nullptr) { - /* TODO(@fclem) thread-safety. */ - delete g_shader_module; - g_shader_module = nullptr; - } -} - -ShaderModule::ShaderModule() -{ - for (GPUShader *&shader : shaders_) { - shader = nullptr; - } - -#ifndef NDEBUG - /* Ensure all shader are described. */ - for (auto i : IndexRange(MAX_SHADER_TYPE)) { - const char *name = static_shader_create_info_name_get(eShaderType(i)); - if (name == nullptr) { - std::cerr << "GPencil: Missing case for eShaderType(" << i - << ") in static_shader_create_info_name_get()." << std::endl; - BLI_assert(0); - } - const GPUShaderCreateInfo *create_info = GPU_shader_create_info_get(name); - BLI_assert_msg(create_info != nullptr, "GPencil: Missing create info for static shader."); - } -#endif -} - -ShaderModule::~ShaderModule() -{ - for (GPUShader *&shader : shaders_) { - DRW_SHADER_FREE_SAFE(shader); - } -} - -const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_type) -{ - switch (shader_type) { - case ANTIALIASING_EDGE_DETECT: - return "gpencil_antialiasing_stage_0"; - case ANTIALIASING_BLEND_WEIGHT: - return "gpencil_antialiasing_stage_1"; - case ANTIALIASING_RESOLVE: - return "gpencil_antialiasing_stage_2"; - case GREASE_PENCIL: - return "gpencil_geometry_next"; - case LAYER_BLEND: - return "gpencil_layer_blend"; - case DEPTH_MERGE: - return "grease_pencil_depth_merge"; - case MASK_INVERT: - return "gpencil_mask_invert"; - case FX_COMPOSITE: - return "gpencil_fx_composite"; - case FX_COLORIZE: - return "gpencil_fx_colorize"; - case FX_BLUR: - return "gpencil_fx_blur"; - case FX_GLOW: - return "gpencil_fx_glow"; - case FX_PIXEL: - return "gpencil_fx_pixelize"; - case FX_RIM: - return "gpencil_fx_rim"; - case FX_SHADOW: - return "gpencil_fx_shadow"; - case FX_TRANSFORM: - return "gpencil_fx_transform"; - /* To avoid compiler warning about missing case. */ - case MAX_SHADER_TYPE: - return ""; - } - return ""; -} - -GPUShader *ShaderModule::static_shader_get(eShaderType shader_type) -{ - if (shaders_[shader_type] == nullptr) { - const char *shader_name = static_shader_create_info_name_get(shader_type); - - shaders_[shader_type] = GPU_shader_create_from_info_name(shader_name); - - if (shaders_[shader_type] == nullptr) { - std::cerr << "GPencil: error: Could not compile static shader \"" << shader_name << "\"" - << std::endl; - } - BLI_assert(shaders_[shader_type] != nullptr); - } - return shaders_[shader_type]; -} - -} // namespace blender::draw::greasepencil diff --git a/source/blender/draw/engines/gpencil/gpencil_shader.hh b/source/blender/draw/engines/gpencil/gpencil_shader.hh deleted file mode 100644 index 23fc2f12619..00000000000 --- a/source/blender/draw/engines/gpencil/gpencil_shader.hh +++ /dev/null @@ -1,66 +0,0 @@ -/* SPDX-FileCopyrightText: 2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup draw - */ - -#pragma once - -#include "DRW_render.hh" - -namespace blender::draw::greasepencil { - -enum eShaderType { - /* SMAA anti-aliasing. */ - ANTIALIASING_EDGE_DETECT = 0, - ANTIALIASING_BLEND_WEIGHT, - ANTIALIASING_RESOLVE, - /* GPencil Object rendering */ - GREASE_PENCIL, - /* All layer blend types in one shader! */ - LAYER_BLEND, - /* Merge the final object depth to the depth buffer. */ - DEPTH_MERGE, - /* Invert the content of the mask buffer. */ - MASK_INVERT, - /* Final Compositing over rendered background. */ - FX_COMPOSITE, - /* Effects. */ - FX_COLORIZE, - FX_BLUR, - FX_GLOW, - FX_PIXEL, - FX_RIM, - FX_SHADOW, - FX_TRANSFORM, - - MAX_SHADER_TYPE, -}; - -/** - * Shader module. shared between instances. - */ -class ShaderModule { - private: - std::array shaders_; - - /** Shared shader module across all engine instances. */ - static ShaderModule *g_shader_module; - - public: - ShaderModule(); - ~ShaderModule(); - - GPUShader *static_shader_get(eShaderType shader_type); - - /** Only to be used by Instance constructor. */ - static ShaderModule *module_get(); - static void module_free(); - - private: - const char *static_shader_create_info_name_get(eShaderType shader_type); -}; - -} // namespace blender::draw::greasepencil diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.cc b/source/blender/draw/engines/gpencil/gpencil_shader_fx.cc index 65fa3a1ccfc..850e039ab61 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.cc +++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.cc @@ -22,17 +22,12 @@ #include "gpencil_engine.h" /* verify if this fx is active */ -static bool effect_is_active(bGPdata *gpd, ShaderFxData *fx, bool is_viewport) +static bool effect_is_active(ShaderFxData *fx, bool is_edit, bool is_viewport) { if (fx == nullptr) { return false; } - if (gpd == nullptr) { - return false; - } - - bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd); if (((fx->mode & eShaderFxMode_Editmode) == 0) && (is_edit) && (is_viewport)) { return false; } @@ -590,9 +585,11 @@ static void gpencil_vfx_swirl(SwirlShaderFxData *fx, Object * /*ob*/, gpIterVfxD DRW_shgroup_call_procedural_triangles(grp, nullptr, 1); } -void gpencil_vfx_cache_populate(GPENCIL_Data *vedata, Object *ob, GPENCIL_tObject *tgp_ob) +void gpencil_vfx_cache_populate(GPENCIL_Data *vedata, + Object *ob, + GPENCIL_tObject *tgp_ob, + const bool is_edit_mode) { - bGPdata *gpd = (bGPdata *)ob->data; GPENCIL_FramebufferList *fbl = vedata->fbl; GPENCIL_PrivateData *pd = vedata->stl->pd; @@ -610,7 +607,7 @@ void gpencil_vfx_cache_populate(GPENCIL_Data *vedata, Object *ob, GPENCIL_tObjec /* If simplify enabled, nothing more to do. */ if (!pd->simplify_fx) { LISTBASE_FOREACH (ShaderFxData *, fx, &ob->shader_fx) { - if (effect_is_active(gpd, fx, pd->is_viewport)) { + if (effect_is_active(fx, is_edit_mode, pd->is_viewport)) { switch (fx->type) { case eShaderFxType_Blur: gpencil_vfx_blur((BlurShaderFxData *)fx, ob, &iter); diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_shared.h b/source/blender/draw/engines/gpencil/gpencil_shader_shared.h index 846c20583ca..36c5b432410 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_shared.h +++ b/source/blender/draw/engines/gpencil/gpencil_shader_shared.h @@ -8,11 +8,8 @@ # include "GPU_shader_shared_utils.h" # ifndef __cplusplus -typedef struct gpScene gpScene; typedef struct gpMaterial gpMaterial; typedef struct gpLight gpLight; -typedef struct gpObject gpObject; -typedef struct gpLayer gpLayer; typedef enum gpMaterialFlag gpMaterialFlag; # ifdef GP_LIGHT typedef enum gpLightType gpLightType; @@ -38,8 +35,6 @@ enum gpMaterialFlag { GP_FILL_TEXTURE_CLIP = (1u << 12u), GP_FILL_GRADIENT_USE = (1u << 13u), GP_FILL_GRADIENT_RADIAL = (1u << 14u), - GP_SHOW_STROKE = (1u << 15u), - GP_SHOW_FILL = (1u << 16u), GP_FILL_FLAGS = (GP_FILL_TEXTURE_USE | GP_FILL_TEXTURE_PREMUL | GP_FILL_TEXTURE_CLIP | GP_FILL_GRADIENT_USE | GP_FILL_GRADIENT_RADIAL | GP_FILL_HOLDOUT), }; @@ -60,12 +55,6 @@ enum gpLightType { # define gpLightType uint #endif -struct gpScene { - float2 render_size; - float2 _pad0; -}; -BLI_STATIC_ASSERT_ALIGN(gpScene, 16) - struct gpMaterial { float4 stroke_color; float4 fill_color; @@ -132,38 +121,6 @@ struct gpLight { BLI_STATIC_ASSERT_ALIGN(gpLight, 16) #endif -struct gpObject { - /** Weather or not to apply lighting to the GPencil object. */ - bool32_t is_shadeless; - /** Switch between 2d and 3D stroke order. */ - bool32_t stroke_order3d; - /** Offset inside the layer buffer to the first layer data of this object. */ - uint layer_offset; - /** Offset inside the material buffer to the first material data of this object. */ - uint material_offset; - /** Color to multiply to the final mixed color. */ - float4 tint; - /** Color to multiply to the final mixed color. */ - float3 normal; - - float _pad0; -}; -BLI_STATIC_ASSERT_ALIGN(gpObject, 16) - -struct gpLayer { - /** Amount of vertex color to blend with actual material color. */ - float vertex_color_opacity; - /** Thickness change of all the strokes. */ - float thickness_offset; - /** Thickness change of all the strokes. */ - float opacity; - /** Offset to apply to stroke index to be able to insert a currently drawn stroke in between. */ - float stroke_index_offset; - /** Color to multiply to the final mixed color. */ - float4 tint; -}; -BLI_STATIC_ASSERT_ALIGN(gpLayer, 16) - #ifndef GPU_SHADER # undef gpMaterialFlag # undef gpLightType diff --git a/source/blender/draw/engines/gpencil/gpencil_vfx.hh b/source/blender/draw/engines/gpencil/gpencil_vfx.hh deleted file mode 100644 index eacbc8617f1..00000000000 --- a/source/blender/draw/engines/gpencil/gpencil_vfx.hh +++ /dev/null @@ -1,336 +0,0 @@ -/* SPDX-FileCopyrightText: 2017 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup draw - */ -#include "BKE_camera.h" -#include "BLI_listbase_wrapper.hh" -#include "DNA_camera_types.h" -#include "DNA_gpencil_legacy_types.h" -#include "DNA_shader_fx_types.h" - -#include "draw_manager.hh" -#include "draw_pass.hh" - -#include "gpencil_engine.h" -#include "gpencil_shader.hh" -#include "gpencil_shader_shared.h" - -namespace blender::draw::greasepencil { - -using namespace draw; - -struct VfxContext { - PassMain::Sub *object_subpass; - SwapChain vfx_fb; - SwapChain color_tx; - SwapChain reveal_tx; - bool is_viewport; - - VfxContext(PassMain::Sub &object_subpass_, - Framebuffer &layer_fb, - Framebuffer &object_fb, - TextureFromPool &object_color_tx, - TextureFromPool &layer_color_tx, - TextureFromPool &object_reveal_tx, - TextureFromPool &layer_reveal_tx, - bool is_render_) - { - object_subpass = &object_subpass_; - /* These may not be allocated yet, use address of future pointer. */ - vfx_fb.current() = &layer_fb; - vfx_fb.next() = &object_fb; - - color_tx.current() = &object_color_tx; - color_tx.next() = &layer_color_tx; - reveal_tx.current() = &object_reveal_tx; - reveal_tx.next() = &layer_reveal_tx; - - is_viewport = (is_render_ == false); - } - - PassMain::Sub &create_vfx_pass(const char *name, GPUShader *shader) - { - PassMain::Sub &sub = object_subpass->sub(name); - sub.framebuffer_set(vfx_fb.current()); - sub.shader_set(shader); - sub.bind_texture("colorBuf", color_tx.current()); - sub.bind_texture("revealBuf", reveal_tx.current()); - - vfx_fb.swap(); - color_tx.swap(); - reveal_tx.swap(); - - return sub; - } - - /* Verify if the given fx is active. */ - bool effect_is_active(const bGPdata *gpd, const ShaderFxData *fx) - { - if (fx == NULL) { - return false; - } - - if (gpd == NULL) { - return false; - } - - bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd); - if (((fx->mode & eShaderFxMode_Editmode) == 0) && (is_edit) && (is_viewport)) { - return false; - } - - if (((fx->mode & eShaderFxMode_Realtime) && (is_viewport == true)) || - ((fx->mode & eShaderFxMode_Render) && (is_viewport == false))) - { - return true; - } - - return false; - } -}; - -class VfxModule { - private: - ShaderModule &shaders; - /* Global switch for all vfx. */ - bool vfx_enabled_ = false; - /* Global switch for all Depth Of Field blur. */ - bool dof_enabled_ = false; - /* Pseudo depth of field parameter. Used to scale blur radius. */ - float dof_parameters_[2]; - - public: - VfxModule(ShaderModule &shaders_) : shaders(shaders_){}; - - void init(bool enable, const Object *camera_object, const RegionView3D *rv3d) - { - vfx_enabled_ = enable; - - const Camera *camera = (camera_object != nullptr) ? - static_cast(camera_object->data) : - nullptr; - - /* Pseudo DOF setup. */ - if (camera && (camera->dof.flag & CAM_DOF_ENABLED)) { - const float *vp_size = DRW_viewport_size_get(); - float fstop = camera->dof.aperture_fstop; - float sensor = BKE_camera_sensor_size( - camera->sensor_fit, camera->sensor_x, camera->sensor_y); - float focus_dist = BKE_camera_object_dof_distance(camera_object); - float focal_len = camera->lens; - - const float scale_camera = 0.001f; - /* We want radius here for the aperture number. */ - float aperture = 0.5f * scale_camera * focal_len / fstop; - float focal_len_scaled = scale_camera * focal_len; - float sensor_scaled = scale_camera * sensor; - - if (rv3d != nullptr) { - sensor_scaled *= rv3d->viewcamtexcofac[0]; - } - - dof_parameters_[1] = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled)); - dof_parameters_[1] *= vp_size[0] / sensor_scaled; - dof_parameters_[0] = -focus_dist * dof_parameters_[1]; - } - else { - /* Disable DoF blur scaling. Produce Circle of Confusion of 0 pixel. */ - dof_parameters_[0] = dof_parameters_[1] = 0.0f; - } - } - - /* Return true if any vfx is needed */ - bool object_sync(Framebuffer &main_fb, - ObjectRef &object_ref, - VfxContext &vfx_ctx, - bool do_material_holdout) - { - Object *object = object_ref.object; - bGPdata *gpd = (bGPdata *)object->data; - - int vfx_count = 0; - - if (vfx_enabled_) { - for (const ShaderFxData *fx : ListBaseWrapper(&object->shader_fx)) { - if (!vfx_ctx.effect_is_active(gpd, fx)) { - continue; - } - switch (fx->type) { - case eShaderFxType_Blur: - vfx_count += vfx_blur(*(const BlurShaderFxData *)fx, object, vfx_ctx); - break; - case eShaderFxType_Colorize: - vfx_count += vfx_colorize(*(const ColorizeShaderFxData *)fx, object, vfx_ctx); - break; - case eShaderFxType_Flip: - vfx_count += vfx_flip(*(const FlipShaderFxData *)fx, object, vfx_ctx); - break; - case eShaderFxType_Pixel: - vfx_count += vfx_pixelize(*(const PixelShaderFxData *)fx, object, vfx_ctx); - break; - case eShaderFxType_Rim: - vfx_count += vfx_rim(*(const RimShaderFxData *)fx, object, vfx_ctx); - break; - case eShaderFxType_Shadow: - vfx_count += vfx_shadow(*(const ShadowShaderFxData *)fx, object, vfx_ctx); - break; - case eShaderFxType_Glow: - vfx_count += vfx_glow(*(const GlowShaderFxData *)fx, object, vfx_ctx); - break; - case eShaderFxType_Swirl: - vfx_count += vfx_swirl(*(const SwirlShaderFxData *)fx, object, vfx_ctx); - break; - case eShaderFxType_Wave: - vfx_count += vfx_wave(*(const WaveShaderFxData *)fx, object, vfx_ctx); - break; - default: - break; - } - } - } - - if (do_material_holdout) { - vfx_count += 1; - } - - if (vfx_count > 0) { - /* We need an extra pass to combine result to main buffer. */ - merge_sync(main_fb, vfx_ctx); - } - - return vfx_count > 0; - } - - private: - int vfx_blur(const BlurShaderFxData &fx, const Object *object, VfxContext &vfx_ctx) - { - if ((fx.flag & FX_BLUR_DOF_MODE) && !dof_enabled_) { - /* No blur outside camera view (or when DOF is disabled on the camera). */ - return 0; - } - - float winmat[4][4], persmat[4][4]; - float2 blur_size = {fx.radius[0], fx.radius[1]}; - - /* TODO(fclem): Replace by draw::View. */ - DRW_view_persmat_get(nullptr, persmat, false); - const float w = fabsf(mul_project_m4_v3_zfac(persmat, object->object_to_world().location())); - - if (fx.flag & FX_BLUR_DOF_MODE) { - /* Compute circle of confusion size. */ - float coc = (dof_parameters_[0] / -w) - dof_parameters_[1]; - blur_size = float2(fabsf(coc)); - } - else { - /* Modify by distance to camera and object scale. */ - /* TODO(fclem): Replace by draw::View. */ - DRW_view_winmat_get(nullptr, winmat, false); - /* TODO(fclem): Replace by this->render_size. */ - const float *vp_size = DRW_viewport_size_get(); - - float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(object->object_to_world().ptr()); - float distance_factor = world_pixel_scale * scale * winmat[1][1] * vp_size[1] / w; - blur_size *= distance_factor; - } - - if ((fx.samples == 0.0f) || (blur_size[0] == 0.0f && blur_size[1] == 0.0f)) { - return 0; - } - - GPUShader *sh = shaders.static_shader_get(eShaderType::FX_BLUR); - - const float rot_sin = sin(fx.rotation); - const float rot_cos = cos(fx.rotation); - - if (blur_size[0] > 0.0f) { - PassMain::Sub &sub = vfx_ctx.create_vfx_pass("Fx Blur H", sh); - sub.state_set(DRW_STATE_WRITE_COLOR); - sub.push_constant("offset", float2(blur_size[0] * rot_cos, blur_size[0] * rot_sin)); - sub.push_constant("sampCount", max_ii(1, min_ii(fx.samples, blur_size[0]))); - sub.draw_procedural(GPU_PRIM_TRIS, 1, 3); - } - if (blur_size[1] > 0.0f) { - PassMain::Sub &sub = vfx_ctx.create_vfx_pass("Fx Blur V", sh); - sub.state_set(DRW_STATE_WRITE_COLOR); - sub.push_constant("offset", float2(-blur_size[1] * rot_sin, blur_size[1] * rot_cos)); - sub.push_constant("sampCount", max_ii(1, min_ii(fx.samples, blur_size[1]))); - sub.draw_procedural(GPU_PRIM_TRIS, 1, 3); - } - - /* Return number of passes. */ - return int(blur_size[0] > 0.0f) + int(blur_size[1] > 0.0f); - } - - int vfx_colorize(const ColorizeShaderFxData &fx, const Object *object, VfxContext &vfx_ctx) - { - UNUSED_VARS(fx, object, vfx_ctx); - return 0; - } - - int vfx_flip(const FlipShaderFxData &fx, const Object *object, VfxContext &vfx_ctx) - { - UNUSED_VARS(fx, object, vfx_ctx); - return 0; - } - - int vfx_pixelize(const PixelShaderFxData &fx, const Object *object, VfxContext &vfx_ctx) - { - UNUSED_VARS(fx, object, vfx_ctx); - return 0; - } - - int vfx_rim(const RimShaderFxData &fx, const Object *object, VfxContext &vfx_ctx) - { - UNUSED_VARS(fx, object, vfx_ctx); - return 0; - } - - int vfx_shadow(const ShadowShaderFxData &fx, const Object *object, VfxContext &vfx_ctx) - { - UNUSED_VARS(fx, object, vfx_ctx); - return 0; - } - - int vfx_glow(const GlowShaderFxData &fx, const Object *object, VfxContext &vfx_ctx) - { - UNUSED_VARS(fx, object, vfx_ctx); - return 0; - } - - int vfx_swirl(const SwirlShaderFxData &fx, const Object *object, VfxContext &vfx_ctx) - { - UNUSED_VARS(fx, object, vfx_ctx); - return 0; - } - - int vfx_wave(const WaveShaderFxData &fx, const Object *object, VfxContext &vfx_ctx) - { - UNUSED_VARS(fx, object, vfx_ctx); - return 0; - } - - void merge_sync(Framebuffer &main_fb, VfxContext &vfx_ctx) - { - PassMain::Sub &sub = vfx_ctx.object_subpass->sub("GPencil Object Composite"); - sub.framebuffer_set(&main_fb); - - sub.shader_set(shaders.static_shader_get(FX_COMPOSITE)); - sub.bind_texture("colorBuf", vfx_ctx.color_tx.current()); - sub.bind_texture("revealBuf", vfx_ctx.reveal_tx.current()); - - sub.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL); - sub.push_constant("isFirstPass", true); - sub.draw_procedural(GPU_PRIM_TRIS, 1, 3); - /* We cannot do custom blending on multi-target frame-buffers. - * Workaround by doing 2 passes. */ - sub.state_set(DRW_STATE_WRITE_COLOR, DRW_STATE_BLEND_ADD_FULL); - sub.push_constant("isFirstPass", false); - sub.draw_procedural(GPU_PRIM_TRIS, 1, 3); - } -}; - -} // namespace blender::draw::greasepencil diff --git a/source/blender/draw/engines/gpencil/shaders/grease_pencil_depth_merge_vert.glsl b/source/blender/draw/engines/gpencil/shaders/grease_pencil_depth_merge_vert.glsl deleted file mode 100644 index 64529a62424..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/grease_pencil_depth_merge_vert.glsl +++ /dev/null @@ -1,9 +0,0 @@ -/* SPDX-FileCopyrightText: 2020-2022 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ -#pragma BLENDER_REQUIRE(draw_model_lib.glsl) - -void main() -{ - gl_Position = drw_point_object_to_homogenous(pos); -} diff --git a/source/blender/draw/engines/gpencil/shaders/grease_pencil_frag.glsl b/source/blender/draw/engines/gpencil/shaders/grease_pencil_frag.glsl deleted file mode 100644 index 2e12e7d549e..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/grease_pencil_frag.glsl +++ /dev/null @@ -1,153 +0,0 @@ -/* SPDX-FileCopyrightText: 2020-2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma BLENDER_REQUIRE(common_grease_pencil_lib.glsl) -#pragma BLENDER_REQUIRE(common_colormanagement_lib.glsl) - -float length_squared(vec2 v) -{ - return dot(v, v); -} -float length_squared(vec3 v) -{ - return dot(v, v); -} - -vec3 gpencil_lighting(void) -{ - vec3 light_accum = vec3(0.0); - for (int i = 0; i < GPENCIL_LIGHT_BUFFER_LEN; i++) { - if (gp_lights[i]._color.x == -1.0) { - break; - } - vec3 L = gp_lights[i]._position - gp_interp.pos; - float vis = 1.0; - gpLightType type = floatBitsToUint(gp_lights[i]._type); - /* Spot Attenuation. */ - if (type == GP_LIGHT_TYPE_SPOT) { - mat3 rot_scale = mat3(gp_lights[i]._right, gp_lights[i]._up, gp_lights[i]._forward); - vec3 local_L = rot_scale * L; - local_L /= abs(local_L.z); - float ellipse = inversesqrt(length_squared(local_L)); - vis *= smoothstep(0.0, 1.0, (ellipse - gp_lights[i]._spot_size) / gp_lights[i]._spot_blend); - /* Also mask +Z cone. */ - vis *= step(0.0, local_L.z); - } - /* Inverse square decay. Skip for suns. */ - float L_len_sqr = length_squared(L); - if (type < GP_LIGHT_TYPE_SUN) { - vis /= L_len_sqr; - } - else { - L = gp_lights[i]._forward; - L_len_sqr = 1.0; - } - /* Lambertian falloff */ - if (type != GP_LIGHT_TYPE_AMBIENT) { - L /= sqrt(L_len_sqr); - vis *= clamp(dot(gpNormal, L), 0.0, 1.0); - } - light_accum += vis * gp_lights[i]._color; - } - /* Clamp to avoid NaNs. */ - return clamp(light_accum, 0.0, 1e10); -} - -/* TODO: Remove this once we can render textures. */ -vec4 debug_texture(vec2 uv) -{ - vec4 col = vec4(mod(uv.xy, 1.0), 0.0, 1.0); - return col * min(length(uv.xy * 2.0 - 1.0), 1.0); -} - -void main() -{ - vec4 col; - if (flag_test(gp_interp_flat.mat_flag, GP_STROKE_TEXTURE_USE)) { - bool premul = flag_test(gp_interp_flat.mat_flag, GP_STROKE_TEXTURE_PREMUL); - col = texture_read_as_linearrgb(gpStrokeTexture, premul, gp_interp.uv); - - /* TODO: Remove this once we can render textures. */ - /* Debug color. (Because textures are not yet implemented) */ - col = debug_texture(gp_interp.uv); - } - else if (flag_test(gp_interp_flat.mat_flag, GP_FILL_TEXTURE_USE)) { - bool use_clip = flag_test(gp_interp_flat.mat_flag, GP_FILL_TEXTURE_CLIP); - vec2 uvs = (use_clip) ? clamp(gp_interp.uv, 0.0, 1.0) : gp_interp.uv; - bool premul = flag_test(gp_interp_flat.mat_flag, GP_FILL_TEXTURE_PREMUL); - col = texture_read_as_linearrgb(gpFillTexture, premul, uvs); - } - else if (flag_test(gp_interp_flat.mat_flag, GP_FILL_GRADIENT_USE)) { - bool radial = flag_test(gp_interp_flat.mat_flag, GP_FILL_GRADIENT_RADIAL); - float fac = clamp(radial ? length(gp_interp.uv * 2.0 - 1.0) : gp_interp.uv.x, 0.0, 1.0); - uint matid = gp_interp_flat.mat_flag >> GPENCIl_MATID_SHIFT; - col = mix(gp_materials[matid].fill_color, gp_materials[matid].fill_mix_color, fac); - } - else /* SOLID */ { - col = vec4(1.0); - } - col.rgb *= col.a; - - /* Composite all other colors on top of texture color. - * Everything is pre-multiply by `col.a` to have the stencil effect. */ - fragColor = col * gp_interp.color_mul + col.a * gp_interp.color_add; - - fragColor.rgb *= gpencil_lighting(); - - fragColor *= gpencil_stroke_round_cap_mask(gp_interp_flat.sspos.xy, - gp_interp_flat.sspos.zw, - gp_interp_flat.aspect, - gp_interp_noperspective.thickness.x, - gp_interp_noperspective.hardness); - - /* To avoid aliasing artifacts, we reduce the opacity of small strokes. */ - fragColor *= smoothstep(0.0, 1.0, gp_interp_noperspective.thickness.y); - - /* Holdout materials. */ - if (flag_test(gp_interp_flat.mat_flag, GP_STROKE_HOLDOUT | GP_FILL_HOLDOUT)) { - revealColor = fragColor.aaaa; - } - else { - /* NOT holdout materials. - * For compatibility with colored alpha buffer. - * Note that we are limited to mono-chromatic alpha blending here - * because of the blend equation and the limit of 1 color target - * when using custom color blending. */ - revealColor = vec4(0.0, 0.0, 0.0, fragColor.a); - - if (fragColor.a < 0.001) { - discard; - return; - } - } - - vec2 fb_size = max(vec2(textureSize(gpSceneDepthTexture, 0).xy), - vec2(textureSize(gpMaskTexture, 0).xy)); - vec2 uvs = gl_FragCoord.xy / fb_size; - /* Manual depth test */ - float scene_depth = texture(gpSceneDepthTexture, uvs).r; - if (gl_FragCoord.z > scene_depth) { - discard; - return; - } - - /* FIXME(@fclem): Alas. This is bad for performance but it's the easiest way to not get - * depth written where the mask obliterate the layer. */ - float mask = texture(gpMaskTexture, uvs).r; - if (mask < 0.001) { - discard; - return; - } - - /* We override the fragment depth using the fragment shader to ensure a constant value. - * This has a cost as the depth test cannot happen early. - * We could do this in the vertex shader but then perspective interpolation of uvs and - * fragment clipping gets really complicated. */ - if (gp_interp_flat.depth >= 0.0) { - gl_FragDepth = gp_interp_flat.depth; - } - else { - gl_FragDepth = gl_FragCoord.z; - } -} diff --git a/source/blender/draw/engines/gpencil/shaders/grease_pencil_vert.glsl b/source/blender/draw/engines/gpencil/shaders/grease_pencil_vert.glsl deleted file mode 100644 index f931c15092b..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/grease_pencil_vert.glsl +++ /dev/null @@ -1,139 +0,0 @@ -/* SPDX-FileCopyrightText: 2020-2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma BLENDER_REQUIRE(common_grease_pencil_lib.glsl) - -void gpencil_color_output(vec4 stroke_col, vec4 vert_col, float vert_strength, float mix_tex) -{ - /* Mix stroke with other colors. */ - vec4 mixed_col = stroke_col; - mixed_col.rgb = mix(mixed_col.rgb, vert_col.rgb, vert_col.a); - mixed_col.rgb = mix(mixed_col.rgb, gpLayerTint.rgb, gpLayerTint.a); - mixed_col.a *= vert_strength * gpLayerOpacity; - /** - * This is what the fragment shader looks like. - * out = col * gp_interp.color_mul + col.a * gp_interp.color_add. - * gp_interp.color_mul is how much of the texture color to keep. - * gp_interp.color_add is how much of the mixed color to add. - * Note that we never add alpha. This is to keep the texture act as a stencil. - * We do however, modulate the alpha (reduce it). - */ - /* We add the mixed color. This is 100% mix (no texture visible). */ - gp_interp.color_mul = vec4(mixed_col.aaa, mixed_col.a); - gp_interp.color_add = vec4(mixed_col.rgb * mixed_col.a, 0.0); - /* Then we blend according to the texture mix factor. - * Note that we keep the alpha modulation. */ - gp_interp.color_mul.rgb *= mix_tex; - gp_interp.color_add.rgb *= 1.0 - mix_tex; -} - -void main() -{ - PASS_RESOURCE_ID - - float vert_strength; - vec4 vert_color; - vec3 vert_N; - - ivec4 ma1 = floatBitsToInt(texelFetch(gp_pos_tx, gpencil_stroke_point_id() * 3 + 1)); - gpMaterial gp_mat = gp_materials[ma1.x + gpMaterialOffset]; - gpMaterialFlag gp_flag = floatBitsToUint(gp_mat._flag); - - gl_Position = gpencil_vertex(vec4(viewportSize, 1.0 / viewportSize), - gp_flag, - gp_mat._alignment_rot, - gp_interp.pos, - vert_N, - vert_color, - vert_strength, - gp_interp.uv, - gp_interp_flat.sspos, - gp_interp_flat.aspect, - gp_interp_noperspective.thickness, - gp_interp_noperspective.hardness); - - if (gpencil_is_stroke_vertex()) { - if (!flag_test(gp_flag, GP_STROKE_ALIGNMENT)) { - gp_interp.uv.x *= gp_mat._stroke_u_scale; - } - - /* Special case: We don't use vertex color if material Holdout. */ - if (flag_test(gp_flag, GP_STROKE_HOLDOUT)) { - vert_color = vec4(0.0); - } - - gpencil_color_output( - gp_mat.stroke_color, vert_color, vert_strength, gp_mat._stroke_texture_mix); - - gp_interp_flat.mat_flag = gp_flag & ~GP_FILL_FLAGS; - - if (gpStrokeOrder3d) { - /* Use the fragment depth (see fragment shader). */ - gp_interp_flat.depth = -1.0; - } - else if (flag_test(gp_flag, GP_STROKE_OVERLAP)) { - /* Use the index of the point as depth. - * This means the stroke can overlap itself. */ - float point_index = float(ma1.z); - gp_interp_flat.depth = (point_index + gpStrokeIndexOffset + 2.0) * 0.0000002; - } - else { - /* Use the index of first point of the stroke as depth. - * We render using a greater depth test this means the stroke - * cannot overlap itself. - * We offset by one so that the fill can be overlapped by its stroke. - * The offset is ok since we pad the strokes data because of adjacency infos. */ - float stroke_index = float(ma1.y); - gp_interp_flat.depth = (stroke_index + gpStrokeIndexOffset + 2.0) * 0.0000002; - } - } - else { - int stroke_point_id = gpencil_stroke_point_id(); - vec4 uv1 = texelFetch(gp_pos_tx, stroke_point_id * 3 + 2); - vec4 fcol1 = texelFetch(gp_col_tx, stroke_point_id * 2 + 1); - vec4 fill_col = gp_mat.fill_color; - - /* Special case: We don't modulate alpha in gradient mode. */ - if (flag_test(gp_flag, GP_FILL_GRADIENT_USE)) { - fill_col.a = 1.0; - } - - /* Decode fill opacity. */ - vec4 fcol_decode = vec4(fcol1.rgb, floor(fcol1.a / 10.0)); - float fill_opacity = fcol1.a - (fcol_decode.a * 10); - fcol_decode.a /= 10000.0; - - /* Special case: We don't use vertex color if material Holdout. */ - if (flag_test(gp_flag, GP_FILL_HOLDOUT)) { - fcol_decode = vec4(0.0); - } - - /* Apply opacity. */ - fill_col.a *= fill_opacity; - /* If factor is > 1 force opacity. */ - if (fill_opacity > 1.0) { - fill_col.a += fill_opacity - 1.0; - } - - fill_col.a = clamp(fill_col.a, 0.0, 1.0); - - gpencil_color_output(fill_col, fcol_decode, 1.0, gp_mat._fill_texture_mix); - - gp_interp_flat.mat_flag = gp_flag & GP_FILL_FLAGS; - gp_interp_flat.mat_flag |= uint(ma1.x + gpMaterialOffset) << GPENCIl_MATID_SHIFT; - - gp_interp.uv = mat2(gp_mat.fill_uv_rot_scale.xy, gp_mat.fill_uv_rot_scale.zw) * uv1.xy + - gp_mat._fill_uv_offset; - - if (gpStrokeOrder3d) { - /* Use the fragment depth (see fragment shader). */ - gp_interp_flat.depth = -1.0; - } - else { - /* Use the index of first point of the stroke as depth. */ - float stroke_index = float(ma1.y); - gp_interp_flat.depth = (stroke_index + gpStrokeIndexOffset + 1.0) * 0.0000002; - } - } -} diff --git a/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh index af893352351..f3231e79e50 100644 --- a/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh +++ b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh @@ -54,41 +54,6 @@ GPU_SHADER_CREATE_INFO(gpencil_geometry) .depth_write(DepthWrite::ANY) .additional_info("draw_gpencil"); -GPU_SHADER_CREATE_INFO(gpencil_geometry_next) - .do_static_compilation(true) - .define("GP_LIGHT") - .typedef_source("gpencil_defines.h") - .sampler(GPENCIL_SCENE_DEPTH_TEX_SLOT, ImageType::DEPTH_2D, "gpSceneDepthTexture") - .sampler(GPENCIL_MASK_TEX_SLOT, ImageType::FLOAT_2D, "gpMaskTexture") - .sampler(GPENCIL_FILL_TEX_SLOT, ImageType::FLOAT_2D, "gpFillTexture") - .sampler(GPENCIL_STROKE_TEX_SLOT, ImageType::FLOAT_2D, "gpStrokeTexture") - .storage_buf(GPENCIL_OBJECT_SLOT, Qualifier::READ, "gpObject", "gp_object[]") - .storage_buf(GPENCIL_LAYER_SLOT, Qualifier::READ, "gpLayer", "gp_layer[]") - .storage_buf(GPENCIL_MATERIAL_SLOT, Qualifier::READ, "gpMaterial", "gp_materials[]") - .storage_buf(GPENCIL_LIGHT_SLOT, Qualifier::READ, "gpLight", "gp_lights[]") - .uniform_buf(GPENCIL_SCENE_SLOT, "gpScene", "gp_scene") - /* Per Scene */ - .define("viewportSize", "gp_scene.render_size") - /* Per Object */ - .define("gpNormal", "gp_object[resource_id].normal") - .define("gpStrokeOrder3d", "gp_object[resource_id].stroke_order3d") - .define("gpMaterialOffset", "gp_object[resource_id].material_offset") - /* Per Layer */ - .define("layer_id", "gp_object[resource_id].layer_offset") /* TODO */ - .define("gpVertexColorOpacity", "gp_layer[layer_id].vertex_color_opacity") - .define("gpLayerTint", "gp_layer[layer_id].tint") - .define("gpLayerOpacity", "gp_layer[layer_id].opacity") - .define("gpStrokeIndexOffset", "gp_layer[layer_id].stroke_index_offset") - .fragment_out(0, Type::VEC4, "fragColor") - .fragment_out(1, Type::VEC4, "revealColor") - .vertex_out(gpencil_geometry_iface) - .vertex_out(gpencil_geometry_flat_iface) - .vertex_out(gpencil_geometry_noperspective_iface) - .vertex_source("grease_pencil_vert.glsl") - .fragment_source("grease_pencil_frag.glsl") - .additional_info("draw_gpencil_new") - .depth_write(DepthWrite::ANY); - /** \} */ /* -------------------------------------------------------------------- */ @@ -126,16 +91,6 @@ GPU_SHADER_CREATE_INFO(gpencil_depth_merge) .depth_write(DepthWrite::ANY) .additional_info("draw_view"); -GPU_SHADER_CREATE_INFO(grease_pencil_depth_merge) - .do_static_compilation(true) - .define("strokeOrder3d", "false") - .sampler(0, ImageType::DEPTH_2D, "depthBuf") - .vertex_in(0, Type::VEC3, "pos") - .vertex_source("grease_pencil_depth_merge_vert.glsl") - .fragment_source("gpencil_depth_merge_frag.glsl") - .depth_write(DepthWrite::ANY) - .additional_info("draw_modelmat_new", "draw_view"); - /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/draw/engines/overlay/overlay_engine.cc b/source/blender/draw/engines/overlay/overlay_engine.cc index 6a7b586ca07..fe180e3baa1 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.cc +++ b/source/blender/draw/engines/overlay/overlay_engine.cc @@ -444,9 +444,7 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob) OVERLAY_edit_curves_cache_populate(data, ob); break; case OB_GREASE_PENCIL: - if (U.experimental.use_grease_pencil_version3) { - OVERLAY_edit_grease_pencil_cache_populate(data, ob); - } + OVERLAY_edit_grease_pencil_cache_populate(data, ob); break; } } diff --git a/source/blender/draw/engines/overlay/overlay_outline.cc b/source/blender/draw/engines/overlay/overlay_outline.cc index ca7be6f6ff6..73969b8d94e 100644 --- a/source/blender/draw/engines/overlay/overlay_outline.cc +++ b/source/blender/draw/engines/overlay/overlay_outline.cc @@ -10,13 +10,17 @@ #include "DRW_render.hh" +#include "BKE_curves.hh" #include "BKE_global.hh" #include "BKE_gpencil_legacy.h" +#include "BKE_grease_pencil.hh" #include "BKE_object.hh" #include "DNA_gpencil_legacy_types.h" +#include "ED_grease_pencil.hh" + #include "UI_resources.hh" #include "overlay_private.hh" @@ -273,6 +277,92 @@ static void OVERLAY_outline_gpencil(OVERLAY_PrivateData *pd, Object *ob) pd->cfra); } +static void OVERLAY_outline_grease_pencil(OVERLAY_PrivateData *pd, Scene *scene, Object *ob) +{ + using namespace blender; + using namespace blender::ed::greasepencil; + GreasePencil &grease_pencil = *static_cast(ob->data); + /* Outlines only in object mode. */ + if (ob->mode != OB_MODE_OBJECT) { + return; + } + + float plane[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + if ((grease_pencil.flag & GREASE_PENCIL_STROKE_ORDER_3D) == 0) { + gpencil_depth_plane(ob, plane); + } + + int t_offset = 0; + const Vector drawings = retrieve_visible_drawings(*scene, grease_pencil); + for (const DrawingInfo info : drawings) { + const bool is_screenspace = false; + const bool is_stroke_order_3d = (grease_pencil.flag & GREASE_PENCIL_STROKE_ORDER_3D) != 0; + + float object_scale = mat4_to_scale(ob->object_to_world().ptr()); + /* Negate thickness sign to tag that strokes are in screen space. + * Convert to world units (by default, 1 meter = 1000 pixels). */ + float thickness_scale = (is_screenspace) ? -1.0f : 1.0f / 1000.0f; + + GPUVertBuf *position_tx = draw::DRW_cache_grease_pencil_position_buffer_get(scene, ob); + GPUVertBuf *color_tx = draw::DRW_cache_grease_pencil_color_buffer_get(scene, ob); + + DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->outlines_gpencil_grp); + DRW_shgroup_uniform_bool_copy(grp, "gpStrokeOrder3d", is_stroke_order_3d); + DRW_shgroup_uniform_float_copy(grp, "gpThicknessScale", object_scale); + DRW_shgroup_uniform_float_copy(grp, "gpThicknessOffset", 0.0f); + DRW_shgroup_uniform_float_copy(grp, "gpThicknessWorldScale", thickness_scale); + DRW_shgroup_uniform_vec4_copy(grp, "gpDepthPlane", plane); + DRW_shgroup_buffer_texture(grp, "gp_pos_tx", position_tx); + DRW_shgroup_buffer_texture(grp, "gp_col_tx", color_tx); + + const bke::CurvesGeometry &curves = info.drawing.strokes(); + const OffsetIndices points_by_curve = curves.points_by_curve(); + const bke::AttributeAccessor attributes = curves.attributes(); + const VArray stroke_materials = *attributes.lookup_or_default( + "material_index", bke::AttrDomain::Curve, 0); + const VArray cyclic = *attributes.lookup_or_default( + "cyclic", bke::AttrDomain::Curve, false); + + IndexMaskMemory memory; + const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes( + *ob, info.drawing, memory); + + visible_strokes.foreach_index([&](const int stroke_i) { + const IndexRange points = points_by_curve[stroke_i]; + const int material_index = stroke_materials[stroke_i]; + MaterialGPencilStyle *gp_style = BKE_object_material_get(ob, material_index + 1)->gp_style; + + const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; + if (hide_material) { + return; + } + + GPUBatch *geom = draw::DRW_cache_grease_pencil_get(scene, ob); + + const bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0; + const bool show_fill = (points.size() >= 3) && (gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0; + const bool is_cyclic = cyclic[stroke_i] && (points.size() > 2); + const int num_stroke_triangles = points.size() - 2; + const int num_stroke_vertices = (points.size() + int(is_cyclic)); + + if (show_fill) { + int vfirst = t_offset * 3; + int vcount = num_stroke_triangles * 3; + DRW_shgroup_call_range(grp, ob, geom, vfirst, vcount); + } + + t_offset += num_stroke_triangles; + + if (show_stroke) { + int vfirst = t_offset * 3; + int vcount = num_stroke_vertices * 2 * 3; + DRW_shgroup_call_range(grp, ob, geom, vfirst, vcount); + } + t_offset += num_stroke_vertices * 2; + }); + } +} + static void OVERLAY_outline_volume(OVERLAY_PrivateData *pd, Object *ob) { using namespace blender::draw; @@ -326,6 +416,11 @@ void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata, return; } + if (ob->type == OB_GREASE_PENCIL) { + OVERLAY_outline_grease_pencil(pd, draw_ctx->scene, ob); + return; + } + if (ob->type == OB_VOLUME) { OVERLAY_outline_volume(pd, ob); return; diff --git a/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc b/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc index cfe42561d38..eaf1e8c63f4 100644 --- a/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc +++ b/source/blender/draw/intern/draw_cache_impl_grease_pencil.cc @@ -558,6 +558,9 @@ static void grease_pencil_geom_batch_ensure(Object &object, copy_v3_v3(s_vert.pos, math::transform_point(layer_space_to_object_space, positions[point_i])); s_vert.radius = radii[point_i] * ((end_cap == GP_STROKE_CAP_TYPE_ROUND) ? 1.0f : -1.0f); + /* Convert to legacy "pixel" space. The shader expects the values to be in this space. + * Otherwise the values will get clamped. */ + s_vert.radius *= 1000.0f; s_vert.opacity = opacities[point_i] * ((start_cap == GP_STROKE_CAP_TYPE_ROUND) ? 1.0f : -1.0f); s_vert.point_id = verts_range[idx]; @@ -620,7 +623,7 @@ static void grease_pencil_geom_batch_ensure(Object &object, cols_slice[idx]); } - if (is_cyclic) { + if (is_cyclic && points.size() >= 3) { const int idx = points.size() + 1; const float length = points.size() > 1 ? lengths[points.size() - 1] : 0.0f; populate_point(verts_range, diff --git a/source/blender/draw/intern/draw_manager_c.cc b/source/blender/draw/intern/draw_manager_c.cc index 4d62c9b10dc..1b1f630e31d 100644 --- a/source/blender/draw/intern/draw_manager_c.cc +++ b/source/blender/draw/intern/draw_manager_c.cc @@ -1271,8 +1271,7 @@ static void drw_engines_enable(ViewLayer * /*view_layer*/, drw_engines_enable_from_engine(engine_type, drawtype); if (gpencil_engine_needed && ((drawtype >= OB_SOLID) || !use_xray)) { - use_drw_engine(U.experimental.use_grease_pencil_version3 ? &draw_engine_gpencil_next_type : - &draw_engine_gpencil_type); + use_drw_engine(&draw_engine_gpencil_type); } if (is_compositor_enabled()) { @@ -1302,16 +1301,12 @@ static void drw_engines_data_validate() * For slow exact check use `DRW_render_check_grease_pencil` */ static bool drw_gpencil_engine_needed(Depsgraph *depsgraph, View3D *v3d) { - if (U.experimental.use_grease_pencil_version3) { - const bool exclude_gpencil_rendering = v3d ? (v3d->object_type_exclude_viewport & - (1 << OB_GREASE_PENCIL)) != 0 : - false; - return (!exclude_gpencil_rendering) && DEG_id_type_any_exists(depsgraph, ID_GP); - } - const bool exclude_gpencil_rendering = v3d ? (v3d->object_type_exclude_viewport & - (1 << OB_GPENCIL_LEGACY)) != 0 : - false; - return (!exclude_gpencil_rendering) && DEG_id_type_any_exists(depsgraph, ID_GD_LEGACY); + const bool exclude_gpencil_rendering = + v3d ? ((v3d->object_type_exclude_viewport & (1 << OB_GPENCIL_LEGACY)) != 0) || + ((v3d->object_type_exclude_viewport & (1 << OB_GREASE_PENCIL)) != 0) : + false; + return (!exclude_gpencil_rendering) && (DEG_id_type_any_exists(depsgraph, ID_GD_LEGACY) || + DEG_id_type_any_exists(depsgraph, ID_GP)); } /* -------------------------------------------------------------------- */ @@ -1870,9 +1865,7 @@ bool DRW_render_check_grease_pencil(Depsgraph *depsgraph) deg_iter_settings.depsgraph = depsgraph; deg_iter_settings.flags = DEG_OBJECT_ITER_FOR_RENDER_ENGINE_FLAGS; DEG_OBJECT_ITER_BEGIN (°_iter_settings, ob) { - if (ob->type == OB_GPENCIL_LEGACY || - (U.experimental.use_grease_pencil_version3 && ob->type == OB_GREASE_PENCIL)) - { + if (ob->type == OB_GPENCIL_LEGACY || ob->type == OB_GREASE_PENCIL) { if (DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF) { return true; } @@ -1887,9 +1880,7 @@ static void DRW_render_gpencil_to_image(RenderEngine *engine, RenderLayer *render_layer, const rcti *rect) { - DrawEngineType *draw_engine = U.experimental.use_grease_pencil_version3 ? - &draw_engine_gpencil_next_type : - &draw_engine_gpencil_type; + DrawEngineType *draw_engine = &draw_engine_gpencil_type; if (draw_engine->render_to_image) { ViewportEngineData *gpdata = DRW_view_data_engine_data_get_ensure(DST.view_data_active, draw_engine); @@ -2486,8 +2477,7 @@ void DRW_draw_select_loop(Depsgraph *depsgraph, else if (!draw_surface) { /* grease pencil selection */ if (drw_gpencil_engine_needed(depsgraph, v3d)) { - use_drw_engine(U.experimental.use_grease_pencil_version3 ? &draw_engine_gpencil_next_type : - &draw_engine_gpencil_type); + use_drw_engine(&draw_engine_gpencil_type); } drw_engines_enable_overlays(); @@ -2497,8 +2487,7 @@ void DRW_draw_select_loop(Depsgraph *depsgraph, drw_engines_enable_basic(); /* grease pencil selection */ if (drw_gpencil_engine_needed(depsgraph, v3d)) { - use_drw_engine(U.experimental.use_grease_pencil_version3 ? &draw_engine_gpencil_next_type : - &draw_engine_gpencil_type); + use_drw_engine(&draw_engine_gpencil_type); } drw_engines_enable_overlays(); @@ -2671,8 +2660,7 @@ void DRW_draw_depth_loop(Depsgraph *depsgraph, drw_manager_init(&DST, viewport, nullptr); if (use_gpencil) { - use_drw_engine(U.experimental.use_grease_pencil_version3 ? &draw_engine_gpencil_next_type : - &draw_engine_gpencil_type); + use_drw_engine(&draw_engine_gpencil_type); } if (use_basic) { drw_engines_enable_basic(); @@ -3062,7 +3050,6 @@ void DRW_engines_register() RE_engines_register(&DRW_engine_viewport_workbench_type); DRW_engine_register(&draw_engine_gpencil_type); - DRW_engine_register(&draw_engine_gpencil_next_type); DRW_engine_register(&draw_engine_overlay_type); DRW_engine_register(&draw_engine_overlay_next_type);