Files
Brachistochrone/fleet_godot47/PARTICLE_FX.md
T
scorpion21211-cmd b844c1a053 changelog
arcology updated
ship models in
particle fx is broken on kestrel
2026-10-04 19:37:48 -04:00

10 KiB
Raw Blame History

Particle FX handoff — Resolute and Kestrel

The hangar look is not a GPUParticles spray. Drive, RCS, and the abort flame are additive ribbon meshes parented to the Vfx sockets. A spray of quads (what the old Godot scripts built) reads as smoke. The hangar reads as a solid jet.

Source of truth: public/hangar-fx.js, function updateFx. Several helpers in that file are dead and must not be ported:

  • makeDrivePlume / stepDrivePlume — unused. The live drive is makeSpear.
  • makeRcsJet / stepRcsJet — unused. The live RCS jet is makeSpear.
  • makePdcStream / stepPdcStream — unused. The live PDC is spawnTracer.
  • burstChaff — unused. The live chaff is makeChaffCloud.

The scripts in this folder already implement the live path:

  • naf_fx.gd builds ribbons, abort sparks, chaff, tracer bolts, and the exhaust light.
  • ribbon.gdshader is the additive gradient. UV.y 0 is the socket, 1 is the tip. Edges fade so the ribbon is a soft streak, not a rectangle.
  • naf_resolute.gd arms drive, RCS, PDC, chaff.
  • kestrel_ec01.gd arms RCS and the four abort motors.

Do not replace the ribbons with GPUParticles3D. Particles are only used where the hangar uses points: abort sparks and chaff.

Axes and which bell fires

Ship space, same as the GLB: nose +Y, starboard +X, dorsal +Z. Port is -X. Ventral is -Z.

rcs_direction is a thrust, not an exhaust. A bell fires only when its exhaust direction (ribbon local +Y, in ship space) dots the negated thrust by more than 0.7. Off fires nothing. They do not all fire together.

Direction Thrust Bells that fire
Nose +Y exhaust mostly -Y
Tail -Y exhaust mostly +Y
Starboard +X exhaust mostly -X
Port -X exhaust mostly +X
Dorsal +Z exhaust mostly -Z
Ventral -Z exhaust mostly +Z

Exhaust direction comes from the socket, not from a guess. Take the socket's local position, rotate it by the inverse of the socket quaternion, and normalize. That is the nozzle axis. Aim the ribbon so its +Y matches. The socket stays put, so a gimballed drive bell carries the plume with it.

Burn does not pop. Ease toward the target with 1 - exp(-dt / tau). Tau is 0.08 s turning on, 0.14 s turning off.

Opacity flickers. For drive and RCS: 0.82 + 0.18 * sin(time * 37 + seed * 2.1). Hide the ribbon when the flickered opacity drops under 0.02.

Resolute drive

Socket Vfx_DrivePlume. Two ribbons, each three double-sided planes spun by i / 3 * PI (0°, 60°, 120°). Additive, unshaded, no depth write, depth test on, no fog.

Piece Length Width Planes Base opacity Color along the jet
Core 38 m 1.35 m 3 0.95 white f4f8ff at the throat, ice blue at mid, clear at the tip
Sheath 26 m 3.2 m 3 0.50 saturated blue 5aa8ff, wider and shorter than the core

drive_on with throttle is the power. Spool eases toward 1 over 0.26 s when power > 0.04, and back to 0 over 0.07 s. Visible amount is power * spool. The sheath uses 0.82 of that amount.

If the world exhaust points down (world_dir.y < -0.35) and the bell is above the hangar pad, shorten both ribbons by the same factor so they stop at the deck instead of spearing it. Deck is world y = -2.45, with 0.22 m of clearance. Minimum reach 0.9 m. If the bell is already below that plane (the ship sitting at the origin in these scenes), do not clip: the torch stays full length. The sheath mesh is already the shorter one. Do not multiply its scale by 26/38 a second time. In the hangar the ship stands nose-up on the pad, so the torch points at the deck and this clip is why the plume is a short bright jet under the bell instead of a 38 m lance. In space, or with the ship at the scene origin, exhaust is not aimed at a pad under the bell and the full length shows.

Spot light on the socket, 0.35 m out along the exhaust, color c5dcff, cone half-angle 0.3 rad, range follows the clipped length (at least 2.2 m, at most 38 m), decay 2. Energy is 5 * plume amount. Godot's tonemapper is harsher than the hangar. If it blooms white, lower the light energy. Do not dim the ribbon to compensate.

DriveGlow and DrivePlasma are materials, not particles. Emission color (0.55, 0.72, 1.0) * power, energy power * 7. Radiator fins stay cold unless throttle has been above 0.72 with the panels open. That heat path is already in naf_resolute.gd. Leave it.

Resolute RCS

One ribbon per socket whose name ends in _Vfx or starts with Vfx_RCS_. Skip Vfx_DrivePlume, Vfx_Chaff, and anything named Vfx_Abort_.

Length 1.2 m, width 0.09 m, two planes (0° and 90°). Base opacity 0.82. Color dcefff at the throat, fading to pale blue, then clear. Same flicker and burn ease as the drive. No gravity, no spread. It should look like a pencil of light out of the bell, not a cone of sparks.

Resolute PDC

Not a beam and not a particle system. Each PDT_*_Muzzle fires discrete bolts at 42 Hz, at most 2 per frame, 90 bolts alive across the whole ship.

Each bolt is a 5-sided additive cone, color ffe6b0, radius 0.016 at the tail and 0.008 at the nose, then scaled in length to a random 1.5–2.3 m. Life 0.12–0.2 s. Speed 90–140 m/s. Direction is the muzzle exhaust, jittered in a 1.15° cone. Spawn 0.18 m ahead of the socket. When pdc_fire turns off, stop spawning and let the live bolts finish.

Turret slew is not part of this handoff.

Resolute chaff

Socket Vfx_Chaff. This one is particles, because the hangar cloud is points.

28 soft discs. Life about 1.55 s (the hangar rolls 1.35–1.75). Speed 3–8 m/s. Spread 22°. No gravity, no damping. Size 0.07–0.16 m. Color (0.90, 0.93, 0.97), additive. Hold alpha until 55% of life, then fade to nothing. chaff_fire is the continuous cloud.

Kestrel RCS

Same ribbon as Resolute RCS, on every Vfx_RCS_* socket. Kestrel has no drive, no PDC, and no chaff.

Kestrel abort

Socket per motor: Vfx_Abort_FR, Vfx_Abort_FL, Vfx_Abort_RR, Vfx_Abort_RL. abort_burn ramps a hold value up over 0.22 s and down over 0.28 s. All four motors use that one value.

Each motor has:

Piece What it is
Core ribbon Tapered, 2.1 m. Width 0.06 m at the throat, 0.20 m at the tip. Width along the length is w0 + (w1 - w0) * t^0.7. Three planes. White-hot fff4e6 at the root, orange, then clear. Opacity hold * 0.95 * flick.
Sheath ribbon Tapered, 5.2 m. Width 0.10 → 0.78 m, same exponent. Orange ff6418. Opacity hold * 0.82 * flick. Its length scale breathes: 0.9 + 0.1 * sin(time * 19).
Core sparks 10 round additive points. Life 0.12–0.18 s (use 0.15). Speed 18–28 m/s. Spread 1.6°. Size about 0.05 m.
Sheath sparks 18 points. Life 0.20–0.32 s (use 0.26). Speed 14–22 m/s. Spread 4.5°. Size about 0.09 m.
Color of sparks White (1, 0.97, 0.92) at birth, orange (1, 0.46, 0.12) by mid-life, dark red (0.55, 0.16, 0.05) at the end. Opacity hold * 0.55.
Flash Soft additive disc on the throat, color fff1dd, opacity hold * 0.45, scale 0.06 + hold * 0.04 m.
Light Spot, color ff6a28, energy hold * 8, half-angle 0.5 rad, range 6.5 m, decay 1.8, sitting 0.08 m out from the socket.

Abort flicker is not the RCS flicker. Use 0.86 + 0.14 * sin(time * 41).

The ribbons are the flame. The sparks are a thin hot core inside them. If you only keep the sparks, it will look like the old spray.

Hongqi, Soyuz, Phantom II

Same ribbon code as above (naf_fx.gd). Do not invent a second particle style. Sizes match hangar-fx.js.

Hongqi

Axes: nose +Y, starboard +X, dorsal +Z. Torch exhaust -Y.

Socket Piece Length Width Planes Color
Vfx_DrivePlume Core 30 m 1.15 m 3 gold-white fff6d4
Vfx_DrivePlume Sheath 22 m 2.7 m 3 cinnabar e23b2f
Vfx_Drive_Port / Vfx_Drive_Stbd Core 12 m 0.55 m 3 same gold
Vfx_Drive_Port / Vfx_Drive_Stbd Sheath 8 m 1.2 m 3 same cinnabar

RCS is the Resolute pencil (1.2 m, two planes) on every *_Vfx / Vfx_RCS_* socket. PDC is the same 42 Hz tracer stream on PDT_*_Muzzle. Chaff is the Resolute cloud on Vfx_Chaff. battle_lights uses cinnabar c4342c, not Resolute red. Radiator fins glow only after a hard burn, same rule as Resolute.

Soyuz-MS

Axes: dock +Z, dorsal +Y, starboard +X. Service-engine exhaust -Z. rcs_direction Nose is +Z thrust.

Socket Piece Length Width Planes Color
Vfx_DrivePlume Core 7 m 0.5 m 4 warm fff3d4
Vfx_DrivePlume Sheath 5 m 1.25 m 3 chemical orange e85a12

Vfx_Abort_0 … Vfx_Abort_5 are the six soft-landing motors. They use the Kestrel abort recipe (tapered core, orange sheath, sparks). abort_burn holds all six.

Phantom II (shrike)

Axes: nose +Z, belly -Y, starboard +X. Torch exhaust -Z. rcs_direction Nose is +Z thrust. Dorsal is +Y.

Socket Piece Length Width Planes Color
Vfx_DrivePlume Core 22 m 0.68 m 3 ice f4f8ff
Vfx_DrivePlume Sheath 14 m 1.7 m 3 blue 5aa8ff

RCS, the two PDT_*_Muzzle guns, and Vfx_Chaff match Resolute. cabin_dim only lowers the cabin lights. There is no battle-red swap.

What to give Godot 4.7

One folder, with project.godot. Open it in Godot 4.7. Hongqi is the main scene. Shared: naf_fx.gd, ribbon.gdshader, this file.

  • Resolute: naf_resolute.glb, naf_resolute.gd, resolute.tscn
  • Kestrel: kestrel_ec01_escape_capsule.glb, kestrel_ec01.gd, kestrel.tscn
  • Hongqi: hongqi.glb, hongqi.gd, hongqi.tscn
  • Soyuz: soyuz.glb, soyuz.gd, soyuz.tscn
  • Phantom II: shrike.glb, shrike.gd, shrike.tscn

Textures and the 0..1 clips are already in the glb. Play the scene before judging the jets. Additive ribbons disappear on the default grey sky. The tscn world is near-black on purpose.

Play, then:

  • Resolute: drive_on, throttle 0.8. White core, blue sheath, flickering. Not a cloud of quads.
  • Resolute: rcs_direction Starboard. Only the bells pushing that way light.
  • Resolute: pdc_fire. Separate bolts, not one beam. chaff_fire is a small silver cloud.
  • Kestrel: abort_burn. Four motors, white throat into an orange plume.
  • Hongqi: drive_on, throttle 0.8. Gold core, cinnabar sheath, on the main bell and both outboards.
  • Soyuz: drive_on is a short chemical plume on the service engine. abort_burn lights the six landing motors.
  • Phantom II: drive_on is the ice/blue torch out the tail. canopy_open and gear_deploy are the two clips.