Initial Grease Pencil 3.0 stage #106848
|
@ -2318,6 +2318,7 @@ class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
|
|||
({"property": "use_full_frame_compositor"}, "T88150"),
|
||||
({"property": "enable_eevee_next"}, "T93220"),
|
||||
({"property": "use_draw_manager_acquire_lock"}, "T98016"),
|
||||
({"property": "enable_gpencil_next"}, ""),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
@ -172,9 +172,11 @@ set(SRC
|
|||
engines/gpencil/gpencil_cache_utils.c
|
||||
engines/gpencil/gpencil_draw_data.c
|
||||
engines/gpencil/gpencil_engine.c
|
||||
engines/gpencil/gpencil_engine.cc
|
||||
engines/gpencil/gpencil_engine.h
|
||||
engines/gpencil/gpencil_render.c
|
||||
engines/gpencil/gpencil_shader.c
|
||||
engines/gpencil/gpencil_shader.cc
|
||||
engines/gpencil/gpencil_shader_fx.c
|
||||
engines/select/select_draw_utils.c
|
||||
engines/select/select_engine.c
|
||||
|
@ -772,4 +774,3 @@ if(WITH_GTESTS)
|
|||
blender_add_test_lib(bf_draw_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2022 Blender Foundation. */
|
||||
filedescriptor marked this conversation as resolved
Outdated
|
||||
|
||||
/** \file
|
||||
* \ingroup draw
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_image.h"
|
||||
#include "DRW_gpu_wrapper.hh"
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "draw_manager.hh"
|
||||
#include "draw_pass.hh"
|
||||
|
||||
#include "gpencil_shader.hh"
|
||||
|
||||
#include "smaa_textures.h"
|
||||
|
||||
namespace blender::gpencil {
|
||||
Hans Goudey
commented
It looks like this should be in the Same with elsewhere in this diff. It looks like this should be in the `blender::draw::` namespace first, given the file path. Since `greasepencil` isn't a top-level module, a `blender::greasepencil` namespace probably doesn't make sense in general.
Same with elsewhere in this diff.
|
||||
|
||||
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, int2(SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT)};
|
||||
Texture smaa_area_tx_ = {"smaa_area", GPU_RG8, 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"};
|
||||
|
||||
Framebuffer output_fb_ = {"output_fb"};
|
||||
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_ = GPENCIL_SIMPLIFY_AA(scene);
|
||||
}
|
||||
|
||||
void begin_sync(TextureFromPool &color_tx, 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]};
|
||||
|
||||
if (anti_aliasing_enabled_) {
|
||||
/* Stage 1: Edge detection. */
|
||||
PassSimple &pass = edge_detect_ps_;
|
||||
pass.init();
|
||||
pass.framebuffer_set(&edge_detect_fb_);
|
||||
Sergey Sharybin
commented
I would totally split the code into smaller functions. I do not see what are we winning from such inlined code. I would totally split the code into smaller functions. I do not see what are we winning from such inlined code.
|
||||
pass.state_set(DRW_STATE_WRITE_COLOR);
|
||||
pass.shader_set(shaders_.static_shader_get(ANTIALIASING_EDGE_DETECT));
|
||||
pass.bind_texture("colorTex", &color_tx);
|
||||
pass.bind_texture("revealTex", &reveal_tx);
|
||||
pass.push_constant("viewportMetrics", metrics);
|
||||
pass.push_constant("lumaWeight", luma_weight_);
|
||||
pass.clear_color(float4(0.0f));
|
||||
pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
|
||||
}
|
||||
if (anti_aliasing_enabled_) {
|
||||
/* Stage 2: Blend Weight/Coord. */
|
||||
PassSimple &pass = blend_weight_ps_;
|
||||
pass.init();
|
||||
|
||||
pass.framebuffer_set(&blend_weight_fb_);
|
||||
pass.state_set(DRW_STATE_WRITE_COLOR);
|
||||
pass.shader_set(shaders_.static_shader_get(ANTIALIASING_BLEND_WEIGHT));
|
||||
pass.bind_texture("edgesTex", &edge_detect_tx_);
|
||||
pass.bind_texture("areaTex", smaa_area_tx_);
|
||||
pass.bind_texture("searchTex", smaa_search_tx_);
|
||||
pass.push_constant("viewportMetrics", metrics);
|
||||
pass.clear_color(float4(0.0f));
|
||||
pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
|
||||
}
|
||||
{
|
||||
/* Stage 3: Resolve. */
|
||||
PassSimple &pass = resolve_ps_;
|
||||
pass.init();
|
||||
pass.framebuffer_set(&output_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 diabled. */
|
||||
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, GPUTexture *dst_color_tx)
|
||||
{
|
||||
int2 render_size = {GPU_texture_width(dst_color_tx), GPU_texture_height(dst_color_tx)};
|
||||
|
||||
DRW_stats_group_start("Anti-Aliasing");
|
||||
|
||||
if (anti_aliasing_enabled_) {
|
||||
edge_detect_tx_.acquire(render_size, GPU_RG8);
|
||||
edge_detect_fb_.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(edge_detect_tx_));
|
||||
manager.submit(edge_detect_ps_);
|
||||
}
|
||||
|
||||
if (anti_aliasing_enabled_) {
|
||||
blend_weight_tx_.acquire(render_size, GPU_RGBA8);
|
||||
blend_weight_fb_.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(blend_weight_tx_));
|
||||
manager.submit(blend_weight_ps_);
|
||||
edge_detect_tx_.release();
|
||||
Sergey Sharybin
commented
Why this extra check is needed? Why this extra check is needed?
|
||||
}
|
||||
|
||||
output_fb_.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(dst_color_tx));
|
||||
manager.submit(resolve_ps_);
|
||||
blend_weight_tx_.release();
|
||||
|
||||
DRW_stats_group_end();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::gpencil
|
|
@ -6,3 +6,16 @@
|
|||
|
||||
/* High bits are used to pass material ID to fragment shader. */
|
||||
#define GPENCIl_MATID_SHIFT 16u
|
||||
|
||||
/* Textures */
|
||||
#define GPENCIL_SCENE_DEPTH_TEX_SLOT 2
|
||||
#define GPENCIL_MASK_TEX_SLOT 3
|
||||
#define GPENCIL_FILL_TEX_SLOT 4
|
||||
#define GPENCIL_STROKE_TEX_SLOT 5
|
||||
/* SSBOs */
|
||||
#define GPENCIL_OBJECT_SLOT 0
|
||||
#define GPENCIL_LAYER_SLOT 1
|
||||
#define GPENCIL_MATERIAL_SLOT 2
|
||||
#define GPENCIL_LIGHT_SLOT 3
|
||||
/* UBOs */
|
||||
#define GPENCIL_SCENE_SLOT 2
|
||||
|
|
|
@ -396,7 +396,7 @@ static void gpencil_sbuffer_cache_populate(gpIterPopulateData *iter)
|
|||
* Remember, sbuffer stroke indices start from 0. So we add last index to avoid
|
||||
* masking issues. */
|
||||
iter->grp = DRW_shgroup_create_sub(iter->grp);
|
||||
DRW_shgroup_uniform_block(iter->grp, "materials", iter->ubo_mat);
|
||||
DRW_shgroup_uniform_block(iter->grp, "gp_materials", iter->ubo_mat);
|
||||
DRW_shgroup_uniform_float_copy(iter->grp, "gpStrokeIndexOffset", iter->stroke_index_last);
|
||||
|
||||
const DRWContextState *ctx = DRW_context_state_get();
|
||||
|
@ -444,8 +444,8 @@ static void gpencil_layer_cache_populate(bGPDlayer *gpl,
|
|||
|
||||
/* Iterator dependent uniforms. */
|
||||
DRWShadingGroup *grp = iter->grp = tgp_layer->base_shgrp;
|
||||
DRW_shgroup_uniform_block(grp, "lights", iter->ubo_lights);
|
||||
DRW_shgroup_uniform_block(grp, "materials", iter->ubo_mat);
|
||||
DRW_shgroup_uniform_block(grp, "gp_lights", iter->ubo_lights);
|
||||
DRW_shgroup_uniform_block(grp, "gp_materials", iter->ubo_mat);
|
||||
DRW_shgroup_uniform_texture(grp, "gpFillTexture", iter->tex_fill);
|
||||
DRW_shgroup_uniform_texture(grp, "gpStrokeTexture", iter->tex_stroke);
|
||||
DRW_shgroup_uniform_int_copy(grp, "gpMaterialOffset", iter->mat_ofs);
|
||||
|
@ -492,7 +492,7 @@ static void gpencil_stroke_cache_populate(bGPDlayer *gpl,
|
|||
|
||||
iter->grp = DRW_shgroup_create_sub(iter->grp);
|
||||
if (iter->ubo_mat != ubo_mat) {
|
||||
DRW_shgroup_uniform_block(iter->grp, "materials", ubo_mat);
|
||||
DRW_shgroup_uniform_block(iter->grp, "gp_materials", ubo_mat);
|
||||
iter->ubo_mat = ubo_mat;
|
||||
}
|
||||
if (tex_fill) {
|
||||
|
|
|
@ -0,0 +1,318 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2022 Blender Foundation. */
|
||||
filedescriptor marked this conversation as resolved
Outdated
Sergey Sharybin
commented
2023 2023
|
||||
|
||||
/** \file
|
||||
* \ingroup draw
|
||||
*/
|
||||
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_gpencil_modifier.h"
|
||||
#include "BLI_listbase_wrapper.hh"
|
||||
#include "DEG_depsgraph_query.h"
|
||||
#include "DNA_shader_fx_types.h"
|
||||
#include "DRW_engine.h"
|
||||
#include "DRW_render.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_view3d.h"
|
||||
#include "GPU_capabilities.h"
|
||||
#include "IMB_imbuf_types.h"
|
||||
|
||||
#include "draw_manager.hh"
|
||||
#include "draw_pass.hh"
|
||||
|
||||
Sergey Sharybin
commented
What is this about? What is this about?
|
||||
#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::gpencil {
|
||||
|
||||
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"};
|
||||
|
||||
/** 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, int2(1), (float *)dummy_px_};
|
||||
Texture dummy_color_tx_ = {"dummy_color", GPU_RGBA16F, 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;
|
||||
|
||||
/** \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, const View3D *v3d, const RegionView3D *rv3d)
|
||||
{
|
||||
depsgraph_ = depsgraph;
|
||||
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(Manager & /* manager */)
|
||||
{
|
||||
/* TODO(fclem): Remove global draw manager access. */
|
||||
View main_view("GPencil_MainView", DRW_view_default_get());
|
||||
|
||||
objects.begin_sync(depsgraph_, main_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_, reveal_tx_);
|
||||
}
|
||||
|
||||
void object_sync(Manager &manager, ObjectRef &object_ref)
|
||||
{
|
||||
switch (object_ref.object->type) {
|
||||
case OB_GPENCIL:
|
||||
objects.sync_gpencil(manager, object_ref, main_fb_, main_ps_);
|
||||
break;
|
||||
case OB_LAMP:
|
||||
lights.sync(object_ref);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void end_sync(Manager & /* manager */)
|
||||
{
|
||||
objects.end_sync();
|
||||
layers.end_sync();
|
||||
materials.end_sync();
|
||||
lights.end_sync();
|
||||
}
|
||||
|
||||
void draw_viewport(Manager &manager,
|
||||
View &view,
|
||||
GPUTexture *dst_depth_tx,
|
||||
GPUTexture *dst_color_tx)
|
||||
{
|
||||
if (!objects.scene_has_visible_gpencil_object()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int2 render_size = {GPU_texture_width(dst_depth_tx), GPU_texture_height(dst_depth_tx)};
|
||||
|
||||
depth_tx_.acquire(render_size, GPU_DEPTH24_STENCIL8);
|
||||
color_tx_.acquire(render_size, texture_format_);
|
||||
reveal_tx_.acquire(render_size, 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_size);
|
||||
scene_buf_.push_update();
|
||||
|
||||
objects.acquire_temporary_buffers(render_size, texture_format_);
|
||||
|
||||
manager.submit(main_ps_, view);
|
||||
|
||||
objects.release_temporary_buffers();
|
||||
|
||||
anti_aliasing.draw(manager, dst_color_tx);
|
||||
|
||||
depth_tx_.release();
|
||||
color_tx_.release();
|
||||
reveal_tx_.release();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::gpencil
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Interface with legacy C DRW manager
|
||||
* \{ */
|
||||
|
||||
using namespace blender;
|
||||
|
||||
struct GPENCIL_NEXT_Data {
|
||||
DrawEngineType *engine_type;
|
||||
DRWViewportEmptyList *fbl;
|
||||
DRWViewportEmptyList *txl;
|
||||
DRWViewportEmptyList *psl;
|
||||
Hans Goudey
commented
This struct name is interesting... I guess it's temporary though :P This struct name is interesting... I guess it's temporary though :P
Falk David
commented
Yes it is :) Yes it is :)
|
||||
DRWViewportEmptyList *stl;
|
||||
gpencil::Instance *instance;
|
||||
|
||||
char info[GPU_INFO_SIZE];
|
||||
};
|
||||
|
||||
static void gpencil_engine_init(void *vedata)
|
||||
{
|
||||
/* TODO(fclem): Remove once it is minimum required. */
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
|
||||
GPENCIL_NEXT_Data *ved = reinterpret_cast<GPENCIL_NEXT_Data *>(vedata);
|
||||
if (ved->instance == nullptr) {
|
||||
ved->instance = new gpencil::Instance();
|
||||
}
|
||||
|
||||
const DRWContextState *ctx_state = DRW_context_state_get();
|
||||
|
||||
ved->instance->init(ctx_state->depsgraph, ctx_state->v3d, ctx_state->rv3d);
|
||||
}
|
||||
|
||||
static void gpencil_draw_scene(void *vedata)
|
||||
{
|
||||
GPENCIL_NEXT_Data *ved = reinterpret_cast<GPENCIL_NEXT_Data *>(vedata);
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
STRNCPY(ved->info, "Error: No shader storage buffer support");
|
||||
return;
|
||||
}
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
const DRWView *default_view = DRW_view_default_get();
|
||||
draw::Manager *manager = DRW_manager_get();
|
||||
draw::View view("DefaultView", default_view);
|
||||
ved->instance->draw_viewport(*manager, view, dtxl->depth, dtxl->color);
|
||||
}
|
||||
|
||||
static void gpencil_cache_init(void *vedata)
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
draw::Manager *manager = DRW_manager_get();
|
||||
reinterpret_cast<GPENCIL_NEXT_Data *>(vedata)->instance->begin_sync(*manager);
|
||||
}
|
||||
|
||||
static void gpencil_cache_populate(void *vedata, Object *object)
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
draw::Manager *manager = DRW_manager_get();
|
||||
|
||||
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(*manager, ref);
|
||||
}
|
||||
|
||||
static void gpencil_cache_finish(void *vedata)
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
draw::Manager *manager = DRW_manager_get();
|
||||
reinterpret_cast<GPENCIL_NEXT_Data *>(vedata)->instance->end_sync(*manager);
|
||||
}
|
||||
|
||||
static void gpencil_instance_free(void *instance)
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
delete reinterpret_cast<gpencil::Instance *>(instance);
|
||||
}
|
||||
|
||||
static void gpencil_engine_free()
|
||||
{
|
||||
blender::gpencil::ShaderModule::module_free();
|
||||
}
|
||||
|
||||
static void gpencil_render_to_image(void *vedata,
|
||||
struct RenderEngine *engine,
|
||||
struct RenderLayer *layer,
|
||||
const struct rcti *UNUSED(rect))
|
||||
{
|
||||
UNUSED_VARS(vedata, engine, layer);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
static const DrawEngineDataSize gpencil_data_size = DRW_VIEWPORT_DATA_SIZE(GPENCIL_NEXT_Data);
|
||||
|
||||
DrawEngineType draw_engine_gpencil_next_type = {
|
||||
Hans Goudey
commented
Commented argument names instead of this macro here Commented argument names instead of this macro here
|
||||
nullptr,
|
||||
nullptr,
|
||||
N_("Gpencil"),
|
||||
&gpencil_data_size,
|
||||
&gpencil_engine_init,
|
||||
&gpencil_engine_free,
|
||||
&gpencil_instance_free,
|
||||
&gpencil_cache_init,
|
||||
&gpencil_cache_populate,
|
||||
&gpencil_cache_finish,
|
||||
&gpencil_draw_scene,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&gpencil_render_to_image,
|
||||
nullptr,
|
||||
};
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -25,6 +25,7 @@ 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;
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2022 Blender Foundation. */
|
||||
Sergey Sharybin
commented
Check everywhere else :) 2023.
Check everywhere else :)
|
||||
|
||||
/** \file
|
||||
* \ingroup draw
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_image.h"
|
||||
filedescriptor marked this conversation as resolved
Sergey Sharybin
commented
I am not sure all of those are needed here. I am not sure all of those are needed here.
I.e. I do not see any `BKE_image` API used in this header. Might be missing something.
|
||||
#include "DRW_gpu_wrapper.hh"
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "draw_manager.hh"
|
||||
#include "draw_pass.hh"
|
||||
|
||||
namespace blender::gpencil {
|
||||
|
||||
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 bGPDlayer *gpl, bool &do_layer_blending)
|
||||
{
|
||||
UNUSED_VARS(object, gpl);
|
||||
Sergey Sharybin
commented
In C++ use In C++ use `void sync(const Object * /*object*/, const bke::greasepencil::Layer & /*layer*/, bool &do_layer_blending)`
|
||||
/* TODO(fclem): All of this is placeholder. */
|
||||
gpLayer layer;
|
||||
layer.vertex_color_opacity = 0.0f;
|
||||
layer.opacity = 1.0f;
|
||||
layer.thickness_offset = 0.0f;
|
||||
layer.tint = float4(1.0f, 1.0f, 1.0f, 0.0f);
|
||||
|
||||
layers_buf_.append(layer);
|
||||
|
||||
do_layer_blending = false;
|
||||
}
|
||||
|
||||
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::gpencil
|
|
@ -0,0 +1,130 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2022 Blender Foundation. */
|
||||
|
||||
/** \file
|
||||
* \ingroup draw
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_image.h"
|
||||
#include "DRW_gpu_wrapper.hh"
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "draw_manager.hh"
|
||||
#include "draw_pass.hh"
|
||||
|
||||
namespace blender::gpencil {
|
||||
|
||||
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 = float4x4(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);
|
||||
invert_m4(mat.ptr());
|
||||
break;
|
||||
case LA_SUN:
|
||||
light.forward = math::normalize(float3(ob->object_to_world[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[3]);
|
||||
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::gpencil
|
|
@ -0,0 +1,313 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2022 Blender Foundation. */
|
||||
|
||||
/** \file
|
||||
* \ingroup draw
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_image.h"
|
||||
#include "DRW_gpu_wrapper.hh"
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "draw_manager.hh"
|
||||
#include "draw_pass.hh"
|
||||
|
||||
namespace blender::gpencil {
|
||||
|
||||
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)
|
||||
{
|
||||
ImBuf *ibuf;
|
||||
ImageUser iuser = {nullptr};
|
||||
GPUTexture *gpu_tex = nullptr;
|
||||
void *lock;
|
||||
bool premul = false;
|
||||
|
||||
if (image == nullptr) {
|
||||
texture_pool_.append(nullptr);
|
||||
return GP_FLAG_NONE;
|
||||
}
|
||||
|
||||
ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
|
||||
|
||||
if (ibuf != nullptr && ibuf->rect != nullptr) {
|
||||
gpu_tex = BKE_image_get_gpu_texture(image, &iuser, ibuf);
|
||||
premul = (image->alpha_mode == IMA_ALPHA_PREMUL) != 0;
|
||||
}
|
||||
BKE_image_release_ibuf(image, ibuf, lock);
|
||||
|
||||
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);
|
||||
|
||||
/* 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::gpencil
|
|
@ -0,0 +1,304 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2022 Blender Foundation. */
|
||||
|
||||
/** \file
|
||||
* \ingroup draw
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_image.h"
|
||||
#include "DRW_gpu_wrapper.hh"
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "draw_manager.hh"
|
||||
#include "draw_pass.hh"
|
||||
|
||||
#include "gpencil_layer.hh"
|
||||
#include "gpencil_material.hh"
|
||||
#include "gpencil_shader.hh"
|
||||
|
||||
namespace blender::gpencil {
|
||||
|
||||
using namespace draw;
|
||||
|
||||
class ObjectModule {
|
||||
private:
|
||||
/* TODO(fclem): This is a workaround to the current GPencil data structure.
|
||||
* Rendering is much easier if we have frame containing layers. */
|
||||
struct LayerData {
|
||||
/* Layer / Frame tuple representing a layer inside a frame. */
|
||||
const bGPDlayer *gpl;
|
||||
const bGPDframe *gpf;
|
||||
};
|
||||
struct FrameData {
|
||||
/* First layer frame to access frame members. */
|
||||
const bGPDframe *gpf;
|
||||
Vector<LayerData, 8> layers;
|
||||
};
|
||||
|
||||
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;
|
||||
/** Forward vector used to sort gpencil objects. */
|
||||
float3 camera_forward_;
|
||||
/** Scene current frame. */
|
||||
float current_frame_ = 0;
|
||||
|
||||
/** \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);
|
||||
|
||||
if (is_viewport) {
|
||||
/* TODO(fclem): Avoid access to global DRW. */
|
||||
const struct 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_ = float3(main_view.viewinv()[2]);
|
||||
current_frame_ = DEG_get_ctime(depsgraph);
|
||||
|
||||
is_object_fb_needed_ = false;
|
||||
is_layer_fb_needed_ = false;
|
||||
|
||||
/* TODO(fclem): Shrink buffer. */
|
||||
// objects_buf_.shrink();
|
||||
}
|
||||
|
||||
void sync_gpencil(Manager &manager,
|
||||
ObjectRef &object_ref,
|
||||
Framebuffer &main_fb,
|
||||
PassSortable &main_ps)
|
||||
{
|
||||
Object *object = object_ref.object;
|
||||
bGPdata *gpd = static_cast<bGPdata *>(object->data);
|
||||
ListBaseWrapper<const bGPDlayer> layers(&gpd->layers);
|
||||
|
||||
if (BLI_listbase_is_empty(&gpd->layers)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool is_stroke_order_3d = (gpd->draw_mode == GP_DRAWMODE_3D);
|
||||
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 (auto i : IndexRange(BKE_object_material_count_eval(object))) {
|
||||
materials_.sync(object, i, do_material_holdout);
|
||||
}
|
||||
|
||||
uint layer_offset = layers_.object_offset_get();
|
||||
for (const bGPDlayer *layer : layers) {
|
||||
layers_.sync(object, layer, do_layer_blending);
|
||||
}
|
||||
|
||||
/* Order rendering using camera Z distance. */
|
||||
float3 position = float3(object->object_to_world[3]);
|
||||
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));
|
||||
|
||||
Vector<FrameData, 5> frames;
|
||||
displayed_frame_select(frames, layers);
|
||||
|
||||
for (const FrameData &frame : frames) {
|
||||
/* TODO(fclem): Pass per frame object matrix here. */
|
||||
Sergey Sharybin
commented
Typically dead code is discouraged. Typically dead code is discouraged.
Not sure what is it part of, so can't really give strong suggestions.
|
||||
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 = frame_tint_get(gpd, frame.gpf, current_frame_);
|
||||
ob.layer_offset = layer_offset;
|
||||
ob.material_offset = material_offset;
|
||||
|
||||
GPUVertBuf *position_tx = DRW_cache_gpencil_position_buffer_get(object, frame.gpf->framenum);
|
||||
GPUVertBuf *color_tx = DRW_cache_gpencil_color_buffer_get(object, frame.gpf->framenum);
|
||||
GPUBatch *geom = DRW_cache_gpencil_get(object, frame.gpf->framenum);
|
||||
|
||||
if (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.draw(geom, handle);
|
||||
|
||||
Sergey Sharybin
commented
Add a comment what is this about, or remove. Add a comment what is this about, or remove.
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
#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()
|
||||
{
|
||||
Sergey Sharybin
commented
Same as above. Same as above.
|
||||
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;
|
||||
}
|
||||
|
||||
private:
|
||||
static float4 frame_tint_get(const bGPdata *gpd, const bGPDframe *gpf, int /* current_frame */)
|
||||
{
|
||||
/* TODO(fclem): Onion color should rely on time and or frame id and not on runtime.onion_id.
|
||||
* This should be evaluated at draw time as it is just a way of displaying the data. */
|
||||
const bool use_onion_custom_col = (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) != 0;
|
||||
const bool use_onion_fade = (gpd->onion_flag & GP_ONION_FADE) != 0;
|
||||
const bool use_next_col = gpf->runtime.onion_id > 0.0f;
|
||||
|
||||
const float *onion_col_custom = (use_onion_custom_col) ?
|
||||
(use_next_col ? gpd->gcolor_next : gpd->gcolor_prev) :
|
||||
U.gpencil_new_layer_col;
|
||||
|
||||
float4 tint = {UNPACK3(onion_col_custom), 1.0f};
|
||||
|
||||
tint[3] = use_onion_fade ? (1.0f / abs(gpf->runtime.onion_id)) : 0.5f;
|
||||
tint[3] *= gpd->onion_factor;
|
||||
tint[3] = (gpd->onion_factor > 0.0f) ? clamp_f(tint[3], 0.1f, 1.0f) :
|
||||
clamp_f(tint[3], 0.01f, 1.0f);
|
||||
return tint;
|
||||
}
|
||||
|
||||
void displayed_frame_select(Vector<FrameData, 5> &frames,
|
||||
ListBaseWrapper<const bGPDlayer> layers)
|
||||
{
|
||||
/* TODO(fclem): Select onion skin frames. */
|
||||
/** \note Change data layout to be Frame major instead of Layer major.
|
||||
* Hopefully the GPencil data layout will be closer to that in the future. */
|
||||
FrameData frame_data;
|
||||
frame_data.gpf = layers.get(0)->actframe;
|
||||
for (const bGPDlayer *layer : layers) {
|
||||
LayerData layer_data;
|
||||
layer_data.gpf = layer->actframe;
|
||||
layer_data.gpl = layer;
|
||||
frame_data.layers.append(layer_data);
|
||||
}
|
||||
frames.append(frame_data);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::gpencil
|
|
@ -0,0 +1,115 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2022 Blender Foundation. */
|
||||
|
||||
/** \file
|
||||
* \ingroup draw
|
||||
*/
|
||||
|
||||
#include "gpencil_shader.hh"
|
||||
|
||||
namespace blender::gpencil {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/* 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().";
|
||||
Sergey Sharybin
commented
Also, why not to assert the details in the P.S. I think we should implement Glog style of checkers: `<< std::endl` to put new line and flush the output buffer.
Also, why not to assert the details in the `static_shader_create_info_name_get()` ? It is a bit weird to print an error about mistake in some other code.
P.S. I think we should implement Glog style of checkers: `DCHECK_NE(name, nullptr) << "GPencil: Missing case for eShaderType(" << i << ") in static_shader_create_info_name_get()."`
|
||||
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 "gpencil_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) {
|
||||
fprintf(stderr, "GPencil: error: Could not compile static shader \"%s\"\n", shader_name);
|
||||
Sergey Sharybin
commented
Pick a side between Pick a side between `fprintf` and `std::cerr` ;)
|
||||
}
|
||||
BLI_assert(shaders_[shader_type] != nullptr);
|
||||
}
|
||||
return shaders_[shader_type];
|
||||
}
|
||||
|
||||
} // namespace blender::gpencil
|
|
@ -0,0 +1,65 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2022 Blender Foundation. */
|
||||
|
||||
/** \file
|
||||
* \ingroup draw
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DRW_render.h"
|
||||
|
||||
namespace blender::gpencil {
|
||||
|
||||
enum eShaderType {
|
||||
/* SMAA antialiasing */
|
||||
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::gpencil
|
|
@ -1,11 +1,16 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#ifndef GPU_SHADER
|
||||
# pragma once
|
||||
|
||||
# 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;
|
||||
|
@ -14,6 +19,7 @@ typedef enum gpLightType gpLightType;
|
|||
#endif
|
||||
|
||||
enum gpMaterialFlag {
|
||||
GP_FLAG_NONE = 0u,
|
||||
GP_STROKE_ALIGNMENT_STROKE = 1u,
|
||||
GP_STROKE_ALIGNMENT_OBJECT = 2u,
|
||||
GP_STROKE_ALIGNMENT_FIXED = 3u,
|
||||
|
@ -50,6 +56,12 @@ 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;
|
||||
|
@ -116,6 +128,38 @@ struct gpLight {
|
|||
BLI_STATIC_ASSERT_ALIGN(gpLight, 16)
|
||||
#endif
|
||||
|
||||
struct gpObject {
|
||||
/** Wether or not to apply lighting to the GPencil object. */
|
||||
bool1 is_shadeless;
|
||||
/** Switch between 2d and 3D stroke order. */
|
||||
bool1 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
|
||||
|
|
|
@ -0,0 +1,334 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2017 Blender Foundation. */
|
||||
|
||||
/** \file
|
||||
* \ingroup draw
|
||||
*/
|
||||
#include "BKE_camera.h"
|
||||
#include "BLI_listbase_wrapper.hh"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_gpencil_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::gpencil {
|
||||
|
||||
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[3]));
|
||||
|
||||
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);
|
||||
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::gpencil
|
|
@ -15,19 +15,19 @@ vec3 gpencil_lighting(void)
|
|||
{
|
||||
vec3 light_accum = vec3(0.0);
|
||||
for (int i = 0; i < GPENCIL_LIGHT_BUFFER_LEN; i++) {
|
||||
if (lights[i]._color.x == -1.0) {
|
||||
if (gp_lights[i]._color.x == -1.0) {
|
||||
break;
|
||||
}
|
||||
vec3 L = lights[i]._position - gp_interp.pos;
|
||||
vec3 L = gp_lights[i]._position - gp_interp.pos;
|
||||
float vis = 1.0;
|
||||
gpLightType type = floatBitsToUint(lights[i]._type);
|
||||
gpLightType type = floatBitsToUint(gp_lights[i]._type);
|
||||
/* Spot Attenuation. */
|
||||
if (type == GP_LIGHT_TYPE_SPOT) {
|
||||
mat3 rot_scale = mat3(lights[i]._right, lights[i]._up, lights[i]._forward);
|
||||
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 - lights[i]._spot_size) / lights[i]._spot_blend);
|
||||
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);
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ vec3 gpencil_lighting(void)
|
|||
vis /= L_len_sqr;
|
||||
}
|
||||
else {
|
||||
L = lights[i]._forward;
|
||||
L = gp_lights[i]._forward;
|
||||
L_len_sqr = 1.0;
|
||||
}
|
||||
/* Lambertian falloff */
|
||||
|
@ -45,7 +45,7 @@ vec3 gpencil_lighting(void)
|
|||
L /= sqrt(L_len_sqr);
|
||||
vis *= clamp(dot(gpNormal, L), 0.0, 1.0);
|
||||
}
|
||||
light_accum += vis * lights[i]._color;
|
||||
light_accum += vis * gp_lights[i]._color;
|
||||
}
|
||||
/* Clamp to avoid NaNs. */
|
||||
return clamp(light_accum, 0.0, 1e10);
|
||||
|
@ -68,7 +68,7 @@ void main()
|
|||
bool radial = flag_test(gp_interp.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.mat_flag >> GPENCIl_MATID_SHIFT;
|
||||
col = mix(materials[matid].fill_color, materials[matid].fill_mix_color, fac);
|
||||
col = mix(gp_materials[matid].fill_color, gp_materials[matid].fill_mix_color, fac);
|
||||
}
|
||||
else /* SOLID */ {
|
||||
col = vec4(1.0);
|
||||
|
|
|
@ -27,12 +27,14 @@ void gpencil_color_output(vec4 stroke_col, vec4 vert_col, float vert_strength, f
|
|||
|
||||
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 = materials[ma1.x + gpMaterialOffset];
|
||||
gpMaterial gp_mat = gp_materials[ma1.x + gpMaterialOffset];
|
||||
gpMaterialFlag gp_flag = floatBitsToUint(gp_mat._flag);
|
||||
|
||||
gl_Position = gpencil_vertex(vec4(viewportSize, 1.0 / viewportSize),
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
#include "gpencil_defines.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name GPencil Object rendering
|
||||
* \{ */
|
||||
|
@ -26,8 +28,8 @@ GPU_SHADER_CREATE_INFO(gpencil_geometry)
|
|||
.sampler(3, ImageType::FLOAT_2D, "gpStrokeTexture")
|
||||
.sampler(4, ImageType::DEPTH_2D, "gpSceneDepthTexture")
|
||||
.sampler(5, ImageType::FLOAT_2D, "gpMaskTexture")
|
||||
.uniform_buf(4, "gpMaterial", "materials[GPENCIL_MATERIAL_BUFFER_LEN]", Frequency::BATCH)
|
||||
.uniform_buf(3, "gpLight", "lights[GPENCIL_LIGHT_BUFFER_LEN]", Frequency::BATCH)
|
||||
.uniform_buf(4, "gpMaterial", "gp_materials[GPENCIL_MATERIAL_BUFFER_LEN]", Frequency::BATCH)
|
||||
.uniform_buf(3, "gpLight", "gp_lights[GPENCIL_LIGHT_BUFFER_LEN]", Frequency::BATCH)
|
||||
.push_constant(Type::VEC2, "viewportSize")
|
||||
/* Per Object */
|
||||
.push_constant(Type::VEC3, "gpNormal")
|
||||
|
@ -43,7 +45,39 @@ GPU_SHADER_CREATE_INFO(gpencil_geometry)
|
|||
.vertex_out(gpencil_geometry_iface)
|
||||
.vertex_source("gpencil_vert.glsl")
|
||||
.fragment_source("gpencil_frag.glsl")
|
||||
.additional_info("draw_gpencil");
|
||||
.additional_info("draw_gpencil", "draw_resource_id_varying");
|
||||
|
||||
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_source("gpencil_vert.glsl")
|
||||
.fragment_source("gpencil_frag.glsl")
|
||||
.additional_info("draw_gpencil_new");
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -1276,7 +1276,8 @@ static void drw_engines_enable(ViewLayer *UNUSED(view_layer),
|
|||
|
||||
drw_engines_enable_from_engine(engine_type, drawtype);
|
||||
if (gpencil_engine_needed && ((drawtype >= OB_SOLID) || !use_xray)) {
|
||||
use_drw_engine(&draw_engine_gpencil_type);
|
||||
use_drw_engine(((U.experimental.enable_gpencil_next) ? &draw_engine_gpencil_next_type :
|
||||
&draw_engine_gpencil_type));
|
||||
}
|
||||
|
||||
if (is_compositor_enabled()) {
|
||||
|
@ -1888,10 +1889,13 @@ static void DRW_render_gpencil_to_image(RenderEngine *engine,
|
|||
struct RenderLayer *render_layer,
|
||||
const rcti *rect)
|
||||
{
|
||||
if (draw_engine_gpencil_type.render_to_image) {
|
||||
DrawEngineType *draw_engine = U.experimental.enable_gpencil_next ?
|
||||
&draw_engine_gpencil_next_type :
|
||||
&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_gpencil_type);
|
||||
draw_engine_gpencil_type.render_to_image(gpdata, engine, render_layer, rect);
|
||||
draw_engine);
|
||||
draw_engine->render_to_image(gpdata, engine, render_layer, rect);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2455,7 +2459,8 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
|
|||
else if (!draw_surface) {
|
||||
/* grease pencil selection */
|
||||
if (drw_gpencil_engine_needed(depsgraph, v3d)) {
|
||||
use_drw_engine(&draw_engine_gpencil_type);
|
||||
use_drw_engine(((U.experimental.enable_gpencil_next) ? &draw_engine_gpencil_next_type :
|
||||
&draw_engine_gpencil_type));
|
||||
}
|
||||
|
||||
drw_engines_enable_overlays();
|
||||
|
@ -2465,7 +2470,8 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
|
|||
drw_engines_enable_basic();
|
||||
/* grease pencil selection */
|
||||
if (drw_gpencil_engine_needed(depsgraph, v3d)) {
|
||||
use_drw_engine(&draw_engine_gpencil_type);
|
||||
use_drw_engine(((U.experimental.enable_gpencil_next) ? &draw_engine_gpencil_next_type :
|
||||
&draw_engine_gpencil_type));
|
||||
}
|
||||
|
||||
drw_engines_enable_overlays();
|
||||
|
@ -2630,7 +2636,8 @@ void DRW_draw_depth_loop(struct Depsgraph *depsgraph,
|
|||
drw_manager_init(&DST, viewport, NULL);
|
||||
|
||||
if (use_gpencil) {
|
||||
use_drw_engine(&draw_engine_gpencil_type);
|
||||
use_drw_engine(((U.experimental.enable_gpencil_next) ? &draw_engine_gpencil_next_type :
|
||||
&draw_engine_gpencil_type));
|
||||
}
|
||||
if (use_basic) {
|
||||
drw_engines_enable_basic();
|
||||
|
@ -2998,6 +3005,7 @@ void DRW_engines_register(void)
|
|||
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_select_type);
|
||||
|
|
|
@ -130,6 +130,22 @@ GPU_SHADER_CREATE_INFO(draw_gpencil)
|
|||
.push_constant(Type::FLOAT, "gpThicknessOffset")
|
||||
.additional_info("draw_modelmat", "draw_object_infos");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(draw_gpencil_new)
|
||||
.typedef_source("gpencil_shader_shared.h")
|
||||
.define("DRW_GPENCIL_INFO")
|
||||
.sampler(0, ImageType::FLOAT_BUFFER, "gp_pos_tx")
|
||||
.sampler(1, ImageType::FLOAT_BUFFER, "gp_col_tx")
|
||||
/* Per Object */
|
||||
.define("gpThicknessScale", "1.0") /* TODO(fclem): Replace with object info. */
|
||||
.define("gpThicknessWorldScale", "1.0 / 2000.0") /* TODO(fclem): Same as above. */
|
||||
.define("gpThicknessIsScreenSpace", "(gpThicknessWorldScale < 0.0)")
|
||||
/* Per Layer */
|
||||
.define("gpThicknessOffset", "0.0") /* TODO(fclem): Remove. */
|
||||
.additional_info("draw_modelmat_new",
|
||||
"draw_resource_id_varying",
|
||||
"draw_view",
|
||||
"draw_object_infos_new");
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -29,6 +29,7 @@ set(INC
|
|||
# For *_info.hh includes.
|
||||
../compositor/realtime_compositor
|
||||
../draw/engines/eevee_next
|
||||
../draw/engines/gpencil
|
||||
../draw/intern
|
||||
|
||||
# For node muting stuff.
|
||||
|
|
|
@ -653,7 +653,8 @@ typedef struct UserDef_Experimental {
|
|||
char use_sculpt_texture_paint;
|
||||
char use_draw_manager_acquire_lock;
|
||||
char use_realtime_compositor;
|
||||
char _pad[7];
|
||||
char enable_gpencil_next;
|
||||
char _pad[6];
|
||||
/** `makesdna` does not allow empty structs. */
|
||||
} UserDef_Experimental;
|
||||
|
||||
|
|
|
@ -6389,6 +6389,10 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
|
|||
RNA_def_property_boolean_sdna(prop, NULL, "enable_eevee_next", 1);
|
||||
RNA_def_property_ui_text(prop, "EEVEE Next", "Enable the new EEVEE codebase, requires restart");
|
||||
|
||||
prop = RNA_def_property(srna, "enable_gpencil_next", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "enable_gpencil_next", 1);
|
||||
RNA_def_property_ui_text(prop, "GPENCIL Next", "Enable the new GPencil codebase");
|
||||
|
||||
prop = RNA_def_property(srna, "use_viewport_debug", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "use_viewport_debug", 1);
|
||||
RNA_def_property_ui_text(prop,
|
||||
|
|
2023