Documentation

// UI Blur Pro for URP · v1.0.0 · Unity 6 / URP 17+

How It Works

UI Blur Pro for URP integrates with URP's rendering pipeline, captures the scene at a configurable point, runs a blur algorithm, and makes the result available for UI panels and 3D world objects to sample. The blur computes once per profile per frame — panels themselves do no blur work at draw time.

The blur only runs when at least one active BlurImage or BlurObject references that profile. Profiles with no active consumers cost nothing.

01
Scene renders normally

Geometry, skybox, and transparents render through URP as usual.

02
Background is captured

The Blur Renderer Feature captures the rendered scene at the point controlled by each profile's CaptureMode.

03
Blur passes run on the GPU

The captured image is processed by the selected algorithm. Up to 16 profiles can run simultaneously, each fully independent.

04
Panels sample the result

BlurImage (UI panels) and BlurObject (3D meshes) sample the blurred output and apply frost tint, brightness, desaturation, and optional normal-map distortion.

Requirements

RequirementVersion
Unity6000.0 or later
Universal Render Pipeline17.0.0 or later
RenderGraphEnabled in Project Settings → Graphics → URP Global Settings
PlatformsPC, Mobile — VR/XR not tested, not officially supported

Quick Start

01Open the Setup Wizard via Tools → UIBlurPro → Setup Wizard. It also opens automatically on first import.
02Tick the URP Renderer assets you want to add the feature to, then click Add Blur Feature.
03Add a UI Image component to your Canvas and add a BlurImage component to the same GameObject — or use GameObject → UI → Blur Image (also in the Hierarchy + menu) to create an already-wired panel in one step. For 3D, GameObject → 3D Object → Blur Object does the same on a Quad.
04Assign a BlurProfile asset to the Profile field, or click New to create one inline.
05Set Capture ModeWithout Post Processing works with all Canvas modes and is the recommended default.
06Press Play. The blur is active immediately.

You can also create profiles directly from the Blur Renderer Feature inspector by clicking Create New Profile next to any slot in the profiles list.

Capture Mode

CaptureMode controls which point in URP's frame the background is captured at.

CaptureModeRender EventNotes
WithoutPostProcessingBeforeRenderingTransparentsCompatible with all Canvas modes and BlurObject. Use in most cases.
WithPostProcessingAfterRenderingPostProcessingIncludes bloom, tonemapping, color grading. Screen Space Overlay only — using this with Screen Space Camera or World Space produces a black panel.
Both branches simultaneously: a single profile can serve WithoutPostProcessing and WithPostProcessing at the same time for different BlurImage components with no conflict — each branch is an independent pass-chain with its own render textures.

Blur Methods

MethodCostBest For
Dual Kawase●●○○○Frosted-glass UI — widest radius at lowest cost
Custom Kawase●●○○○Fast circular blur with tunable tap count
Poisson Disk●●●○○Cinematic bokeh — eliminates grid sampling artifacts
Gaussian Separable●●●○○Mathematically exact Gaussian circle
Tent / Hex●●●●●Hexagonal lens bokeh — cinematic moments
Radial●●○○○Zoom-burst blur, impact effects, cutscenes — not a soft bokeh

BlurProfile

A BlurProfile is a serializable asset describing how to blur — algorithm, pass count, and per-algorithm parameters. It contains no appearance settings; those live on the BlurImage or BlurObject that references it. Up to 16 profiles can be active simultaneously.

Ways to create a profile: Assets → Create → UIBlurPro → Blur Profile, click New next to the Profile field on any BlurImage component, or click Create New Profile next to any slot in the Blur Renderer Feature's profiles list.

Common parameters

PropertyTypeRangeDescription
blurMethodBlurMethodAlgorithm used for this profile
intensityfloat0–1Blur strength multiplier. 0 = no blur, 1 = full authored strength. Scales parameters each frame without modifying serialized values. Shared across all BlurImages referencing this profile.
iterationsint1–8Pass count / mip pyramid depth — more = wider blur
blurOffsetfloat0–5Tap spread multiplier (scales with screen resolution)
downsampleint1–8RT resolution divisor — auto-adjusted for screens wider than 1920 px

Dual Kawase

Uses iterations and blurOffset. The mip pyramid is built automatically; no additional parameters needed.

Custom Kawase / Poisson Disk

PropertyRangeDescription
taps3–12Number of samples per pass
useIGNRotationbool(Poisson only) Per-pixel sincos rotation — higher quality, minimal cost

Gaussian Separable / Tent Hex

PropertyRangeDescription
gaussianRadius1–16Sample radius in pixels (scales with screen resolution, capped at 64)

Radial

Zoom-burst blur: streaks radiate from a focal point, strongest at the edges and vanishing toward the point itself. radialInnerRadius / radialOuterRadius control exactly where that sharp-to-blurred transition happens. This pass draws with a single material, so it has one focal point per frame — by default the screen center; enabling radialFocusOnPanelCenter moves that point to the first panel's rect center instead. Best suited to a full-screen effect or a preset used by a single panel. If you need several panels each with their own independent zoom-burst center, give each one its own BlurProfile.

The scissor padding needed to cover the outward streak (driven by radialZoomStrength) scales with each panel's own on-screen size rather than the screen size — a small panel keeps a small, cheap scissor rect even at high radialZoomStrength instead of padding out toward full-screen.

PropertyRangeDescription
radialTaps4–32Number of samples taken along each streak
radialZoomStrength0–0.5Fraction of distance-to-focal-point pulled per pixel (resolution-independent)
radialInnerRadius0–1.2Normalized distance from the focal point below which the image stays sharp
radialOuterRadius0–1.2Normalized distance from the focal point beyond which blur is at full strength
radialFocusOnPanelCenterboolOff = focal point at screen center; on = focal point at the first panel's rect center (still one shared point)

Update Mode

Controls how often the blur pass chain re-runs. Skipped frames reuse the last blurred result at zero added cost.

PropertyTypeDescription
updateModeBlurUpdateModeEveryFrame (default) or Throttled
throttleFpsint 0–120Max blur updates per second in Throttled mode. 0 = freeze: blurs once on activation, holds that frame, re-captures each time the panel reopens.
Panel typeSuggested Update Mode
Damage/speed feedback, fast-moving contentEveryFrame
HUD (health bar, minimap)Throttled, 30–60 fps
Inventory / crafting menuThrottled, ~10 fps
Pause menu / modalThrottled, 0 fps (freeze)

Re-blur frequency can never exceed your game's actual frame rate, so setting throttleFps higher than needed is harmless. When sharing one profile across panels with different needs, use the highest rate any of them actually requires rather than creating a separate profile just for a different throttleFps.

Sharing a profile between a Throttled/frozen panel and a consumer with unstable visibility costs more than expected, though it isn't visually wrong. The re-blur clock is tracked per-profile, not per-consumer: whenever a profile has zero active consumers for even one frame, its clock resets so the next reactivation captures a fresh frame instead of stale content. A BlurObject is only "active" while it's actually visible to the camera, which can flicker as the camera or object moves. If such a BlurObject shares a profile with a Throttled/frozen BlurImage panel, the object's visibility flicker keeps resetting the shared clock — the panel keeps re-blurring (correctly, with no visible glitch) far more often than its throttleFps suggests, quietly giving up the performance savings freezing was meant to provide. Give the panel its own dedicated profile if you need it to actually stay at its throttled/frozen cost while sharing a scene with such an object.
A frozen panel that keeps moving or resizing will not track its new position. Freezing stops capturing new blur data entirely — the panel keeps sampling the single frame captured when it froze. If the panel then moves outside the screen region that was captured, the uncaptured area reads as black. Reserve Throttled/frozen for panels that stay in one place while visible (pause menus, modals) — not ones with slide-in/slide-out or drag animations.

BlurImage Component

BlurImage attaches a profile's blur output to a UI Graphic (Image, RawImage, etc.). It creates and manages a private Material instance, enabling the correct slot keyword and syncing appearance lazily via a dirty flag.

Settings

FieldTypeDescription
profileBlurProfileThe blur recipe to sample. Supports up to 16 profiles simultaneously.
captureModeCaptureModeWhether to include post-processing in the blur (see Capture Mode).
frostTintColorColor tinted over the blurred background.
frostStrengthfloat 0–1Tint blend weight (0 = no tint, 1 = full tint).
brightnessfloat 0.8–1.5Brightness multiplier applied after tint.
desaturatefloat 0–1Desaturation amount (0 = full color, 1 = grayscale).
vignetteColorColorColor blended in toward the panel edges. Alpha is ignored — use vignetteStrength for blend amount.
vignetteStrengthfloat 0–1How strongly vignetteColor blends in toward the edges (0 = no vignette).
normalMapTextureNormal map driving glass surface distortion.
bumpStrengthfloat -1–1Distortion intensity. Positive = convex bulge, negative = concave dish.
normalMapTilingVector2Tiling of the normal map texture.
normalMapOffsetVector2Offset of the normal map texture.
normalModeNormalModeUV calculation mode for the normal map (see below).
edgeDistancePixelsfloat 0–50Width of the procedural edge bevel, in on-screen pixels — stays a consistent visual width regardless of panel size or resolution.
heightStrengthfloat 0–1Strength of the procedural edge bevel distortion.
contentNormalStrengthfloat -1–1Treats the image's own content as a pseudo normal map for a subtle ripple/refraction look. 0 (default) is off — most noticeable on full-bleed photos/illustrations.

Normal Mode

ValueDescription
StandardTileUses the Image's own UV directly.
LocalFixedScaleScales with screen resolution — resolution-independent (default).
ScreenSpaceFixProjected in screen space, aspect-corrected.

Public API

BlurImage API
// Force appearance fields to push into the material on the next Canvas repaint.
// Call this after changing appearance fields from script.
blurImage.MarkDirty();

// Animate profile.intensity from its current value to 1 over `duration` seconds.
// Reverses smoothly if called while a FadeOut is in progress.
// Uses unscaled time -- works during Time.timeScale = 0.
blurImage.FadeIn(0.4f);

// Animate profile.intensity from its current value to 0, then stop.
blurImage.FadeOut(0.4f);
Shared profile note: FadeIn and FadeOut animate profile.intensity, which is per-profile. If multiple BlurImage components share the same profile, all of them fade together. Use a dedicated profile per panel to fade them independently.

BlurObject Component

BlurObject attaches a profile's blur output to a MeshRenderer (windows, floors, glass panels in 3D space). It always uses WithoutPostProcessing capture — 3D transparent objects render during the transparent pass, so capturing any later would include the object's own draw call and produce a black surface.

Settings

FieldTypeDescription
profileBlurProfileThe blur profile to sample.
frostTintColorColor tinted over the blurred background.
frostStrengthfloat 0–1Tint blend weight.
brightnessfloat 0.8–1.5Brightness multiplier applied after tint.
desaturatefloat 0–1Desaturation amount.
refractionIndexfloat 0–0.5IOR offset — how strongly the surface bends the background sample.
normalMapTextureSurface detail driving refraction direction.
bumpStrengthfloat 0–1Refraction bend intensity.
tintColorColorOverall tint multiplied with vertex color.
mainTexTextureAlbedo texture blended over the blur result. Leave empty for plain frosted glass.

Modifying Parameters at Runtime

All fields on a BlurProfile can be written at runtime. Changes take effect on the next rendered frame.

RuntimeParameters.cs
BlurProfile p = myBlurProfile;

// Continuous -- takes effect next frame, zero overhead
p.blurOffset          = 2f;    // Dual Kawase / Kawase / Poisson tap spread
p.gaussianRadius      = 8;     // Gaussian / Tent-Hex pixel radius
p.radialZoomStrength  = 0.15f; // Radial: zoom-burst strength
p.radialInnerRadius   = 0f;   // Radial: sharp region radius (0-1.2)
p.radialOuterRadius   = 0.7f; // Radial: full-blur region start (0-1.2)

// Discrete -- takes effect next frame, no pass rebuild
p.iterations = 4;
p.taps       = 8;
p.downsample = 2;
p.radialTaps = 16;
p.radialFocusOnPanelCenter = false; // false = screen center, true = first panel's center

// Method -- triggers pass rebuild on next frame
// May produce a one-frame hitch on mobile. Change during loading screens.
p.blurMethod = BlurMethod.GaussianSeparable;

After changing appearance fields on BlurImage or BlurObject from script, call MarkDirty() to push the changes to the material:

AppearanceRuntime.cs
blurImage.frostTint     = new Color(0.8f, 0.9f, 1f, 1f);
blurImage.frostStrength = 0.5f;
blurImage.brightness    = 1.1f;
blurImage.MarkDirty();

Intensity & Fade

profile.intensity scales all blur-strength parameters each frame without modifying the serialized values. Unlike toggling isActive, intensity 0 keeps the pass alive so there is no one-frame black flash when the blur returns.

ScaledNot Scaled
blurOffset, gaussianRadius, radialZoomStrength, iterations, downsample blurMethod, taps, radialTaps, useIGNRotation
IntensityAPI.cs
// Set directly
myProfile.intensity = 0.5f;

// Or via the typed API
myProfile.SetIntensity(0.5f);
float current = myProfile.GetIntensity();

// Built-in coroutine fade on BlurImage
blurImage.FadeIn(0.4f);   // current -> 1 over 0.4s, unscaled time
blurImage.FadeOut(0.3f);  // current -> 0 over 0.3s, unscaled time
Shared profile note: intensity is per-profile, not per-BlurImage. Multiple BlurImage components sharing the same profile are all affected simultaneously. Use a dedicated profile per panel to control them independently.

Update Mode

Use updateMode and throttleFps to reduce how often the blur pass re-runs. Skipped frames reuse the persistent render texture untouched — zero added cost beyond the BlurImage's own sample.

UpdateModeAPI.cs
// Throttle to 30 blur updates/sec
myProfile.updateMode  = BlurUpdateMode.Throttled;
myProfile.throttleFps = 30;

// Freeze: blur once on activation, hold until panel closes and reopens
myProfile.updateMode  = BlurUpdateMode.Throttled;
myProfile.throttleFps = 0;

// Return to every-frame blur
myProfile.updateMode = BlurUpdateMode.EveryFrame;

Common Patterns

Pause menu with blur fade

PauseMenu.cs
[SerializeField] BlurImage _blurImage;

void OpenMenu()
{
    gameObject.SetActive(true);
    _blurImage.FadeIn(0.4f);
    Time.timeScale = 0f;
}

void CloseMenu()
{
    _blurImage.FadeOut(0.3f);
    Time.timeScale = 1f;
}

Manual intensity animation

ManualFade.cs
[SerializeField] BlurProfile _profile;
float _target;

void Update()
{
    float current = _profile.GetIntensity();
    _profile.SetIntensity(Mathf.MoveTowards(current, _target, Time.deltaTime * 4f));
}

void OnMenuOpen()  => _target = 1f;
void OnMenuClose() => _target = 0f;

Quality preset switching

Switch algorithm and parameters during scene load to match player graphics settings.

QualityManager.cs
[SerializeField] BlurProfile _profile;

void ApplyQuality(int level)
{
    switch (level)
    {
        case 0: // Low
            _profile.blurMethod = BlurMethod.DualKawase;
            _profile.iterations = 2;
            _profile.downsample = 4;
            break;
        case 1: // Medium
            _profile.blurMethod = BlurMethod.DualKawase;
            _profile.iterations = 3;
            _profile.downsample = 2;
            break;
        case 2: // High
            _profile.blurMethod = BlurMethod.PoissonDisk;
            _profile.iterations = 4;
            _profile.downsample = 2;
            break;
    }
}

Battery saver mode

Disable all BlurImage components to stop the blur from running entirely.

PowerManager.cs
BlurImage[] _allImages;

void Awake()
{
    _allImages = FindObjectsByType<BlurImage>(
        FindObjectsInactive.Include, FindObjectsSortMode.None);
}

void SetBatterySaver(bool enabled)
{
    foreach (var img in _allImages)
        img.enabled = !enabled;
}

Known Limitations

These are by-design constraints from how URP's RenderGraph schedules render passes. They are not bugs.

3D objects may not appear inside the blur

WithoutPostProcessing captures at BeforeRenderingTransparents. Any 3D object that hasn't rendered yet at that point is entirely absent from the captured texture.

Workaround: use WithPostProcessing on a Screen Space Overlay canvas — it captures after all geometry has finished rendering.

World Space canvas panels are always occluded by Screen Space Camera canvases

Unity draws Screen Space Camera canvases on top of World Space canvases regardless of scene hierarchy. Additionally, the two canvas modes capture at different stages, so neither blur can see the other's panel content.

There is no workaround for this combination. Change the Screen Space Camera canvas to Screen Space Overlay instead — Overlay always renders after World Space geometry, so layering and blur capture both work correctly.

Foreground objects can bleed color into a panel's blur

Screen-space blur has no concept of depth — each pass blurs neighboring pixels in the captured texture regardless of what the camera considers in front of or behind the panel. An opaque object standing between the camera and a world-space panel (a BlurObject, or a BlurImage on a World Space / Screen Space Camera canvas) can bleed its color into the blur near the panel's edges, even at pixels the object doesn't actually occlude — most noticeable with bright or highly saturated objects. This is inherent to screen-space blur convolution in general, not specific to any one algorithm here.

Workaround: keep strongly emissive or brightly lit objects a little further from panel edges, or lower the blur radius/iterations on that profile if the bleed is noticeable.

Blur panels rendered by the same camera cannot see each other's blur output

When two BlurImage panels are rendered by the same camera, both capture at BeforeRenderingTransparents — the same moment in the same frame. The front panel's blur runs before the back panel has been composited into the color buffer, so it samples the raw scene rather than the already-blurred backdrop.

Screen Space Overlay: no workaround. All Overlay canvases render through the same implicit camera and share the same capture point.

Workaround — separate canvases on separate cameras via Camera Stack: place each panel on its own Screen Space Camera canvas, each assigned to a different camera. Stack the cameras so the popup camera renders after the backdrop camera. The popup's BlurImage then captures a color buffer that already contains the backdrop blur.

  1. Keep your Main Camera with Culling Mask set to Everything.
  2. Add a second camera. Set Render Type to Overlay and Culling Mask to UI only. Match projection, FOV, and clipping planes to the Main Camera.
  3. Make the new camera a child of the Main Camera and zero its local position and rotation.
  4. In the Main Camera's Camera Stack, add the new camera as the last entry.
  5. Set the backdrop canvas to Screen Space Camera, Render Camera = Main Camera.
  6. Set the popup canvas to Screen Space Camera, Render Camera = Stack Camera.

Both canvases must use Screen Space Camera mode — placing both panels on the same canvas or the same camera will not work even with a Camera Stack. Use a separate BlurProfile per panel to control each independently.

Screen Space Overlay blurs everything

Overlay + WithPostProcessing captures after all geometry — opaque, transparent, world-space, and 3D objects — and includes post-processing effects. It is the most reliable option when you need the blur to include all scene content.

Troubleshooting

UI panel is black / shows no blur

• Confirm the Blur Renderer Feature is added and enabled on the active URP Renderer asset.

• Ensure a BlurProfile is assigned to the BlurImage component.

• If using WithPostProcessing, confirm the Canvas is set to Screen Space Overlay.

Blur appears pixelated or blocky

• Reduce downsample — high values produce a low-resolution RT that becomes visible at low blur strength or when intensity is below 1.

• Increase iterations or blurOffset to widen the blur and soften the pixelation.

Blur stops updating / freezes unexpectedly

• Check updateMode on the profile — Throttled with throttleFps = 0 intentionally freezes the blur after the first frame.

• Confirm at least one BlurImage referencing the profile is enabled and visible — profiles with no active consumers stop running automatically.

Normal map shows dark fringe / black edges at high bump strength

• The distortion UV is sampling outside the blur RT's scissor region. The scissor automatically expands to cover the distortion range — confirm bumpStrength is not larger than the panel's screen-space margin allows.

• Move the panel away from screen edges, or reduce bumpStrength.

Performance is poor

• Switch to Dual Kawase (lowest cost per quality).

• Increase downsample to 4 and reduce iterations to 2.

• See Performance Tips below for profiling-level optimisations.

Setup Wizard shows no renderers

• Open it manually via Tools → UIBlurPro → Setup Wizard.

• If no renderers appear, create a URP Universal Renderer asset first: Assets → Create → Rendering → URP Universal Renderer.

Blur works in the Editor but shows a flat, un-blurred panel in a Player Build

• This package's Materials are created purely at runtime, so no .mat asset in your project directly references these shaders — Unity's build pipeline strips any shader nothing references, which would otherwise remove them from the build even though everything works fine in the Editor.

• The bundled Runtime/Resources/ folder contains one dummy Material per shader specifically to prevent this — anything inside a Resources folder is always included in a build. Don't delete or move these Materials out of Resources/.

• If you still see this after confirming the Resources/ folder is intact, do a full clean Player build (delete Library/ShaderCache or the whole Library folder) so shaders recompile from scratch.

BlurImage looks correct in Scene view but wrong in Game view

• The Scene view camera is separate from the Game camera and may capture at a different resolution or with different post-processing. Always treat Game view as the reference.

• If the Scene view blur looks distorted, this is expected — the scissor rect is computed from the Game camera's viewport, not the Scene camera's.

Still stuck? Email hello@owlhours.space with your Unity version and a screenshot — that's usually enough to figure out what's going on.

Performance Tips

These optimisations apply to any platform, not just mobile. Each active profile runs its full pass chain every frame it is needed — reducing what runs and how often has the most impact.

Share one profile across multiple BlurImages

If multiple panels need identical blur parameters, assign them the same BlurProfile. The pass chain runs once and all panels sample the same result — zero additional GPU cost per extra panel.

Use Update Mode to reduce how often the blur re-runs

Set updateMode to Throttled for panels over a mostly-still background. Skipped frames reuse the last blurred result at zero added cost.

Set throttleFps to 0 to freeze the blur after its first frame — ideal for pause menus, modals, and any background that does not move while the panel is open.

Assign the same CaptureMode to all BlurImages on a profile

Each distinct CaptureMode branch (WithoutPostProcessing / WithPostProcessing) is a separate pass chain with its own render textures. Mixing capture modes on the same profile doubles the GPU and memory cost for that profile.

Keep the active profile count low

Each active profile is an independent pass chain. Consolidate panels that share parameters into fewer profiles rather than giving every panel its own profile.

Disable BlurImage components when not visible

A profile's pass chain stops running automatically when all its BlurImage consumers are disabled or invisible. Disable the component (not just the GameObject's alpha) when a panel is fully hidden to eliminate its cost entirely.

Third-Party Credits

Dual Kawase Blur — algorithm by Marius Bjørge, presented at GDC 2015 (ARM).