V1 · MRenderOverride
Viewport post-process for Maya 2024–2026 · Long Winter Studios

How It Works

AXE Lens replaces Maya's standard VP2 renderer with a custom MRenderOverride that runs a multi-pass post-process pipeline on top of the normal scene render. Click ACTIVATE to swap the renderer; click again to revert. Every parameter change updates in real time — no toggle required after activation.

1
MRenderOverride Registration

The C++ plugin axe_lens_override.mll registers an override named AXELensOverride with VP2. Activation routes modelPanel4 through this override via setRendererInModelPanel. Deactivation routes it back to vp2Renderer. The override intercepts the full render loop — scene render, HUD, and present.

2
optionVar Parameter Bus

All 18 post-process parameters live as Maya optionVars (prefixed axeLensPost_). Every UI interaction writes to optionVars first, then calls axeLensSetParams — a custom MEL command registered by the C++ plugin — which flushes the current optionVar values into the override's uniform state. This means settings survive Maya restarts and can be set from any Python or MEL script without opening the UI.

3
OGSFX Shader Pipeline

Each post-process pass runs as a full-screen quad render using an OGSFX (OpenGL Shading Framework) shader. The shaders are loaded from a shaders/ folder alongside the plugin and are hot-reloadable without a Maya restart. Six shader files handle distinct passes: the main grade, bloom threshold, bloom blur (Gaussian), bloom composite, geometry outline (Sobel edge detection), and the final blit to the viewport.

4
PostSceneRender scriptJob

A permanent scriptJob fires on PostSceneRender and calls push_params() in the bridge. This ensures parameters are re-pushed to the C++ side after every scene render — catching edge cases where VP2 resets its override state (e.g. after a panel focus change or a hardware renderer reset via ogs -reset).

Activation targets modelPanel4 specifically. If your primary viewport is a different panel (e.g. a custom panel layout), the override may not appear in the panel you're working in. To redirect to a different panel, use the MEL command directly: setRendererInModelPanel "AXELensOverride" yourPanelName;

Pass Stack

Passes execute in a fixed order each frame. Each pass reads from an off-screen render target and writes to the next. The bloom and outline passes are skipped entirely when their respective enables are off — zero shader cost when not in use.

SCENE
Standard VP2 scene render
Normal Maya VP2 rendering — shaders, shadows, SSAO, MSAA. Output written to the main render target.
GRADE
axe_lens.ogsfx
Full-screen quad. Applies in order: sharpen (unsharp mask), color temperature (RGB channel shift), exposure (linear scale), Hable tonemapping (filmic S-curve), contrast (pivot at 0.5), saturation (luma mix), vignette (radial darken).
if bloom enabled
BLOOM
axe_bloom_threshold.ogsfx
Isolates pixels above the threshold value into a separate bright-pass target. Pixels below threshold → black.
BLOOM
axe_bloom_blur.ogsfx
Gaussian blur on the bright-pass target. Blur radius scales with the Radius parameter — larger values spread the glow further.
BLOOM
axe_bloom_composite.ogsfx
Additively blends the blurred bright pass back onto the grade output, scaled by Strength.
if outline enabled
OUTLINE
axe_outline.ogsfx
Sobel edge-detection on the scene depth/normal buffer. Detected edges are drawn in the chosen outline colour at the set thickness and strength. Runs on the geometry pass output, not the post-process output, so edges are always crisp regardless of grade settings.
PRESENT
axe_blit.ogsfx + HUD
Blits the final composited target to the viewport. Maya's HUD (frame counter, camera info, etc.) is composited on top via the standard HUD pass.
Sharpen runs before tonemapping. This is intentional — sharpening in linear light (pre-tonemap) produces cleaner results without the haloing artefacts that occur in gamma-compressed output. If you're seeing halos around bright edges, try reducing Sharpen or raising the bloom threshold to prevent over-sharpened bright areas from bleeding.

Grade Controls

ParameterRangeDefaultWhat it does
Filmic Tonemapping On / Off On Applies the Hable filmic curve (the same curve used in Uncharted 2 and widely adopted in games/film pipelines). Compresses bright highlights into a pleasing roll-off rather than hard clipping. Leave On unless you need a purely linear comparison pass.
Exposure 0.1 – 4.0 1.0 Linear multiplier applied before tonemapping. Scales the entire image up or down in linear light. 1.0 = no change. Boosting exposure before a filmic tonemap is the correct way to brighten a scene without losing highlight detail.
Contrast 0.5 – 2.0 1.08 S-curve pivot at 0.5 applied after tonemapping. Values above 1.0 push darks darker and brights brighter. Values below 1.0 flatten the image toward grey.
Saturation 0.0 – 2.0 1.08 Mixes between greyscale (0.0) and full colour (1.0) and beyond to hypersaturation (2.0). Uses luminance-preserving interpolation so brightness doesn't shift with saturation changes.
Sharpen 0.0 – 3.0 0.0 Unsharp mask. Subtracts a 4-tap blur from the original and adds the difference back, scaled by this value. Runs pre-tonemap. Higher values increase perceived crispness but will exaggerate compression artefacts on noisy geometry.
Color Temp −1.0 – +1.0 0.0 Shifts the RGB balance toward warm (orange-red) at positive values or cool (blue) at negative. Implemented as a channel offset: positive boosts R/G slightly and reduces B; negative does the inverse. More subtle than saturation — good for mood without obvious hue shifts.
Vignette Strength 0.0 – 1.0 0.5 How dark the vignette gets at the corners. 0 = no vignette, 1 = fully black corners.
Vignette Radius 0.0 – 0.7 0.35 How far the vignette extends inward from the edges. Smaller values push the dark area closer to the centre. Values above ~0.5 begin to encroach noticeably on the image.

Bloom

ParameterRangeDefaultWhat it does
Enable Bloom On / Off Off Activates three additional render passes (threshold → blur → composite). No cost when off.
Threshold 0.0 – 1.0 0.75 Luminance cutoff for the bright pass. Only pixels brighter than this value contribute to the bloom. Lower thresholds create broad, diffuse glows across mid-tones; higher thresholds restrict bloom to only the brightest specular or emissive areas.
Strength 0.0 – 2.0 0.35 Additive blend weight of the blurred bright pass. Higher values make the glow more intense. Values above 1.0 can cause noticeable overbright halos — useful for neon/fantasy looks but not for naturalistic rendering.
Radius 0.5 – 4.0 1.5 Controls how far the Gaussian blur spreads the bright-pass pixels. Larger values create wider, softer glows. Higher values also carry a proportionally higher GPU cost on large viewports.

Outline

ParameterRangeDefaultWhat it does
Enable Outline On / Off Off Activates Sobel edge detection on the geometry buffer. Runs on the pre-grade scene output so edges are always crisp.
Thickness 1.0 – 8.0 2.0 Pixel width of detected edges.
Strength 0.0 – 1.0 1.0 Opacity of the outline over the scene. Lower values give a ghosted, subtle line; 1.0 is fully opaque.
Color RGB swatch AXE cyan Line colour. Click the swatch to open the colour picker. Each look preset overrides this with its own paired outline colour where applicable.
Outline routing note: toggling the outline enable fires two push_params() calls 50ms apart. This is intentional — the first call sets the enable flag, and the second ensures the C++ override has fully recalculated its pass routing before VP2 draws the next frame. You may see a single dropped frame on toggle. This is expected.

Looks

Looks are one-click preset combinations of all 18 post-process parameters. Selecting a look updates every slider and checkbox in the UI and immediately pushes to the override. You can then tweak individual parameters freely after applying a look — it's a starting point, not a lock.

NEUTRAL
Unity pass — no colour changes, no vignette, no bloom. A clean baseline.
CINEMATIC
Warm push, subtle vignette, light bloom. The all-purpose filmic look.
WARM
Natural golden hour. Pulled-back saturation with a gentle colour temp shift.
COOL
Crisp and clean. Slight desaturation and blue-cool temp, no bloom.
SHARP
High sharpening, minimal colour shift. Good for detail review.
NEON
Heavy bloom, boosted saturation, cyan outline. Cyberpunk/VFX.
RIG
Desaturated with cyan outline. Designed for rig review — lets control structure read clearly over the mesh.
PAINTERLY
Boosted contrast and saturation, soft bloom, warm temp. No sharpening.
GOLDEN
Amber push, warm outline, moderate bloom. Sunrise/sunset.
DUSK
Dark, high contrast, orange-red outline. Moody late evening.
ARCTIC
Desaturated, cold temp, ice-blue outline. Clean and clinical.
FADE
Washed-out with thin black outline. Understated and matte.
COMIC
Maximum contrast and saturation, thick black outline, high sharpen. Flat illustration feel.
B+W
Full desaturation with slight vignette and orange outline accent.
NOIR
Crushed blacks, deep vignette, white outline. High-contrast monochrome.
SKETCH
Greyscale with heavy sharpening and a thin white outline. Pencil drawing feel.
Looks do not lock the controls. After clicking a look, every slider reflects the look's values and you can adjust freely. The active look button stays highlighted until you make a manual change or apply a different look. Saving a custom lens with the same name as a look will not overwrite the built-in look — saved lenses and built-in looks are separate lists.

Quality

The Quality accordion section controls Maya's hardwareRenderingGlobals node — the VP2 renderer settings that govern SSAO, MSAA, HDR buffer, and line anti-aliasing. These are independent of the post-process pipeline and apply regardless of whether AXE Lens is activated.

PresetSSAOMSAAHDR BufferBest for
PERFORMANCE Off Off (1×) Off Blocking, quick turnaround, low-spec GPU, playback scrubbing
BALANCED On (16 samples) On (4×) On Day-to-day animation work — good quality without heavy SSAO cost
QUALITY On (32 samples) On (8×) On Presentation screenshots, review sessions, hero shot work
Quality settings persist via optionVars and survive Maya restarts. When you apply a preset, the settings are written to both hardwareRenderingGlobals and to axeLens_* optionVars. On next launch, restore_from_optionvars() (called from userSetup) reapplies the last-used preset. If you want to go back to Maya's factory defaults and stop auto-restoring, click RESET ALL in the status bar — this removes all axeLens_* optionVars.
Individual adjustments are non-destructive. The SSAO amount, radius, sample count, and MSAA sample count sliders update immediately and are layered on top of whichever preset is active. Changing a slider after selecting QUALITY doesn't deselect the preset button — it just overrides that one value while keeping everything else from the preset.

Saved Lenses

Saved Lenses are named snapshots of all 18 post-process parameters. They persist via Maya optionVars and survive across scenes and restarts. Use them to save a calibrated look for a specific show, shot type, or playblast style.

ActionHow it works
Save Type a name in the text field and click SAVE (or press Enter). The current values of all 18 post-process parameters are written to individual optionVars keyed as axeLensSaved_{name}_{param}. The lens name is added to an index optionVar (axeLensSaved__index) as a ||-delimited list.
Load Click the lens name in the list. Values are copied from the saved optionVars into the live axeLensPost_* optionVars, the UI is refreshed, and push_params() fires twice (50ms apart) to ensure the outline routing recalculates. Any active look button is deselected.
Delete Click the ✕ next to a saved lens. Removes all 18 param optionVars for that name and updates the index. This cannot be undone.
Saved Lenses are per-machine, not per-scene. They live in Maya's global optionVar store, not in the scene file. If you open the scene on a different machine, the saved lens list will be empty unless you re-save them there. For show-level distribution, consider scripting a startup snippet that calls axeLensSetParams() with your studio-approved values directly.

FAQ

ACTIVATE does nothing — the viewport looks unchanged

The most common cause is that axe_lens_override.mll is not loaded. The ACTIVATE button calls bridge.activate(), which loads the plugin if needed — but if the module path isn't on Maya's plugin search path, the load will silently fail.

Check the Script Editor for a warning like AXE Lens Bridge: could not load plugin. If present, ensure the axeLens.mod file is in a directory Maya scans for modules (Documents/maya/modules/ on Windows) and that it correctly points to the build folder for your Maya version.

Also confirm VP2 is the renderer in modelPanel4 before activating. AXE Lens replaces the VP2 renderer — if the panel is running Legacy Viewport, the override assignment has no effect.

The post-process looks correct but resets to flat after a camera move or panel focus change

The PostSceneRender scriptJob in the bridge is designed to catch exactly this. If it gets killed — by a Maya crash recovery, a forced scene load, or another tool that clears all scriptJobs — the params won't be re-pushed automatically.

Fix: call from axe_lens_override.python import axe_lens_bridge as b; b.install() from the Script Editor to reinstall the scriptJob. Or simply close and reopen the AXE Lens panel, which reinstalls the bridge on open.

Bloom isn't visible even though it's enabled and strength is high

Bloom is additive on top of the grade pass output, so there must be pixels bright enough to survive the threshold filter. In a typical VP2 scene with default lighting and a gamma-corrected output, many surfaces are below 0.75 in luminance even if they look bright — especially with the Hable tonemap engaged, which compresses highlights.

Try lowering the Threshold to 0.4–0.5, or temporarily boosting Exposure above 1.5 to push more pixels above the threshold. Once you can see the bloom, adjust back to taste.

Also check that the HDR float buffer is enabled (Quality → HDR float buffer). Without floating-point precision the bright pass has limited dynamic range to work with and bloom will be weak or absent.

Outlines are appearing on every mesh edge, not just silhouettes

The Sobel edge detection reads from the depth and normal buffer. In VP2 every geometric edge produces a depth or normal discontinuity, so all visible edges get detected — including internal edge loops and flat-shaded faces.

To get cleaner silhouette-only outlines: lower the Strength slider (0.3–0.5) so interior edges are less visible, and keep Thickness at 1.0. This mimics a silhouette-only look without actually changing the detection algorithm.

For rig review, the RIG look uses exactly this approach — thin cyan outlines at reduced strength give a clean structure read without mesh clutter.

The viewport background colour is wrong after activating — it's black or a different colour than my Maya background

On activation, the bridge reads Maya's current background colour with displayRGBColor("background") and pushes it to the override's clear colour via axeLensSetParams(bgR, bgG, bgB). If your background is a gradient or uses a different colour path (e.g. a background plane, image plane, or gradient background setting), the clear colour may not match.

Workaround: after activation, call the bridge directly with the correct colour:
from axe_lens_override.python import axe_lens_bridge as b; b.push_params()
Or set the background colour before activating so it can be read correctly.

My saved lenses disappeared after upgrading Maya

Saved Lenses are stored in Maya's optionVar store, which is version-specific on most systems. Upgrading from Maya 2024 to 2025 means a fresh optionVar store and your saved lenses won't carry over automatically.

To migrate: before upgrading, use the Script Editor to dump your lens values:
import maya.cmds as cmds; print([cmds.optionVar(q=k) for k in cmds.optionVar(list=True) if k.startswith("axeLensSaved")])
Save the output, then recreate your lenses in the new version by entering the values manually and re-saving.

The RESET ALL button doesn't seem to fully restore Maya's default viewport

RESET ALL does two things: resets hardwareRenderingGlobals to Maya factory defaults and clears all axeLens_* optionVars. It calls cmds.ogs(reset=True) to force a VP2 reinitialisation.

What it doesn't do: deactivate the AXE Lens override. If the post-process is still active when you reset, the grade parameters are cleared (back to NEUTRAL values) but the MRenderOverride is still routing the panel through the custom pipeline. Click DEACTIVATE first if you want to fully return to standard VP2.

Performance drops noticeably with AXE Lens active

Each active pass adds a full-screen quad render. The grade pass is always active once the override is on. Bloom adds three passes; outline adds one. At 1080p the total overhead is low on a modern GPU (typically <2ms per frame for grade-only). At 4K or with many passes active it becomes more significant.

Reduce cost: disable Bloom when not needed (the biggest single cost). Disable Outline. For playback review, consider switching to the NEUTRAL look (which minimises all effects) or deactivating the override entirely during heavy scrubbing.

SSAO note: the Quality settings affect VP2's own SSAO, which is separate from the post-process pipeline. If playback is slow, PERFORMANCE preset (no SSAO, no MSAA) will give the biggest framerate improvement independently of whether AXE Lens is active.

AXE Lens activates on modelPanel4 but I work in a different panel

The bridge hardcodes modelPanel4 as the target. To route the override to a different panel, run the MEL directly from the Script Editor after clicking ACTIVATE:

setRendererInModelPanel "AXELensOverride" yourPanelName;

Replace yourPanelName with your panel's name (e.g. modelPanel1). You can query which panels exist with cmds.lsUI(editors=True) filtered for modelPanel.

Note that deactivation via the UI button will still target modelPanel4. To deactivate from a custom panel: setRendererInModelPanel "vp2Renderer" yourPanelName;

Can I use AXE Lens for playblasts?

Yes — if AXE Lens is active when you run a playblast from modelPanel4, the playblast captures the post-processed output exactly as you see it in the viewport. All effects (grade, bloom, outline) will be baked into the playblast frames.

For clean production playblasts you may prefer to save a NEUTRAL lens and load it before blasting, then reload your working look afterward. The saved lens workflow makes this fast.

One gotcha: cmds.playblast() with the viewer=True flag sometimes opens its own panel which may not have the override active. Use viewer=False and review the output file directly for reliable results.

The license widget appears every time I open Maya

After a valid activation the license key is cached to a Maya optionVar. If the dialog reappears, the most likely cause is that the optionVar store is being cleared on launch (e.g. by a studio pipeline script that resets prefs) or the cached key has expired.

You can also set the key via environment variable to bypass the optionVar entirely: set AXE_LENS_LICENSE=your_key_here in your shell or Maya.env before launching Maya. The license module checks this environment variable first before reading the optionVar.

Requirements

Maya Version
2024, 2025, 2026 (Windows)
Renderer
Viewport 2.0 — override requires VP2 as the base renderer
Plugin
axe_lens_override.mll — C++ MRenderOverride + 6 OGSFX shaders
Python
Python 3 + PySide6 (bundled with Maya 2024+)
Panel
Activates on modelPanel4 by default — see FAQ for custom panels
Docking
MayaQWidgetDockableMixin — floatable, dockable to left or right