Skip to content
This repository was archived by the owner on Apr 29, 2021. It is now read-only.

Commit 456e2b6

Browse files
committed
fast shadow
1 parent 9ec0292 commit 456e2b6

File tree

14 files changed

+365
-65
lines changed

14 files changed

+365
-65
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
Shader "UIWidgets/ShadowBox"
2+
{
3+
//originally from http://madebyevan.com/shaders/fast-rounded-rectangle-shadows/
4+
Properties
5+
{
6+
_SrcBlend("_SrcBlend", Int) = 1 // One
7+
_DstBlend("_DstBlend", Int) = 10 // OneMinusSrcAlpha
8+
_StencilComp("_StencilComp", Float) = 8 // - Equal, 8 - Always
9+
}
10+
SubShader
11+
{
12+
ZTest Always
13+
ZWrite Off
14+
Blend [_SrcBlend] [_DstBlend]
15+
16+
Stencil {
17+
Ref 128
18+
Comp [_StencilComp]
19+
}
20+
21+
Pass {
22+
CGPROGRAM
23+
24+
float4 box;
25+
float4 _viewport;
26+
float sigma;
27+
float4 color;
28+
float _mat[9];
29+
30+
struct appdata
31+
{
32+
float4 vertex : POSITION;
33+
};
34+
35+
struct v2f
36+
{
37+
float4 vertex : SV_POSITION;
38+
float2 coord : TEXCOORD0;
39+
};
40+
41+
float4 erf(float4 x)
42+
{
43+
float4 s = sign(x);
44+
float4 a = abs(x);
45+
x = 1.0 + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a;
46+
x = x * x;
47+
return s - s / (x * x);
48+
return s;
49+
}
50+
51+
float boxShadow(float2 lower, float2 upper, float2 pnt, float sigma)
52+
{
53+
float4 query = float4(pnt - lower, pnt - upper);
54+
float4 integral = 0.5 + 0.5 * erf(query * (sqrt(0.5) / sigma));
55+
return (integral.z - integral.x) * (integral.w - integral.y);
56+
}
57+
58+
v2f vert(appdata v){
59+
v2f o;
60+
float padding = 3.0 * sigma;
61+
o.coord = lerp(box.xy - padding, box.zw + padding, v.vertex.xy);
62+
float3x3 mat = float3x3(_mat[0], _mat[1], _mat[2], _mat[3], _mat[4], _mat[5], 0, 0, 1);
63+
float2 p = mul(mat, float3(o.coord.xy, 1.0)).xy - _viewport.xy;
64+
65+
#if UNITY_UV_STARTS_AT_TOP
66+
o.vertex = float4(2.0 * p.x / _viewport.z - 1.0, 2.0 * p.y / _viewport.w - 1.0, 0, 1);
67+
#else
68+
o.vertex = float4(2.0 * p.x / _viewport.z - 1.0, 1.0 - 2.0 * p.y / _viewport.w, 0, 1);
69+
#endif
70+
return o;
71+
}
72+
73+
float4 frag(v2f i) : SV_TARGET {
74+
float4 fragColor = color;
75+
fragColor.a = fragColor.a * boxShadow(box.xy, box.zw, i.coord, sigma);
76+
return fragColor;
77+
}
78+
79+
#pragma vertex vert
80+
#pragma fragment frag
81+
82+
ENDCG
83+
}
84+
}
85+
}

Runtime/Resources/UIWidgets_canvas_shadowBox.shader.meta

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
Shader "UIWidgets/ShadowRBox"
2+
{
3+
//originally from http://madebyevan.com/shaders/fast-rounded-rectangle-shadows/
4+
Properties
5+
{
6+
_SrcBlend("_SrcBlend", Int) = 1 // One
7+
_DstBlend("_DstBlend", Int) = 10 // OneMinusSrcAlpha
8+
}
9+
SubShader
10+
{
11+
Blend [_SrcBlend] [_DstBlend]
12+
Pass {
13+
CGPROGRAM
14+
15+
float4 box;
16+
float2 window;
17+
float sigma;
18+
float4 color;
19+
float corner;
20+
21+
struct appdata
22+
{
23+
float4 vertex : POSITION;
24+
};
25+
26+
struct v2f
27+
{
28+
float4 vertex : SV_POSITION;
29+
float2 coord : TEXCOORD0;
30+
};
31+
32+
float gaussian(float x, float sigma)
33+
{
34+
float pi = 3.141592653589793;
35+
return exp(-(x*x) / (2.0 * sigma * sigma)) / (sqrt(2.0 * pi) * sigma);
36+
}
37+
38+
float2 erf(float2 x)
39+
{
40+
float2 s = sign(x);
41+
float2 a = abs(x);
42+
x = 1.0 + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a;
43+
x = x * x;
44+
return s - s / (x * x);
45+
return s;
46+
}
47+
48+
float roundedBoxShadowX(float x, float y, float sigma, float corner, float2 halfSize)
49+
{
50+
float delta = min(halfSize.y - corner - abs(y), 0.0);
51+
float curved = halfSize.x - corner + sqrt(max(0.0, corner * corner - delta * delta));
52+
float2 integral = 0.5 + 0.5 * erf((x + float2(-curved, curved)) * (sqrt(0.5)/sigma));
53+
return integral.y - integral.x;
54+
}
55+
56+
float roundedBoxShadow(float2 lower, float2 upper, float2 pnt, float sigma, float corner)
57+
{
58+
float2 center = (lower + upper) * 0.5;
59+
float2 halfSize = (upper - lower) * 0.5;
60+
pnt -= center;
61+
62+
float low = pnt.y - halfSize.y;
63+
float high = pnt.y + halfSize.y;
64+
float start = clamp(-3.0 * sigma, low, high);
65+
float end = clamp(3.0 * sigma, low, high);
66+
67+
float step = (end - start) / 4.0;
68+
float y = start + step * 0.5;
69+
float value = 0.0;
70+
71+
for(int i=0; i<4;i++)
72+
{
73+
value += roundedBoxShadowX(pnt.x, pnt.y - y, sigma, corner, halfSize) * gaussian(y, sigma) * step;
74+
y += step;
75+
}
76+
77+
return value;
78+
}
79+
80+
v2f vert(appdata v){
81+
v2f o;
82+
float padding = 3.0 * sigma;
83+
o.coord = lerp(box.xy - padding, box.zw + padding, v.vertex.xy);
84+
o.vertex = float4(o.coord.x * 2.0 /window.x - 1.0, o.coord.y * 2.0/window.y - 1.0, 0, 1);
85+
return o;
86+
}
87+
88+
float4 frag(v2f i) : SV_TARGET {
89+
float4 fragColor = color;
90+
fragColor.a = fragColor.a * roundedBoxShadow(box.xy, box.zw, i.coord, sigma, corner);
91+
return fragColor;
92+
}
93+
94+
#pragma vertex vert
95+
#pragma fragment frag
96+
97+
ENDCG
98+
}
99+
}
100+
}

Runtime/Resources/UIWidgets_canvas_shadowRBox.shader.meta

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/engine/UIWidgetsPanel.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ public override void OnGUI(Event evt) {
4343
this._needsPaint = true;
4444
}
4545

46+
this._needsPaint = true;
47+
4648
if (evt.type == EventType.Repaint) {
4749
if (!this._needsPaint) {
4850
return;

Runtime/ui/painting/painting.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ public enum BlurStyle {
200200
solid,
201201
outer,
202202
inner,
203-
shadow
203+
fast_shadow
204204
}
205205

206206
public class MaskFilter : IEquatable<MaskFilter> {
@@ -213,8 +213,8 @@ public static MaskFilter blur(BlurStyle style, float sigma) {
213213
return new MaskFilter(style, sigma);
214214
}
215215

216-
public static MaskFilter shadow(float sigma) {
217-
return new MaskFilter(BlurStyle.shadow, sigma);
216+
public static MaskFilter fastShadow(float sigma) {
217+
return new MaskFilter(BlurStyle.fast_shadow, sigma);
218218
}
219219

220220
public readonly BlurStyle style;

Runtime/ui/painting/path.cs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ public class Path {
2424

2525
bool _isRRect = false;
2626
public bool isRRect => this._isRRect;
27+
28+
PathShapeHint _shapeHint = PathShapeHint.Other;
29+
public PathShapeHint shapeHint => this._shapeHint;
2730

2831
public uint pathKey {
2932
get {
@@ -38,11 +41,12 @@ public Path(int capacity = 128) {
3841

3942
public List<float> commands => this._commands;
4043

41-
void _updateRRectFlag(bool isRRect) {
44+
void _updateRRectFlag(bool isRRect, PathShapeHint shapeHint = PathShapeHint.Other) {
4245
if (this._commands.Count > 0 && !this._isRRect) {
4346
return;
4447
}
4548
this._isRRect = isRRect && this._hasOnlyMoveTos();
49+
this._shapeHint = shapeHint;
4650
}
4751

4852
bool _hasOnlyMoveTos() {
@@ -501,7 +505,7 @@ public void winding(PathWinding dir) {
501505
}
502506

503507
public void addRect(Rect rect) {
504-
this._updateRRectFlag(true);
508+
this._updateRRectFlag(true, PathShapeHint.Rect);
505509
this._appendMoveTo(rect.left, rect.top);
506510
this._appendLineTo(rect.left, rect.bottom);
507511
this._appendLineTo(rect.right, rect.bottom);
@@ -510,7 +514,7 @@ public void addRect(Rect rect) {
510514
}
511515

512516
public void addRRect(RRect rrect) {
513-
this._updateRRectFlag(true);
517+
this._updateRRectFlag(true, PathShapeHint.RRect);
514518
float w = rrect.width;
515519
float h = rrect.height;
516520
float halfw = Mathf.Abs(w) * 0.5f;
@@ -546,7 +550,7 @@ public void addRRect(RRect rrect) {
546550
}
547551

548552
public void addEllipse(float cx, float cy, float rx, float ry) {
549-
this._updateRRectFlag(true);
553+
this._updateRRectFlag(true, PathShapeHint.Oval);
550554
this._appendMoveTo(cx - rx, cy);
551555
this._appendBezierTo(cx - rx, cy + ry * _KAPPA90,
552556
cx - rx * _KAPPA90, cy + ry, cx, cy + ry);
@@ -560,13 +564,13 @@ public void addEllipse(float cx, float cy, float rx, float ry) {
560564
}
561565

562566
public void addCircle(float cx, float cy, float r) {
563-
this._updateRRectFlag(true);
567+
this._updateRRectFlag(true, PathShapeHint.Oval);
564568
this.addEllipse(cx, cy, r, r);
565569
}
566570

567571
public void addOval(Rect oval) {
568572
D.assert(oval != null);
569-
this._updateRRectFlag(true);
573+
this._updateRRectFlag(true, PathShapeHint.Oval);
570574
var center = oval.center;
571575
this.addEllipse(center.dx, center.dy, oval.width / 2, oval.height / 2);
572576
}
@@ -759,7 +763,7 @@ public void addPath(Path path, Offset offset) {
759763
public void addPath(Path path, Matrix3 transform = null) {
760764
D.assert(path != null);
761765

762-
this._updateRRectFlag(path.isRRect);
766+
this._updateRRectFlag(path.isRRect, path.shapeHint);
763767
var i = 0;
764768
while (i < path._commands.Count) {
765769
var cmd = (PathCommand) path._commands[i];
@@ -1398,6 +1402,13 @@ void _chop(out _Conic c1, out _Conic c2) {
13981402
};
13991403
}
14001404
}
1405+
1406+
public enum PathShapeHint {
1407+
Rect,
1408+
Oval,
1409+
RRect,
1410+
Other
1411+
}
14011412

14021413
enum PathCommand {
14031414
moveTo,

Runtime/ui/painting/shadow_utils.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,8 @@ static void drawShadowFull2(Canvas canvas, Path path, Vector3 zPlaneParams, Vect
237237
_shadowMatrix.reset();
238238
canvas.setMatrix(_shadowMatrix);
239239
float sigma = convertRadiusToSigma(blurRadius);
240-
_shadowPaint.maskFilter = MaskFilter.blur(BlurStyle.normal, sigma);
241-
canvas.drawPath(_devSpacePath, _shadowPaint);
240+
_shadowPaint.maskFilter = _devSpacePath.isRRect ? MaskFilter.fastShadow(sigma) : MaskFilter.blur(BlurStyle.normal, sigma);
241+
//canvas.drawPath(_devSpacePath, _shadowPaint);
242242
canvas.restore();
243243

244244
//spot light
@@ -256,7 +256,7 @@ static void drawShadowFull2(Canvas canvas, Path path, Vector3 zPlaneParams, Vect
256256
_shadowPaint.strokeWidth = 0;
257257
_shadowPaint.style = PaintingStyle.fill;
258258
float sigma2 = convertRadiusToSigma(radius);
259-
_shadowPaint.maskFilter = MaskFilter.blur(BlurStyle.normal, sigma2);
259+
_shadowPaint.maskFilter = path.isRRect ? MaskFilter.fastShadow(sigma2) : MaskFilter.blur(BlurStyle.normal, sigma2);
260260
canvas.drawPath(path, _shadowPaint);
261261

262262
canvas.restore();

Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_impl.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,12 @@ void _drawPathDrawMeshQuit(uiMeshMesh mesh, TextBlobMesh textMesh) {
594594

595595
void _drawPath(uiPath path, uiPaint paint) {
596596
D.assert(path != null);
597+
598+
//draw fast shadow
599+
if (paint.maskFilter != null && paint.maskFilter.Value.style == BlurStyle.fast_shadow) {
600+
this._drawRRectShadow(path, paint);
601+
return;
602+
}
597603

598604
if (paint.style == PaintingStyle.fill) {
599605
var state = this._currentLayer.currentState;
@@ -602,7 +608,6 @@ void _drawPath(uiPath path, uiPaint paint) {
602608
bool convex;
603609
var fillMesh = cache.getFillMesh(out convex);
604610
var mesh = fillMesh.transform(state.matrix);
605-
606611
if (paint.maskFilter != null && paint.maskFilter.Value.sigma != 0) {
607612
this._drawWithMaskFilter(mesh.bounds, paint, paint.maskFilter.Value, mesh, convex, 0, null,
608613
uiRectHelper.zero, null, false, this.___drawPathDrawMeshCallback);
@@ -636,7 +641,6 @@ void _drawPath(uiPath path, uiPaint paint) {
636641
paint.strokeMiterLimit);
637642

638643
var mesh = strokenMesh.transform(state.matrix);
639-
640644
if (paint.maskFilter != null && paint.maskFilter.Value.sigma != 0) {
641645
this._drawWithMaskFilter(mesh.bounds, paint, paint.maskFilter.Value, mesh, false, alpha, null,
642646
uiRectHelper.zero, null, false, this.___drawPathDrawMeshCallback2);

0 commit comments

Comments
 (0)