#pragma BLENDER_REQUIRE(common_gpencil_lib.glsl) #pragma BLENDER_REQUIRE(common_colormanagement_lib.glsl) 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.x == -1.0) { break; } vec3 L = lights[i]._position - gp_interp.pos; float vis = 1.0; gpLightType type = floatBitsToUint(lights[i]._type); /* Spot Attenuation. */ 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); /* 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 (type < GP_LIGHT_TYPE_SUN) { vis /= L_len_sqr; } else { L = lights[i]._forward; L_len_sqr = 1.0; } /* Lambertian falloff */ 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; } /* Clamp to avoid NaNs. */ return clamp(light_accum, 0.0, 1e10); } void main() { vec4 col; 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 (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 (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); } 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 * gp_interp.color_mul + col.a * gp_interp.color_add; fragColor.rgb *= gpencil_lighting(); 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, gp_interp.thickness.y); /* Holdout materials. */ if (flag_test(gp_interp.mat_flag, 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 (gp_interp.depth >= 0.0) { gl_FragDepth = gp_interp.depth; } else { gl_FragDepth = gl_FragCoord.z; } }