arcology updated ship models in particle fx is broken on kestrel
10 KiB
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 ismakeSpear.makeRcsJet/stepRcsJet— unused. The live RCS jet ismakeSpear.makePdcStream/stepPdcStream— unused. The live PDC isspawnTracer.burstChaff— unused. The live chaff ismakeChaffCloud.
The scripts in this folder already implement the live path:
naf_fx.gdbuilds ribbons, abort sparks, chaff, tracer bolts, and the exhaust light.ribbon.gdshaderis 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.gdarms drive, RCS, PDC, chaff.kestrel_ec01.gdarms 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_directionStarboard. Only the bells pushing that way light. - Resolute:
pdc_fire. Separate bolts, not one beam.chaff_fireis 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_onis a short chemical plume on the service engine.abort_burnlights the six landing motors. - Phantom II:
drive_onis the ice/blue torch out the tail.canopy_openandgear_deployare the two clips.