Performance optimization is crucial for delivering quality gaming experiences on mobile and web platforms. Unity games must run smoothly on devices with varying capabilities while maintaining visual fidelity and engaging gameplay. This guide covers essential optimization techniques that will help you achieve 60 FPS performance across different platforms.
Graphics Optimization
Texture Management
Textures often consume the most memory in Unity games. Proper texture optimization can dramatically reduce memory usage and improve loading times.
- Use texture atlases to combine multiple textures into single files, reducing draw calls and state changes
- Enable texture compression (ASTC for mobile, ETC2 for Android, PVRTC for iOS) to reduce memory footprint by up to 75%
- Implement mipmaps for 3D textures to prevent aliasing and improve performance at different viewing distances
- Limit maximum texture size to 2048x2048 for mobile devices, 1024x1024 for UI elements
- Use sprite packing for 2D games to automatically combine sprites into efficient atlases
// Example: Programmatic texture compression
TextureImporter importer = (TextureImporter)assetImporter;
importer.textureCompression = TextureImporterCompression.Compressed;
importer.compressionQuality = 50; // Balance quality vs size
importer.maxTextureSize = 2048;
importer.mipmapEnabled = true;
Mesh and Model Optimization
3D models should be optimized to reduce polygon count while maintaining visual quality through efficient use of textures and normal maps.
- Target polygon budgets: 1,500-3,000 tris for mobile characters, 500-1,000 for props
- Use LOD (Level of Detail) systems to automatically reduce mesh complexity based on camera distance
- Enable mesh compression in Player Settings to reduce build size
- Combine static meshes using Unity's Static Batching for objects that don't move
- Bake lighting and shadows where possible instead of real-time calculations
Pro Tip: LOD Groups
Unity's LOD Group component can automatically swap between different mesh resolutions. Set up at least 3 LOD levels: high detail (0-25m), medium (25-50m), and low (50m+) with a billboard or disable for very far distances.
Shader Optimization
Complex shaders can bring even powerful GPUs to their knees on mobile devices. Simplifying shaders is one of the fastest ways to improve performance.
- Use Unity's Standard Shader carefully - it's powerful but expensive. Consider Mobile or Lightweight shaders for better performance
- Minimize texture samples in fragment shaders - each texture lookup costs GPU cycles
- Avoid alpha blending where possible - it requires sorting and multiple passes
- Use shader variants sparingly to reduce compilation time and build size
- Profile with Frame Debugger to identify expensive shader operations
Code and Logic Optimization
Efficient Scripting Practices
Well-written code can mean the difference between smooth 60 FPS gameplay and choppy performance.
- Cache component references in Awake() or Start() instead of using GetComponent() repeatedly
- Use object pooling for frequently instantiated objects like bullets, particles, or enemies
- Avoid expensive operations in Update() - use coroutines or spread calculations across frames
- Minimize garbage collection by avoiding unnecessary allocations in frequently called methods
- Use structs instead of classes for small, simple data containers to reduce heap allocations
// Bad: Allocates new array every frame
void Update() {
foreach (var enemy in FindObjectsOfType<Enemy>()) {
enemy.UpdateBehavior();
}
}
// Good: Cache and reuse
private Enemy[] enemies;
void Start() {
enemies = FindObjectsOfType<Enemy>();
}
void Update() {
foreach (var enemy in enemies) {
enemy.UpdateBehavior();
}
}
Physics Optimization
Physics calculations can be computationally expensive, especially with many colliders and rigidbodies in the scene.
- Reduce Fixed Timestep in Project Settings if precise physics aren't critical (0.02 instead of 0.016)
- Use simplified colliders (box, sphere, capsule) instead of mesh colliders when possible
- Layer-based collision matrix to disable unnecessary collision checks between certain object types
- Put static objects on Static layer and mark them as static in the inspector
- Use Rigidbody sleeping to automatically disable physics on stationary objects
Common Pitfall: Raycasts in Update
Performing raycasts every frame for every object is extremely expensive. Instead, use raycasts sparingly, cache results when possible, or use Unity's job system for parallel processing of multiple raycasts.
Mobile-Specific Optimizations
Resolution and Rendering
Mobile devices have limited GPU power and thermal constraints. Adjust rendering settings to maintain performance.
- Dynamic resolution scaling to maintain target framerate by adjusting render resolution
- Disable Anti-Aliasing or use only FXAA (not MSAA) on mobile
- Limit shadow distance and quality - shadows are expensive on mobile GPUs
- Use lightweight rendering pipeline (URP) instead of Built-in for better mobile performance
- Implement quality settings that users can adjust based on their device capabilities
Memory Management
Mobile devices have strict memory limits. Exceeding them can cause crashes or OS killing your app.
- Profile memory usage with Unity Profiler and Memory Profiler package
- Implement asset bundling to load resources on-demand rather than all at once
- Use Resources.UnloadUnusedAssets() after scene transitions
- Compress audio files using Vorbis for music, ADPCM for short sound effects
- Target 150-200MB RAM usage for broad device compatibility
WebGL Optimization
Build Size Reduction
WebGL builds are downloaded by users, so smaller file sizes mean faster loading and better user retention.
- Enable code stripping to remove unused engine code
- Use Brotli compression for maximum file size reduction
- Implement asset bundles for loading heavy assets asynchronously
- Remove unused audio formats and disable platforms you're not targeting
- Target under 50MB for initial download, additional assets loaded as needed
// Player Settings for WebGL optimization
PlayerSettings.WebGL.compressionFormat = WebGLCompressionFormat.Brotli;
PlayerSettings.WebGL.memorySize = 256; // Limit to 256MB
PlayerSettings.SetManagedStrippingLevel(
BuildTargetGroup.WebGL,
ManagedStrippingLevel.High
);
Runtime Performance
WebGL runs in browsers with additional constraints compared to native platforms.
- Limit maximum FPS to 30-60 to reduce CPU/GPU usage in browsers
- Avoid synchronous loading - use async operations for all asset loading
- Implement loading screens with progress bars for better user experience
- Test across browsers (Chrome, Firefox, Safari) as performance varies
- Use WebGL 2.0 for better performance when available
WebAssembly Performance
Unity WebGL builds use WebAssembly (WASM) for better performance than JavaScript. Ensure your server sends the correct MIME types: application/wasm for .wasm files and enable compression headers for .br (Brotli) files.
Testing and Profiling
Profiling Tools
You can't optimize what you don't measure. Use Unity's built-in profiling tools to identify bottlenecks.
- Unity Profiler for real-time CPU, GPU, memory, and rendering statistics
- Frame Debugger to visualize draw calls and rendering order
- Memory Profiler package for detailed memory analysis and leak detection
- Android Profiler via Android Studio for device-specific metrics
- Xcode Instruments for iOS performance analysis
Performance Targets
Establish clear performance budgets for your project based on target devices and platforms.