Screen Effect Packs

Whole-screen post-processing packs (API 3): chromatic aberration, film grain, CRT and your own. Manifest fields, PackEffect, stages, the effect stack and the online gallery.

What an Effect Pack Is

A surface pack replaces the shading of one character’s materials. An effect pack ("type": "effect") works on the finished frame instead: chromatic aberration, film grain, CRT scanlines, glitch, a custom vignette. Effects belong to the whole picture, not to a model.

Effects are not bundled with the app. Install them from the online gallery (the “Shaders” tab, online list) or import a zip. The gallery currently offers chromatic_aberration, film_grain and crt_scanlines. Effect packs need MMDX12 1.4.0 or newer (API version 3).

Using Effects

  1. Install an effect pack from the online list of the Shaders tab.
  2. Open the lobby’s Shaders tab and expand the Screen effects row, or press the sparkle button on the play bar.
  3. Enable the effects you want, change their order with the arrows and tune their sliders.

The stack runs top to bottom on the final image. It applies to play mode, the lobby preview and the real-time video and still renders (raster, real-time RT, real-time PT). It does not apply to the offline GI renderer, the unlit and wireframe views or the Studio quad view. With no effect enabled the frame is identical to one rendered without the feature: no extra targets, no extra passes.

From the command line, --effect <id>[,<id>...] replaces the stack for one run and --effect none clears it.

Folder Layout

my_effect/
  pack.json      manifest (same fields as surface packs, plus type / stage)
  effect.hlsl    implements PackEffect
  preview.png    optional, 16:9 recommended
  textures/      optional, pack.json "textures" (same rules as surface packs)

Manifest Additions

{
  "format": 1,
  "id": "film_grain",
  "version": "1.0.0",
  "apiVersion": 3,
  "minAppVersion": "1.4.0",
  "type": "effect",
  "stage": "post",
  "name": { "ko": "필름 그레인", "en": "Film grain" },
  "params": [
    { "key": "strength", "label": { "en": "Strength" }, "default": 0.12, "min": 0.0, "max": 0.6 }
  ]
}
  • "type": "effect" selects an effect pack ("surface" is the default).
  • "stage" is "post" (default) or "pre-bloom".
  • classes are not used. params (at most 16) and textures (at most 16) work exactly like in surface packs, see Manifest.
stageinput and outputuse for
postdisplay-referred sRGB after tonemap and colour LUT, 8-bitgrain, scanlines, lens fringes, vignette
pre-bloomlinear HDR RGBA16F, before the bloomglow-friendly or exposure-aware effects

Effects of both stages can sit in one stack. Each stage runs its own effects in stack order.

effect.hlsl

A pack implements one function:

float3 PackEffect(PackEffectInput i) { return i.color.rgb; }

PackEffectInput fields:

fieldmeaning
uvtexel centre, 0..1, top left = (0, 0)
pixelSV_Position.xy in pixels
outputSizeoutput resolution in pixels
timeseconds since the scene started
frameIndexframe counter (wraps at 64)
colorthe frame so far at this pixel (alpha kept)
depthraw device depth, 1 = background (LinearZ() converts it)
normalworld-space normal, undefined on the background
motionmotion vector, uv(current) - uv(previous)

Helpers:

  • gEffectSource.SampleLevel(gLinear, uv, 0) reads any pixel of the frame so far (bilinear, clamped). This is how lens effects look around the current pixel.
  • PackParam(i) returns the slider value (or manifest default) of parameter i, in pack.json order.
  • PackFxSampleTex(i, uv), PackFxSampleTexLevel, PackFxTexSize, PackFxTexCount sample the pack’s textures. sRGB textures return linear values.
  • Everything in common.hlsli: Luminance, LinearZ, Ign, SrgbToLinear, gTime and so on.

line is a reserved word in HLSL.

Example: Chromatic Aberration

float3 PackEffect(PackEffectInput i) {
    const float2 dir = i.uv - 0.5;
    const float r = length(dir) * 1.41421356;   // 0 at the centre, 1 in the corners
    const float2 offset = dir * (PackParam(0) * 0.03 * pow(r, PackParam(1)));
    float3 c;
    c.r = gEffectSource.SampleLevel(gLinear, i.uv + offset, 0).r;
    c.g = i.color.g;
    c.b = gEffectSource.SampleLevel(gLinear, i.uv - offset, 0).b;
    return c;
}

Red and blue are sampled along the direction away from the screen centre, and the offset grows towards the edges.

Compiling and Debugging

The shader is compiled at runtime with DXC (ps_6_0). A compile error skips the effect, writes an [E] line to mmdx12.log, shows a toast and a status in the shader manager. It never crashes. Saving effect.hlsl while the app runs reloads it.

Check a pack from the command line with pack_check <folder|zip> --compile, see Debugging. The release ships a starting point in shaders/pack_template_effect.

Publishing

Effect packs use the same zip layout, versioning and review rules as surface packs, see Publishing. Set "minAppVersion": "1.4.0" because the API version is 3.