Skip to content

Procedural inserts - #30

Merged
freezy merged 86 commits into
masterfrom
feat/insert-creator
Oct 10, 2026
Merged

freezy merged 86 commits into
masterfrom
feat/insert-creator

Conversation

@freezy

@freezy freezy commented Oct 10, 2026

Copy link
Copy Markdown
Member

The HDRP side of procedural inserts, the counterpart of freezy/VisualPinball.Engine#580: the shaders, their inspectors and the presets the insert component uses.

Insert shaders

  • Hybrid body shader (Pinball/Insert Hybrid): up to four virtual bulbs, each with its own position, level and colour, summed into the glow and the spill. On top of that:
    • Bulb: Lamp Spread, and the bulb kept in view past the facets' critical angle, with the view ray traced through both faces of the plastic.
    • Facets: contrast, Facet Flatten for the shading normal, and starburst, ribs, rings and gem patterns followed in the material.
    • Clear plastic: Clarity with Cavity Color, Spread and Contrast. Room Return reflects the room through the grooves, followed face to face and off the top, normalised by the sky and lit by the scene's own light.
    • Surface: flecks along the ridges, surface grain drawn in the material, and mottle that clouds the unlit plastic.
    • Brightness: Min and Max Brightness, Tint With Lamp, and an output factor for LED kits.
  • Clear cover shader (Pinball/Insert Cover): the top of a slab of plastic with HDRP planar refraction, Tint and Tint Depth, haze with its colour turned towards the lamp's hue, and the playfield's normal map projected onto it.
  • Inspectors for both materials. Fields a linked color preset owns are locked, and a read-only library material offers a way out ("Edit for This Insert" / "Edit for All N Inserts").

Presets and templates

  • Lamp presets (incandescent and LED), color presets carrying the cover's tint and haze, and look presets (Clear Plastic and Colored Plastic, plus Clear Cool and Clear Plastic Faceted), shipped as editable assets.
  • Clear and Colored material templates.

HDRP and packaging

  • Packaged insert shader templates load in the player. Insert shader material profiles and editor bake dependencies are captured for packaging.
  • The spill light's shape radius is set on the light, and the camera's depth of field gets auto focus.
  • An asset browser preview environment for HDRP.
  • LookDev: the insert shapes with their bakes, previews cut into a shared playfield, backgrounds marked as playfields for asset placement, and thumbnails only for valid material combinations.
  • Shaders are under Pinball instead of Visual Pinball.

@greptile-apps

greptile-apps Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium impact] The latest update appears safe to merge and fixes the Roughness control on inserts without facets.

Summary

Adds procedural insert body and cover shaders, material inspectors, presets, packaged material support, auto focus, and LookDev previews.

  • Insert bodies glow under faceted plastic covers.
  • Insert materials have grouped controls and ready-to-use looks.
  • Packaged tables keep their insert materials in HDRP.
  • Cameras focus on the table, and insert spill lights use soft spot beams.
  • LookDev builds insert cutouts and previews on a shared playfield.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Bake[Insert bake] --> Body[Hybrid body shader]
  Presets[Color and look presets] --> Materials[Insert materials]
  Materials --> Body
  Materials --> Cover[Clear cover shader]
  Export[Material export] --> Profiles[Packaged profiles and textures]
  Profiles --> Resolver[HDRP material resolver]
  Templates[Resources templates] --> Resolver
  Resolver --> Materials
Loading

Reviews (11) · Last reviewed commit: "insert: roughness without a starburst" · Reviewed by Greptile

Comment thread Runtime/VpeMaterialResolverBootstrap.cs
Comment thread Runtime/HdrpMaterialResolver.cs
Comment thread Runtime/HdrpMaterialResolver.cs
Comment thread Runtime/AutoFocusComponent.cs Outdated
Comment thread Editor/Insert/InsertHybridGUI.cs Outdated
Comment thread Editor/Insert/InsertHybridGUI.cs Outdated
Comment thread Assets/Art/Graphs/InsertOptics.hlsl Outdated
@freezy
freezy force-pushed the feat/insert-creator branch from d7265cb to de0df8e Compare October 10, 2026 21:18
Comment thread LookDev~/Assets/Runtime/ThumbGenerator.cs
freezy added 26 commits October 11, 2026 00:11
Under a key light a clear insert alternated bright and dark ribs like a
metal grille, because every second starburst facet faced the light. Room
light enters a real clear insert through its flat top and the facets
underneath only redistribute what is already inside. The new Facet
Flatten slider turns the shading normal the lights and probes see towards
that flat top, through the frame's proper inverse; the baked optical
normals that refract the lamp are untouched. Zero, the default, leaves
coloured inserts as they were.
An off clear insert is nearly as bright as the white artwork around it,
because the plastic absorbs nothing and shows the lamp board or reflector
underneath, lit by room light that came in through the top. The hybrid
material darkened every off body to its tint times Min Brightness, which
suits a red insert and turns a clear one dark grey. A new Clarity slider
switches the body albedo to a Cavity Color shaped by the baked irradiance
and, on the starburst floor, by where each face's refracted view ray lands
in a wide, soft falloff around the virtual lamp, so the ribs shift with
the viewpoint instead of alternating with the lights. Zero, the default,
leaves coloured inserts as they were.
The cover's base colour was whatever the Lit block defaulted to, and its
opacity could not go above a tenth, so it only ever added a reflection.
A Haze Color, light grey by default, is what the cover now blends in at
its opacity: a few percent lays a milky veil over the body that softens
the ribs the way a worn, slightly frosted top does. The default opacity
stays at one percent, so existing covers look as they did.
HDRP listed the shader's two dozen properties flat. The material now
draws three sections of its own between HDRP's surface and advanced
options: the plastic as room light shows it, the lamp with its virtual
bulb, glow and facets, and the maps the bake wrote. Every control carries
a tooltip, the virtual lamp is edited in millimetres, and a control is
greyed out wherever the shader would ignore it in the current state, such
as the cavity without Clarity or the facets without a starburst.
The bake leaves float noise in the lamp's metres, which printed as
scientific notation and crowded the position row. The fields now show a
hundredth of a millimetre and stay on one line.
Two sections between HDRP's surface and advanced options: the haze the
cover lays over the body, and the top's reflections with the normal map,
its tiling and strength. Every control carries a tooltip, the haze colour
is greyed out at zero opacity and the tiling without a map. Inserts that
take their normals from the playfield override the map on their own
renderer, so the inspector counts those in the open scenes or the prefab
being edited, variants included, and says so instead of pretending the
map here is what shows on them.
Copying another material's properties over a hybrid material, for a
colour of its own, replaces its baked maps and starburst with the
other's. The Baked Data section now lets them be put back: the three
maps are editable, and the starburst's sector count and centre are
edited per material, so a multi-edit leaves each material's floor
height alone.
Both custom functions take a lamp tint amount, the cover its lamp
colour and level as well, all hidden runtime properties the Insert
Light writes. The body's colour and the cover's haze turn their hue and
saturation towards the lamp's, the short way round the wheel, by the
amount times the lamp colour's brightness, and keep their value, so a
grey haze comes out the lamp's colour as bright as the grey was, a
white lamp changes nothing, and a lamp that is off, or whose RGB
channels are all down, leaves both untouched.
An RGB lamp carries its intensity in its colour, and the attract show
runs its colours dim: scaling the tint by the colour's brightness left
the haze grey under a half-bright red, which read as milky. A dim lamp
is still its colour, so the amount is full from a tenth of full
brightness up; only a lamp with its channels all down leaves the haze
untouched.
A real insert is brightest around its bulb and dims towards its far
end; ours lit the whole body alike as Max Brightness went up, since
every facet tilted towards the lamp shows its halo whatever its
distance and the baked glow reaches everywhere. Lamp Spread, in
millimetres, is the distance across the insert from the virtual lamp at
which the lit look has fallen to half, a sixteenth at twice that: the
whole emission, halo and glow alike, falls off with it, steep enough
to show against an emission far above white. Zero, the default, leaves
every existing material as it was. The lamp's position stays editable
while a spread positions the glow with the bulb off.
A 2 mm source, no volumetrics and no shadows on top of the cone the
converter's default gives, the cheapest light that does the job.
A banana has its bulbs in a row; the material faked one. The per-bulb
maths, the halo, the clear body's cavity look-through and the spread,
moved into a function the shader calls for up to four lamps, each with
a position of its own and the shared radius, off while its radius is
zero. Each bulb is driven on its own, the first by the lamp colour and
level as before, the others by a colour with the level in w, so its
halo carries its own colour; the baked glow, one for the whole body,
takes at each point the colour of the nearest bulb, the others blending
in by the inverse square of their distance, since a plain mean turned
three coloured bulbs white.

The material's Lamp section has a Bulbs count, a position per bulb and
one radius, edited per material under a scope on every property they
touch; a bulb switched off keeps its place for when it comes back, and
a revert that leaves a lower bulb off under a higher one has it
switched back on, so what the inspector shows is what the shader
draws.
Tint With Lamp followed the first bulb alone. The body's tint now takes
the same inverse-square mix of the bulbs' drives the glow takes, and
the cover computes that mix itself from the bulb positions, drives and
spread the Insert Light hands it, so a banana lit red, green and blue
along its length is hazed red, green and blue. The bulb layout and the
spread stay editable whatever the brightness, since they shape the
tint even with the emission off.
The baked glow took its drive from a mean over all bulbs weighted by how
near each is, lit or not, so with one bulb on the glow stopped in a seam
halfway to the next bulb that was off, and the Gaussian spread left
nothing past three spreads. Now the light falls off from each bulb by
the inverse square of the distance over the spread, every lit bulb adds
its own glow and off bulbs take nothing away; the glow's colour is the
nearest lit bulb's. The cover's tint mixes the same way.
Tint With Lamp's amount was gated by the light's brightness at each
point, so a bulb fading in tinted the body from the bulb outwards, like
a drop on paper, instead of tinting its whole reach at once and growing
brighter within it. The tint now reaches as far as the light does,
whatever the intensity, each bulb's reach clamped before its level
fades it, so below a tenth of full it fades uniformly. A partial amount
on a grey haze turned pink on the way round the wheel to blue: the hue
now turns by the lamp's share of the saturation the mix ends up with, so
a grey takes the lamp's hue at any amount and only its saturation
grows.
The glow's colour weighed each bulb by how near it was, so at a point
beside one bulb another's colour was shut out whatever its level, and
came in only once its halo won: a bulb fading in moved its colour along
the body instead of colouring every point it reaches in proportion. The
glow is now the plain sum of every bulb's light, colour and all, each
reaching by its spread; the cover's tint mixes the same way.
The view ray was refracted once, with the facet's normal, and that
steeper in-plastic ray was followed all the way down to the bulb: half
the bulb's parallax, and the facet bending it the wrong way. The ray now
enters through the flat top and leaves through the facet into the air
of the cavity, the facet a prism, so the bulb shows its full depth as
the eye moves and each eye of a headset sees it in its own place. What
a facet lets through fades with the exit's Fresnel reflectance to
nothing where it traps the ray, so the sharp image and the cavity view
fade out at the critical angle instead of jumping.
Two looks for the hybrid insert, taken from a clear and a red insert:
the clear one shows the cavity through a flattened, faceted body, the
coloured one a tinted body lit from a spread lamp.
freezy added 19 commits October 11, 2026 00:11
Roughness is a visible body value in the Facets block, part of the
look: it softens the facet contrast and scatters the rays and the
bulb's image into the glow, and leaves the top's smoothness alone,
which is the cover's. The smoothness no longer goes through the
optics function.
The DXR passes of the Insert Hybrid graph failed to compile in player
builds with ray tracing enabled (DerivCoarseX/Y not valid in lib_6_3),
because the optics function used ddx/ddy for the detail fade and fwidth
for the facet crease width. Ray tracing stages now keep the detail fully
visible and fall back to the minimum crease width.
None of the three showed a difference between their extremes at a
lamp's full intensity, where the tonemapper clips the bulb's image. The
facets now tilt the ray as baked, and the bulb's image keeps the
definition both looks had and takes the emission's colour like the glow
around it. The looks no longer carry the two of them they stored.
The cover inspector's link row said Haze Color, but the color preset
owns the plastic's tint as well.
Pinball in the editor marks VPE's features, the shader menu included.
The importer and the translator find the shaders by their new names; a
package records the material type rather than the shader's name, so
existing ones import as before.
The inspector of a read-only insert material says why it can't be
edited and offers to edit the inserts wearing it, the selected ones or
all of them, through project copies. It's disabled for a locked asset
library's material too, which Unity doesn't know about. A material
linked to a read-only color preset says how to keep changes the preset
would overwrite.
It's the material that is edited, for those inserts, not the inserts.
A material linked to a color preset shows the preset's colors grayed out, the cover's Haze Color and Tint included: they're changed in the preset, which Manage opens, or after unlinking. Copy to the preset is gone.

A library material's inspector no longer forks: it points to the top of the Insert component, with a button to select the inserts wearing it. Copy to Project stays for a material no insert wears.
Clear inserts looked like a painted slab when the lamp was off. The hybrid body gets three new controls: Flecks, the nicks along a moulded rib's ridges, drawn as sparse dashes of value noise stretched along the rib that brighten the plastic and tilt the shading normal so they glint with the lights; Room Return, the light that enters the flat top, is thrown across a groove off one facet and its mirrored neighbour and leaves through the top again, traced per pixel with the plastic's own Fresnel and read from the sky's reflection cubemap, replacing as much of the cavity as it weighs, tinted by the bulbs that are on and kept lighter than its neighbours when the lamp is up, with the facet relief kept as the shading normal where it returns so the scene's lights glint off it too; and Room Return Exposure and Room Blur to scale and soften it. Tint With Lamp keeps three fifths of the plastic's brightness while the lamp is weak, in the body and the clear cover alike, so a grey insert goes pink rather than dark red at the first glimmer. The Clear presets take the values tuned on a real table's clear triangles: a cool cavity, the facets kept, flecks on; two more presets, Clear Cool and Clear Plastic Faceted, keep the earlier stage. Colored Plastic carries neutral entries for the new controls so switching looks leaves nothing behind.
Room Return followed two fixed paths, off the facet and out through the top, or off the facet and its mirrored neighbour and out, and returned nothing for facets between about 18 and 38 degrees, where both rays meet the top past the critical angle; the library starburst triangles sit right in that band. The ray is now followed through the groove for up to four facets: on to the other facet when it heads into it, otherwise up to the top, where what escapes brings the room seen that way and the rest comes back down onto the facet it heads into. What follows a near tie between the two facets fades in, so the path never flips across the room within a facet.

The returned room went out as emission read from the sky in absolute units, so it vanished under a dim sky however brightly the table was lit, and no light in the scene reached it. It is now the sky over its own average brightness, put into the albedo, so the sky gives the room its shape and the light falling on the insert, directional, probes or ambient, its brightness, in a dark room as in a bright one. Tint With Lamp's lift goes the same way: the brightness the plastic loses to the lamp's hue comes back as a brighter colour of that hue, as far as the hue allows, instead of emission scaled by the sky. Pixels that return nothing skip the trace and the sky's average.
Mottle only scaled the light the facets pass straight through, a few percent at most, which the baked glow and the lit body's place in the tonemapper's shoulder hid entirely: Mottle Amount and Size changed nothing anyone could see. It now also varies the body's albedo under room light, blotches up to two fifths lighter or darker at full Variation, the cellular noise widened to its full range first, and a blotch brightens no further than the albedo's brightest channel can go, so the forward and deferred paths agree. The lamp-light share stays as it was.

Mottle Amount, Mottle Size and Variation Seed are no longer tied to a lit insert with facets in the material inspector, since the mottle now shows on any body, lamp or no lamp.
…thored

The player builds packaged insert bodies and covers from two template materials in Resources, which were never shipped, so every packaged insert fell back to its glTF material: both are there now. Restoring a packaged insert material repacks its surface normal maps for HDRP, as every other source normal is, leaving the optical maps as the data they are, and rebuilds the HDRP keywords from the restored values, so a cover saved without refraction doesn't keep the template's.

The hybrid material's inspector no longer switches a bulb on behind the user's back when a revert left it off below a higher one: it says so and offers an undoable button, on materials that can be edited. Variation Seed is enabled when only the surface grain uses it. The unlit plastic brightens with any of its bulbs that is on, not only the first.

One camera drives a volume's depth of field: a second Auto Focus on the same volume warns and leaves it alone, and switching one off no longer switches off the other's.
Pinball/Automation/Showcase shoots the scene's "Insert Showcase" straight from above for the overview page of the inserts documentation: lit, and as the geometry gizmo rebuilt as meshes, each rendered once on black and once on white so the background can be matted out. List and Align Colors check and set every showcase insert to the same color and lamp first.
The Colored Plastic look halves its facet contrast, flattens the facets' shading to 0.8 so the ribs don't read as a lit relief with the lamp off, and lowers the mottle to 0.6 now that it clouds the unlit plastic.
A batch that rendered an insert switched the insert playfield on; when it had been off before, finishing or stopping the batch now switches it off again.
@freezy
freezy force-pushed the feat/insert-creator branch from f6d8eb1 to efa3a46 Compare October 10, 2026 22:12
Comment thread Runtime/AutoFocusComponent.cs Outdated
Comment thread Editor/Insert/InsertHybridGUI.cs Outdated
The inserts the Insert Showcase uses, renamed in the project without their hash suffixes and with the shapes added since, and the scene pointing at them. The obsolete copies are gone.
…om return

Auto focus without an assigned volume took the highest-priority global volume even when it sat on a layer the camera's volume mask leaves out, so the focus it wrote never reached the picture. It now picks among the volumes on the camera's volume layers.

Surface Normal Strength stays editable at full Facet Flatten when Room Return is on, since the returning facets keep the baked normal for the scene's lights.
The bake now writes the optical response in eight bits with the sRGB curve, which its importer takes off. The package records it as sRGB then, so the player decodes it the same way; older sixteen-bit bakes stay linear.
Comment thread Editor/Insert/InsertHybridGUI.cs Outdated
Roughness softens the bulb's image into the glow on any body, not only on the facets of a starburst, so it stays editable on stippled and plain inserts whenever the lamp or the scatter shows.
@freezy
freezy merged commit d20b95b into master Oct 10, 2026
5 checks passed
@freezy
freezy deleted the feat/insert-creator branch October 10, 2026 23:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant