GPv3: Switch back to the current grease pencil render engine
This makes it so GPv3 objects are rendered using the current grease pencil render engine. A new `gpencil_next` engine was added at the beginning of the project, but it couldn't be finished in time. This commit removes the `gpencil_next` engine as it is no longer used. The current status of the new engine been pushed to the `gpencil-next` branch on the `blender` repository. Note: Onion skinning is not supported yet. This work will be done in a separate PR. Fixes #115467 and #116347. Pull Request: https://projects.blender.org/blender/blender/pulls/118664
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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<blender::Bounds<float3>> bounds)
|
||||
{
|
||||
using namespace blender;
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
GPENCIL_tObject *tgp_ob = static_cast<GPENCIL_tObject *>(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<float3>> 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<int> /*onion_id*/,
|
||||
GPENCIL_tObject *tgp_ob)
|
||||
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
const GreasePencil &grease_pencil = *static_cast<GreasePencil *>(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<GPENCIL_tLayer *>(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_bitmap *>(BLI_memblock_alloc(pd->gp_maskbit_pool));
|
||||
tgp_layer->mask_invert_bits = static_cast<BLI_bitmap *>(
|
||||
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;
|
||||
}
|
||||
/** \} */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<gpScene> 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<float4, 2> 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<Instance *>(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<GPENCIL_NEXT_Data *>(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<GPENCIL_NEXT_Data *>(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<GPENCIL_NEXT_Data *>(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<GPENCIL_NEXT_Data *>(vedata)->instance->object_sync(ref);
|
||||
}
|
||||
|
||||
static void gpencil_cache_finish(void *vedata)
|
||||
{
|
||||
reinterpret_cast<GPENCIL_NEXT_Data *>(vedata)->instance->end_sync();
|
||||
}
|
||||
|
||||
static void gpencil_instance_free(void *instance)
|
||||
{
|
||||
delete reinterpret_cast<draw::greasepencil::Instance *>(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<float *>(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<float *>(color_tx.read<float4>(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,
|
||||
};
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -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<blender::Bounds<float3>> 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<int> 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);
|
||||
|
||||
@@ -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<blender::Bounds<float3>> 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<GreasePencil *>(ob->data);
|
||||
const bool is_vertex_mode = (ob->mode & OB_MODE_VERTEX_PAINT) != 0;
|
||||
const std::optional<blender::Bounds<float3>> 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<DrawingInfo> drawings = retrieve_visible_drawings(*pd->scene, grease_pencil);
|
||||
const Span<const Layer *> 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<int> points_by_curve = curves.points_by_curve();
|
||||
const bke::AttributeAccessor attributes = curves.attributes();
|
||||
const VArray<int> stroke_materials = *attributes.lookup_or_default<int>(
|
||||
"material_index", bke::AttrDomain::Curve, 0);
|
||||
const VArray<bool> cyclic = *attributes.lookup_or_default<bool>(
|
||||
"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<blender::Bounds<float3>> 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);
|
||||
|
||||
@@ -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<gpLayer> 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
|
||||
@@ -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<gpLight> 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<Light *>(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<float4x4 *>(&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
|
||||
@@ -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<gpMaterial> materials_buf_ = "gp_materials_buf";
|
||||
/** List of all the texture used. */
|
||||
Vector<GPUTexture *> 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
|
||||
@@ -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<gpObject> 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<float4, 2> 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<GreasePencil *>(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<const GreasePencil *>(object.data);
|
||||
const std::optional<Bounds<float3>> 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<float4x4>(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<float4x4>(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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 <iostream>
|
||||
|
||||
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
|
||||
@@ -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<GPUShader *, MAX_SHADER_TYPE> 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
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<GPUFrameBuffer **, 2> vfx_fb;
|
||||
SwapChain<GPUTexture **, 2> color_tx;
|
||||
SwapChain<GPUTexture **, 2> 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<const Camera *>(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<const ShaderFxData>(&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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<GreasePencil *>(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<DrawingInfo> 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<int> points_by_curve = curves.points_by_curve();
|
||||
const bke::AttributeAccessor attributes = curves.attributes();
|
||||
const VArray<int> stroke_materials = *attributes.lookup_or_default<int>(
|
||||
"material_index", bke::AttrDomain::Curve, 0);
|
||||
const VArray<bool> cyclic = *attributes.lookup_or_default<bool>(
|
||||
"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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user