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 | |
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.
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 |