This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl
Jamell Moore 09f7c93858 Fix T80862: Small stroke opacity modulation is best done in the fragment shader
To avoid anti-aliasing artifacts on GPencil strokes that have a size smaller than 1 the thickness
is clamped and the opacity reduced. This was done in vertex shader but this had the side effect
of causing strokes that go from large to small to fade across their lengths.

**Solution**

The opacity modulation has now been moved to the fragment shader as advised by Clément Foucault.

The strokeThickness that was passed to the shader was clamped to prevent it from being too small so an additional
unclamped thickness has been passed to the fragment to calculate the opacity modulation. Alternatively I could have chosen
strokeThickness and clampedThickness but I decided against renaming the variables in the current code.


Reviewed By: fclem

Differential Revision: https://developer.blender.org/D10438
2021-02-17 13:40:38 +01:00

139 lines
4.4 KiB
GLSL

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;
float length_squared(vec2 v)
{
return dot(v, v);
}
float length_squared(vec3 v)
{
return dot(v, v);
}
vec3 gpencil_lighting(void)
{
vec3 light_accum = vec3(0.0);
for (int i = 0; i < GPENCIL_LIGHT_BUFFER_LEN; i++) {
if (lights[i].color_type.x == -1.0) {
break;
}
vec3 L = lights[i].position.xyz - finalPos;
float vis = 1.0;
/* 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);
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);
/* 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) {
vis /= L_len_sqr;
}
else {
L = lights[i].forward.xyz;
L_len_sqr = 1.0;
}
/* Lambertian falloff */
if (lights[i].color_type.w != 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;
}
/* Clamp to avoid NaNs. */
return clamp(light_accum, 0.0, 1e10);
}
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);
}
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);
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 /* SOLID */ {
col = vec4(1.0);
}
col.rgb *= col.a;
/* 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.rgb *= gpencil_lighting();
fragColor *= stroke_round_cap_mask(
strokePt1, strokePt2, strokeAspect, strokeThickness, strokeHardeness);
/* To avoid aliasing artifacts, we reduce the opacity of small strokes. */
fragColor *= smoothstep(0.0, 1.0, unclampedThickness);
/* Holdout materials. */
if (GP_FLAG_TEST(matFlag, GP_STROKE_HOLDOUT | GP_FILL_HOLDOUT)) {
revealColor = fragColor.aaaa;
}
else {
/* NOT holdout materials.
* For compatibility with colored alpha buffer.
* Note that we are limited to mono-chromatic alpha blending here
* because of the blend equation and the limit of 1 color target
* when using custom color blending. */
revealColor = vec4(0.0, 0.0, 0.0, fragColor.a);
if (fragColor.a < 0.001) {
discard;
}
}
vec2 fb_size = max(vec2(textureSize(gpSceneDepthTexture, 0).xy),
vec2(textureSize(gpMaskTexture, 0).xy));
vec2 uvs = gl_FragCoord.xy / fb_size;
/* Manual depth test */
float scene_depth = texture(gpSceneDepthTexture, uvs).r;
if (gl_FragCoord.z > scene_depth) {
discard;
}
/* FIXME(fclem): Grrr. This is bad for performance but it's the easiest way to not get
* depth written where the mask obliterate the layer. */
float mask = texture(gpMaskTexture, uvs).r;
if (mask < 0.001) {
discard;
}
/* We override the fragment depth using the fragment shader to ensure a constant value.
* This has a cost as the depth test cannot happen early.
* We could do this in the vertex shader but then perspective interpolation of uvs and
* fragment clipping gets really complicated. */
if (depth >= 0.0) {
gl_FragDepth = depth;
}
else {
gl_FragDepth = gl_FragCoord.z;
}
}