diff options
Diffstat (limited to 'source/blender/draw/engines/gpencil')
8 files changed, 71 insertions, 668 deletions
diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index a41918e7e0d..06bf531cded 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -39,9 +39,9 @@ GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob) tgp_ob->layers.first = tgp_ob->layers.last = NULL; tgp_ob->vfx.first = tgp_ob->vfx.last = NULL; - tgp_ob->camera_z = dot_v3v3(pd->camera_z_axis, ob->obmat[3]); + tgp_ob->camera_z = dot_v3v3(pd->camera_z_axis, ob->object_to_world[3]); tgp_ob->is_drawmode3d = (gpd->draw_mode == GP_DRAWMODE_3D) || pd->draw_depth_only; - tgp_ob->object_scale = mat4_to_scale(ob->obmat); + tgp_ob->object_scale = mat4_to_scale(ob->object_to_world); /* Check if any material with holdout flag enabled. */ tgp_ob->do_mat_holdout = false; @@ -71,7 +71,7 @@ GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob) add_v3_fl(size, 1e-8f); rescale_m4(mat, size); /* BBox space to World. */ - mul_m4_m4m4(mat, ob->obmat, mat); + mul_m4_m4m4(mat, ob->object_to_world, mat); if (DRW_view_is_persp_get(NULL)) { /* BBox center to camera vector. */ sub_v3_v3v3(tgp_ob->plane_normal, pd->camera_pos, mat[3]); @@ -96,9 +96,9 @@ GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob) unit_m4(tgp_ob->plane_mat); copy_v3_v3(tgp_ob->plane_mat[2], tgp_ob->plane_normal); orthogonalize_m4(tgp_ob->plane_mat, 2); - mul_mat3_m4_v3(ob->obmat, size); + mul_mat3_m4_v3(ob->object_to_world, size); float radius = len_v3(size); - mul_m4_v3(ob->obmat, center); + mul_m4_v3(ob->object_to_world, center); rescale_m4(tgp_ob->plane_mat, (float[3]){radius, radius, radius}); copy_v3_v3(tgp_ob->plane_mat[3], center); diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c index e54ac99a888..1ebf3982a12 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_data.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c @@ -380,27 +380,27 @@ void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob) float(*mat)[4] = (float(*)[4])gp_light->right; if (la->type == LA_SPOT) { - copy_m4_m4(mat, ob->imat); + copy_m4_m4(mat, ob->world_to_object); gp_light->type = GP_LIGHT_TYPE_SPOT; 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); + normalize_m4_m4(mat, ob->object_to_world); invert_m4(mat); gp_light->type = GP_LIGHT_TYPE_SPOT; 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]); + normalize_v3_v3(gp_light->forward, ob->object_to_world[2]); gp_light->type = GP_LIGHT_TYPE_SUN; } else { gp_light->type = GP_LIGHT_TYPE_POINT; } - copy_v4_v4(gp_light->position, ob->obmat[3]); + copy_v4_v4(gp_light->position, ob->object_to_world[3]); copy_v3_v3(gp_light->color, &la->r); mul_v3_fl(gp_light->color, la->energy * light_power_get(la)); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index b24e4c605e4..6a4312e572a 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -289,7 +289,7 @@ void GPENCIL_cache_init(void *ved) DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } - Camera *cam = (pd->camera != NULL) ? pd->camera->data : NULL; + Camera *cam = (pd->camera != NULL && pd->camera->type == OB_CAMERA) ? pd->camera->data : NULL; /* Pseudo DOF setup. */ if (cam && (cam->dof.flag & CAM_DOF_ENABLED)) { @@ -342,7 +342,6 @@ typedef struct gpIterPopulateData { int stroke_index_offset; /* Infos for call batching. */ struct GPUBatch *geom; - bool instancing; int vfirst, vcount; } gpIterPopulateData; @@ -352,12 +351,7 @@ static void gpencil_drawcall_flush(gpIterPopulateData *iter) { #if !DISABLE_BATCHING if (iter->geom != NULL) { - if (iter->instancing) { - DRW_shgroup_call_instance_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount); - } - else { - DRW_shgroup_call_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount); - } + DRW_shgroup_call_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount); } #endif @@ -367,25 +361,22 @@ static void gpencil_drawcall_flush(gpIterPopulateData *iter) } /* Group draw-calls that are consecutive and with the same type. Reduces GPU driver overhead. */ -static void gpencil_drawcall_add( - gpIterPopulateData *iter, struct GPUBatch *geom, bool instancing, int v_first, int v_count) +static void gpencil_drawcall_add(gpIterPopulateData *iter, + struct GPUBatch *geom, + int v_first, + int v_count) { #if DISABLE_BATCHING - if (instancing) { - DRW_shgroup_call_instance_range(iter->grp, iter->ob, geom, v_first, v_count); - } - else { - DRW_shgroup_call_range(iter->grp, iter->ob, geom, v_first, v_count); - } + DRW_shgroup_call_range(iter->grp, iter->ob, geom, v_first, v_count); + return; #endif int last = iter->vfirst + iter->vcount; /* Interrupt draw-call grouping if the sequence is not consecutive. */ - if ((geom != iter->geom) || (v_first - last > 3)) { + if ((geom != iter->geom) || (v_first - last > 0)) { gpencil_drawcall_flush(iter); } iter->geom = geom; - iter->instancing = instancing; if (iter->vfirst == -1) { iter->vfirst = v_first; } @@ -516,22 +507,33 @@ static void gpencil_stroke_cache_populate(bGPDlayer *gpl, bool do_sbuffer = (iter->do_sbuffer_call == DRAW_NOW); + GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_get(iter->ob, show_fill) : + DRW_cache_gpencil_get(iter->ob, iter->pd->cfra); + if (geom != iter->geom) { + gpencil_drawcall_flush(iter); + + GPUVertBuf *position_tx = do_sbuffer ? + DRW_cache_gpencil_sbuffer_position_buffer_get(iter->ob, + show_fill) : + DRW_cache_gpencil_position_buffer_get(iter->ob, iter->pd->cfra); + GPUVertBuf *color_tx = do_sbuffer ? + DRW_cache_gpencil_sbuffer_color_buffer_get(iter->ob, show_fill) : + DRW_cache_gpencil_color_buffer_get(iter->ob, iter->pd->cfra); + DRW_shgroup_buffer_texture(iter->grp, "gp_pos_tx", position_tx); + DRW_shgroup_buffer_texture(iter->grp, "gp_col_tx", color_tx); + } + if (show_fill) { - GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_fill_get(iter->ob) : - DRW_cache_gpencil_fills_get(iter->ob, iter->pd->cfra); int vfirst = gps->runtime.fill_start * 3; int vcount = gps->tot_triangles * 3; - gpencil_drawcall_add(iter, geom, false, vfirst, vcount); + gpencil_drawcall_add(iter, geom, vfirst, vcount); } if (show_stroke) { - GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_stroke_get(iter->ob) : - DRW_cache_gpencil_strokes_get(iter->ob, iter->pd->cfra); - /* Start one vert before to have gl_InstanceID > 0 (see shader). */ - int vfirst = gps->runtime.stroke_start - 1; - /* Include "potential" cyclic vertex and start adj vertex (see shader). */ - int vcount = gps->totpoints + 1 + 1; - gpencil_drawcall_add(iter, geom, true, vfirst, vcount); + int vfirst = gps->runtime.stroke_start * 3; + bool is_cyclic = ((gps->flag & GP_STROKE_CYCLIC) != 0) && (gps->totpoints > 2); + int vcount = (gps->totpoints + (int)is_cyclic) * 2 * 3; + gpencil_drawcall_add(iter, geom, vfirst, vcount); } iter->stroke_index_last = gps->runtime.stroke_start + gps->totpoints + 1; diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c index a7d8570dbaa..9b1129e77be 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c +++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c @@ -96,7 +96,7 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it float winmat[4][4], persmat[4][4]; float blur_size[2] = {fx->radius[0], fx->radius[1]}; DRW_view_persmat_get(NULL, persmat, false); - const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3])); + const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->object_to_world[3])); if (fx->flag & FX_BLUR_DOF_MODE) { /* Compute circle of confusion size. */ @@ -108,7 +108,7 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it DRW_view_winmat_get(NULL, winmat, false); const float *vp_size = DRW_viewport_size_get(); float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(ob->obmat); + float scale = mat4_to_scale(ob->object_to_world); float distance_factor = world_pixel_scale * scale * winmat[1][1] * vp_size[1] / w; mul_v2_fl(blur_size, distance_factor); } @@ -175,11 +175,11 @@ static void gpencil_vfx_rim(RimShaderFxData *fx, Object *ob, gpIterVfxData *iter const float *vp_size = DRW_viewport_size_get(); const float *vp_size_inv = DRW_viewport_invert_size_get(); - const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3])); + const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->object_to_world[3])); /* Modify by distance to camera and object scale. */ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(ob->obmat); + float scale = mat4_to_scale(ob->object_to_world); float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w; mul_v2_fl(offset, distance_factor); mul_v2_v2(offset, vp_size_inv); @@ -248,8 +248,8 @@ static void gpencil_vfx_pixelize(PixelShaderFxData *fx, Object *ob, gpIterVfxDat mul_v2_v2(pixel_size, vp_size_inv); /* Fixed pixelisation center from object center. */ - const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3])); - mul_v3_m4v3(ob_center, persmat, ob->obmat[3]); + const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->object_to_world[3])); + mul_v3_m4v3(ob_center, persmat, ob->object_to_world[3]); mul_v3_fl(ob_center, 1.0f / w); const bool use_antialiasing = ((fx->flag & FX_PIXEL_FILTER_NEAREST) == 0); @@ -260,7 +260,7 @@ static void gpencil_vfx_pixelize(PixelShaderFxData *fx, Object *ob, gpIterVfxDat /* Modify by distance to camera and object scale. */ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(ob->obmat); + float scale = mat4_to_scale(ob->object_to_world); mul_v2_fl(pixel_size, (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w); /* Center to texel */ @@ -310,7 +310,9 @@ static void gpencil_vfx_shadow(ShadowShaderFxData *fx, Object *ob, gpIterVfxData const float *vp_size_inv = DRW_viewport_invert_size_get(); const float ratio = vp_size_inv[1] / vp_size_inv[0]; - copy_v3_v3(rot_center, (use_obj_pivot && fx->object) ? fx->object->obmat[3] : ob->obmat[3]); + copy_v3_v3(rot_center, + (use_obj_pivot && fx->object) ? fx->object->object_to_world[3] : + ob->object_to_world[3]); const float w = fabsf(mul_project_m4_v3_zfac(persmat, rot_center)); mul_v3_m4v3(rot_center, persmat, rot_center); @@ -318,7 +320,7 @@ static void gpencil_vfx_shadow(ShadowShaderFxData *fx, Object *ob, gpIterVfxData /* Modify by distance to camera and object scale. */ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(ob->obmat); + float scale = mat4_to_scale(ob->object_to_world); float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w; mul_v2_fl(offset, distance_factor); mul_v2_v2(offset, vp_size_inv); @@ -485,13 +487,13 @@ static void gpencil_vfx_wave(WaveShaderFxData *fx, Object *ob, gpIterVfxData *it const float *vp_size = DRW_viewport_size_get(); const float *vp_size_inv = DRW_viewport_invert_size_get(); - const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3])); - mul_v3_m4v3(wave_center, persmat, ob->obmat[3]); + const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->object_to_world[3])); + mul_v3_m4v3(wave_center, persmat, ob->object_to_world[3]); mul_v3_fl(wave_center, 1.0f / w); /* Modify by distance to camera and object scale. */ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(ob->obmat); + float scale = mat4_to_scale(ob->object_to_world); float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w; wave_center[0] = wave_center[0] * 0.5f + 0.5f; @@ -542,7 +544,7 @@ static void gpencil_vfx_swirl(SwirlShaderFxData *fx, Object *UNUSED(ob), gpIterV DRW_view_persmat_get(NULL, persmat, false); const float *vp_size = DRW_viewport_size_get(); - copy_v3_v3(swirl_center, fx->object->obmat[3]); + copy_v3_v3(swirl_center, fx->object->object_to_world[3]); const float w = fabsf(mul_project_m4_v3_zfac(persmat, swirl_center)); mul_v3_m4v3(swirl_center, persmat, swirl_center); @@ -550,7 +552,7 @@ static void gpencil_vfx_swirl(SwirlShaderFxData *fx, Object *UNUSED(ob), gpIterV /* Modify by distance to camera and object scale. */ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(fx->object->obmat); + float scale = mat4_to_scale(fx->object->object_to_world); float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w; mul_v2_fl(swirl_center, 0.5f); diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_shared.h b/source/blender/draw/engines/gpencil/gpencil_shader_shared.h index 4c621e955b9..3f0f73e7c13 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_shared.h +++ b/source/blender/draw/engines/gpencil/gpencil_shader_shared.h @@ -41,6 +41,9 @@ enum gpLightType { GP_LIGHT_TYPE_AMBIENT = 3u, }; +#define GP_IS_STROKE_VERTEX_BIT (1 << 30) +#define GP_VERTEX_ID_SHIFT 2 + /* Avoid compiler funkiness with enum types not being strongly typed in C. */ #ifndef GPU_SHADER # define gpMaterialFlag uint diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl index 7ddfdc5f65c..642939136c8 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl @@ -1,92 +1,4 @@ -/* Must match C declaration. */ -struct gpMaterial { - vec4 stroke_color; - vec4 fill_color; - vec4 fill_mix_color; - vec4 fill_uv_rot_scale; - vec4 fill_uv_offset; - /* Put float/int at the end to avoid padding error */ - /* 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. */ - vec4 gp_mat_packed_1; - // float stroke_texture_mix; - // float stroke_u_scale; - // float fill_texture_mix; - // int gp_flag; - /* Please ensure 16 byte alignment (multiple of vec4). */ -}; - -#define MATERIAL(m) materials[m + gpMaterialOffset] - -#define stroke_texture_mix gp_mat_packed_1.x -#define stroke_u_scale gp_mat_packed_1.y -#define fill_texture_mix gp_mat_packed_1.z -#define GP_FLAG(m) floatBitsToInt(MATERIAL(m).gp_mat_packed_1.w) - -/* flag */ -#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) -/* High bits are used to pass material ID to fragment shader. */ -#define GP_MATID_SHIFT 16 - -/* Multiline defines can crash blender with certain GPU drivers. */ -/* clang-format off */ -#define 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) -/* clang-format on */ - -#define GP_FLAG_TEST(flag, val) (((flag) & (val)) != 0) - -/* Must match C declaration. */ -struct gpLight { - vec4 color_type; - vec4 right; - vec4 up; - vec4 forward; - vec4 position; - /* Please ensure 16 byte alignment (multiple of vec4). */ -}; - -#define spot_size right.w -#define spot_blend up.w - -#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 - -#ifdef GP_MATERIAL_BUFFER_LEN - -layout(std140) uniform gpMaterialBlock -{ - gpMaterial materials[GP_MATERIAL_BUFFER_LEN]; -}; - -#endif - -#ifdef GPENCIL_LIGHT_BUFFER_LEN - -layout(std140) uniform gpLightBlock -{ - gpLight lights[GPENCIL_LIGHT_BUFFER_LEN]; -}; - -#endif - /* Must match eGPLayerBlendModes */ #define MODE_REGULAR 0 #define MODE_HARDLIGHT 1 @@ -149,510 +61,3 @@ void blend_mode_output( break; } } - -#ifndef USE_GPU_SHADER_CREATE_INFO - -IN_OUT ShaderStageInterface -{ - vec4 finalColorMul; - vec4 finalColorAdd; - vec3 finalPos; - vec2 finalUvs; - noperspective float strokeThickness; - noperspective float unclampedThickness; - noperspective float strokeHardeness; - flat vec2 strokeAspect; - flat vec2 strokePt1; - flat vec2 strokePt2; - flat int matFlag; - flat float depth; -}; - -#endif - -#ifdef GPU_FRAGMENT_SHADER - -# define linearstep(p0, p1, v) (clamp(((v) - (p0)) / abs((p1) - (p0)), 0.0, 1.0)) - -float stroke_round_cap_mask(vec2 p1, vec2 p2, vec2 aspect, float thickness, float hardfac) -{ - /* We create our own uv space to avoid issues with triangulation and linear - * interpolation artifacts. */ - vec2 line = p2.xy - p1.xy; - vec2 pos = gl_FragCoord.xy - p1.xy; - float line_len = length(line); - float half_line_len = line_len * 0.5; - /* Normalize */ - line = (line_len > 0.0) ? (line / line_len) : vec2(1.0, 0.0); - /* Create a uv space that englobe the whole segment into a capsule. */ - vec2 uv_end; - uv_end.x = max(abs(dot(line, pos) - half_line_len) - half_line_len, 0.0); - uv_end.y = dot(vec2(-line.y, line.x), pos); - /* Divide by stroke radius. */ - uv_end /= thickness; - uv_end *= aspect; - - float dist = clamp(1.0 - length(uv_end) * 2.0, 0.0, 1.0); - if (hardfac > 0.999) { - return step(1e-8, dist); - } - else { - /* Modulate the falloff profile */ - float hardness = 1.0 - hardfac; - dist = pow(dist, mix(0.01, 10.0, hardness)); - return smoothstep(0.0, 1.0, dist); - } -} - -#endif - -uniform vec2 sizeViewport; -uniform vec2 sizeViewportInv; - -/* Per Object */ -uniform bool strokeOrder3d; -uniform int gpMaterialOffset; -uniform float thicknessScale; -uniform float thicknessWorldScale; -#define thicknessIsScreenSpace (thicknessWorldScale < 0.0) - -#ifdef GPU_VERTEX_SHADER - -/* Per Layer */ -uniform float thicknessOffset; -uniform float vertexColorOpacity; -uniform vec4 layerTint; -uniform float layerOpacity; /* Used for onion skin. */ -uniform float strokeIndexOffset = 0.0; - -/* All of these attributes are quad loaded the same way - * as GL_LINES_ADJACENCY would feed a geometry shader: - * - ma reference the previous adjacency point. - * - ma1 reference the current line first point. - * - ma2 reference the current line second point. - * - ma3 reference the next adjacency point. - * Note that we are rendering quad instances and not using any index buffer (except for fills). - */ -/* x is material index, y is stroke_id, z is point_id, w is aspect & rotation & hardness packed. */ -in ivec4 ma; -in ivec4 ma1; -in ivec4 ma2; -in ivec4 ma3; -/* Position contains thickness in 4th component. */ -in vec4 pos; /* Prev adj vert */ -in vec4 pos1; /* Current edge */ -in vec4 pos2; /* Current edge */ -in vec4 pos3; /* Next adj vert */ -/* xy is UV for fills, z is U of stroke, w is strength. */ -in vec4 uv1; -in vec4 uv2; -in vec4 col1; -in vec4 col2; -in vec4 fcol1; -/* WARNING: Max attribute count is actually 14 because OSX OpenGL implementation - * considers gl_VertexID and gl_InstanceID as vertex attribute. (see T74536) */ -# define stroke_id1 ma1.y -# define point_id1 ma1.z -# define thickness1 pos1.w -# define thickness2 pos2.w -# define strength1 uv1.w -# define strength2 uv2.w -/* Packed! need to be decoded. */ -# define hardness1 ma1.w -# define hardness2 ma2.w -# define uvrot1 ma1.w -# define aspect1 ma1.w - -vec2 decode_aspect(int packed_data) -{ - float asp = float(uint(packed_data) & 0x1FFu) * (1.0 / 255.0); - return (asp > 1.0) ? vec2(1.0, (asp - 1.0)) : vec2(asp, 1.0); -} - -float decode_uvrot(int packed_data) -{ - uint udata = uint(packed_data); - float uvrot = 1e-8 + float((udata & 0x1FE00u) >> 9u) * (1.0 / 255.0); - return ((udata & 0x20000u) != 0u) ? -uvrot : uvrot; -} - -float decode_hardness(int packed_data) -{ - return float((uint(packed_data) & 0x3FC0000u) >> 18u) * (1.0 / 255.0); -} - -void discard_vert() -{ - /* We set the vertex at the camera origin to generate 0 fragments. */ - gl_Position = vec4(0.0, 0.0, -3e36, 0.0); -} - -vec2 project_to_screenspace(vec4 v) -{ - return ((v.xy / v.w) * 0.5 + 0.5) * sizeViewport; -} - -vec2 rotate_90deg(vec2 v) -{ - /* Counter Clock-Wise. */ - return vec2(-v.y, v.x); -} - -mat4 model_matrix_get() -{ - return ModelMatrix; -} - -vec3 transform_point(mat4 m, vec3 v) -{ - return (m * vec4(v, 1.0)).xyz; -} - -vec2 safe_normalize(vec2 v) -{ - float len_sqr = dot(v, v); - if (len_sqr > 0.0) { - return v / sqrt(len_sqr); - } - else { - return vec2(1.0, 0.0); - } -} - -vec2 safe_normalize_len(vec2 v, out float len) -{ - len = sqrt(dot(v, v)); - if (len > 0.0) { - return v / len; - } - else { - return vec2(1.0, 0.0); - } -} - -float stroke_thickness_modulate(float thickness) -{ - /* Modify stroke thickness by object and layer factors. */ - thickness *= thicknessScale; - thickness += thicknessOffset; - thickness = max(1.0, thickness); - - if (thicknessIsScreenSpace) { - /* Multiply offset by view Z so that offset is constant in screenspace. - * (e.i: does not change with the distance to camera) */ - thickness *= gl_Position.w; - } - else { - /* World space point size. */ - thickness *= thicknessWorldScale * drw_view.winmat[1][1] * sizeViewport.y; - } - return thickness; -} - -float clamp_small_stroke_thickness(float thickness) -{ - /* To avoid aliasing artifacts, we clamp the line thickness and - * reduce its opacity in the fragment shader. */ - float min_thickness = gl_Position.w * 1.3; - thickness = max(min_thickness, thickness); - - return thickness; -} - -# ifdef GP_MATERIAL_BUFFER_LEN -void 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 * vertexColorOpacity); - mixed_col.rgb = mix(mixed_col.rgb, layerTint.rgb, layerTint.a); - mixed_col.a *= vert_strength * layerOpacity; - /** - * This is what the fragment shader looks like. - * out = col * finalColorMul + col.a * finalColorAdd. - * finalColorMul is how much of the texture color to keep. - * finalColorAdd 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). */ - finalColorMul = vec4(mixed_col.aaa, mixed_col.a); - finalColorAdd = 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. */ - finalColorMul.rgb *= mix_tex; - finalColorAdd.rgb *= 1.0 - mix_tex; -} -# endif - -void stroke_vertex() -{ - int m = ma1.x; - bool is_dot = false; - bool is_squares = false; - -# ifdef GP_MATERIAL_BUFFER_LEN - if (m != -1) { - is_dot = GP_FLAG_TEST(GP_FLAG(m), GP_STROKE_ALIGNMENT); - is_squares = !GP_FLAG_TEST(GP_FLAG(m), GP_STROKE_DOTS); - } -# endif - - /* Special Case. Stroke with single vert are rendered as dots. Do not discard them. */ - if (!is_dot && ma.x == -1 && ma2.x == -1) { - is_dot = true; - is_squares = false; - } - - /* Endpoints, we discard the vertices. */ - if (ma1.x == -1 || (!is_dot && ma2.x == -1)) { - discard_vert(); - return; - } - - mat4 model_mat = model_matrix_get(); - - /* Avoid using a vertex attribute for quad positioning. */ - float x = float(gl_VertexID & 1) * 2.0 - 1.0; /* [-1..1] */ - float y = float(gl_VertexID & 2) - 1.0; /* [-1..1] */ - - bool use_curr = is_dot || (x == -1.0); - - vec3 wpos_adj = transform_point(model_mat, (use_curr) ? pos.xyz : pos3.xyz); - vec3 wpos1 = transform_point(model_mat, pos1.xyz); - vec3 wpos2 = transform_point(model_mat, pos2.xyz); - - vec4 ndc_adj = point_world_to_ndc(wpos_adj); - vec4 ndc1 = point_world_to_ndc(wpos1); - vec4 ndc2 = point_world_to_ndc(wpos2); - - gl_Position = (use_curr) ? ndc1 : ndc2; - finalPos = (use_curr) ? wpos1 : wpos2; - - vec2 ss_adj = project_to_screenspace(ndc_adj); - vec2 ss1 = project_to_screenspace(ndc1); - vec2 ss2 = project_to_screenspace(ndc2); - /* Screenspace Lines tangents. */ - float line_len; - vec2 line = safe_normalize_len(ss2 - ss1, line_len); - vec2 line_adj = safe_normalize((use_curr) ? (ss1 - ss_adj) : (ss_adj - ss2)); - - float thickness = abs((use_curr) ? thickness1 : thickness2); - thickness = stroke_thickness_modulate(thickness); - float clampedThickness = clamp_small_stroke_thickness(thickness); - - finalUvs = vec2(x, y) * 0.5 + 0.5; - strokeHardeness = decode_hardness(use_curr ? hardness1 : hardness2); - - if (is_dot) { -# ifdef GP_MATERIAL_BUFFER_LEN - int alignement = GP_FLAG(m) & GP_STROKE_ALIGNMENT; - /* For one point strokes use object alignment. */ - if (ma.x == -1 && ma2.x == -1 && alignement == GP_STROKE_ALIGNMENT_STROKE) { - alignement = GP_STROKE_ALIGNMENT_OBJECT; - } -# endif - - vec2 x_axis; -# ifdef GP_MATERIAL_BUFFER_LEN - if (alignement == GP_STROKE_ALIGNMENT_STROKE) { - x_axis = (ma2.x == -1) ? line_adj : line; - } - else if (alignement == GP_STROKE_ALIGNMENT_FIXED) { - /* Default for no-material drawing. */ - x_axis = vec2(1.0, 0.0); - } - else -# endif - { /* GP_STROKE_ALIGNMENT_OBJECT */ - vec4 ndc_x = point_world_to_ndc(wpos1 + model_mat[0].xyz); - vec2 ss_x = project_to_screenspace(ndc_x); - x_axis = safe_normalize(ss_x - ss1); - } - - /* Rotation: Encoded as Cos + Sin sign. */ - float uv_rot = decode_uvrot(uvrot1); - float rot_sin = sqrt(max(0.0, 1.0 - uv_rot * uv_rot)) * sign(uv_rot); - float rot_cos = abs(uv_rot); - x_axis = mat2(rot_cos, -rot_sin, rot_sin, rot_cos) * x_axis; - -# ifdef GP_MATERIAL_BUFFER_LEN - if (is_dot) { - float alignment_cos = MATERIAL(m).fill_uv_offset.z; - float alignment_sin = MATERIAL(m).fill_uv_offset.w; - x_axis = mat2(alignment_cos, -alignment_sin, alignment_sin, alignment_cos) * x_axis; - } -# endif - - vec2 y_axis = rotate_90deg(x_axis); - - strokeAspect = decode_aspect(aspect1); - - x *= strokeAspect.x; - y *= strokeAspect.y; - - /* Invert for vertex shader. */ - strokeAspect = 1.0 / strokeAspect; - - gl_Position.xy += (x * x_axis + y * y_axis) * sizeViewportInv.xy * clampedThickness; - - strokePt1 = ss1; - strokePt2 = ss1 + x_axis * 0.5; - strokeThickness = (is_squares) ? 1e18 : (clampedThickness / gl_Position.w); - unclampedThickness = (is_squares) ? 1e18 : (thickness / gl_Position.w); - } - else { - bool is_stroke_start = (ma.x == -1 && x == -1); - bool is_stroke_end = (ma3.x == -1 && x == 1); - - /* Mitter tangent vector. */ - vec2 miter_tan = safe_normalize(line_adj + line); - float miter_dot = dot(miter_tan, line_adj); - /* Break corners after a certain angle to avoid really thick corners. */ - const float miter_limit = 0.5; /* cos(60°) */ - bool miter_break = (miter_dot < miter_limit); - miter_tan = (miter_break || is_stroke_start || is_stroke_end) ? line : (miter_tan / miter_dot); - - vec2 miter = rotate_90deg(miter_tan); - - strokePt1.xy = ss1; - strokePt2.xy = ss2; - strokeThickness = clampedThickness / gl_Position.w; - unclampedThickness = thickness / gl_Position.w; - strokeAspect = vec2(1.0); - - vec2 screen_ofs = miter * y; - - /* Reminder: we packed the cap flag into the sign of strength and thickness sign. */ - if ((is_stroke_start && strength1 > 0.0) || (is_stroke_end && thickness1 > 0.0) || - (miter_break && !is_stroke_start && !is_stroke_end)) { - screen_ofs += line * x; - } - - gl_Position.xy += screen_ofs * sizeViewportInv.xy * clampedThickness; - - finalUvs.x = (use_curr) ? uv1.z : uv2.z; -# ifdef GP_MATERIAL_BUFFER_LEN - finalUvs.x *= MATERIAL(m).stroke_u_scale; -# endif - } - -# ifdef GP_MATERIAL_BUFFER_LEN - vec4 vert_col = (use_curr) ? col1 : col2; - float vert_strength = abs((use_curr) ? strength1 : strength2); - vec4 stroke_col = MATERIAL(m).stroke_color; - float mix_tex = MATERIAL(m).stroke_texture_mix; - - /* Special case: We don't use vertex color if material Holdout. */ - if (GP_FLAG_TEST(GP_FLAG(m), GP_STROKE_HOLDOUT)) { - vert_col = vec4(0.0); - } - - color_output(stroke_col, vert_col, vert_strength, mix_tex); - - matFlag = GP_FLAG(m) & ~GP_FILL_FLAGS; -# endif - - if (strokeOrder3d) { - /* Use the fragment depth (see fragment shader). */ - depth = -1.0; - } -# ifdef GP_MATERIAL_BUFFER_LEN - else if (GP_FLAG_TEST(GP_FLAG(m), GP_STROKE_OVERLAP)) { - /* Use the index of the point as depth. - * This means the stroke can overlap itself. */ - depth = (point_id1 + strokeIndexOffset + 1.0) * 0.0000002; - } -# endif - 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. */ - depth = (stroke_id1 + strokeIndexOffset + 1.0) * 0.0000002; - } -} - -void fill_vertex() -{ - mat4 model_mat = model_matrix_get(); - - vec3 wpos = transform_point(model_mat, pos1.xyz); - gl_Position = point_world_to_ndc(wpos); - finalPos = wpos; - -# ifdef GP_MATERIAL_BUFFER_LEN - int m = ma1.x; - - vec4 fill_col = MATERIAL(m).fill_color; - float mix_tex = MATERIAL(m).fill_texture_mix; - - /* Special case: We don't modulate alpha in gradient mode. */ - if (GP_FLAG_TEST(GP_FLAG(m), 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 (GP_FLAG_TEST(GP_FLAG(m), 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); - - color_output(fill_col, fcol_decode, 1.0, mix_tex); - - matFlag = GP_FLAG(m) & GP_FILL_FLAGS; - matFlag |= m << GP_MATID_SHIFT; - - vec2 loc = MATERIAL(m).fill_uv_offset.xy; - mat2x2 rot_scale = mat2x2(MATERIAL(m).fill_uv_rot_scale.xy, MATERIAL(m).fill_uv_rot_scale.zw); - finalUvs = rot_scale * uv1.xy + loc; -# endif - - strokeHardeness = 1.0; - strokeThickness = 1e18; - unclampedThickness = 1e20; - strokeAspect = vec2(1.0); - strokePt1 = strokePt2 = vec2(0.0); - - if (strokeOrder3d) { - /* Use the fragment depth (see fragment shader). */ - depth = -1.0; - /* We still offset the fills a little to avoid overlaps */ - gl_Position.z += 0.000002; - } - else { - /* Use the index of first point of the stroke as depth. */ - depth = (stroke_id1 + strokeIndexOffset) * 0.0000002; - } -} - -void gpencil_vertex() -{ - /* Trick to detect if a drawcall is stroke or fill. - * This does mean that we need to draw an empty stroke segment before starting - * to draw the real stroke segments. */ - bool is_fill = (gl_InstanceID == 0); - - if (!is_fill) { - stroke_vertex(); - } - else { - fill_vertex(); - } -} - -#endif diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl index 8ed03b23809..2e7544cea29 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl @@ -31,23 +31,11 @@ void main() 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]; gpMaterialFlag gp_flag = floatBitsToUint(gp_mat._flag); - gl_Position = gpencil_vertex(ma, - ma1, - ma2, - ma3, - pos, - pos1, - pos2, - pos3, - uv1, - uv2, - col1, - col2, - fcol1, - vec4(viewportSize, 1.0 / viewportSize), + gl_Position = gpencil_vertex(vec4(viewportSize, 1.0 / viewportSize), gp_flag, gp_mat._alignment_rot, gp_interp.pos, @@ -60,7 +48,7 @@ void main() gp_interp.thickness, gp_interp.hardness); - if (GPENCIL_IS_STROKE_VERTEX) { + if (gpencil_is_stroke_vertex()) { if (!flag_test(gp_flag, GP_STROKE_ALIGNMENT)) { gp_interp.uv.x *= gp_mat._stroke_u_scale; } @@ -83,7 +71,7 @@ void main() /* 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; + gp_interp.depth = (point_index + gpStrokeIndexOffset + 2.0) * 0.0000002; } else { /* Use the index of first point of the stroke as depth. @@ -92,10 +80,13 @@ void main() * 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; + gp_interp.depth = (stroke_index + gpStrokeIndexOffset + 2.0) * 0.0000002; } } else { + int stroke_point_id = gpencil_stroke_point_id(); + vec4 uv1 = texelFetch(gp_pos_tx, stroke_point_id * 3 + 2); + vec4 fcol1 = texelFetch(gp_col_tx, stroke_point_id * 2 + 1); vec4 fill_col = gp_mat.fill_color; /* Special case: We don't modulate alpha in gradient mode. */ @@ -137,7 +128,7 @@ void main() 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; + gp_interp.depth = (stroke_index + gpStrokeIndexOffset + 1.0) * 0.0000002; } } } diff --git a/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh index edd51e71242..da2776254e6 100644 --- a/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh +++ b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh @@ -22,10 +22,10 @@ GPU_SHADER_CREATE_INFO(gpencil_geometry) .do_static_compilation(true) .define("GP_LIGHT") .typedef_source("gpencil_defines.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") + .sampler(2, ImageType::FLOAT_2D, "gpFillTexture") + .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) .push_constant(Type::VEC2, "viewportSize") |