Skip to content

Spider-Man (Stern)

Spider-Man is a Stern SAM-era table that received a comprehensive VPW treatment with custom Flupper-style inserts, an advanced RGB GI system, detailed lighting work, and full VR support. The project went through 14+ release candidates and demonstrates many VPW techniques for insert rendering, GI implementation, and multi-platform optimization.

Build Notes

Flupper Insert Workflow

Instead of exporting and importing OBJ files separately, insert primitives can be copied directly between VPX tables. Open both source and target tables, drag-select the insert set in the source, copy via Edit > Copy, then paste in the destination using Edit > "Paste at." This preserves all parameters and materials automatically -- only materials and images need separate export from their respective managers.

Insert trays sit at Z=0 because the axis/anchor point is at the top of the tray model, with walls extending downward below zero. This makes the top walls flush with the bottom of the playfield. The actual rendering is only visible in F5/F6 play mode, not in the editor.

Insert Text Shadows

Insert text shadows simulate ambient occlusion, not actual light-source shadows. The shadow angle is relative to the text baseline with an extremely exaggerated angle. The purpose is to add darkness around text to prevent a "floating" appearance and help it blend into the insert. Direction should come from overhead, simulating multiple ambient lights where shadow only shows underneath. Use Photoshop for quality -- PSP shadow effects are too crude.

GI Lighting Structure

Proper GI implementation uses three lights per physical bulb:

  1. PF light -- illuminates the playfield
  2. Plastic light -- for plastic mesh and hot spot
  3. Bulb tip light -- additional highlight

A fourth, larger light at plastic height can be added for environmental spill. This three-light system provides proper balance between ball reflection, plastic transmit, and reduces insert bleed.

Plastic Bevel Rendering

Adding bevels to plastics simulates 3D depth and reduces the "flat cutout" appearance. Bevel edges must fade smoothly -- a hard cutoff line indicates incorrect height. Some tables use multiple overlapping primitives for a depth illusion (front and back layers slightly offset).

VR Room Options

VR room tiers are controlled via the VRROOM variable:

  • Minimal room: Basic environment with backglass
  • Ultra minimal room: Table and essential surroundings only

The backglass must hook into the GI system to turn off on tilt. Global GI flasher, backglass, and back wall all need GI callbacks.

Scripting

Insert Opacity

Material opacity on the insert top tray is extremely sensitive: tiny changes between 0.990 and 0.999 create huge visual differences in how well the bottom tray shows through. Default should be .9999. The range 0.995-0.999 determines depth perception and color saturation -- lower values show the tray better with more depth, higher values are more transparent but less defined.

Insert Light Color Balance

Flupper's advice: avoid mono colors like RGB(0,255,0) for green. Use RGB(32,255,32) instead with higher transmit values. This makes inserts less "blob-like" and more translucent. Red is the hardest color -- it needs to be non-mono but still look red. Combine with ysize adjustment (40 to 80) for better depth perception in fullscreen view.

Disable Lighting Method

The DisableLighting method removes ball reflections. The workaround is to keep an old VPX light for reflections only -- set halo height to 1, crank the falloff power really high, and set intensity really low. The light is barely visible but the ball still gets reflections. Both systems must be tuned: the DisableLighting primitive for insert appearance, plus the ghost light for ball and target reflections.

Lamp Mapping Order

Order matters when calling lighting functions:

' This works:
FadeDisableLighting 63, p63on
NFadeL 63, l63

' This does NOT work (reversed order):
NFadeL 63, l63
FadeDisableLighting 63, p63on

When implementing DisableLighting, rename every insert primitive to match light numbers (e.g., p30, p30off) from the start. Renaming after the fact is extremely time-consuming.

FadeDisableLighting for SAM ROMs

Spider-Man's ROM uses odd FadingLevel values (0, 1, 4, 5). Custom states (-1, 6) were added to handle transitions:

  • Fade out: subtract 88 per loop until 0
  • Fade in: add 100 per loop until 200
  • Brightness range: 0-200 on BlendDisableLighting

Light-up is slightly faster than fade-out. Material opacity is also adjusted for total brightness control.

SAM GI Implementation

SAM tables have simple on/off GI relay with no complex WPC zone dimming:

Set GICallback = GetRef("GIUpdate")
Sub GIUpdate(no, Enabled)
    If enabled Then GIOn
    Else GIOff
    end if
End Sub

There is no lamp ID for GI -- it comes directly from the IO board. For fading, the ROM sends on/off for lights; only flashers with UseVPMModSol=1 receive 0-255 intensity levels.

RGB GI Color Mixing

Custom RGB GI reads lamp states to determine color:

ar = Lampz.state(74) + Lampz.state(76)  'red
ag = Lampz.state(74) + Lampz.state(77)  'green
ab = Lampz.state(75) + Lampz.state(76)  'blue
sum = ar+ag+ab
GIColorRed = ar/sum*240

A 2-second timer delay debounces flickering mode lamps. GI falloff adjusts during modes (350 in mode, 200 normal).

Global GI Flasher for RGB Color Wash

A single large flasher covers the entire table with no image, just color. It is keyed off the GI color -- if GI is purple, the whole table gets a purple haze. Opacity is adjustable (50% to 400%+ depending on the desired effect). This technique was used in X-Men LE with spectacular results.

Fast Flips for SAM Tables

For SAM tables like Spider-Man, fast flips are controlled via InitVpmFFlipsSAM, not the usesolenoids parameter. The Vault Edition ROM is required for fast flips compatibility.

Solenoid-Controlled Primitive Movement

To animate multiple primitives together from a single solenoid, add TransZ lines to the existing timer sub:

Sub GoblinShakeTimer_Timer
    Goblin.TransZ = GoblinPos
    GoblinBracket.TransZ = GoblinPos  'add this line
    If GoblinPos = 0 Then GoblinShakeTimer.Enabled = 0:Exit Sub
    If GoblinPos < 0 Then
        GoblinPos = ABS(GoblinPos) - 1
    Else
        GoblinPos = - GoblinPos + 1
    End If
End Sub

Use -GoblinPos for opposite movement. No separate subs or timers needed.

Fleep Sound Implementation

Sling and bumper sound functions need a primitive/object name for SSF positioning:

Sub LeftSlingShot_Slingshot
    RandomSoundSlingshotLeft sling1  'use sling arm primitive
End Sub

Use the sling arm primitive, not the wall. For bumpers, use the bumper object itself. Do not use parentheses in some VBS contexts. If vol(activeball) returns 0, replace with a static value like 0.2.

DMD Color Configuration

For proper colored DMD support without breaking standard users, conditional script checking the user's PinMAME settings is needed. Default DMD settings should work for most users without modification.

3D & Art

Depth Bias Layering

GI was bleeding into insert primitives even when inserts should not be lit. Depth bias organizes the "VPX sandwich" into layers. A bigger negative number means closer to camera. If GI is at 0, insert prims need -50 or more to punch through without GI affecting them. DLFB limits light from below; depth bias limits from above.

Alpha Mask for Playfield Cutouts

In the image manager, the Alpha Mask slider (not just the alpha channel) helps hide odd pixels and smooth edges. However, 30-degree angled cuts always lose anti-aliasing and look jagged -- the best fix is an overlapping text layer to mask edges.

UV Unwrapping Issues

UV maps unwrapped with top/bottom parts crossing over in 2D space cause texture corruption when both areas render both texture sections. Flupper's recommended Blender add-on can auto-unwrap geometry in one click. Alternatively, Flupper's procedural flow-based method avoids unwrapping entirely but is finicky to tune.

VR Ramp Rendering

POV-baked ramps do not work in VR because they reflect the playfield from a fixed angle. Use Flupper's procedural/flow textures without playfield reflection -- just grey tones placed "in world." VR users see through transparent objects naturally. Full-screen flashers need proper height and angle to avoid cutting through cabinet sides.

Wire Ramp Poly Reduction

Wire ramps were reduced from 70,000 to 17,000 triangles with no visible quality loss. For wire geometry, perfect reflections are not needed. Render with current table lighting/colors and adjust in Photoshop if the table brightness changes later.

Metal Texture Rendering with Octane

For metal rails and fixtures: import the VPX playfield and environmental image into an Octane scene. Metals pick up reflections naturally without building a full 3D table. Poly count on wire ramps can be reduced significantly (70k to 17k triangles) without visible quality loss.

Troubleshooting

Black Layer Blocking Inserts

If inserts are not visible except from weird angles, a black layer at Z-zero is blocking the view. Create a new playfield material (do not edit the existing "Playfield" material, which keeps resetting). Check that insert lights have the correct image assigned in the dropdown to properly pick up the alpha channel.

VPX Options Panel Bug

When switching between open tables, the VPX options panel does not update properly. Typing values updates the other table instead of the active one. Toggle the backglass view button twice to force the options panel to refresh.

DOF/B2S Crashes

B2S backglass service can write 10mb/s to disk, causing freezes even without a B2S file present. This happens when DOF GI controls trigger. Disable the DOF lines calling GI in the script. DOF runs as a service and can corrupt even on a clean VPX install.

Ball Stuck Behind Ramps

Balls getting stuck between ramps and walls or jumping over targets into plastic areas can be fixed by:

  1. Enabling collision on walls that were turned off
  2. Checking wall/ramp intersections where decals sit proud of ramp geometry
  3. Setting plastic primitives to collidable as barriers
  4. Extending solid walls under targets to cover the full area

Gate Positioning

One-way gates can completely block ball flow if positioned even 1 unit wrong. Check metal primitive alignment with gates -- if primitives changed, gate holders may need height/angle adjustment.

Flipper Nudge Fix

When two balls are cradled (one per flipper), one ball bounces on its own due to the flipper-nudge code. The fix from the Metallica table modifies only the flipper nudge function to prevent phantom ball movement when multiple balls are resting.

Resources

Hardware Requirements (4K)

  • i7-3770 + GTX 1060 3GB: Borderline, some tables lag during complex modes
  • i7-6700 + GTX 1060: Runs well at 4K
  • GTX 1660 Ti: Maintains 60fps on any table at 4K
  • GTX 2080 Ti / 3000 series: More than enough for VR + 4K

Turn off antivirus on cabinet PCs. Internet connection is not needed for play.

VR Headset Recommendations (2020 era)

  • Quest 2: $300-400, needs USB-C cable for PC VR, works standalone
  • HP Reverb G2: Best quality, $600, long wait times
  • Rift S: Good but older, wired
  • Minimum GPU: GTX 1660 Ti / RTX 2060

Best Practices

  • File size: Audit and remove unused images before release. Spider-Man removed 20 MB of unused assets between RC1 and release.
  • Release candidates: Only minor updates allowed during RC phase. Spider-Man had 14+ RCs.
  • Playtesting: Issues that never arise during development appear after release due to volume of testing. Quick update releases for physics issues are expected.