Why Engine-Specific Optimization Matters
Unity and Unreal Engine handle normal maps differently due to distinct rendering pipelines, compression formats, and coordinate system conventions. Optimizing for each engine ensures:
- Better visual quality at equivalent memory budgets
- Faster loading times through appropriate compression
- Correct lighting by matching coordinate systems
- Efficient memory usage on target platforms
Unity Normal Map Settings
Import Configuration
When importing a normal map texture in Unity:
Inspector Settings:
├─ Texture Type: Normal map
├─ Create from Grayscale: Unchecked (if already a normal map)
├─ Bumpiness: 1.0 (default)
└─ Filtering: Bilinear or TrilinearFormat and Compression
Desktop (PC/Mac/Linux):
- DXT5nm (BC5): Best quality, industry standard
- Stores X in alpha, Y in green
- Z calculated in shader (saves memory)
- 4:1 compression ratio
Mobile (iOS):
- ASTC 6x6: Best quality/size balance
- PVRTC 4-bit: Older devices, lower quality
- Test on actual device hardware
Mobile (Android):
- ETC2_RGB: Widely supported
- ASTC 6x6: Better quality if min SDK ≥7.0
Platform Override Settings
// Example: Configure normal map import settings
// Place in Editor folder
using UnityEditor;
using UnityEngine;
public class NormalMapProcessor : AssetPostprocessor
{
void OnPreprocessTexture()
{
TextureImporter importer = (TextureImporter)assetImporter;
if (assetPath.Contains("_normal") || assetPath.Contains("_n."))
{
importer.textureType = TextureImporterType.NormalMap;
importer.mipmapEnabled = true;
importer.textureCompression = TextureImporterCompression.CompressedHQ;
}
}
}Material Setup (URP/HDRP)
URP:
- Normal Map strength controlled in material inspector
- Range: 0.0 (flat) to 2.0 (exaggerated)
- Default: 1.0
HDRP:
- More granular normal map controls
- Separate tangent and object space options
- Can blend multiple normal maps with masks
Unreal Engine Normal Map Settings
Texture Import
Unreal auto-detects normal maps by naming convention:
- Files ending in
_N,_Normal,_Norm - Automatically set to TC_Normalmap compression
Manual override:
Texture Properties:
├─ Compression: TC_Normalmap
├─ sRGB: False (auto-unchecked)
├─ Flip Green Channel: Depends on authoring software
└─ LOD Group: Match other material texturesCompression Settings
Desktop:
- TC_Normalmap: Uses BC5/BC7 depending on RHI
- Optimal quality for normal maps
- Automatically configured
Mobile:
- TC_Normalmap still used
- Converts to ASTC/ETC internally
- No manual override needed
Coordinate System
Unreal uses:
- +X = Right (red channel)
- +Y = Down (green channel)
- +Z = Toward camera
Some software (Substance, Photoshop with certain plugins) uses +Y Up.
Solution: Enable "Flip Green Channel" if normals appear inverted.
Material Graph Setup
// Basic normal map setup
NormalMap -> NormalMap Node (Texture Sample)
-> Strength Parameter (optional)
-> Final Material Normal Input
// Advanced: Detail normal overlay
BaseNormal + DetailNormal (blended) -> Final NormalCross-Engine Format Considerations
Tangent Space vs. Object Space
Tangent Space (Standard):
- Purple/blue dominant color
- Used by both Unity and Unreal
- Required for deforming meshes (characters)
- Works with all UV layouts
Object Space:
- Full RGB color variation
- Baked to specific mesh
- No deformation support
- Rarely used in modern workflows
Normal Map Channels
| Channel | Data | Compression Benefit |
|---|---|---|
| R (Red) | X | Moderate |
| G (Green) | Y | High |
| B (Blue) | Z | Reconstructed |
| A (Alpha) | Unused or X | High if used |
Both engines reconstruct Z channel in shader:
float3 normal;
normal.xy = texture.rg * 2.0 - 1.0;
normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));This allows 2-channel compression (BC5) instead of 3-channel (BC7).
Performance Optimization
Resolution Guidelines
| Asset Type | Resolution | Use Case |
|---|---|---|
| Hero character | 4096 | Player character, cutscenes |
| Standard prop | 2048 | Weapons, furniture, vehicles |
| Environment tile | 2048 | Walls, floors (will tile) |
| Background object | 1024 | Distant scenery, fillers |
| Small detail | 512 | Screws, rivets, decals |
Mipmap Optimization
Enable mipmaps for:
- ✅ Tiling textures (walls, floors)
- ✅ Objects viewed at varying distances
- ✅ Anything using texture streaming
Disable for:
- ❌ UI elements
- ❌ Decals viewed at fixed distance
- ❌ Skydomes and skyboxes
Virtual Texturing
Unreal Engine:
Material → Use Virtual Texturing: True
Texture → Virtual Texture Streaming: TrueBenefits:
- Reduced memory overhead
- Better streaming performance
- Support for massive texture atlases
Unity (2022.2+):
- Virtual Texturing still experimental
- Use standard texture streaming for now
Memory Budget Examples
Console/High-End PC
Character (Full Body):
├─ Albedo: 4K (DXT1) = 11 MB
├─ Normal: 4K (BC5) = 11 MB
├─ Roughness: 2K (BC4) = 3 MB
└─ Total: ~25 MB
Environment Tile:
├─ Albedo: 2K (DXT1) = 3 MB
├─ Normal: 2K (BC5) = 3 MB
├─ Roughness: 1K (BC4) = 0.75 MB
└─ Total: ~7 MBMobile
Character:
├─ Albedo: 2K (ASTC 6x6) = 2 MB
├─ Normal: 2K (ASTC 6x6) = 2 MB
├─ Packed RMA: 1K (ASTC 6x6) = 0.5 MB
└─ Total: ~4.5 MB
Prop:
├─ Albedo: 1K (ASTC 6x6) = 0.5 MB
├─ Normal: 1K (ASTC 6x6) = 0.5 MB
└─ Total: ~1 MBCommon Pitfalls
Wrong Color Space
Problem: Normal map tinted green/purple overall
Cause: sRGB enabled on normal map texture
Fix: Ensure sRGB is disabled (both engines auto-disable for normal map type)
Inverted Normals
Problem: Bumps appear as holes, vice versa
Cause: Coordinate system mismatch
Fix:
- Unity: Check normal map generation tool's output space
- Unreal: Toggle "Flip Green Channel" in texture properties
Compression Artifacts
Problem: Banding or blockiness on smooth surfaces
Cause: Wrong compression format
Fix:
- Use BC5/TC_Normalmap compression
- Increase texture resolution if needed
- Check source normal map quality before compression
Seams on UV Boundaries
Problem: Visible lines where UVs meet
Cause: Normal map generated without UV padding
Fix:
- Generate with padding (2-4 pixels)
- Use texture tool to dilate edges
- Adjust UV islands to minimize seams
Export Settings Checklist
When exporting from a normal map generator:
For Unity:
- ✅ 16-bit PNG or 8-bit PNG (16 if quality critical)
- ✅ Tangent space
- ✅ OpenGL format (+Y up) - Unity converts internally
- ✅ Power of 2 dimensions for mipmaps
For Unreal:
- ✅ 8-bit PNG sufficient
- ✅ Tangent space
- ✅ DirectX format (+Y down) or use "Flip Green Channel"
- ✅ Power of 2 dimensions
Testing and Validation
Visual Checks
- Lighting Consistency: Rotate light source, normals should respond correctly
- Seam Inspection: Check UV boundaries in wireframe view
- Distance LODs: View at multiple distances to verify mipmap quality
- Performance: Profile texture memory usage in engine's profiler
Unity Profiler
Window → Analysis → Profiler
├─ Memory → Textures
└─ Filter by "normal" to see all normal mapsUnreal Statistics
Console command: stat texture
or
Console command: stat streamingPlatform-Specific Recommendations
Mobile Optimization
- Prefer 1K for most assets
- Use ASTC 6x6 minimum
- Combine roughness/metallic/AO into single texture with normal
- Test on low-end devices (not just flagship)
Console (PS5/Xbox Series X)
- 2K-4K normal maps acceptable
- BC7 for highest quality (where supported)
- Rely on hardware texture compression
- Leverage SSD streaming for rapid loads
WebGL
- Keep total texture memory under 256MB
- Use DXT compression where supported
- Aggressive mipmapping to reduce bandwidth
- Consider optional quality settings for low-end GPUs
Conclusion
Optimizing normal maps for Unity and Unreal Engine requires understanding each engine's texture pipeline, compression systems, and coordinate conventions. Key principles:
- Use engine-appropriate compression: BC5 for Unity desktop, ASTC for mobile, TC_Normalmap for Unreal
- Match coordinate systems: Check green channel flip requirements
- Budget wisely: Allocate resolution based on visual importance and viewing distance
- Test on target hardware: Profiling reveals real-world performance
By following these guidelines, your normal maps will deliver maximum visual impact while respecting memory and performance constraints across all target platforms.
