con un clic
mobile-post-processing
// Single-pass post-processing, URP Renderer Features, and mobile-safe screen effects for Unity
// Single-pass post-processing, URP Renderer Features, and mobile-safe screen effects for Unity
Generate AI videos with Luma Dream Machine via AceDataCloud API. Use when creating videos from text prompts, generating videos from reference images, extending existing videos, or any video generation task with Luma. Supports text-to-video, image-to-video, and video extension.
GPU architecture, precision types, fillrate, overdraw, baked lighting, and LOD optimization for Unity mobile/WebGL shaders
Node budgets, custom lighting, sub-graphs, precision control, and mobile workflows for Unity Shader Graph
Channel packing, variant reduction, shader_feature vs multi_compile, and build size optimization for Unity
Mobile-optimized water shaders with depth coloring, foam, Gerstner waves, refraction, and caustics for Unity URP
WebGL 1.0/2.0 shader restrictions, variant stripping, loop/indexing rules, and browser deployment workarounds for Unity
| name | mobile-post-processing |
| description | Single-pass post-processing, URP Renderer Features, and mobile-safe screen effects for Unity |
Use this skill when the user wants to add, create, or optimize post-processing effects in Unity for mobile or WebGL targets. Triggers include: "post-processing", "bloom", "vignette", "color grading", "blur", "outline", "edge detection", "chromatic aberration", "Renderer Feature", "Full Screen Pass", "Blit", "post-process mobile", or any mention of screen-space effects on constrained hardware. Also trigger when the user reports post-processing is causing frame drops on mobile.
Every post-processing pass costs a full-screen blit — reading the entire framebuffer from main memory and writing it back. On tiled mobile GPUs, this flushes tile memory. Budget 0.5–2ms per pass on mid-range mobile.
Combine all effects into a single pass whenever possible. Unity's default post-processing stack runs each effect as a separate pass. On mobile, this alone can add 6ms+ (measured: vignette alone = 6ms on some devices). Use a single-pass approach instead.
Disable HDR unless you specifically need Bloom. HDR doubles framebuffer bandwidth (16-bit float vs 8-bit per channel). If you only need color grading, apply it in LDR.
Bloom is the most expensive default effect on mobile. It requires downsampling, blurring, and upsampling — multiple passes. If you need it, reduce iterations (2–3 max), use a half-resolution blur, and skip the high-quality prefilter.
Never use Motion Blur or Depth of Field on mobile. They require multiple texture samples per fragment across multiple passes.
Prefer Renderer Features over Volume-based post-processing for custom effects in URP. Renderer Features give you direct control over when and how the blit happens.
This approach combines vignette + color grading + simple bloom in one pass:
Shader "Mobile/PostProcess_SinglePass"
{
Properties
{
_MainTex ("Source", 2D) = "white" {}
_VignetteIntensity ("Vignette Intensity", Range(0, 1)) = 0.3
_VignetteRadius ("Vignette Radius", Range(0, 1)) = 0.7
_Contrast ("Contrast", Range(0.5, 1.5)) = 1.1
_Saturation ("Saturation", Range(0, 2)) = 1.1
_Brightness ("Brightness", Range(0.5, 1.5)) = 1.0
}
SubShader
{
Tags { "RenderPipeline" = "UniversalPipeline" }
Pass
{
ZTest Always ZWrite Off Cull Off
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
CBUFFER_START(UnityPerMaterial)
half _VignetteIntensity;
half _VignetteRadius;
half _Contrast;
half _Saturation;
half _Brightness;
CBUFFER_END
TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex);
struct Attributes { float4 positionOS : POSITION; float2 uv : TEXCOORD0; };
struct Varyings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; };
Varyings vert(Attributes v)
{
Varyings o;
o.positionCS = TransformObjectToHClip(v.positionOS.xyz);
o.uv = v.uv;
return o;
}
half4 frag(Varyings i) : SV_Target
{
half4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
// --- Vignette (no extra texture sample) ---
half2 uvCentered = i.uv - 0.5h;
half vignette = 1.0h - saturate(
length(uvCentered) / _VignetteRadius
);
vignette = smoothstep(0.0h, 1.0h, vignette);
color.rgb *= lerp(1.0h, vignette, _VignetteIntensity);
// --- Brightness / Contrast ---
color.rgb *= _Brightness;
color.rgb = (color.rgb - 0.5h) * _Contrast + 0.5h;
// --- Saturation ---
half luminance = dot(color.rgb, half3(0.2126h, 0.7152h, 0.0722h));
color.rgb = lerp(luminance.xxx, color.rgb, _Saturation);
return saturate(color);
}
ENDHLSL
}
}
}
To inject the post-processing pass into URP:
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class MobilePostProcessFeature : ScriptableRendererFeature
{
[System.Serializable]
public class Settings
{
public Material material;
public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
}
public Settings settings = new Settings();
MobilePostProcessPass pass;
public override void Create()
{
pass = new MobilePostProcessPass(settings);
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (settings.material == null) return;
renderer.EnqueuePass(pass);
}
class MobilePostProcessPass : ScriptableRenderPass
{
Settings settings;
RTHandle tempRT;
public MobilePostProcessPass(Settings settings)
{
this.settings = settings;
this.renderPassEvent = settings.renderPassEvent;
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
var cmd = CommandBufferPool.Get("MobilePostProcess");
var source = renderingData.cameraData.renderer.cameraColorTargetHandle;
// Single blit with our combined shader
Blitter.BlitCameraTexture(cmd, source, source, settings.material, 0);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
}
| Effect | Cost | Mobile Verdict | Notes |
|---|---|---|---|
| Color grading (LDR) | ~0.1ms | SAFE | Pure math, no extra samples |
| Vignette | ~0.1ms | SAFE | UV distance calculation only |
| Film grain | ~0.2ms | SAFE | Noise from UV math, no texture |
| Simple outline (depth) | ~0.5ms | CAUTION | Requires depth texture + 4 neighbor samples |
| Bloom (2-iteration) | ~1-2ms | CAUTION | Use half-res, 2 iterations max |
| Chromatic aberration | ~0.3ms | CAUTION | 3 texture samples instead of 1 |
| Blur (single-pass box) | ~0.5ms | CAUTION | Use 4-tap box blur, never Gaussian |
| Motion blur | ~3-5ms | AVOID | Multiple samples along velocity |
| Depth of field | ~3-5ms | AVOID | CoC calculation + variable blur |
| Screen-space reflections | ~4-8ms | AVOID | Ray marching in screen space |
| Ambient occlusion (SSAO) | ~2-4ms | AVOID | Multiple depth samples per fragment |
| Repo | Purpose | Why It Matters |
|---|---|---|
| demonixis/FastPostProcessing | Single-pass mobile post-FX | Go-to for mobile. Everything in one pass. |
| TPiotr/SimpleMobilePostProcessing-Unity | Blur + vignette | Created because Unity's vignette cost 6ms alone |
| yahiaetman/URPCustomPostProcessingStack | URP Volume-compatible custom FX | 8 example effects with proper URP integration |
| QianMo/X-PostProcessing-Library | Dozens of effects (MIT) | Desktop-quality reference; adapt for mobile |
| GarrettGunnell/Post-Processing | Modular bloom/grade/edge | Notes on single-pass condensation |