You've spent weeks polishing your game's art. Then you compress the assets, and suddenly your character's face looks like a watercolor painting left in the rain. Or your beautifully textured terrain turns into a blocky mess. We've all been there.
Compression is necessary—deploying raw 4K textures is insane. But picking the wrong setting can ruin your visuals. This isn't a close look into every codec spec. It's a practical guide to choosing compression that doesn't wreck your game. We'll talk real numbers, real mistakes, and what to look for.
Who Needs This and What Goes Wrong Without It
The cost of ignoring compression
You pick a texture setting in five seconds, hit export, and move on. That's how it starts. A week later your artists notice banding across the skybox—those smooth gradients now look like cheap contour maps. Or worse: your build ships and players on mid-range GPUs report stuttering every time they open a menu. The culprit isn't bad art. It's the compression you clicked without thinking. I have seen teams lose two days of bug fixes just because someone selected 'BC1' for an alpha-heavy UI element. The artifacts weren't obvious in the editor—they bloomed under different lighting, different resolutions, different driver versions. That's the real trap: compression damage hides until your game is in someone else's hands.
Common horror stories: banding, blur, ghosting
Let's name the usual suspects. Banding shows up as harsh color steps where you intended a smooth falloff—sky gradients, health-bar fills, volumetric fog. Blur happens when compression discards high-frequency detail: text on a sign becomes unreadable, a character's stubble turns into smudge. Ghosting, my personal nightmare, appears as translucent after-images trailing moving objects—it's a temporal artifact from video-encode-like compression on sprite sheets. "That's not a bug, it's the asset format" is never a satisfying answer to your QA lead. The catch is these artifacts rarely show in a single screenshot. You need to animate, rotate the camera, vary the contrast. Most teams skip this step. They don't see the problem until a streamer zooms in on your main menu and the UI looks like JPEG cancer.
'We shipped with DXT5 on normal maps. The specular highlights broke on every metallic surface. Took us three patches to even find the root cause.'
— lead technical artist, indie RPG studio, recounting a five-week fix cycle
Why 'just use maximum quality' isn't an option
Raw RGBA32 at 4K—no compression, no loss. Sounds safe. But try shipping a 12GB title on a mobile store or a Game Pass download cap. You'll get rejected by platform cert, or your users will delete the game after the first update. Mobile stores flag anything over 4GB. Console patches are capped. Steam users on metered connections will refund before your title screen fades in. The trade-off is brutal: compress too hard and your game looks like a PS2 emulator running on a muddy CRT; compress too little and nobody can download it. What usually breaks first is the middle ground—compression settings that look fine on your dev machine but fall apart on the RTX 3060 or the Steam Deck. I have watched a beautifully painted sky shatter into macroblocks because the ASTC profile didn't match the target GPU. So you can't default to 'best quality.' You have to choose deliberately, test across hardware, and accept that some trade-offs hurt less than others. That's what the rest of this guide exists for.
What You Should Settle Before Picking a Setting
Target platform: mobile, PC, console?
You can't pick a compression setting in a vacuum — the device your players actually use dictates half your options before you even open a tool. Mobile GPUs, for instance, often mandate ASTC (Android) or PVRTC (older iOS), while desktop and console hardware typically prefers BC1–BC7 families. I have seen teams spend two weeks tuning a beautiful BC7 texture set, only to discover their lead platform was a mid-range phone that refuses to decode BC formats without brutal software fallback. That hurts. The catch is that "mobile" alone isn't specific enough: a 2024 flagship runs ASTC 4×4 at full speed; a budget 2020 handset might choke on anything beyond ETC2. So before you even think about sliders, lock down your lowest common denominator device and check its hardware decoder table. Wrong order, and you'll re-export everything.
Texture resolution and mipmap strategy
Most teams skip this: they pick a compression format, then later realize their 4096×4096 albedo map produces mip-level artifacts that look like static on a distant hill. The resolution you target directly shapes which compression settings are viable — higher base resolutions demand better block efficiency, or banding creeps in. A stylized character with cel-shaded flats can often get away with BC1 at 1024×1024 and look fine; a photorealistic face needs BC7 or ASTC 6×6 at the same size to avoid contouring on the nose. And mipmaps? They aren't optional — you must decide whether you'll generate them yourself (controlled) or let the engine auto-generate (risky). I once watched a project ship with auto-mips that blurred a thin UI icon into muddy garbage at 50 meters — the compression format was fine; the mip strategy was broken. Settle your mipchain count and filter type before you run any batch test.
Not every performance checklist earns its ink.
'The easiest compression mistake is treating all textures as if they belong to the same game.'
— quote overheard at a Unity Unite roundtable, before someone demoed a grass texture that looked like vomit on a Switch
Understanding your content: photorealistic vs stylized
Your art style isn't just a vibe — it's a compression compatibility signal. Stylized content, with its flat color fields, hard edges, and limited palette, handles aggressive block compression surprisingly well: BC1 or ETC2 at 4 bpp often retains the intent because there's little high-frequency noise to ruin. Photorealistic textures, by contrast, carry subtle gradients, micro-detail, and film grain — exactly the stuff that BC3 and ASTC 4×4 murder first. You'll see banding in skies, posterized skin tones, and aliasing on wet surfaces. The fix isn't always a higher bitrate; sometimes switching from BC1 to BC5 for normal maps buys you more fidelity than just boosting resolution. Does that mean you should test every single texture in isolation? No — but you should categorize your asset library into three buckets: flat stylized, complex stylized, and photo-real. Each bucket gets a separate compression preset. That sounds tedious until you realize it takes two hours and saves you two weeks of pixel-by-pixel debugging later. Grab a spreadsheet, map each bucket to a format + resolution ceiling, and only then open the compressor.
Core Workflow: How to Test and Choose Compression
Step-by-step visual comparison method
Most teams skip this: they pick a slider, click export, and pray. That hurts. Instead, grab five representative assets—a character face, a foliage cluster, a metal panel, a sky gradient, and a UI icon. Export each at four compression levels: BC1 (DXT1) at 4:1, BC3 (DXT5) at 4:1, BC7 at roughly 3:1, and your engine's super‑aggressive default. Lay the exports side‑by‑side in a viewer that lets you toggle at 100% zoom. I have seen a perfectly normal wall texture turn into ring‑shaped banding because somebody trusted the default on a normal map. The catch: a 2K screen hides artifacts that bloom at 4K or on mobile panels—always check at your target output resolution, not your dev monitor.
Using tools like NVIDIA Texture Tools Exporter
NVIDIA Texture Tools Exporter gives you a quick quality slider and a batch mode. Run your five test images through it, outputting each at settings 0, 3, 6, and 9. Why those? Because the difference between 3 and 6 is often invisible on diffuse but catastrophic on alpha‑cutout leaves—you won't know unless you force the comparison. Open the uncompressed originals next to each compressed version in separate layers of Photoshop or GIMP, then subtract blend mode (difference). Any pixel area that lights up above 10‑15 gray values is showing real loss. That said, the subtract trick works best on flat lit shots; a high‑contrast scene hides artifacts under specular highlights. Pull a frame from your game's darkest corner and test there too.
Quantitative checks: file size vs PSNR/SSIM
The numbers lie less than your eyes—though not by much. PSNR (peak signal‑to‑noise ratio) above 35 dB usually means imperceptible loss, but I have seen BC1 hit 38 dB and still crush a stucco texture into flat plastic because PSNR doesn't weight high‑frequency detail the way human vision does. Pair it with SSIM (structural similarity index); keep SSIM above 0.97 for critical hero assets and 0.92 for background filler. Build a quick spreadsheet mapping each setting's output size in kilobytes versus its SSIM score. The trade‑off curve typically flattens after a certain point—on moderate‑detail textures, there's rarely a quality gain above BC7 quality 6. Anything beyond that just bloats your download. Most teams chase the last 2% improvement and bloat their package by 15%. Stop there.
“We compressed a whole forest at BC7 quality 4 and saved 30% over quality 9. Nobody saw the difference—we measured it.”
— Lead Technical Artist, a mid‑sized studio that learned the hard way on a 12GB day‑one patch
The golden rule: always test in motion
A static screenshot can lie. Load your compressed textures into an actual scene with camera movement, particle effects, and dynamic lighting. Walk the camera along a wall at slow speed—sudden banding that looked fine in a still will pulse. Rotate a character under a directional light; normal‑map artifacts that blended into the static render will crawl across the specular lobe. We fixed this by building a 30‑second automated fly‑through that captured every texture at every compression setting, then had three artists rank the results blind. The winning setting was never the highest quality—it was the one where the worst compression artifact was a tiny gradient step nobody noticed during gameplay. Write that finding into a short decision doc: asset type, target platform, chosen setting, and why you rejected the next higher level. Next time you update a texture, you won't start from zero. That's the whole point of a repeatable workflow—remove the guesswork, leave only the evidence.
Tools, Setup, and Environment Realities
Engine-specific compression: Unity vs Unreal vs Godot
Each engine plays favorites with compression—and ignoring those defaults is where the pixel mess starts. Unity's Texture Importer defaults to DXT for PC and ASTC for mobile, but that's a starting point, not a finish line. I have seen teams ship an entire build with DXT5 on iOS because nobody flipped the override platform tab. That hurts. Unreal's Texture Editor gives you a dropdown labeled 'Compression Settings' with names like 'Default (DXT)' or 'Normalmap'—and yes, 'NoAlpha' sounds like a speed hack, but it'll turn your emissive decals into gray blocks if you slap it on the wrong channel. Godot handles things differently: its compress mode is global per-project unless you override it per texture via import flags. The catch is Godot's 3.x series doesn't support ASTC natively; you need a plugin or you're stuck with ETC2. That kills texture quality on older Android devices. You'll also hit a wall if your normal maps use BC5—Godot wants RGTC. Wrong order and your normal map looks like it was drawn with a broken stylus.
Third-party encoders: crunch, Oodle, ASTC encoder
Engine-native codecs get you 80% of the way. For the last 20%—and to avoid that melted-detail look on distant props—you reach for a third-party encoder. The 'crunch' library (integrated into Unity's Texture Packer via the crunch option) shrinks DXT textures aggressively; it's good for baked lightmaps that don't need per-pixel fidelity. But crunchy lightmaps on characters? Bad idea—they smear subsurface detail into a waxy blur. Oodle Texture from RAD Tools (now Epic-owned) ships inside Unreal's Project Settings toggle, and it's a cheat code for mobile: same file size, visibly cleaner gradients. We fixed a shimmering foliage issue on Switch by swapping Oodle from 'Fast' to 'Better'—cost us an extra 40 seconds per build step but killed the sparkle. For ASTC you can run ARM's standalone encoder outside the engine, which matters when your build pipeline doesn't support per-platform overrides. It's a command-line beast: astcenc -cl source.png target.astc 6x6 -medium. Most teams skip this—they let the engine auto-encode. Then they wonder why a 512×512 UI element looks like a crushed soda can on a tablet.
The compression encoder you pick is the last thing you test, but the first thing players notice when a texture ripples like a heat mirage.
— comment from a technical artist I worked with who debugged a day-one patch on a 12MB texture set
Honestly — most performance posts skip this.
Pipeline integration: batch processing and automation
Running compression by hand per texture is a trap. You forget one, or you apply BC7 to a sprite sheet that's supposed to use ETC2, and the asset store listing photos show a UI that looks smeared. The fix is a batch script or a custom PostImport step. In Unity, a simple editor script that loops through all textures in a folder and assigns a compression override based on naming convention—_ui gets ASTC 8x8, _bg gets ASTC 6x6—saves you a day of manual clicking. Unreal's Data Prep system can automate compression rules per LOD level, but I have seen it misapply to textures that already have custom compression flags. That's a debug hour you don't get back. Godot's import_defaults.tres file lets you set per-type compression globally, but it's JSON-like and easy to typo. The real pipeline reality? Your build server needs the SDK and encoder binaries installed. If your CI container doesn't have the ASTC encoder runtime, the build falls back to DXT and every Android device sees crushed alpha channels. What usually breaks first is the automation step: you think it's working, ship a QA build, and three days later someone notices the title screen gradient is banding like a 256-color GIF. Test the pipeline with one known-bad texture first. Don't trust the tool—trust the output.
Variations for Different Constraints
Mobile: ASTC vs ETC2 vs PVRTC
Pick the wrong format here and you don't get a warning—you get a black screen on half your test devices. ASTC is the modern darling: flexible block sizes (4×4 through 12×12) let you trade quality per pixel almost surgically. I have seen teams slam everything into ASTC 8×8 and wonder why their stylized wood texture looks like oatmeal—too aggressive for high-frequency detail. ETC2 is your fallback for older Android hardware (pre-2014-ish), but it chokes on alpha channels unless you use ETC2 with EAC. PVRTC? Only if you're shipping to legacy iOS devices that predate the A8 chip. The trap is assuming one format covers all: you'll need at least two texture variants or a runtime fallback path, because ASTC isn't guaranteed on every GPU.
That sounds fine until you realize ASTC 4×4 eats 1 byte per pixel—roughly 2× the memory of 8×8. Mobile VRAM is stingy; a 2K texture at 4×4 costs ~5.3 MB, while 8×8 drops to ~1.3 MB. Most teams skip this: they test on a flagship phone with 8 GB RAM, ship at 4×4, and then the budget device with 3 GB starts swapping to system memory. Not a crash—just stuttering that looks like a memory leak. We fixed this by building a small in-engine quality preset per device tier: ASTC 6×6 for mid-range, 8×8 for low-end, and a fallback to ETC2 4×4 for unsupported chips. The catch? You must actually test on the low-end device, not an emulator.
'Switching from ASTC 8×8 to ETC2 on a single normal map saved 40% loading time on our Kindle Fire test unit—but the color banding on the skybox was unusable.'
— mobile optimization lead, after a late-night build pipeline fix
PC: BC7, BC5, and when to use uncompressed
Desktop gives you breathing room, but not infinite—BC7 is your workhorse for color textures with alpha: 8 bits per pixel, decent HDR support, and it handles smooth gradients far better than BC3 or BC1. The mistake is using BC7 for everything. Normal maps want BC5 (two-channel, R and G only)—it preserves vector direction better and halves the data compared to shoving a normal into BC7. What usually breaks first is the specular mask or metallic map crammed into a single-channel BC4: the lossy compression can shift the edge of a scratch texture by two pixels, and suddenly your gun barrel looks scratched in the wrong place.
Then there's uncompressed. I rarely recommend it, but for UI elements, text atlases, and any asset that gets sampled with point filtering at 1:1 pixel mapping—compression artifacts turn crisp icons into blurry messes. Same for lightmap atlases with sharp shadow boundaries: BC7 will smear the transition by 3–4 texels, producing a soft shadow where you wanted a hard edge. One concrete anecdote: we shipped a night level with uncompressed lightmaps (32-bit float) on PC only, and the build ballooned from 600 MB to 1.4 GB. The fix was baking shadow-cascade boundaries into a separate mask texture, compressed with BC4, while keeping the main lightmap as a lower-resolution BC7. That cut the total by half and preserved the hard edges.
Stylized vs realistic art: different tolerance thresholds
Realistic textures lean on subtle noise, microfacet detail, and color variation—compression that smears these into flat patches kills the illusion of photorealism. Stylized art, by contrast, often uses sharp color regions, bold outlines, and cel-like shading: heavy compression introduces banding, but the brain reads it as intentional cell shading. Wrong order to assume stylized always tolerates more. I have seen a cartoon rock texture crushed to ETC2 4×4 that looked fine until the character's flat-colored cape (intentionally two-tone) developed a seven-step gradient across the folds—because the encoder couldn't preserve the hard color edge.
What you should actually test: take your most saturated, high-contrast texture and your subtlest gradient texture. Compress both with your candidate setting, then overlay the difference map in Photoshop or equivalent. The gradient will show a delta of 8–12 pixel values; the saturated one might show 2–3. If the gradient texture is a skybox or a character face, that delta is visible. If it's a brick wall with heavy normal-map microdetail, nobody notices. The pragmatic rule: run a batch diff on your whole texture folder, sort by average absolute error, and manually inspect the top 10% of offenders. That tells you which compression setting actually breaks your specific art style—instead of guessing.
Reality check: name the optimization owner or stop.
Pitfalls, Debugging, and What to Check When It Fails
Color banding from low bit depth
You compress a sky gradient, and suddenly it looks like a topographic map. That staircase of ugly color steps—banding—is the most common artifact I debug, and it usually traces back to one mistake: tossing textures into a 4-bit or 5:6:5 format without checking the content. The fix isn't always obvious. Most teams skip this: look at the actual bit allocation per channel. ASTC 4×4 might give you 8 bits per channel; ETC2 on older mobile drops to 5 bits for blue. A slow sunrise gradient needs at least 6–7 bits. Test with a solid ramp texture first—if you see rings within three seconds, your format is starving the data.
Nobody talks about the monitor factor. You debug on a 10-bit panel, ship to a 6-bit TN screen with FRC dithering, and the banding doubles. That hurts. Always verify on the worst display your target audience owns—cheap phone, old laptop, whatever. One trick: force 16-bit color in your engine's render settings during QA. If the banding vanishes when you switch to 32-bit, your compression setting is the culprit, not the art. Switch to BC7 or ASTC HDR if your platform allows it. Don't crank up dithering as a band-aid—it introduces noise that multiplies in motion.
Alpha channel artifacts and premultiplied alpha
The catch is that alpha doesn't compress like RGB. I have seen entire particle systems fall apart because a DXT5 texture squeezed the alpha to 3 bits. What usually breaks first is the fuzzy edge: a 50 % transparent window frame suddenly gains a white halo. That's premultiplied alpha saved in straight-alpha format—or vice versa. The pipeline matters more than the slider. Are you packing alpha into a separate channel? Are you using EAC R11? Wrong order, and you get ghosting pixels around every glass shard.
Test alpha with a checkerboard behind the asset—not a solid black backdrop. Black hides transparency errors. Most deviation tools fail here because they compare pixels, not perceived edges. I watched a team spend two days re-exporting foliage because their compression test used a white background. Switch to gray—50 % neutral. One more thing: never compress a normal map alpha with the same settings as diffuse. The tangent-space math amplifies every 1-bit error into a visible lighting seam. Use separate format or, better yet, reconstruct the normal W in the shader. Drop the alpha channel entirely if you can.
Performance vs quality false trade-offs
It's tempting to blame compression when frame rate dips—'we need smaller textures.' But here's the thing I keep seeing: a 256×256 DXT5 texture at 0.5 MB loads faster and renders the same as a 512×512 BC7 at 2 MB, yet people chase the bigger size, compress harder, then wonder why their character faces look like a watercolor painting five feet away. The trade-off isn't really quality versus speed—it's mipmap discipline versus lazy LOD settings. If you haven't generated proper mip chains before compression, the lowest mip levels alias horribly, and you'll over-compensate by lowering bitrate on the base texture. That's backward.
Profile before you tweak. Use RenderDoc or your platform's GPU counters: how many texture cache misses per frame? If the answer is under 15 %, your bottleneck is shader complexity, not compression size. I have fixed 'compression problems' by simply reducing anisotropic filtering from 16× to 4× and keeping the original ASTC 6×6 setting. Zero artifacts gained, three milliseconds back. The real question: is the artifact visible during gameplay at typical viewing distance, or are you pixel-peeping in the editor at 400 % zoom? Stop doing that.
“The worst compression setting isn't the one that makes the image ugly—it's the one that looks fine in the editor but breaks on the device your player actually uses.”
— lead technical artist, shipping two mobile titles
When it does break, don't recompress everything. Isolate the failing texture. Export it as an uncompressed PNG, load it next to the compressed version in a diff tool, subtract the channels mathematically. If the error is concentrated in one color or one alpha gradient, that's your clue: your compression format starves that channel. Swap format for only that texture. Keep the rest. Most people waste an afternoon rebuilding an entire atlas when the fix is a single override on a glass texture—and a five-minute chat with the artist about how premultiplied alpha actually works.
Comments (0)
Please sign in to post a comment.
Don't have an account? Create one
No comments yet. Be the first to comment!