Johnny Mnemonic¶
3D art, troubleshooting, best practices, scripting, and software setup across a comprehensive VLM toolkit build. VP9-to-VPX conversion with full toolkit pipeline to v1.2.2 release, featuring extensive optimization work and VR implementation.
Build Notes¶
VP9-to-VPX Conversion¶
The existing Johnny Mnemonic VPX table was based on VP9 code. The playfield dimensions were incorrect -- the table had been horizontally correct but vertically stretched to fit an incorrect playfield image. After fixing dimensions, all objects were slightly out vertically but not horizontally, requiring realignment of all walls, triggers, and elements.
Insert Creation Workflow¶
Insert creation workflow for VPW tables:
- Use Photoshop with the playfield image at full resolution
- Use polygonal lasso tool to trace insert shapes
- Create layer masks for light transparency and text transparency
- Two separate mask files needed:
lightmask(which parts let light through) andtextmask(which parts have text/graphics) - White areas in the plastic scan indicate clear/transparent portions
- Insert blocker meshes placed under playfield prevent light bleeding between adjacent inserts
VLM Insert Tray System¶
With the updated VLM toolkit, the insert workflow was simplified:
- No need to cut out playfield and do inserts separately
- Inserts are now inside 3D trays in the toolkit library
- Toolkit uses a mask to show transparent parts of the playfield
- Another mask handles insert letters/text that let some light through
- Two mask files required:
jm_pf_insertmaskandjm_pf_textmask
Plastics Transparency Workflow¶
Process for handling plastic transparency:
- Source PSD file (660MB for JM) contains all plastics on layers with color correction
- White areas in plastic scans indicate clear/transparent sections
- Cutouts must be made in Photoshop -- extract clear sections for alpha masks
- Ramp decals can have a white backside visible from below -- for VR, keep them visible from both sides
- Wire mesh flooring decals require alpha PNG with transparent background
- The dolphin decal is physically a bent piece of card/plastic jammed inside a ramp
3D Hand Scanning¶
The Johnny Mnemonic data glove was 3D scanned using an Einscan EP scanner. The scan was "fairly difficult to get due to the blackness" of the glove material. Actual glove dimensions: 7in x 4in, scan is 1:1 scale.
After decimating the 3D-scanned glove from raw scan to 25k triangles, UV maps broke. Instead of trying to preserve the scanned texture:
- Separated the black and white parts of the mesh
- Applied two different plain materials (no texture)
- Result looked great without any texture mapping needed
- The thumb was split as a separate mesh piece and rotated independently
- Left hand was derived from the right hand scan by modification
- Magnet cylinder placed under hand to close bottom gap
Blender Plastics Workflow¶
Recommended approach for plastics in VPW tables:
- Put all plastics source images in one PNG
- Drag and drop that image into Blender
- Draw the plastic shapes in Blender using the image as reference
- Work entirely in Blender rather than building plastics in VPX first
- For transparent/clear sections, use alpha masks
- Decals on ramp walls should be visible from both sides for VR compatibility
Ramp Modeling¶
Key ramp modeling principles:
- "The ball goes to plastics level" -- ramp base height equals plastic height
- Ramp drops should lower the front, not raise the back
- Ramp end should be approximately 25-30 units higher than sling plastic
- Inlane plastic height is definitely higher than rest of plastics -- visible above flipper level
- Metal flap under ramp is diagonal (45 degrees), not a prism with separate top and side
- Figure under ramp stickers are at 45 degree angle
- Post heights between VPX and Blender library may not match -- metal washers on real machines add height
AI Image Upscaling¶
AI upscaling tool produces "very nice results" for pinball textures. Used for improving resolution of ramp decals and backboard textures. The technique was applied to existing scanned assets to improve detail for the high-resolution VLM renders.
VLM Toolkit¶
GI Collection Structure¶
Proper GI collection setup for dynamic shadows:
- Need one "grouped" collection per GI string + one "split" collection for shadow-casting lights
- Grouped collections: all bulbs turn on/off together, share timerInterval in VPX
- Split collection: individual lights that cast raytraced ball shadows
- For performance: only put a subset of GI lights in the split collection (e.g., one of two adjacent bulbs)
- JM has 3 GI strings on playfield, so needed 3 grouped + 1 split = 4 collections
- Lights in split collection driven by respective VPX lights independently
Dynamic Shadows Setup¶
Dynamic shadow setup process:
- Enable raytraced shadows checkbox on selected GI lights
- GI lights that cast shadows go in the "split" collection
- GI light Z position affects shadow calculation -- street-level GI should be at Z=25
- Setting Z to 1 hides oversized shadow artifacts (workaround for JM)
- Ambient shadows separate from dynamic shadows -- can combine old ambient with new dynamic
- The blend file must be set up for new dynamic shadows with GI split before batch rendering
4K Batch Rendering Pipeline¶
Full VLM batch rendering pipeline:
- Set render height to 4096, render ratio to 100% for 4K (50% = 2K test)
- Texture size should be at least render size (4096 or 8192)
- Max lights setting affects RAM usage: 16 lights with 16GB RAM, 32 with 32GB, 64 with 64GB
- Steps: Renders (Groups) → Meshes → Nestmaps → Export
- Can skip completed steps by unticking "perform groups" in batch all
- Renders can be force-quit and resumed -- toolkit checks renders folder and picks up where it left off
- Delete specific renders from folder to force re-render of those items
- Don't force-quit during nesting step -- must start over
- CUDA renders significantly faster than CPU; check CUDA stays selected after crashes
- Denoising runs on CPU regardless, uses peak RAM during this phase
Bake times: ~10 hours on 3070ti at 4K, ~5 hours at 2K
Refraction Probes¶
Refraction probe management for transparent ramps:
- Ramp decals must be split into smaller pieces to avoid VPX confusion about rendering order
- VPX can't determine if a large decal primitive is above or below a refracting ramp
- Overlapping ramp layers need different probe numbers
- Wall decals should be UV-unwrapped and baked rather than projected
- Refractions need to be reapplied after batch import
- The refraction "thickness" parameter causes decals to appear to "sink" into ramp plastic
Refraction thickness: On the central plastic ramp should be set to 1 or 2 to avoid duplicated decals.
Post-Batch Import Checklist¶
Critical post-batch-import fixes:
- Set all Parts primitives to "static" for performance
- Check primitive name lengths -- VPX has a max name length; too-long names break script references
- Lightmaps need VPX material set to
VLM.Bake.Lightmap(orVLM.Lightmap) - BM_room layers need correct refraction probe assignments
playfield_meshmust exist but be invisible and non-collidable (set to "toy")playfield_physicsin VLM.Visuals layer must be deleted (keep only the one in Physics layer)- Movable primitives need
VLM.Bake.Activematerial - Pincab rails need bakemap color modulation added for room brightness to affect them
- GI light Z height affects dynamic shadow size
UV Corruption at 4K¶
The glove and rail primitives rendered correctly at 2K but corrupted at 4K due to mesh optimization. Objects were decimated to extreme levels (from 19555 to 208 faces for glove).
Root cause: A UV map named "BakeMap" on the objects was confusing the toolkit's optimization.
Fixes:
- Quick fix: Tick "no optimization" on affected parts
- Proper fix: Delete the "BakeMap" UV from objects -- "all the uvs are useless on projected objects"
Insert Light Positioning¶
Insert overhead lights were positioned beneath the playfield (negative Z), causing inserts to appear dark or only partially lit. Moving lights above PF resolved the issue, but revealed they were all set to white instead of insert colors. Solution: Use Niwak's newer playfield material that allows some subsurface transmission, plus colored overhead lights.
Polygon Count Optimization¶
Screw primitives missing the noExp modifier contribute unnecessary polygon count. The noExp custom property on objects tells the VLM toolkit not to apply subdivision/expansion during mesh generation.
Select Occluded: The "select occluded" function in the VLM toolkit removes mesh faces not visible from the player's POV. This helps reduce file size and improve performance. However, it can cause problems in VR where the player can look at the table from angles not anticipated by the occlusion calculation. Compromise: set backface to 45 degrees.
Major Optimization via Re-bake¶
Re-baking the table through the updated toolkit cut polygon count roughly in half:
- Old: 2,358,056 faces, 219 MiB GPU memory
- New: 1,063,488 faces, 96 MiB GPU memory
The table looked better despite fewer polygons.
Scripting¶
Glove Magnet Mechanism¶
The original JM code used destroy/create ball sequences for the glove magnet. Rewrote it to track the ball with the glove without destroying it:
- Original approach:
TriggerGloveMag.DestroyBallthenGloveMag.CreateBallto reposition - New approach: Start a timer and move the active ball position to follow glove movement
- Key insight: "don't destroy a ball. Just start a timer and start moving that ball with the glove" (like Judge Dredd implementation)
- The original
CheckPickupfunction that used proximity-based destroy/create was found to be unnecessary
Matrix Mechanism¶
The JM cyber matrix (9-slot ball lock) was reimplemented:
- 9 kickers with different kick angles and slight scatter for ejection
- Droppable walls added around kickers to create proper ball pockets
- Space is very limited -- magnet position had to be raised to prevent balls going past walls
- Original
MatrixMetalkept collidable but should be replaced with a wall or ramp that becomes collidable whenDoClearMatrixis called - The matrix plates have springs underneath -- circles are offset because the spring sits on the metal plate, not centered with the lamp
- This offset causes the characteristic half-lit appearance of matrix insert lights
GI String Research¶
The team reverse-engineered JM's GI wiring through multiple methods:
- Wire color tracing from under-playfield photos
- Visited a real arcade to run GI string test from ROM menu
- Frame-by-frame video analysis using
,and.keys in YouTube to identify which lights share strings - 3 GI strings on playfield (not 5 as manual suggested), string 4 is only the spotlight on the left glove, string 5 is backbox/coin door only
- Key finding: GI strings are NOT arranged in geographic "islands" -- they alternate across the table creating a "sweep" effect when cycling 3-2-1-3-2-1
VPX 10.8 Incandescent Fader¶
VPX 10.8 introduced built-in incandescent light fading, replacing the external Lampz system:
- Select "incandescent" fading type to get correct fading curve
- Physics-based fade up/down: ~40ms for insert lamps
- Suggested starting values: 40ms up, 120ms down
- Same value for fade up and down is physically correct -- the fading curve handles the asymmetry
- Insert lamps use 6.3V bulbs powered at 12-16V with short overcurrent peaks
- All lights should be set to hidden with ball reflections enabled
Room Brightness Control¶
Room brightness control implementation:
- Bakemaps rendered with environment/room lighting baked in
- Can only make table darker than base render, not brighter
SetRoomBrightnessfunction modulates bakemap colors at runtime- Key learning: "Always render with bright room as default, then darken in VPX as needed"
Ball Brightness Balancing¶
Ball brightness code (UpdateBallBrightness) adjusts ball appearance to match the baked lighting environment. Key finding: "It's not really worth balancing the ball brightness until the final render is imported."
The ball brightness equation can be tuned via script:
This formula controls the range of brightness adjustment.
GI Light Naming¶
GI light naming and hookup process:
- GI lights named as
l[number][letter]-- e.g.,l142k,l142l,l141kfor pop bumper GI - The spotlight (only light on string 4) named
l143a - Pop bumper GI lights had to be invented since they didn't exist in VPX
- GI naming must match between VPX light objects and Blender bake names
- VLM Script Helper file must be updated when lights are renamed
UseVPMModSol=2 Updates¶
v1.1.3 updates for UseVPMModSol=2: Removed InitPWM sub and ModSol option, updated UpdateGI and FlashXXX subs for new physics output, set all light fader models to None. The InitPWM initialization is now automatic. Also fixed timers causing stutters, added FlipperCradleCollision, updated CheckLiveCatch, enabled more reflections.
Scriptable Refraction Materials¶
VPX added the ability to change refraction materials for ramps at runtime. Fish Tales implements this as an F12 option menu. This allows players to toggle refractions on/off based on their hardware.
Game Knowledge¶
Broken Dataglove Compensation Mode¶
When the JM dataglove is broken, the ROM enters compensation mode:
- Locks become virtual; balls auto-plunged for multiball
- Crazy Bob's gives awards immediately (no player choice)
- Drop target registers as center lane shot (warning: tends to drain SDTM)
- Spinner/right loop shots that would lock go around left orbit instead
- When ball reaches VUK, game "repeatedly and quickly fires the kicker, so that the ball will eventually accumulate enough spin to bounce off the dataglove sideways" -- typically 5-10 kicks
- This compensation makes the game harder by removing the best scoring opportunity
Standard Flipper Length¶
Standard flipper length in VPX is 147 vpunits.
Troubleshooting¶
VPX Playfield Physics Duplication¶
The VLM toolkit consistently exported a playfield_physics primitive into VLM.Visuals layer that was collidable but had no holes. This overlapped with the proper physics mesh in the Physics layer.
Fix: Delete the playfield_physics in VLM.Visuals, keep the one in Physics layer.
Table VSync Override¶
Johnny Mnemonic shipped with table vsync override set to 1 in User Properties tab. Changing to -1 can help performance but users reported intermittent crashes and inability to save the setting. Loading through Popper (front-end) bypassed the crash issue.
Negative Depth Bias Breaking Ball Trails¶
The table's playfield had a negative depth bias causing the playfield to render after the ball trail, making ball trails non-functional. Ball trails were on the list of features to be removed in favor of proper motion blur.
GPU Load and Refractions¶
Removing ramp refractions dropped GPU load from 100% to 90% on a GTX 1060 at 4K 60Hz, making the table playable. To disable refractions without deleting them: in Render Probe Manager, set the ramp's Plane Reflection probe Max Quality to "Disabled."
Pure Black Breaks Rendering¶
Using RGB 0,0,0 (pure black) in VPX images breaks renderers -- causes divide by zero errors or gets hard-coded to 1,1,1 minimum. A pure black playfield makes lights not work properly. Use at minimum 10,10,10 for blacks. Same applies to pure white.
VR Room VRAM Impact¶
Adding DaRdog's 1K mega VR room to JM increased video RAM from 2.6 GB to 4.3 GB (+1.7 GB). The room needed optimization before inclusion.
Post Passing Adjustments¶
Issues identified during JM testing:
- Post passes were not working at all
- Inlanes needed speed limits applied
- Flippers felt too powerful
- Ramp entrance plates needed sounds
Software Setup¶
Required PinMAME Build¶
v1.1.3 requires an updated PinMAME build. Bumpers and slingshots stopped working without the update.
VPX Build Compatibility¶
VPX 10.8.1 BGFX should not be used for JM. Solenoid callbacks are now auto-optimized in the newest version of VPX.
Tools & Resources¶
VPX Live Editor¶
VPX live editor usage tips:
- Rotate view by clicking and dragging the box on the RIGHT side (not left -- the "stop" button)
- Pan view: hold Shift + middle mouse drag (same as Blender)
- Can edit table during actual gameplay with a ball in play
- Changes show instantly (e.g., changing light color immediately affects ball reflections)
- Must press "save" icon next to a property to persist changes -- otherwise lost on exit
- "Halo" light mode is the traditional light display; "Classic" shows through playfield
Texture Swapping in Toolkitted Tables¶
In toolkitted tables, textures are not easy to swap directly -- the toolkit generates a base image and overlays lighting scenarios on top. New base textures need to be plugged into Blender as the basis to generate new images. In non-toolkitted tables, texture swapping is straightforward.
Ramp Material Reuse¶
Ramp materials can be reused across table Blender projects. The Earthshaker ramp material was suggested for JM's ramp.
Best Practices¶
Playfield Source and Color Correction¶
The JM playfield image was not a scan but a high-quality stitch of photographs with decent halftones. Despite looking dull/gray in areas, manual color correction could address this without a full re-render.
Boosting Lightmap Brightness¶
To boost brightness of a dark object without re-rendering: change the opacity of all lightmaps associated with that movable in the VPX editor to a value greater than 100. For example, the holographic spinner lightmap opacity was set to 300 to make it appear properly lit.
NoExp Script Optimization¶
Before re-running a Blender batch render, run the NoExp script on the project first to optimize results. The toolkit has progressed significantly, allowing more optimized results with a re-run.
Contributors: sixtoe, iaakki, tomate80, apophis79, flux5009, baldgeek, its.me.dazz, niwak, benji084, DJRobX, leojreimroc, DGrimmReaper