Changeset View
Changeset View
Standalone View
Standalone View
src/scenegraph/shadowedrectangle_core.frag
- This file was added.
1 | /* | ||||
---|---|---|---|---|---|
2 | * SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl> | ||||
3 | * | ||||
4 | * SPDX-License-Identifier: LGPL-2.0-or-later | ||||
5 | */ | ||||
6 | | ||||
7 | // This is based on the 2D SDF functions provided by Inigo Quilez: | ||||
8 | // https://iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm | ||||
9 | | ||||
10 | uniform lowp float opacity; | ||||
11 | uniform lowp float size; | ||||
12 | uniform lowp float radius; | ||||
13 | uniform lowp vec4 color; | ||||
14 | uniform lowp vec4 shadowColor; | ||||
15 | uniform lowp vec2 offset; | ||||
16 | uniform lowp vec2 aspect; | ||||
17 | | ||||
18 | in lowp vec2 uv; | ||||
19 | | ||||
20 | const lowp float minimum_shadow_radius = 0.05; | ||||
21 | | ||||
22 | // Calculate the distance to a rectangle with rounded corners. | ||||
23 | // \param point The point to calculate the distance of. | ||||
24 | // \param rect The rectangle to calculate the distance of. | ||||
25 | // \param translation The amount of translation to apply to the rectangle. | ||||
26 | // \param radius A vec4 with the radius of each corner. | ||||
27 | lowp float sdf_rounded_rectangle(in lowp vec2 point, in lowp vec2 rect, in lowp vec2 translation, in lowp vec4 radius) | ||||
28 | { | ||||
29 | radius.xy = (point.x > 0.0) ? radius.xy : radius.zw; | ||||
30 | radius.x = (point.y > 0.0) ? radius.x : radius.y; | ||||
31 | lowp vec2 d = abs(point - translation) - rect + radius.x; | ||||
32 | return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - radius.x; | ||||
33 | } | ||||
34 | | ||||
35 | void main() | ||||
36 | { | ||||
37 | // Scaling factor that is the inverse of the amount of scaling applied to the geometry. | ||||
38 | lowp float inverse_scale = 1.0 / (1.0 + size + length(offset * 2.0)); | ||||
39 | | ||||
40 | // Correction factor to round the corners of a larger shadow. | ||||
41 | // We want to account for size in regards to shadow radius, so that a larger shadow is | ||||
42 | // more rounded, but only if we are not already rounding the corners due to corner radius. | ||||
43 | lowp float size_factor = 0.5 * (minimum_shadow_radius / max(radius, minimum_shadow_radius)); | ||||
44 | | ||||
45 | lowp float shadowRadius = radius + size * size_factor; | ||||
46 | | ||||
47 | lowp vec4 col = vec4(0.0); | ||||
48 | | ||||
49 | // Calculate the shadow's distance field. | ||||
50 | lowp float shadow = sdf_rounded_rectangle(uv, aspect * inverse_scale, offset * inverse_scale, vec4(shadowRadius * inverse_scale)); | ||||
51 | // Render it, interpolating the color over the distance. | ||||
52 | col = mix(col, shadowColor * sign(size), shadowColor.a * (1.0 - smoothstep(-size * 0.5, size * 0.5, shadow))); | ||||
53 | | ||||
54 | // Calculate the main rectangle distance field. | ||||
55 | lowp float rect = sdf_rounded_rectangle(uv, aspect * inverse_scale, vec2(0.0), vec4(radius * inverse_scale)); | ||||
56 | | ||||
57 | lowp float g = fwidth(rect); | ||||
58 | | ||||
59 | // First, remove anything that was rendered by the shadow if it is inside the rectangle. | ||||
60 | // This allows us to use colors with alpha without rendering artifacts. | ||||
61 | col = mix(col, vec4(0.0), 1.0 - smoothstep(0.001 - g, 0.001 + g, rect)); | ||||
62 | | ||||
63 | // Then, render it again but this time with the proper color and properly alpha blended. | ||||
64 | col = mix(col, color, color.a * (1.0 - smoothstep(0.001 - g, 0.001 + g, rect))); | ||||
65 | | ||||
66 | gl_FragColor = col * opacity; | ||||
67 | } |