For education purposes only · no game files included · bring your own THUG
Guide 10 · experimental branch

Remaster

A 2003 game, a 2026 GPU, and one checkbox. Options › Graphics switches on an optional remaster layer: a real skater shadow, a little extra light, bloom, a filmic tone curve, FXAA, sharp textures, a wider field of view, and camera motion blur. No textures, meshes or scripts were harmed.

GoalMake THUG look the way you remember it looking. Keep every original asset untouched, keep the HUD crisp, and keep the stock renderer one click away.

1One switch, and a clean way back

Everything new hangs off visual in config.ini. With it off (and no blur running), the frame takes the exact path it took before: world straight into the backbuffer, stock shaders. With it on, the world goes into a scene target in the backbuffer's own format, gets post-processed, and only then the HUD is drawn on top, so no text ever gets bloomed, blurred or vignetted.

excerptWn32/Code/Plat/Gfx/nx/postfx.cpp

The mesh shaders got the same treatment. The remaster code lives in #ifdef VISUAL blocks, and the stock program is compiled from the very same text without the define, so the preprocessor hands the GPU the old shader.

excerptWn32/Code/Plat/Gfx/nx/shader.cpp · 22268ec

Two shader programs, one source of truth. Like a skater with a regular and a switch stance.

2"Motion blur doesn't work": the mystery

It did work. It just never ran. The game's only blur is SetScreenBlur, and outside the menus the only thing that turns it on is a special trick with the Cool Specials cheat on. When it did run, it blended the whole frame, HUD included, so your score ghosted around the screen too.

So now there are two blurs, both on the 3D view only:

The catch with camera blur in a third-person game: the skater moves with the camera, so a "the world is static" blur would smear them. The fix is a distance fade, and samples that land on something close are thrown out, so the skater never bleeds into the background.

excerptWn32/Code/Plat/Gfx/nx/postfx.cpp (motion blur shader)

Camera cuts (a jump of more than 10 feet or a 40° turn in a 60th of a second) skip the blur, so the replay camera doesn't smear the whole park across the screen.

3The skater finally gets a shadow

Plot twist: on the Xbox, THUG renders the skater's shadow into a texture and projects it onto the level. In this port that code was stubbed out, so the skater hovered over the ground like a ghost. And the shadow direction came out as NaN, because the light getter it asks was a stub returning a zero vector:

diffWn32/Code/Plat/Gfx/p_NxLight.cpp · 22268ec

The new shadow is a small depth map of the skater, rendered from the game's own shadow camera (it slants along the level's main light, goes straight down in the air, and fades as you get higher). It's applied in screen space from the scene's depth, so every surface gets it exactly once: ground, walls, decals, curbs. The skater writes "don't shadow me" into a spare channel, so it doesn't land on their own body.

excerptWn32/Code/Plat/Gfx/nx/projshadow.cpp · f0017f3

Twenty-three years later, the skater is finally standing on the ground. Physics remains optional.

4A little extra light (on top, never instead)

THUG's levels are lit by baked vertex colors, and they're good. So the remaster keeps them as the base and only adds:

excerptWn32/Code/Plat/Gfx/nx/shader.cpp (fragment shader)

5Fake HDR, real vibes

There's no HDR buffer, and no need for one. The post chain is four steps, each skippable:

  1. Expose: scale the scene a touch (1.05).
  2. Bloom: a bright pass at half resolution, a second downsample, a gaussian blur. Only things marked as glowing take part: the brightest baked light and additive effects (light beams, glows), so white walls don't start radiating.
  3. Shoulder: a filmic roll-off for the highlights; blacks and mid tones are untouched.
  4. Grade: lift the blacks a hair, take the saturation down a hair, darken the corners a hair. Then dither, so the gradients don't band.
excerptWn32/Code/Plat/Gfx/nx/postfx.cpp (composite shader)

No eye adaptation, no temporal tricks, no history buffers to lag behind the replay camera. A handful of fullscreen passes, and it still holds 120 fps at 1080p.

6See more of the park

Field of View goes from 55° to 85° (72° is the game's). It's applied in the game's own camera, not just the renderer, so the game's own culling and screen projections stay in step with what you see. The front end and cutscenes keep the original framing.

diffCode/Gfx/camera.cpp · 22268ec

7The knobs

The menu flips whole features on and off. For fine-tuning, everything lives in config.ini, read when the game starts. The game only writes the section when you change something in the menu; switching a feature off sets its values to neutral, switching it back on restores them. Values outside the ranges are clamped, unknown keys are logged.

configGame/config.ini
KeyRangeDefaultWhat it does
visual0 / 10The remaster layer. 0 is the stock renderer.
motion_blur0.0–1.00Camera motion blur: the fraction of a 60th of a second the shutter is open. Works with visual=0 too.
fov55–8572World field of view, in degrees, at 4:3.
hemi / wrap / spec0–0.4 / 0–0.5 / 0–0.350.18 / 0.25 / 0.12Fill light, wrap diffuse on skaters and peds, highlights on shiny materials.
shadow0 / 11Skater shadow.
shadow_res / shadow_soft1–2 / 0–11 / 0Shadow map 256² or 512²; a 3-tap softer edge.
exposure / shoulder0.8–1.3 / 0–0.351.05 / 0.15Brightness, highlight roll-off.
bloom0–0.250.08Glow strength.
lift / sat / vignette0–0.04 / 0.9–1 / 0–0.120.015 / 0.96 / 0.06Black lift, saturation, corner darkening.
aa / aniso0–1 / 1–161 / 8FXAA, anisotropic texture filtering.

The comparison shots were taken with game time slowed to 0.0001×, so the stock and remaster frames are one frame apart, not one kickflip apart.

8Where it lives

FileWhat
Wn32/Code/Plat/Gfx/nx/visual.cppThe [Graphics] settings, menu features, FOV scale, anisotropy.
Wn32/Code/Plat/Gfx/nx/postfx.cppScene target, screen blur, motion blur, bloom, tone and grade, vignette, FXAA.
Wn32/Code/Plat/Gfx/nx/projshadow.cppThe skater shadow map and its screen-space pass.
Wn32/Code/Plat/Gfx/nx/shader.cppThe VISUAL lighting terms and the bloom / shadow masks.
Scripts/patches/levels/mainmenu/mainmenu_scripts.qOptions › Graphics.

It's on the experimental branch (22268ec, f0017f3), so expect the odd rough edge. The Graphics menu is in the main menu's Options, like Screen.