Slide 1

Slide 1 text

Chris Banes Real-time blurring Haze

Slide 2

Slide 2 text

Glassmorphism

Slide 3

Slide 3 text

https://dribbble.com/shots/23435614-Glass-UI-Kit https://dribbble.com/shots/24160940-Mental-Health-App-Glassmorphism-style https://dribbble.com/shots/23944285-Smart-Home-App

Slide 4

Slide 4 text

Microsoft Fluent

Slide 5

Slide 5 text

VisionOS

Slide 6

Slide 6 text

Apple HCI Apple provide different ‘materials’ for developers The values differ per platform, but the names are consistent They’re a great place to start from https://developer.apple.com/design/human-interface-guidelines/materials

Slide 7

Slide 7 text

iOS Figma UI Kit Apple provide an of fi cial iOS 18 iOS + iPadOS Design File https://www. fi

Slide 8

Slide 8 text

iOS Figma UI Kit You can see how the materials work by drilling down*… https://www. fi * They may not be exactly what is used on iOS, but they look and work very similarly

Slide 9

Slide 9 text

https://uxmis fi t.com/2021/02/03/glassmorphism-guide-to-visual-hierarchy/

Slide 10

Slide 10 text

Add shadow ezpz on Android https://uxmis fi

Slide 11

Slide 11 text

Differentiate content Background blurring, and usually visual noise https://uxmis fi

Slide 12

Slide 12 text

Make content readable Tint the background, and optionally play with opacity https://uxmis fi

Slide 13

Slide 13 text

Android Dif fi cult to implement all of this. More on that later…

Slide 14

Slide 14 text

Blurring

Slide 15

Slide 15 text

Foreground blurring aka content blurring The content itself is blurred. Useful for images

Slide 16

Slide 16 text

Fairly easy on Android, we’ve had tools to blur content for a while: RenderScript (old, slow) RenderEffect (Android 12+, fast) Foreground blurring

Slide 17

Slide 17 text

The content behind is blurred. This is the ‘glass effect’ Background blurring aka backdrop blurring Play me!

Slide 18

Slide 18 text

No built in way to achieve this on Android. Which is why I built… Background blurring Play me!

Slide 19

Slide 19 text

https://chrisbanes.github.io/haze/

Slide 20

Slide 20 text

Haze Glassmorpism for Compose Enables real-time backdrop blurring on Android 12+, iOS and Desktop The performance cost is minimal (but not zero) Really easy to use

Slide 21

Slide 21 text

Haze Materials Haze provides multiple different sets of ‘materials’: • HazeMaterials • CupertinoMaterials (ala iOS) • FluentMaterials (ala MS)

Slide 22

Slide 22 text

Haze Progressive Blurring (aka gradient blurring) The effect is commonly used on iOS A recent addition, which I spent a long time on

Slide 23

Slide 23 text

Haze Progressive Blurring (aka gradient blurring) Works via a custom blur runtime shader on Android 13+ Learning shader language was fun. It’s basically C

Slide 24

Slide 24 text

uniform shader content; // 0 for horizontal pass, 1 for vertical uniform int direction; uniform half blurRadius; uniform half4 crop; uniform shader mask; const int maxRadius = 150; const half2 directionHorizontal = half2(1.0, 0.0); const half2 directionVertical = half2(0.0, 1.0); half4 main(vec2 coord) { half intensity = mask.eval(coord).a; return blur(coord, mix(0.0, blurRadius, intensity)); } half gaussian(half x, half sigma) { return exp(-(x * x) / (2.0 * sigma * sigma)) / (2.0 * ${PI.toFloat()} * sigma * sigma); } half4 blur(vec2 coord, half radius) { half2 directionVec = direction == 0 ? directionHorizontal : directionVertical; half sigma = max(radius / 2, 1.0);

Slide 25

Slide 25 text

const half2 directionVertical = half2(0.0, 1.0); half4 main(vec2 coord) { half intensity = mask.eval(coord).a; return blur(coord, mix(0.0, blurRadius, intensity)); } half gaussian(half x, half sigma) { return exp(-(x * x) / (2.0 * sigma * sigma)) / (2.0 * ${PI.toFloat()} * sigma * sigma); } half4 blur(vec2 coord, half radius) { half2 directionVec = direction == 0 ? directionHorizontal : directionVertical; half sigma = max(radius / 2, 1.0); half weight = gaussian(0.0, sigma); half4 result = weight * content.eval(coord); half weightSum = weight; // We need to use a constant max size Skia to know the size of the program. We use a large // number, along with a break for (int i = 1; i <= maxRadius; i++) { half halfI = half(i); if (halfI > radius) { break; }

Slide 26

Slide 26 text

half4 blur(vec2 coord, half radius) { half2 directionVec = direction == 0 ? directionHorizontal : directionVertical; half sigma = max(radius / 2, 1.0); half weight = gaussian(0.0, sigma); half4 result = weight * content.eval(coord); half weightSum = weight; // We need to use a constant max size Skia to know the size of the program. We use a large // number, along with a break for (int i = 1; i <= maxRadius; i++) { half halfI = half(i); if (halfI > radius) { break; } half weight = gaussian(halfI, sigma); half2 offset = halfI * directionVec; half2 newCoord = coord - offset; if (newCoord.x >= crop[0] && newCoord.y >= crop[1]) { result += weight * content.eval(newCoord); weightSum += weight; } newCoord = coord + offset;

Slide 27

Slide 27 text

// number, along with a break for (int i = 1; i <= maxRadius; i++) { half halfI = half(i); if (halfI > radius) { break; } half weight = gaussian(halfI, sigma); half2 offset = halfI * directionVec; half2 newCoord = coord - offset; if (newCoord.x >= crop[0] && newCoord.y >= crop[1]) { result += weight * content.eval(newCoord); weightSum += weight; } newCoord = coord + offset; if (newCoord.x < crop[2] && newCoord.y < crop[3]) { result += weight * content.eval(newCoord); weightSum += weight; } } result /= weightSum; return result; } 53:

Slide 28

Slide 28 text

Haze Input Scale Just released this week Speci fi cally built for lower- powered devices Haze can scale down content before blurring Less pixels == more performance

Slide 29

Slide 29 text

Haze Performance I have built a number of benchmarks which are regularly They measure frame durations TL;DR: Haze adds ~25% to frame duration on phones TVs don’t use touch input, so the cost should be less