diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2022-03-19 23:59:29 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2022-03-20 00:05:34 +0300 |
commit | eccb0b222e3465baa71430223c5ee2f0206a7b02 (patch) | |
tree | 1b8888acea69d78466a2a727aac93b3fb1ea2e8f /source | |
parent | 36b02c3815af8f76aa9d7ce017fd00b66e8b1965 (diff) |
GPencil: Port main object shader to ShaderCreateInfo
This is quite a huge cleanup. Making use of the `common_gpencil_lib.glsl`
to share more codes and use more consistent codestyle.
The gpencil engine specifics are now out of the `gpencil_vertex()`
function making it easier to add more features.
There should be no regression as all workarounds are kept as is.
Diffstat (limited to 'source')
13 files changed, 384 insertions, 174 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 994fc923aa4..78c01ce5a23 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -364,6 +364,7 @@ set(GLSL_SRC intern/shaders/common_colormanagement_lib.glsl intern/shaders/common_globals_lib.glsl + intern/shaders/common_gpencil_lib.glsl intern/shaders/common_pointcloud_lib.glsl intern/shaders/common_hair_lib.glsl intern/shaders/common_hair_refine_vert.glsl @@ -402,6 +403,9 @@ set(GLSL_SRC engines/gpencil/shaders/gpencil_depth_merge_vert.glsl engines/gpencil/shaders/gpencil_vfx_frag.glsl + engines/gpencil/gpencil_defines.h + engines/gpencil/gpencil_shader_shared.h + engines/select/shaders/selection_id_3D_vert.glsl engines/select/shaders/selection_id_frag.glsl diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index eec38f98788..7bfbcfa9e21 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -268,7 +268,7 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd, !BLI_listbase_is_empty(&gpl->mask_layers); float vert_col_opacity = (override_vertcol) ? - (is_vert_col_mode ? pd->vertex_paint_opacity : 0.0f) : + (is_vert_col_mode ? pd->vertex_paint_opacity : 0.0f) : pd->is_render ? gpl->vertex_paint_opacity : pd->vertex_paint_opacity; /* Negate thickness sign to tag that strokes are in screen space. @@ -388,13 +388,11 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd, 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, "strokeOrder3d", tgp_ob->is_drawmode3d); - DRW_shgroup_uniform_float_copy(grp, "thicknessScale", tgp_ob->object_scale); - DRW_shgroup_uniform_vec2_copy(grp, "sizeViewportInv", DRW_viewport_invert_size_get()); - DRW_shgroup_uniform_vec2_copy(grp, "sizeViewport", DRW_viewport_size_get()); - DRW_shgroup_uniform_float_copy(grp, "thicknessOffset", (float)gpl->line_change); - DRW_shgroup_uniform_float_copy(grp, "thicknessWorldScale", thickness_scale); - DRW_shgroup_uniform_float_copy(grp, "vertexColorOpacity", vert_col_opacity); + DRW_shgroup_uniform_bool_copy(grp, "gpStrokeOrder3d", tgp_ob->is_drawmode3d); + DRW_shgroup_uniform_float_copy(grp, "gpThicknessScale", tgp_ob->object_scale); + DRW_shgroup_uniform_float_copy(grp, "gpThicknessOffset", (float)gpl->line_change); + 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]; @@ -403,9 +401,9 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd, gpencil_layer_random_color_get(ob, gpl, gpl_color); gpl_color[3] = 1.0f; } - DRW_shgroup_uniform_vec4_copy(grp, "layerTint", gpl_color); + DRW_shgroup_uniform_vec4_copy(grp, "gpLayerTint", gpl_color); - DRW_shgroup_uniform_float_copy(grp, "layerOpacity", layer_alpha); + DRW_shgroup_uniform_float_copy(grp, "gpLayerOpacity", layer_alpha); DRW_shgroup_stencil_mask(grp, 0xFF); } diff --git a/source/blender/draw/engines/gpencil/gpencil_defines.h b/source/blender/draw/engines/gpencil/gpencil_defines.h new file mode 100644 index 00000000000..6eb7bd23e4e --- /dev/null +++ b/source/blender/draw/engines/gpencil/gpencil_defines.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#define GPENCIL_MATERIAL_BUFFER_LEN 256 + +#define GPENCIL_LIGHT_BUFFER_LEN 128 + +/* High bits are used to pass material ID to fragment shader. */ +#define GPENCIl_MATID_SHIFT 16u diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c index c3f96ecd0a2..65ddb80ad55 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_data.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c @@ -58,7 +58,8 @@ static struct GPUTexture *gpencil_image_texture_get(Image *image, bool *r_alpha_ static void gpencil_uv_transform_get(const float ofs[2], const float scale[2], const float rotation, - float r_uvmat[3][2]) + 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]; @@ -70,9 +71,9 @@ static void gpencil_uv_transform_get(const float ofs[2], rotate_m4(mat, 'Z', -rotation); translate_m4(mat, ofs[0], ofs[1], 0.0f); /* Convert to 3x2 */ - copy_v2_v2(r_uvmat[0], mat[0]); - copy_v2_v2(r_uvmat[1], mat[1]); - copy_v2_v2(r_uvmat[2], mat[3]); + 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]); } static void gpencil_shade_color(float color[3]) @@ -167,7 +168,7 @@ GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Obje int mat_len = max_ii(1, BKE_object_material_count_eval(ob)); - bool reuse_matpool = matpool && ((matpool->used_count + mat_len) <= GP_MATERIAL_BUFFER_LEN); + bool reuse_matpool = matpool && ((matpool->used_count + mat_len) <= GPENCIL_MATERIAL_BUFFER_LEN); if (reuse_matpool) { /* Share the matpool with other objects. Return offset to first material. */ @@ -188,7 +189,7 @@ GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Obje GPENCIL_MaterialPool *pool = matpool; for (int i = 0; i < mat_len; i++) { - if ((i > 0) && (pool->used_count == GP_MATERIAL_BUFFER_LEN)) { + if ((i > 0) && (pool->used_count == GPENCIL_MATERIAL_BUFFER_LEN)) { pool->next = gpencil_material_pool_add(pd); pool = pool->next; } @@ -235,8 +236,8 @@ GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Obje gp_style = gpencil_viewport_material_overrides(pd, ob, color_type, gp_style, lighting_mode); /* Dots or Squares rotation. */ - mat_data->alignment_rot_cos = cosf(gp_style->alignment_rotation); - mat_data->alignment_rot_sin = sinf(gp_style->alignment_rotation); + mat_data->alignment_rot[0] = cosf(gp_style->alignment_rotation); + mat_data->alignment_rot[1] = sinf(gp_style->alignment_rotation); /* Stroke Style */ if ((gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) && (gp_style->sima)) { @@ -266,7 +267,8 @@ GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Obje gpencil_uv_transform_get(gp_style->texture_offset, gp_style->texture_scale, gp_style->texture_angle, - mat_data->fill_uv_transform); + (float(*)[2])mat_data->fill_uv_rot_scale, + mat_data->fill_uv_offset); copy_v4_v4(mat_data->fill_color, gp_style->fill_rgba); mat_data->fill_texture_mix = 1.0f - gp_style->mix_factor; } @@ -278,7 +280,8 @@ GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Obje gpencil_uv_transform_get(gp_style->texture_offset, gp_style->texture_scale, gp_style->texture_angle, - mat_data->fill_uv_transform); + (float(*)[2])mat_data->fill_uv_rot_scale, + mat_data->fill_uv_offset); copy_v4_v4(mat_data->fill_color, gp_style->fill_rgba); copy_v4_v4(mat_data->fill_mix_color, gp_style->mix_rgba); mat_data->fill_texture_mix = 1.0f - gp_style->mix_factor; @@ -303,11 +306,11 @@ void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool, GPUUniformBuf **r_ubo_mat) { GPENCIL_MaterialPool *matpool = first_pool; - int pool_id = mat_id / GP_MATERIAL_BUFFER_LEN; + int pool_id = mat_id / GPENCIL_MATERIAL_BUFFER_LEN; for (int i = 0; i < pool_id; i++) { matpool = matpool->next; } - mat_id = mat_id % GP_MATERIAL_BUFFER_LEN; + mat_id = mat_id % GPENCIL_MATERIAL_BUFFER_LEN; *r_ubo_mat = matpool->ubo; if (r_tex_fill) { *r_tex_fill = matpool->tex_fill[mat_id]; @@ -379,16 +382,16 @@ void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob) if (la->type == LA_SPOT) { copy_m4_m4(mat, ob->imat); gp_light->type = GP_LIGHT_TYPE_SPOT; - gp_light->spotsize = cosf(la->spotsize * 0.5f); - gp_light->spotblend = (1.0f - gp_light->spotsize) * la->spotblend; + gp_light->spot_size = cosf(la->spotsize * 0.5f); + gp_light->spot_blend = (1.0f - gp_light->spot_size) * la->spotblend; } else if (la->type == LA_AREA) { /* Simulate area lights using a spot light. */ normalize_m4_m4(mat, ob->obmat); invert_m4(mat); gp_light->type = GP_LIGHT_TYPE_SPOT; - gp_light->spotsize = cosf(M_PI_2); - gp_light->spotblend = (1.0f - gp_light->spotsize) * 1.0f; + gp_light->spot_size = cosf(M_PI_2); + gp_light->spot_blend = (1.0f - gp_light->spot_size) * 1.0f; } else if (la->type == LA_SUN) { normalize_v3_v3(gp_light->forward, ob->obmat[2]); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index b7bba35e298..585a508d9ce 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -276,7 +276,7 @@ void GPENCIL_cache_init(void *ved) GPUShader *sh = GPENCIL_shader_depth_merge_get(); grp = DRW_shgroup_create(sh, psl->merge_depth_ps); DRW_shgroup_uniform_texture_ref(grp, "depthBuf", &pd->depth_tx); - DRW_shgroup_uniform_bool(grp, "strokeOrder3d", &pd->is_stroke_order_3d, 1); + DRW_shgroup_uniform_bool(grp, "gpStrokeOrder3d", &pd->is_stroke_order_3d, 1); DRW_shgroup_uniform_vec4(grp, "gpModelMatrix", pd->object_bound_mat[0], 4); DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } @@ -405,8 +405,8 @@ 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, "gpMaterialBlock", iter->ubo_mat); - DRW_shgroup_uniform_float_copy(iter->grp, "strokeIndexOffset", iter->stroke_index_last); + DRW_shgroup_uniform_block(iter->grp, "materials", iter->ubo_mat); + DRW_shgroup_uniform_float_copy(iter->grp, "gpStrokeIndexOffset", iter->stroke_index_last); const DRWContextState *ctx = DRW_context_state_get(); ToolSettings *ts = ctx->scene->toolsettings; @@ -453,12 +453,12 @@ static void gpencil_layer_cache_populate(bGPDlayer *gpl, /* Iterator dependent uniforms. */ DRWShadingGroup *grp = iter->grp = tgp_layer->base_shgrp; - DRW_shgroup_uniform_block(grp, "gpLightBlock", iter->ubo_lights); - DRW_shgroup_uniform_block(grp, "gpMaterialBlock", iter->ubo_mat); + DRW_shgroup_uniform_block(grp, "lights", iter->ubo_lights); + DRW_shgroup_uniform_block(grp, "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); - DRW_shgroup_uniform_float_copy(grp, "strokeIndexOffset", iter->stroke_index_offset); + DRW_shgroup_uniform_float_copy(grp, "gpStrokeIndexOffset", iter->stroke_index_offset); } static void gpencil_stroke_cache_populate(bGPDlayer *gpl, @@ -500,7 +500,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, "gpMaterialBlock", ubo_mat); + DRW_shgroup_uniform_block(iter->grp, "materials", ubo_mat); iter->ubo_mat = ubo_mat; } if (tex_fill) { diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index 9ef558c7a75..332c7f67c64 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -19,6 +19,9 @@ extern "C" { #endif +#include "gpencil_defines.h" +#include "gpencil_shader_shared.h" + extern DrawEngineType draw_engine_gpencil_type; struct GPENCIL_Data; @@ -39,69 +42,17 @@ struct bGPDstroke; #define GP_MAX_MASKBITS 256 -/* UBO structure. Watch out for padding. Must match GLSL declaration. */ -typedef struct gpMaterial { - float stroke_color[4]; - float fill_color[4]; - float fill_mix_color[4]; - float fill_uv_transform[3][2], alignment_rot_cos, alignment_rot_sin; - float stroke_texture_mix; - float stroke_u_scale; - float fill_texture_mix; - int flag; -} gpMaterial; - -/* gpMaterial->flag */ -/* WATCH Keep in sync with GLSL declaration. */ -#define GP_STROKE_ALIGNMENT_STROKE 1 -#define GP_STROKE_ALIGNMENT_OBJECT 2 -#define GP_STROKE_ALIGNMENT_FIXED 3 -#define GP_STROKE_ALIGNMENT 0x3 -#define GP_STROKE_OVERLAP (1 << 2) -#define GP_STROKE_TEXTURE_USE (1 << 3) -#define GP_STROKE_TEXTURE_STENCIL (1 << 4) -#define GP_STROKE_TEXTURE_PREMUL (1 << 5) -#define GP_STROKE_DOTS (1 << 6) -#define GP_STROKE_HOLDOUT (1 << 7) -#define GP_FILL_HOLDOUT (1 << 8) -#define GP_FILL_TEXTURE_USE (1 << 10) -#define GP_FILL_TEXTURE_PREMUL (1 << 11) -#define GP_FILL_TEXTURE_CLIP (1 << 12) -#define GP_FILL_GRADIENT_USE (1 << 13) -#define GP_FILL_GRADIENT_RADIAL (1 << 14) - -#define GPENCIL_LIGHT_BUFFER_LEN 128 - -/* UBO structure. Watch out for padding. Must match GLSL declaration. */ -typedef struct gpLight { - float color[3], type; - float right[3], spotsize; - float up[3], spotblend; - float forward[4]; - float position[4]; -} gpLight; - -/* gpLight->type */ -/* WATCH Keep in sync with GLSL declaration. */ -#define GP_LIGHT_TYPE_POINT 0.0 -#define GP_LIGHT_TYPE_SPOT 1.0 -#define GP_LIGHT_TYPE_SUN 2.0 -#define GP_LIGHT_TYPE_AMBIENT 3.0 - -BLI_STATIC_ASSERT_ALIGN(gpMaterial, 16) -BLI_STATIC_ASSERT_ALIGN(gpLight, 16) - /* *********** Draw Data *********** */ typedef struct GPENCIL_MaterialPool { /* Single linked-list. */ struct GPENCIL_MaterialPool *next; /* GPU representation of materials. */ - gpMaterial mat_data[GP_MATERIAL_BUFFER_LEN]; + gpMaterial mat_data[GPENCIL_MATERIAL_BUFFER_LEN]; /* Matching ubo. */ struct GPUUniformBuf *ubo; /* Texture per material. NULL means none. */ - struct GPUTexture *tex_fill[GP_MATERIAL_BUFFER_LEN]; - struct GPUTexture *tex_stroke[GP_MATERIAL_BUFFER_LEN]; + struct GPUTexture *tex_fill[GPENCIL_MATERIAL_BUFFER_LEN]; + struct GPUTexture *tex_stroke[GPENCIL_MATERIAL_BUFFER_LEN]; /* Number of material used in this pool. */ int used_count; } GPENCIL_MaterialPool; diff --git a/source/blender/draw/engines/gpencil/gpencil_shader.c b/source/blender/draw/engines/gpencil/gpencil_shader.c index fca2e700346..dd12fcc70d8 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader.c +++ b/source/blender/draw/engines/gpencil/gpencil_shader.c @@ -46,18 +46,6 @@ static struct { GPUShader *fx_rim_sh; GPUShader *fx_shadow_sh; GPUShader *fx_transform_sh; - /* general drawing shaders */ - GPUShader *gpencil_fill_sh; - GPUShader *gpencil_stroke_sh; - GPUShader *gpencil_point_sh; - GPUShader *gpencil_edit_point_sh; - GPUShader *gpencil_line_sh; - GPUShader *gpencil_drawing_fill_sh; - GPUShader *gpencil_fullscreen_sh; - GPUShader *gpencil_simple_fullscreen_sh; - GPUShader *gpencil_blend_fullscreen_sh; - GPUShader *gpencil_background_sh; - GPUShader *gpencil_paper_sh; } g_shaders = {{NULL}}; void GPENCIL_shader_free(void) @@ -78,17 +66,6 @@ void GPENCIL_shader_free(void) DRW_SHADER_FREE_SAFE(g_shaders.fx_rim_sh); DRW_SHADER_FREE_SAFE(g_shaders.fx_shadow_sh); DRW_SHADER_FREE_SAFE(g_shaders.fx_transform_sh); - DRW_SHADER_FREE_SAFE(g_shaders.gpencil_fill_sh); - DRW_SHADER_FREE_SAFE(g_shaders.gpencil_stroke_sh); - DRW_SHADER_FREE_SAFE(g_shaders.gpencil_point_sh); - DRW_SHADER_FREE_SAFE(g_shaders.gpencil_edit_point_sh); - DRW_SHADER_FREE_SAFE(g_shaders.gpencil_line_sh); - DRW_SHADER_FREE_SAFE(g_shaders.gpencil_drawing_fill_sh); - DRW_SHADER_FREE_SAFE(g_shaders.gpencil_fullscreen_sh); - DRW_SHADER_FREE_SAFE(g_shaders.gpencil_simple_fullscreen_sh); - DRW_SHADER_FREE_SAFE(g_shaders.gpencil_blend_fullscreen_sh); - DRW_SHADER_FREE_SAFE(g_shaders.gpencil_background_sh); - DRW_SHADER_FREE_SAFE(g_shaders.gpencil_paper_sh); } GPUShader *GPENCIL_shader_antialiasing(int stage) @@ -106,29 +83,7 @@ GPUShader *GPENCIL_shader_antialiasing(int stage) GPUShader *GPENCIL_shader_geometry_get(void) { if (!g_shaders.gpencil_sh) { - g_shaders.gpencil_sh = GPU_shader_create_from_arrays({ - .vert = - (const char *[]){ - datatoc_common_view_lib_glsl, - datatoc_gpencil_common_lib_glsl, - datatoc_gpencil_vert_glsl, - NULL, - }, - .frag = - (const char *[]){ - datatoc_common_colormanagement_lib_glsl, - datatoc_gpencil_common_lib_glsl, - datatoc_gpencil_frag_glsl, - NULL, - }, - .defs = - (const char *[]){ - "#define GP_MATERIAL_BUFFER_LEN " STRINGIFY(GP_MATERIAL_BUFFER_LEN) "\n", - "#define GPENCIL_LIGHT_BUFFER_LEN " STRINGIFY(GPENCIL_LIGHT_BUFFER_LEN) "\n", - "#define UNIFORM_RESOURCE_ID\n", - NULL, - }, - }); + g_shaders.gpencil_sh = GPU_shader_create_from_info_name("gpencil_geometry"); } return g_shaders.gpencil_sh; } diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_shared.h b/source/blender/draw/engines/gpencil/gpencil_shader_shared.h new file mode 100644 index 00000000000..889652c739b --- /dev/null +++ b/source/blender/draw/engines/gpencil/gpencil_shader_shared.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef GPU_SHADER +# include "GPU_shader_shared_utils.h" + +typedef struct gpMaterial gpMaterial; +typedef struct gpLight gpLight; +typedef enum gpMaterialFlag gpMaterialFlag; +typedef enum gpLightType gpLightType; +#endif + +enum gpMaterialFlag { + GP_STROKE_ALIGNMENT_STROKE = 1u, + GP_STROKE_ALIGNMENT_OBJECT = 2u, + GP_STROKE_ALIGNMENT_FIXED = 3u, + GP_STROKE_ALIGNMENT = 0x3u, + GP_STROKE_OVERLAP = (1u << 2u), + GP_STROKE_TEXTURE_USE = (1u << 3u), + GP_STROKE_TEXTURE_STENCIL = (1u << 4u), + GP_STROKE_TEXTURE_PREMUL = (1u << 5u), + GP_STROKE_DOTS = (1u << 6u), + GP_STROKE_HOLDOUT = (1u << 7u), + GP_FILL_HOLDOUT = (1u << 8u), + GP_FILL_TEXTURE_USE = (1u << 10u), + GP_FILL_TEXTURE_PREMUL = (1u << 11u), + GP_FILL_TEXTURE_CLIP = (1u << 12u), + GP_FILL_GRADIENT_USE = (1u << 13u), + GP_FILL_GRADIENT_RADIAL = (1u << 14u), + 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), +}; + +enum gpLightType { + GP_LIGHT_TYPE_POINT = 0u, + GP_LIGHT_TYPE_SPOT = 1u, + GP_LIGHT_TYPE_SUN = 2u, + GP_LIGHT_TYPE_AMBIENT = 3u, +}; + +/* Avoid compiler funkiness with enum types not being strongly typed in C. */ +#ifndef GPU_SHADER +# define gpMaterialFlag uint +# define gpLightType uint +#endif + +struct gpMaterial { + float4 stroke_color; + float4 fill_color; + float4 fill_mix_color; + float4 fill_uv_rot_scale; +#ifndef GPU_SHADER + float2 fill_uv_offset; + float2 alignment_rot; + float stroke_texture_mix; + float stroke_u_scale; + float fill_texture_mix; + gpMaterialFlag flag; +#else + /* Some drivers are completely messing the alignment or the fetches here. + * We are forced to pack these into vec4 otherwise we only get 0.0 as value. */ + /* NOTE(@fclem): This was the case on MacOS OpenGL implementation. + * This might be fixed in newer APIs. */ + float4 packed1; + float4 packed2; +# define _fill_uv_offset packed1.xy +# define _alignment_rot packed1.zw +# define _stroke_texture_mix packed2.x +# define _stroke_u_scale packed2.y +# define _fill_texture_mix packed2.z + /** NOTE(@fclem): Needs floatBitsToUint(). */ +# define _flag packed2.w +#endif +}; +BLI_STATIC_ASSERT_ALIGN(gpMaterial, 16) + +struct gpLight { +#ifndef GPU_SHADER + float3 color; + gpLightType type; + float3 right; + float spot_size; + float3 up; + float spot_blend; + float3 forward; + float _pad0; + float3 position; + float _pad1; +#else + /* Some drivers are completely messing the alignment or the fetches here. + * We are forced to pack these into vec4 otherwise we only get 0.0 as value. */ + /* NOTE(@fclem): This was the case on MacOS OpenGL implementation. + * This might be fixed in newer APIs. */ + float4 packed0; + float4 packed1; + float4 packed2; + float4 packed3; + float4 packed4; +# define _color packed0.xyz +# define _type packed0.w +# define _right packed1.xyz +# define _spot_size packed1.w +# define _up packed2.xyz +# define _spot_blend packed2.w +# define _forward packed3.xyz +# define _position packed4.xyz +#endif +}; +BLI_STATIC_ASSERT_ALIGN(gpLight, 16) + +#ifndef GPU_SHADER +# undef gpMaterialFlag +# undef gpLightType +#endif diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl index 87365c2844d..d0dcea34c6e 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl @@ -1,12 +1,6 @@ -uniform sampler2D gpFillTexture; -uniform sampler2D gpStrokeTexture; -uniform sampler2D gpSceneDepthTexture; -uniform sampler2D gpMaskTexture; -uniform vec3 gpNormal; - -layout(location = 0) out vec4 fragColor; -layout(location = 1) out vec4 revealColor; +#pragma BLENDER_REQUIRE(common_gpencil_lib.glsl) +#pragma BLENDER_REQUIRE(common_colormanagement_lib.glsl) float length_squared(vec2 v) { @@ -21,36 +15,37 @@ vec3 gpencil_lighting(void) { vec3 light_accum = vec3(0.0); for (int i = 0; i < GPENCIL_LIGHT_BUFFER_LEN; i++) { - if (lights[i].color_type.x == -1.0) { + if (lights[i]._color.x == -1.0) { break; } - vec3 L = lights[i].position.xyz - finalPos; + vec3 L = lights[i]._position - gp_interp.pos; float vis = 1.0; + gpLightType type = floatBitsToUint(lights[i]._type); /* Spot Attenuation. */ - if (lights[i].color_type.w == GP_LIGHT_TYPE_SPOT) { - mat3 rot_scale = mat3(lights[i].right.xyz, lights[i].up.xyz, lights[i].forward.xyz); + if (type == GP_LIGHT_TYPE_SPOT) { + mat3 rot_scale = mat3(lights[i]._right, lights[i]._up, 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 - lights[i]._spot_size) / 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 (lights[i].color_type.w < GP_LIGHT_TYPE_SUN) { + if (type < GP_LIGHT_TYPE_SUN) { vis /= L_len_sqr; } else { - L = lights[i].forward.xyz; + L = lights[i]._forward; L_len_sqr = 1.0; } /* Lambertian falloff */ - if (lights[i].color_type.w != GP_LIGHT_TYPE_AMBIENT) { + if (type != GP_LIGHT_TYPE_AMBIENT) { L /= sqrt(L_len_sqr); vis *= clamp(dot(gpNormal, L), 0.0, 1.0); } - light_accum += vis * lights[i].color_type.rgb; + light_accum += vis * lights[i]._color; } /* Clamp to avoid NaNs. */ return clamp(light_accum, 0.0, 1e10); @@ -59,21 +54,21 @@ vec3 gpencil_lighting(void) void main() { vec4 col; - if (GP_FLAG_TEST(matFlag, GP_STROKE_TEXTURE_USE)) { - bool premul = GP_FLAG_TEST(matFlag, GP_STROKE_TEXTURE_PREMUL); - col = texture_read_as_linearrgb(gpStrokeTexture, premul, finalUvs); + if (flag_test(gp_interp.mat_flag, GP_STROKE_TEXTURE_USE)) { + bool premul = flag_test(gp_interp.mat_flag, GP_STROKE_TEXTURE_PREMUL); + col = texture_read_as_linearrgb(gpStrokeTexture, premul, gp_interp.uv); } - else if (GP_FLAG_TEST(matFlag, GP_FILL_TEXTURE_USE)) { - bool use_clip = GP_FLAG_TEST(matFlag, GP_FILL_TEXTURE_CLIP); - vec2 uvs = (use_clip) ? clamp(finalUvs, 0.0, 1.0) : finalUvs; - bool premul = GP_FLAG_TEST(matFlag, GP_FILL_TEXTURE_PREMUL); + else if (flag_test(gp_interp.mat_flag, GP_FILL_TEXTURE_USE)) { + bool use_clip = flag_test(gp_interp.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.mat_flag, GP_FILL_TEXTURE_PREMUL); col = texture_read_as_linearrgb(gpFillTexture, premul, uvs); } - else if (GP_FLAG_TEST(matFlag, GP_FILL_GRADIENT_USE)) { - bool radial = GP_FLAG_TEST(matFlag, GP_FILL_GRADIENT_RADIAL); - float fac = clamp(radial ? length(finalUvs * 2.0 - 1.0) : finalUvs.x, 0.0, 1.0); - int matid = matFlag >> GP_MATID_SHIFT; - col = mix(MATERIAL(matid).fill_color, MATERIAL(matid).fill_mix_color, fac); + else if (flag_test(gp_interp.mat_flag, GP_FILL_GRADIENT_USE)) { + 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); } else /* SOLID */ { col = vec4(1.0); @@ -82,18 +77,21 @@ void main() /* Composite all other colors on top of texture color. * Everything is premult by col.a to have the stencil effect. */ - fragColor = col * finalColorMul + col.a * finalColorAdd; + fragColor = col * gp_interp.color_mul + col.a * gp_interp.color_add; fragColor.rgb *= gpencil_lighting(); - fragColor *= stroke_round_cap_mask( - strokePt1, strokePt2, strokeAspect, strokeThickness, strokeHardeness); + fragColor *= gpencil_stroke_round_cap_mask(gp_interp.sspos.xy, + gp_interp.sspos.zw, + gp_interp.aspect, + gp_interp.thickness.x, + gp_interp.hardness); /* To avoid aliasing artifacts, we reduce the opacity of small strokes. */ - fragColor *= smoothstep(0.0, 1.0, unclampedThickness); + fragColor *= smoothstep(0.0, 1.0, gp_interp.thickness.y); /* Holdout materials. */ - if (GP_FLAG_TEST(matFlag, GP_STROKE_HOLDOUT | GP_FILL_HOLDOUT)) { + if (flag_test(gp_interp.mat_flag, GP_STROKE_HOLDOUT | GP_FILL_HOLDOUT)) { revealColor = fragColor.aaaa; } else { @@ -129,8 +127,8 @@ void main() * 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 (depth >= 0.0) { - gl_FragDepth = depth; + if (gp_interp.depth >= 0.0) { + gl_FragDepth = gp_interp.depth; } else { gl_FragDepth = gl_FragCoord.z; diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl index 225601eb9ba..c0ff8d945f2 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl @@ -1,5 +1,141 @@ +#pragma BLENDER_REQUIRE(common_gpencil_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 * gpVertexColorOpacity); + 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() { - gpencil_vertex(); + float vert_strength; + vec4 vert_color; + vec3 vert_N; + + gpMaterial gp_mat = materials[ma1.x + gpMaterialOffset]; + gpMaterialFlag gp_flag = floatBitsToInt(gp_mat._flag); + + gl_Position = gpencil_vertex(ma, + ma1, + ma2, + ma3, + pos, + pos1, + pos2, + pos3, + uv1, + uv2, + col1, + col2, + fcol1, + vec4(drw_view.viewport_size, drw_view.viewport_size_inverse), + gp_flag, + gp_mat._alignment_rot, + gp_interp.pos, + vert_N, + vert_color, + vert_strength, + gp_interp.uv, + gp_interp.sspos, + gp_interp.aspect, + gp_interp.thickness, + gp_interp.hardness); + + if (GPENCIL_IS_STROKE_VERTEX) { + 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.mat_flag = gp_flag & ~GP_FILL_FLAGS; + + if (gpStrokeOrder3d) { + /* Use the fragment depth (see fragment shader). */ + gp_interp.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.depth = (point_index + gpStrokeIndexOffset + 1.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.depth = (stroke_index + gpStrokeIndexOffset + 1.0) * 0.0000002; + } + } + else { + 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.mat_flag = gp_flag & GP_FILL_FLAGS; + gp_interp.mat_flag |= uint(ma1.x) << 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.depth = -1.0; + } + else { + /* Use the index of first point of the stroke as depth. */ + float stroke_index = float(ma1.y); + gp_interp.depth = (stroke_index + gpStrokeIndexOffset) * 0.0000002; + } + } } diff --git a/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh index 76fa8ae609b..3b4de704c00 100644 --- a/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh +++ b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh @@ -3,6 +3,50 @@ #include "gpu_shader_create_info.hh" /* -------------------------------------------------------------------- */ +/** \name GPencil Object rendering + * \{ */ + +GPU_SHADER_INTERFACE_INFO(gpencil_geometry_iface, "gp_interp") + .smooth(Type::VEC4, "color_mul") + .smooth(Type::VEC4, "color_add") + .smooth(Type::VEC3, "pos") + .smooth(Type::VEC2, "uv") + .no_perspective(Type::VEC2, "thickness") + .no_perspective(Type::FLOAT, "hardness") + .flat(Type::VEC2, "aspect") + .flat(Type::VEC4, "sspos") + .flat(Type::UINT, "mat_flag") + .flat(Type::FLOAT, "depth"); + +GPU_SHADER_CREATE_INFO(gpencil_geometry) + .do_static_compilation(true) + .typedef_source("gpencil_defines.h") + .typedef_source("gpencil_shader_shared.h") + .sampler(0, ImageType::FLOAT_2D, "gpFillTexture") + .sampler(1, ImageType::FLOAT_2D, "gpStrokeTexture") + .sampler(2, ImageType::DEPTH_2D, "gpSceneDepthTexture") + .sampler(3, ImageType::FLOAT_2D, "gpMaskTexture") + .uniform_buf(2, "gpMaterial", "materials[GPENCIL_MATERIAL_BUFFER_LEN]", Frequency::BATCH) + .uniform_buf(3, "gpLight", "lights[GPENCIL_LIGHT_BUFFER_LEN]", Frequency::BATCH) + /* Per Object */ + .push_constant(Type::VEC3, "gpNormal") + .push_constant(Type::BOOL, "gpStrokeOrder3d") + .push_constant(Type::INT, "gpMaterialOffset") + /* Per Layer */ + .push_constant(Type::FLOAT, "gpVertexColorOpacity") + .push_constant(Type::VEC4, "gpLayerTint") + .push_constant(Type::FLOAT, "gpLayerOpacity") + .push_constant(Type::FLOAT, "gpStrokeIndexOffset") + .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"); + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Fullscreen shaders * \{ */ diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c index 08c33555b71..a4465b9aed4 100644 --- a/source/blender/draw/intern/draw_cache_impl_gpencil.c +++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c @@ -28,6 +28,8 @@ #include "draw_cache.h" #include "draw_cache_impl.h" +#include "../engines/gpencil/gpencil_defines.h" + #define BEZIER_HANDLE (1 << 3) #define COLOR_SHIFT 5 @@ -321,7 +323,7 @@ static void gpencil_buffer_add_point(gpStrokeVert *verts, vert->point_id = v; vert->thickness = max_ff(0.0f, gps->thickness * pt->pressure) * (round_cap1 ? 1.0f : -1.0f); /* Tag endpoint material to -1 so they get discarded by vertex shader. */ - vert->mat = (is_endpoint) ? -1 : (gps->mat_nr % GP_MATERIAL_BUFFER_LEN); + vert->mat = (is_endpoint) ? -1 : (gps->mat_nr % GPENCIL_MATERIAL_BUFFER_LEN); float aspect_ratio = gps->aspect_ratio[0] / max_ff(gps->aspect_ratio[1], 1e-8); diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index fe3613548a6..8a30a7e8c99 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -25,8 +25,6 @@ struct MDeformVert; #define GP_DEFAULT_GRID_LINES 4 #define GP_MAX_INPUT_SAMPLES 10 -#define GP_MATERIAL_BUFFER_LEN 256 - #define GP_DEFAULT_CURVE_RESOLUTION 32 #define GP_DEFAULT_CURVE_ERROR 0.1f #define GP_DEFAULT_CURVE_EDIT_CORNER_ANGLE M_PI_2 |