Skip to content

feat(examples): add example game-effect shaders - #291

Open
nmfisher wants to merge 10 commits into
developfrom
game-effect-shaders
Open

feat(examples): add example game-effect shaders#291
nmfisher wants to merge 10 commits into
developfrom
game-effect-shaders

Conversation

@nmfisher

Copy link
Copy Markdown
Owner

Summary

  • add 18 registered Filament game-effect showcases covering combat feedback, holograms, force fields, dissolve, water, smoke, fire, lava, shockwaves, shore waves, wetness, crystal ice, snow accumulation, damage decals, portals, electricity, invisibility, and energy weapons
  • upgrade the original effects with richer procedural detail, layered animation, improved composition, and bloom-aware HDR tuning
  • add reusable animation, billboard, subdivided-plane, and flat-faceted crystal helpers
  • add compatible compiled material assets plus material-build registration
  • document shader architecture, tuning controls, renderer constraints, golden capture times, and iteration workflow
  • extend the headless runner with deterministic still and six-second video capture

Validation

  • flutter analyze in examples/dart/examples_lib: no issues
  • git diff --check: clean
  • all effect materials compiled for Metal, Vulkan, and OpenGL with the Filament v75-compatible compiler
  • all eight new effects rendered and visually reviewed on Metal
  • eight MP4 validations confirmed at 768x768, 30 fps, six seconds, and 180 frames each

Toolchain note

The available material compiler does not include WebGPU support, so local material builds skip WebGPU variants as documented.

nmfisher and others added 10 commits August 24, 2026 22:07
- Replace bash-4-only ${suffix^^} with the tr idiom already used
  elsewhere in the script (macOS /bin/bash is 3.2)
- Replace GNU-style sed -i with perl (BSD sed has no compatible
  in-place editing), matching the earlier cross-platform perl migration
- Quote MATC/RESGEN expansions so FILAMENT_PATH with spaces works
- Resolve Ninja out/<config>/tools layouts where matc/resgen are
  directories containing the binary
- Probe WebGPU support once and skip _webgpu/_web_combined variants
  (and the webgpu example-material backend) with a warning when matc
  was built without FILAMENT_SUPPORTS_WEBGPU=ON, instead of failing

Co-Authored-By: Claude <noreply@anthropic.com>
…r, smoke, hologram, force field)

Six example-level Filament materials in examples/assets, each a
procedural shader driven by uniforms (time, progress, thresholds):

- hit_flash: additive rim-weighted flash, applied as a material swap
- hologram: fresnel shell + scanlines + flicker + glitch bands
- force_field: fresnel bubble + hex lattice + pole-to-pole ripple
- dissolve_burn: 3D fbm threshold discard with glowing ember edge
- water: 3 Gerstner waves displacing a subdivided grid in the vertex
  shader (finite-difference normals), fresnel/sky/foam fragment
- smoke: GPU billboards generated from getVertexIndex() in a single
  draw call, per-puff seeds, fbm turbulence

Registered as game_effects_* examples in examples_lib (headless runner
captures a PNG per effect). The runner now exits immediately after the
capture: destroying a material instance still assigned to a renderable
deadlocks, and Filament panics if a material outlives its instances.

Materials compile via matc (FILAMENT_PATH) - see game_effects_plan.md
for the design and iteration loop.

Co-Authored-By: Claude <noreply@anthropic.com>
Setups register time-driven animators (effectAnimators) mapping
wall-clock seconds to uniform updates - capture() bypasses
requestFrame hooks, so stills and video both drive animation through
these instead. hit_flash now lights the scene (IBL + sun) so the
normal PBR look shows between cyclic flashes, and swap/restore state
lives in its animator.

The runner's --video [seconds] [fps] advances animators per frame,
captures each to output/<name>_frames/, then encodes output/<name>.mp4
with ffmpeg (yuv420p, crf 20).

Co-Authored-By: Claude <noreply@anthropic.com>
Per-effect reference (intent, technique, uniforms, tuning knobs,
limitations, improvement ideas), environment setup, render/iterate
loop, architecture notes, and the gotchas learned while building them.

Co-Authored-By: Claude <noreply@anthropic.com>
Water: 4 Gerstner waves, three scrolled detail-normal layers (incl.
near-pixel frequency) for real sun glitter, foam from crest height +
Gerstner pinch compression, sun-side shading and backlit crest
subsurface glow, dual-lobe specular, horizon haze melting the plane
edge. Hologram: readable interior floor, thin bright scanlines, a
sweeping scan band, gated glitch shear with chromatic split, flicker.
Force field: proper hex distance lattice with per-cell wobble (kills
the moire), shimmer + per-cell twinkle, pole fade, hot rim lip, and
expanding impact ripples driven from Dart. Dissolve/burn: object-space
noise pinned to the mesh, white-hot -> orange -> red temperature
gradient at the front, combustion flicker, charred apron ahead of the
front, ember sparks. Hit flash: shockwave ring expanding from a
per-hit impact point, white-hot -> flashColor shift, rim-weighted
decaying body flash, dim directional lighting so the additive flash
keeps contrast (the default IBL blew the helmet out to pure white).
Smoke: cone/spiral/wind plume structure, vertically stretching puffs,
domain-warped fbm, per-puff brightness, warm young-puff cast.

Renderer fixes found along the way:
- worldPosition in .mat vertex shaders only survives as a pure additive
  displacement; replacement/cancellation forms silently draw nothing on
  Metal. Smoke billboards now keep CPU verts near the origin (but
  non-degenerate, so bounding-volume culling stays valid) and add the
  full animated center + camera-facing corners; water adds its wave
  displacement the same way. This also fixes the per-frame flicker in
  the previous smoke videos.
- headless runner: --time <seconds> for stills - animators stomp any
  golden-time uniforms a setup applied, so stills captured t=0 states
  regardless (hit_flash stills were the max-white impact instant).

docs/game-effects.md updated to match; spurious engine-material
rebuilds from make materials reverted (webgpu-less matc would strip
backends from unrelated blobs).

Co-Authored-By: Claude <noreply@anthropic.com>
Four new effects on the established toolkit (GPU billboards, additive
displacement, analytic noise fields):

- fire: one draw call of 16 flame tongues + 20 ember sparks (vertex
  branch on quadIndex). Downward-scrolled warped noise reads as upward
  licks; blackbody ramp white->yellow->orange->red; embers rise, wobble,
  and cool. Wind shear leans the tips.
- lava: vertex-displaced crust over an inverted-dissolve glow network -
  domain-warped crust fbm, fast-flowing crack interiors, red->orange->
  yellow-white ramp, very dark saturated crust (exposure + ACES lift
  darks hard; stops pushed accordingly), reheat apron, edge fade.
- shockwave: ground ring (sharp leading edge + wake + trailing ring,
  arc-broken, churn-roughened) plus a fresnel dome whose lower
  hemisphere is discarded at the ground plane and whose scale tracks
  the ring front from the Dart animator. One pulse every 2.2s.
- shore_waves: the demo owns the geometry, so the shoreline is an
  analytic function - no depth texture. Swells shoal toward the shore
  (per-vertex amplitude), break into a pulsing two-octave anisotropic
  foam line along the shoreline, whitecap on the way in; deep->turquoise
  gradient, glitter path, and a sand plane reusing the same shoreline
  for its wet band so waterline and beach stay in lockstep.

Registry entries (game_effects_fire/lava/shockwave/shore_waves), the new
mats in materials/build.sh EXAMPLE_MATERIALS, docs section 6.7-6.10, and
roadmap updates. All worldPosition writes follow the additive-only rule;
all stills/videos verified (180 frames each, no dropouts).

Co-Authored-By: Claude <noreply@anthropic.com>
Fixes three pipeline traps that had silently degraded (or entirely
killed) features, then retunes every effect against a verified
headless-capture calibration:

- fragment getWorldPosition() is view-relative here and
  getWorldFromModelMatrix() is garbage for created geometry; pipe world
  position through custom variables instead (the hit-flash ring and the
  shockwave ground ring had never actually rendered)
- exp(-pow(x, 2.0)) with sign-changing x is NaN on Metal - use x*x for
  every gaussian ring/band
- additive blending passes through the engine's HDR exposure (~100-300x
  on rgb*alpha) before tonemapping, so additive materials now scale
  their output into the 0.001-0.05 range; transparent/opaque render
  direct

Per effect: hit_flash gains a saturated orange shockwave ring sweeping
the mesh plus a localized white-hot impact hotspot; force_field's hex
lattice is now ~20 readable cells (was ~124-column sub-pixel moire) with
splash + ring + echo impact response; hologram gets two-band glitch with
complementary chromatic splits, band bars and dropouts; smoke switches
to alpha-blended gray puffs (was an additive white blob) with torn
wispy shaping; fire grows two rings of tongues, a granular ember bed,
blue base and red tips; lava's cracks become a ridged connected web with
flowing near-white hot cores and a reheat halo; dissolve burns hotter
and crisper with concentrated char; shockwave gains an epicenter flash,
radius-relaxed ring width, broken arcs, and a dome with vertical streaks
and an equator lip (fresnel moved to the vertex stage); shore waves'
breaker now travels toward the shore with a phase-locked swash line on
the sand; water gains steeper five-wave Gerstner sets, current-driven
body color, textured foam, a directional glitter path and an alpha-faded
horizon.

Docs updated with the new gotchas, uniforms and golden still times.

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with GitHub Actions
@nmfisher nmfisher changed the title feat(examples): add AAA-targeted game-effect shaders feat(examples): add example game-effect shaders Aug 25, 2026
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