User:The E: Difference between revisions
New page: Hi there. This is The E, the most common letter in the english alphabet. What makes me special among all the E's out there is my unique capacity to troubleshoot FS2Open installs. No other ... |
No edit summary |
||
| (3 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
Hi there. This is The E, the most common letter in the english alphabet. What makes me special among all the E's out there is my unique capacity to troubleshoot FS2Open installs. No other letter of the english alphabet has ever done this. It is my sincere hope that other letters and numbers will follow my example and contribute to the community. | Hi there. This is The E, the most common letter in the english alphabet. What makes me special among all the E's out there is my unique capacity to troubleshoot FS2Open installs. No other letter of the english alphabet has ever done this. It is my sincere hope that other letters and numbers will follow my example and contribute to the community. | ||
{{SCP_table}} | |||
{{Tables}} | |||
<!-- Editor's note: everything on this page is new in FS2 Open 26.1. Template:Table261 | |||
did not exist when this was written (the newest was Template:Table250); once it | |||
is created, the intro line below can be replaced with the usual version box. --> | |||
The '''lens_flares.tbl''' defines physically-based lens systems used to render camera lens flares for suns. Added in '''FS2 Open, 26.1'''. | |||
Unlike the sprite-based '''$Flare:''' effect defined in [[Stars.tbl]], a lens system is described the way a real lens is: as a stack of glass surfaces. The engine traces that stack at table load and derives everything the flare needs from it, so the ghosts, their colours and the starburst all follow from the optics rather than from hand-placed sprites. | |||
A mission mounts exactly '''one''' of these as its camera lens, because there is one camera: every sun in the background flares through the same glass, so the flares of two suns can never disagree about the lens they came from. The lens is chosen with '''$Camera Lens:''' in the mission info section (see [[#Using a lens]]), falling back to the '''$Default Lens:''' this table declares; a mission can also opt out explicitly with '''<nowiki><none></nowiki>'''. A mission with no lens mounted is completely unaffected, which is what the shipped table defaults to, so retail and existing content keeps the retail look until a mod opts in. | |||
While a lens is mounted, the legacy sprite '''$Flare:''' of [[Stars.tbl]] is not drawn at all, since the lens models the same artifact properly. | |||
FreeSpace Open ships a default lens_flares.tbl built into the engine, so the lens systems listed under [[#Default lens systems]] are always available even when no table file is present. | |||
This table is one of the [[Modular Tables]] and can be extended with xxx-lens.tbm | |||
==General Format== | |||
*The table consists of a single section | |||
*Begins with <nowiki>#</nowiki>'''Lens Systems''' | |||
*May be followed by '''$Default Lens:''', then by any number of lens systems, each beginning with '''$Name:''' | |||
*Must be closed with <nowiki>#</nowiki>'''End''' | |||
*A lens system in a .tbm that reuses the '''$Name:''' of an existing one replaces it completely, rather than adding a second lens of the same name | |||
*'''Entries must appear in the order listed on this page.''' Options are read in sequence, so an option placed out of order is skipped, and one placed after the surface list will abort the parsing of the whole table | |||
*Within a lens system, every option except '''$Name:''' is optional and falls back to the default given below | |||
==Table options== | |||
*'''$Default Lens:''' | |||
**The lens mounted by missions that do not name one themselves with '''$Camera Lens:''', and what the '''<nowiki><default></nowiki>''' argument of '''set-camera-lens''' restores | |||
**Appears once, directly after <nowiki>#</nowiki>'''Lens Systems''' and before the first '''$Name:''' | |||
**The shipped table leaves this unset, so no mission gets a flare until either the mission or a .tbm asks for one. Setting it in a xxx-lens.tbm is how a mod puts its whole campaign on the same glass with a single line | |||
**The name is resolved after every table has been read, so it may name a lens declared later in the same table, or in a different table altogether. A later .tbm that sets it again replaces the earlier value | |||
**Syntax: '''String''', default is ''' ''(empty — no lens)'' ''' | |||
==Lens system options== | |||
*'''$Name:''' | |||
**The name used to refer to this lens system from '''$Camera Lens:''' in a mission, from '''$Default Lens:''' above, and from the lens [[#SEXPs|SEXPs]] | |||
**Begins a new lens system | |||
**Syntax: '''String''' | |||
*'''$Entrance Pupil Radius:''' | |||
**Radius of the front element, in millimetres. For a real design this is the focal length divided by twice the f-number | |||
**Controls how large the ghosts are and how much light the lens gathers | |||
**Syntax: '''Float''', default is '''10.0''' | |||
*'''$Aperture Radius:''' | |||
**Half-opening of the iris, in millimetres | |||
**This is the setting that decides whether a ghost is lit at all: each ghost slides across the iris as the sun moves off-axis, by an amount that grows with the field angle and shrinks with this value, and a ghost that slides off the iris goes black. Too small a value confines the whole flare to a sun near the centre of the frame; too large a one shrinks the ghosts within the iris until the blades stop shaping them | |||
**The physical value is the paraxial marginal-ray height where it crosses the '''$Stop:'''. The shipped lenses use 1.25x that | |||
**Syntax: '''Float''', default is '''5.0''' | |||
*'''$Sensor Width:''' | |||
**Width of the film gate, in millimetres. 36.0 is a full 35mm frame | |||
**Together with the focal length the engine derives from the surfaces, this sets how far the ghosts travel as the sun moves off-axis | |||
**Syntax: '''Float''', default is '''36.0''' | |||
*'''$Anamorphic Squeeze:''' | |||
**Stretches every ghost and the starburst horizontally, giving the oval ghosts of the anamorphic look. '''1.0''' is an ordinary spherical lens; '''2.0''' matches a classic 2x anamorphic. Values below 1.0 compress instead of stretching, which is not what the option is for and can thin a tightly focused ghost below a pixel | |||
**A front anamorphic attachment is an afocal cylindrical telescope, so to first order all it does is magnify one meridian. That is why a whole anamorphic lens is one number here rather than a second set of surfaces, and why the iris behind it is unaffected — the aperture, its mask and the starburst shape are all still the ones described below | |||
**Only the '''footprints''' stretch: ghosts stay on the sun exactly where they were, which is what a desqueezed anamorphic frame shows. FSO composes the frame directly and has no desqueeze stage, so treat this as a look control rather than a simulated 2x capture pipeline | |||
**Costs nothing: it is applied as the flare is drawn, so unlike the aperture settings it forces no texture rebuild | |||
**Syntax: '''Float''', default is '''1.0''' | |||
*'''$Anamorphic Streak:''' | |||
**The long horizontal flare a cylindrical element throws across the frame, and the other half of the anamorphic look. On its own '''$Anamorphic Squeeze:''' only ever widens things; the streak is what actually reads as anamorphic, because a real one runs 20-50 times longer than it is thick | |||
**It is a separate effect from the starburst, not a stretched one: the starburst is the iris seen end-on and swings around as the sun moves, while the streak lies along the cylindrical element and so stays '''horizontal wherever the sun is''' | |||
**Like the aperture imperfections it is off by default, and it needs no texture rebuild | |||
**Syntax: '''Float''', strength; default is '''0.0''' (off) | |||
**'''+Length:''' | |||
***Half-length as a fraction of the sensor width. '''1.0''' spans the frame | |||
***Syntax: '''Float''', default is '''1.0''' | |||
**'''+Thickness:''' | |||
***As a fraction of the length, so '''0.02''' gives a 50:1 bar | |||
***Syntax: '''Float''', default is '''0.02''' | |||
**'''+Tint:''' | |||
***Multiplied onto the sun's own colour rather than replacing it, so a red sun keeps a reddish streak | |||
***The default leans blue, which is where the classic look comes from — real streaks take their colour from the coating on the cylindrical element | |||
***Syntax: '''( Float, Float, Float )''', default is '''( 0.35, 0.55, 1.0 )''' | |||
*'''$Coating Wavelength:''' | |||
**Wavelength in nanometres that the anti-reflection coating is tuned to, as a quarter-wave layer | |||
**500-570 (green-centred, like real broadband coatings) gives the classic magenta and cyan ghost tints. '''0''' disables coatings entirely for an uncoated vintage look: much brighter, neutral grey ghosts | |||
**Can be overridden per surface with '''+Coating Wavelength:''' | |||
**Syntax: '''Float''', default is '''540.0''' | |||
===Aperture=== | |||
A lens has exactly one aperture, and it drives both the ghosts and the starburst: every ghost is an image of the iris, and the starburst is that same image's diffraction pattern. Changing a blade count therefore restyles both at once. | |||
*'''$Aperture Blades:''' | |||
**Number of iris blades. Fewer than 3 gives a perfectly round iris | |||
**Syntax: '''Integer''', default is '''6''' | |||
*'''+Blade Rotation:''' | |||
**Rotation of the iris, in degrees | |||
**Syntax: '''Float''', default is '''0.0''' | |||
*'''+Blade Curvature:''' | |||
**How the blades bow. '''0''' leaves them straight, '''1''' bows their midpoints out to the corner radius for a circular iris, and negative values bow them inward into a star | |||
**Syntax: '''Float''', -1.0 to 1.0, default is '''0.0''' | |||
*'''+Edge Softness:''' | |||
**Feathering of the iris edge, as a fraction of the iris radius | |||
**The default is also the floor the engine clamps to (about a two pixel ramp, so the mask never aliases), so asking for less has no effect. Softening the edge visibly weakens the starburst spikes, because those come from the sharpness of that edge | |||
**Syntax: '''Float''', default is '''0.0039''' | |||
===Aperture imperfections=== | |||
Three optional layers darken the iris on top of the blade shape, for a dirty or damaged lens. All are off by default, and each takes its strength on the '''$'''-line followed by optional '''+''' sub-options. | |||
Note that the starburst is normalized against its own brightest value, so these layers dim the core spikes as they add speckle around them, rather than only adding to what was already there. | |||
*'''$Aperture Grating:''' | |||
**A diffraction grating around the rim of the iris: radial ridges that throw extra spikes into the starburst | |||
**Syntax: '''Float''', 0.0 to 1.0, strength; default is '''0.0''' (off) | |||
**'''+Density:''' | |||
***Fraction of the 360 possible ridges | |||
***Syntax: '''Float''', 0.0 to 1.0, default is '''0.5''' | |||
**'''+Length:''' | |||
***How far in from the rim the ridges reach, as a fraction of the iris radius | |||
***Syntax: '''Float''', 0.0 to 1.0, default is '''0.5''' | |||
**'''+Width:''' | |||
***Ridge width, as a duty cycle of the spacing between neighbouring ridges. Because it is relative, raising '''+Density:''' thins the ridges rather than merging them into a solid ring | |||
***Syntax: '''Float''', 0.0 to 1.0, default is '''0.25''' | |||
**'''+Softness:''' | |||
***Syntax: '''Float''', default is '''0.0''' | |||
*'''$Aperture Scratches:''' | |||
**Scratches on the glass: randomly placed slivers | |||
**Syntax: '''Float''', 0.0 to 1.0, strength; default is '''0.0''' (off) | |||
**'''+Density:''' | |||
***Fraction of the 1000 possible scratches | |||
***Syntax: '''Float''', 0.0 to 1.0, default is '''0.5''' | |||
**'''+Length:''' | |||
***Syntax: '''Float''', 0.0 to 1.0, default is '''0.5''' | |||
**'''+Width:''' | |||
***Syntax: '''Float''', 0.0 to 1.0, default is '''0.25''' | |||
**'''+Rotation:''' | |||
***Direction the scratches run, in degrees | |||
***Syntax: '''Float''', default is '''0.0''' | |||
**'''+Rotation Variation:''' | |||
***'''0''' leaves every scratch parallel, '''1''' scatters them completely | |||
***Syntax: '''Float''', 0.0 to 1.0, default is '''0.0''' | |||
**'''+Softness:''' | |||
***Syntax: '''Float''', default is '''0.0''' | |||
*'''$Aperture Dust:''' | |||
**Dust on the glass: randomly placed specks | |||
**Syntax: '''Float''', 0.0 to 1.0, strength; default is '''0.0''' (off) | |||
**'''+Density:''' | |||
***Fraction of the 1000 possible specks | |||
***Syntax: '''Float''', 0.0 to 1.0, default is '''0.5''' | |||
**'''+Radius:''' | |||
***Syntax: '''Float''', 0.0 to 1.0, default is '''0.5''' | |||
**'''+Softness:''' | |||
***Syntax: '''Float''', default is '''0.0''' | |||
===Starburst and brightness=== | |||
*'''$Starburst:''' | |||
**Whether this lens draws the diffraction starburst around the suns themselves. For each sun that gets one, the sun's own bitmap and glow are skipped so the two do not stack. A sun the flare pass does not reach keeps its ordinary bitmap and glow — one that is occluded, one outside the flare's reach, and every sun in an environment map, since those are rendered without the post-processing pass that draws the starburst | |||
**Syntax: '''Boolean''', default is '''YES''' | |||
*'''+Starburst Scale:''' | |||
**Size of the starburst relative to the frame | |||
**Syntax: '''Float''', default is '''1.0''' | |||
*'''$Intensity:''' | |||
**Overall brightness of this lens's flare | |||
**This is the artistic control, and it is best set by comparing against the shipped lenses in the lab. An uncoated lens ('''$Coating Wavelength: 0''') reflects far more light and needs a much smaller value to stay in the same range | |||
**Syntax: '''Float''', default is '''0.2''' | |||
*'''$Max Ghosts:''' | |||
**How many of the brightest ghosts to draw. A lens with many elements can produce several hundred, so this caps the cost | |||
**Values above 63 are clamped to 63 | |||
**Syntax: '''Integer''', default is '''40''' | |||
==Optical prescription== | |||
The rest of the entry is the lens itself: an ordered list of the surfaces light passes through, front element first. Every ordered pair of surfaces produces one ghost, so the number and arrangement of surfaces is what gives a lens its character. | |||
These numbers are "lens prescriptions" as published in lens patents and optical design references, and can be transcribed directly, one element per '''$Surface:''' row. Scaling all radii and thicknesses by the same factor changes the focal length. The engine derives the focal length, the sensor distance, the ghost list and each ghost's brightness and tint from this stack at table load. | |||
*'''$Surface:''' | |||
**One spherical glass surface | |||
**Syntax: '''( Float, Float, Float )''' — curvature radius in millimetres, distance to the next surface in millimetres, and refractive index of the glass '''behind''' the surface ('''1.0''' being air) | |||
**A positive radius means the surface bulges toward the front of the lens, with its centre of curvature behind it; a negative radius bulges toward the sensor; '''0''' is a flat surface | |||
**The distance on the ''last'' surface is ignored: the engine places the sensor at the focus it computes | |||
**'''+Abbe:''' | |||
***Abbe V-number of the glass behind the surface, which sets how much it disperses. Crown glasses are around 55-60, dense flints around 30-40. This only drives the chromatic fringing of the ghosts, so approximate values are fine | |||
***Syntax: '''Float''', default is '''0.0''' (no dispersion) | |||
**'''+Coating Wavelength:''' | |||
***Overrides '''$Coating Wavelength:''' for this surface alone | |||
***Syntax: '''Float''', defaults to the lens's own value | |||
*'''$Stop:''' | |||
**Marks the iris plane. It does not refract or reflect; it is where the aperture sits in the stack | |||
**Syntax: '''( Float )''', distance to the next surface in millimetres | |||
**A lens without a '''$Stop:''' uses its middle surface as the aperture plane | |||
A lens system needs at least two surfaces, and its prescription must actually form an image. One that does not (for instance an afocal stack) is dropped with a warning at table load and cannot be referenced. | |||
==Using a lens== | |||
*Mount a lens on a mission with '''$Camera Lens:''' in its info section (as in <code>$Camera Lens: tessar_50mm</code>), naming a lens system from this table. It sits alongside '''$Lighting Profile:''' and is the same kind of setting: one global render choice belonging to one mission | |||
**The option takes a lens name, or one of two tokens in place of one: '''<nowiki><none></nowiki>''' for no flares at all, and '''<nowiki><default></nowiki>''' for the table's '''$Default Lens:'''. These are the same values '''set-camera-lens''' accepts | |||
**A mission that omits the option entirely gets the table's '''$Default Lens:''', which is what keeps existing content unaffected. An unknown name warns and falls back to that default as well — only '''<nowiki><none></nowiki>''' turns the flares off, so that a typo can never silently read as "this mod wanted none" | |||
**Both FRED and qtFRED expose it as a ''Camera lens'' drop-down in the background editor. '''Default''' leaves the mission silent so it follows the table, '''None''' writes '''<nowiki><none></nowiki>''' — these are different answers whenever a '''$Default Lens:''' is declared, and the drop-down keeps them apart so a saved mission never loses an explicit "no flares" | |||
*Every visible sun in the background flares through the mounted lens — there is no per-sun setting on the lens. What differs between suns is only where each one sits in the frame and how bright it is | |||
*'''A sun only flares if its [[Stars.tbl]] entry says so.''' The sun entry decides ''whether'' a sun flares and the mounted lens only decides ''how'' it is drawn, so mounting a lens never invents flares on suns that were deliberately tabled without one. A sun that does not ask keeps its ordinary bitmap and glow and gets nothing from the lens | |||
**'''<nowiki>+Camera Lens Flare:</nowiki>''' (boolean) is the direct way to say it. It goes in the '''<nowiki>$Sun:</nowiki>''' entry, after any '''<nowiki>$Flare:</nowiki>''' block and before '''<nowiki>$NoGlare:</nowiki>''' | |||
**With the option absent, a legacy sprite '''<nowiki>$Flare:</nowiki>''' block stands in for it, since that was the only way to declare a flare before the option existed — so tables written earlier keep working untouched. Where both are present the option wins, which is the only way to keep a sun's sprite flare while leaving it out of the physically-based one | |||
**This matters because '''<nowiki>$Flare:</nowiki>''' is expensive to write: it requires a full set of sprite fields ('''<nowiki>+FlareCount:</nowiki>''', '''<nowiki>$FlareTexture1:</nowiki>''', '''<nowiki>$FlareGlow1:</nowiki>''' and so on) that are never drawn while a lens is mounted. '''<nowiki>+Camera Lens Flare: YES</nowiki>''' opts a sun in on its own, with none of them | |||
**Retail's stars.tbl declares no '''<nowiki>$Flare:</nowiki>''' at all. The MediaVPs add one to the six standard suns (''SunWhite'', ''SunRed'', ''SunGreen'', ''SunBlue'', ''SunGold'', ''SunViolet'') and to many of the named stars, but not all of them — so if a background's sun shows no flare with a lens mounted, check its sun entry first, and add '''<nowiki>+Camera Lens Flare: YES</nowiki>''' in a '''<nowiki>-str.tbm</nowiki>''' to opt it in | |||
*Missions can swap the lens and edit the iris at runtime with the lens [[#SEXPs|SEXPs]] | |||
*The F3 lab (''Render options'' -> ''Lens flare options'') can override the mission's lens and adjust every aperture setting live, which is the practical way to dial in '''$Intensity:''', the anamorphic settings and the imperfection layers. It also exposes the global ghost and starburst brightness calibration and the HDR headroom, reports the mounted lens's ghost count, computed focal length and f-number, and lists what the last flare pass actually drew for each sun (visibility, off-axis angle, instance count). Lab edits are undone the same way mission edits are | |||
*The flare is suppressed in full-nebula missions, in subspace, in VR, when post-processing is disabled, and when the Planets/Backgrounds detail setting is off | |||
===SEXPs=== | |||
*'''set-camera-lens''' — mount a different lens system. Also accepts '''<nowiki><none></nowiki>''' for no flares at all and '''<nowiki><default></nowiki>''' for the table's '''$Default Lens:''' | |||
*'''set-lens-aperture''' — blade count, rotation, curvature and edge softness | |||
*'''set-lens-grating''', '''set-lens-scratches''', '''set-lens-dust''' — the imperfection layers | |||
The four aperture operators take no lens argument: they restyle the iris of whatever lens is mounted, so a mission cannot edit a lens it is not looking through. With no lens mounted they do nothing and warn — use '''set-camera-lens''' first. | |||
Note that these operators take '''percentages''' (0 to 100) and whole '''degrees''' where the table takes fractions (0.0 to 1.0) and floats; '''+Blade Curvature: 0.3''' in the table is an argument of '''30''' to '''set-lens-aperture'''. | |||
Both the mounted lens and any iris edits are undone when the mission ends, so nothing carries into the next mission. These operators are not sent over the network, so in multiplayer they only affect the host. | |||
The lens name given to '''set-camera-lens''' is validated when the mission loads, and a name that does not resolve aborts the load. This is safe because lens_flares.tbl is an engine default — the built-in lenses always resolve — but a mission naming a lens from a xxx-lens.tbm must ship with that .tbm. | |||
==Default lens systems== | |||
The built-in table ships eight lens systems, transcribed from published patents. All of them are spherical designs that leave the imperfection layers and both anamorphic options off — for an anamorphic look, set '''$Anamorphic Squeeze:''' and '''$Anamorphic Streak:''' on one of these in a xxx-lens.tbm. | |||
*'''angenieux_100mm''' — double-Gauss cine prime, f/2.2. The reference prescription from the research this renderer is based on, and the lens the others are calibrated against | |||
*'''tessar_50mm''' — classic Tessar, f/3.5. Few elements, so a sparse and subtle ghost set | |||
*'''canon_70_200mm''' — modern multicoated telephoto zoom, f/2.8. The busiest shipped lens: a dense, strongly tinted ghost train | |||
*'''kodak_100mm''' — symmetric double Gauss, f/3.8, single-coated. A sparse, orderly ghost set that stays stable as the sun moves off-axis | |||
*'''leica_35mm''' — fast aspherical wide-angle prime, f/1.4. The shortest focal length shipped, so its ghosts sweep the furthest | |||
*'''nikon_50_135mm''' — multicoated telephoto zoom, f/3.5 | |||
*'''color_heliar_105mm''' — uncoated vintage prime, f/3.5. The uncoated reference: few, large, colourless, obvious ghosts | |||
*'''zeiss_master_prime_50mm''' — modern multicoated cine prime, T1.3. Many large, bright, strongly tinted ghosts; the closest to a contemporary cinema look | |||
==Sample== | |||
<pre> | |||
#Lens Systems | |||
; Classic Tessar, f/3.5, f=50mm, with a little dust on the front element. | |||
$Name: tessar_50mm | |||
$Entrance Pupil Radius: 7.0 | |||
$Aperture Radius: 5.0 | |||
$Sensor Width: 36.0 | |||
$Coating Wavelength: 520 | |||
$Aperture Blades: 8 | |||
+Blade Rotation: 0.0 | |||
+Blade Curvature: 0.3 | |||
$Aperture Dust: 0.4 | |||
+Density: 0.3 | |||
+Radius: 0.25 | |||
$Starburst: YES | |||
+Starburst Scale: 0.8 | |||
$Intensity: 0.2 | |||
$Max Ghosts: 24 | |||
$Surface: ( 16.25, 2.90, 1.6116 ) | |||
+Abbe: 56.9 | |||
$Surface: ( -285.90, 0.29, 1.0 ) | |||
$Surface: ( -30.05, 1.20, 1.6053 ) | |||
+Abbe: 43.6 | |||
$Surface: ( 17.47, 1.38, 1.0 ) | |||
$Stop: ( 1.15 ) | |||
$Surface: ( 31.55, 1.20, 1.5123 ) | |||
+Abbe: 51.0 | |||
$Surface: ( 21.30, 3.50, 1.6116 ) | |||
+Abbe: 56.9 | |||
$Surface: ( -23.70, 40.0, 1.0 ) | |||
#End | |||
</pre> | |||
To use it, name it from the info section of a mission (or pick it in the background editor, which writes the same line): | |||
<pre> | |||
$Camera Lens: tessar_50mm | |||
</pre> | |||
To put a whole campaign on it instead, without touching a single mission, declare it as the default in a xxx-lens.tbm: | |||
<pre> | |||
#Lens Systems | |||
$Default Lens: tessar_50mm | |||
#End | |||
</pre> | |||
[[Category:Tables]] | |||
Latest revision as of 11:51, 26 July 2026
Hi there. This is The E, the most common letter in the english alphabet. What makes me special among all the E's out there is my unique capacity to troubleshoot FS2Open installs. No other letter of the english alphabet has ever done this. It is my sincere hope that other letters and numbers will follow my example and contribute to the community.
| This feature requires FreeSpace Open |
| List of Tables and related code files | |
|---|---|
| * Notes Modular Tables | |
| ** Notes tables which only use modular tables | |
| Ai.tbl* | /ai/aicode.cpp |
| Ai_profiles.tbl* | /ai/ai_profiles.cpp |
| Animation.tbl** | /model/modelanimation.cpp |
| Armor.tbl* | /ship/ship.cpp |
| Asteroid.tbl* | /asteroid/asteroid.cpp |
| Autopilot.tbl* | /autopilot/autopilot.cpp |
| Cheats.tbl* | /cheats_table/cheats_table.cpp |
| Colors.tbl* | /globalincs/alphacolors.cpp |
| Curves.tbl* | /math/curves.cpp |
| Controlconfigdefaults.tbl | /controlconfig/controlsconfigcommon.cpp |
| Credits.tbl* | /menuui/credits.cpp |
| Cutscenes.tbl* | /cutscene/cutscenes.cpp |
| Decals.tbl** | /decals/decals.cpp |
| Fireball.tbl* | /fireball/fireballs.cpp |
| Fonts.tbl* | /graphics/font.cpp |
| Game_settings.tbl* | /mod_table/mod_table.cpp |
| Glowpoints.tbl* | /model/modelread.cpp |
| Help.tbl* | /gamehelp/contexthelp.cpp |
| Hud_gauges.tbl* | /hud/hudparse.cpp |
| Icons.tbl* | /mission/missionbriefcommon.cpp |
| Iff_defs.tbl* | /iff_defs/iff_defs.cpp |
| Keywords.tbl* | Not In Codebase |
| Lighting_Profiles.tbl* | /lighting/lighting_profiles.cpp |
| Lightning.tbl* | /nebula/neblightning.cpp |
| Mainhall.tbl* | /menuui/mainhallmenu.cpp |
| Medals.tbl* | /stats/medals.cpp |
| Messages.tbl* | /mission/missionmessage.cpp |
| Mflash.tbl* | /weapon/muzzleflash.cpp |
| Music.tbl* | /gamesnd/eventmusic.cpp |
| Nebula.tbl* | /nebula/neb.cpp |
| Objecttypes.tbl* | /ship/ship.cpp |
| Options.tbl* | Not In Codebase |
| Particle effects(-part.tbm)** | /particle/effects... |
| Post_processing.tbl | /graphics/gropenglpostprocessing.cpp |
| Props.tbl* | /props/props.cpp |
| Rank.tbl* | /stats/scoring.cpp |
| Scpui.tbl* | Not In Codebase |
| Scripting.tbl* | /parse/scripting.cpp |
| Ships.tbl* | /ship/ship.cpp |
| Sexps.tbl** | /parse/sexp/sexp_lookup.cpp |
| Sounds.tbl* | /gamesnd/gamesnd.cpp |
| Species_defs.tbl* | /species_defs/species_defs.cpp |
| Species.tbl* | /menuui/techmenu.cpp |
| Ssm.tbl* | /hud/hudartillery.cpp |
| Stars.tbl* | /starfield/starfield.cpp |
| Strings.tbl* | /localization/localize.cpp |
| Tips.tbl* | /menuui/playermenu.cpp |
| Traitor.tbl* | /stats/scoring.cpp |
| Tstrings.tbl* | /localization/localize.cpp |
| Virtual_pofs.tbl* | /model/modelreplace.cpp |
| Weapon_expl.tbl* | /weapon/weapons.cpp |
| Weapons.tbl* | /weapon/weapons.cpp |
The lens_flares.tbl defines physically-based lens systems used to render camera lens flares for suns. Added in FS2 Open, 26.1.
Unlike the sprite-based $Flare: effect defined in Stars.tbl, a lens system is described the way a real lens is: as a stack of glass surfaces. The engine traces that stack at table load and derives everything the flare needs from it, so the ghosts, their colours and the starburst all follow from the optics rather than from hand-placed sprites.
A mission mounts exactly one of these as its camera lens, because there is one camera: every sun in the background flares through the same glass, so the flares of two suns can never disagree about the lens they came from. The lens is chosen with $Camera Lens: in the mission info section (see #Using a lens), falling back to the $Default Lens: this table declares; a mission can also opt out explicitly with <none>. A mission with no lens mounted is completely unaffected, which is what the shipped table defaults to, so retail and existing content keeps the retail look until a mod opts in.
While a lens is mounted, the legacy sprite $Flare: of Stars.tbl is not drawn at all, since the lens models the same artifact properly.
FreeSpace Open ships a default lens_flares.tbl built into the engine, so the lens systems listed under #Default lens systems are always available even when no table file is present.
This table is one of the Modular Tables and can be extended with xxx-lens.tbm
General Format
- The table consists of a single section
- Begins with #Lens Systems
- May be followed by $Default Lens:, then by any number of lens systems, each beginning with $Name:
- Must be closed with #End
- A lens system in a .tbm that reuses the $Name: of an existing one replaces it completely, rather than adding a second lens of the same name
- Entries must appear in the order listed on this page. Options are read in sequence, so an option placed out of order is skipped, and one placed after the surface list will abort the parsing of the whole table
- Within a lens system, every option except $Name: is optional and falls back to the default given below
Table options
- $Default Lens:
- The lens mounted by missions that do not name one themselves with $Camera Lens:, and what the <default> argument of set-camera-lens restores
- Appears once, directly after #Lens Systems and before the first $Name:
- The shipped table leaves this unset, so no mission gets a flare until either the mission or a .tbm asks for one. Setting it in a xxx-lens.tbm is how a mod puts its whole campaign on the same glass with a single line
- The name is resolved after every table has been read, so it may name a lens declared later in the same table, or in a different table altogether. A later .tbm that sets it again replaces the earlier value
- Syntax: String, default is (empty — no lens)
Lens system options
- $Name:
- The name used to refer to this lens system from $Camera Lens: in a mission, from $Default Lens: above, and from the lens SEXPs
- Begins a new lens system
- Syntax: String
- $Entrance Pupil Radius:
- Radius of the front element, in millimetres. For a real design this is the focal length divided by twice the f-number
- Controls how large the ghosts are and how much light the lens gathers
- Syntax: Float, default is 10.0
- $Aperture Radius:
- Half-opening of the iris, in millimetres
- This is the setting that decides whether a ghost is lit at all: each ghost slides across the iris as the sun moves off-axis, by an amount that grows with the field angle and shrinks with this value, and a ghost that slides off the iris goes black. Too small a value confines the whole flare to a sun near the centre of the frame; too large a one shrinks the ghosts within the iris until the blades stop shaping them
- The physical value is the paraxial marginal-ray height where it crosses the $Stop:. The shipped lenses use 1.25x that
- Syntax: Float, default is 5.0
- $Sensor Width:
- Width of the film gate, in millimetres. 36.0 is a full 35mm frame
- Together with the focal length the engine derives from the surfaces, this sets how far the ghosts travel as the sun moves off-axis
- Syntax: Float, default is 36.0
- $Anamorphic Squeeze:
- Stretches every ghost and the starburst horizontally, giving the oval ghosts of the anamorphic look. 1.0 is an ordinary spherical lens; 2.0 matches a classic 2x anamorphic. Values below 1.0 compress instead of stretching, which is not what the option is for and can thin a tightly focused ghost below a pixel
- A front anamorphic attachment is an afocal cylindrical telescope, so to first order all it does is magnify one meridian. That is why a whole anamorphic lens is one number here rather than a second set of surfaces, and why the iris behind it is unaffected — the aperture, its mask and the starburst shape are all still the ones described below
- Only the footprints stretch: ghosts stay on the sun exactly where they were, which is what a desqueezed anamorphic frame shows. FSO composes the frame directly and has no desqueeze stage, so treat this as a look control rather than a simulated 2x capture pipeline
- Costs nothing: it is applied as the flare is drawn, so unlike the aperture settings it forces no texture rebuild
- Syntax: Float, default is 1.0
- $Anamorphic Streak:
- The long horizontal flare a cylindrical element throws across the frame, and the other half of the anamorphic look. On its own $Anamorphic Squeeze: only ever widens things; the streak is what actually reads as anamorphic, because a real one runs 20-50 times longer than it is thick
- It is a separate effect from the starburst, not a stretched one: the starburst is the iris seen end-on and swings around as the sun moves, while the streak lies along the cylindrical element and so stays horizontal wherever the sun is
- Like the aperture imperfections it is off by default, and it needs no texture rebuild
- Syntax: Float, strength; default is 0.0 (off)
- +Length:
- Half-length as a fraction of the sensor width. 1.0 spans the frame
- Syntax: Float, default is 1.0
- +Thickness:
- As a fraction of the length, so 0.02 gives a 50:1 bar
- Syntax: Float, default is 0.02
- +Tint:
- Multiplied onto the sun's own colour rather than replacing it, so a red sun keeps a reddish streak
- The default leans blue, which is where the classic look comes from — real streaks take their colour from the coating on the cylindrical element
- Syntax: ( Float, Float, Float ), default is ( 0.35, 0.55, 1.0 )
- $Coating Wavelength:
- Wavelength in nanometres that the anti-reflection coating is tuned to, as a quarter-wave layer
- 500-570 (green-centred, like real broadband coatings) gives the classic magenta and cyan ghost tints. 0 disables coatings entirely for an uncoated vintage look: much brighter, neutral grey ghosts
- Can be overridden per surface with +Coating Wavelength:
- Syntax: Float, default is 540.0
Aperture
A lens has exactly one aperture, and it drives both the ghosts and the starburst: every ghost is an image of the iris, and the starburst is that same image's diffraction pattern. Changing a blade count therefore restyles both at once.
- $Aperture Blades:
- Number of iris blades. Fewer than 3 gives a perfectly round iris
- Syntax: Integer, default is 6
- +Blade Rotation:
- Rotation of the iris, in degrees
- Syntax: Float, default is 0.0
- +Blade Curvature:
- How the blades bow. 0 leaves them straight, 1 bows their midpoints out to the corner radius for a circular iris, and negative values bow them inward into a star
- Syntax: Float, -1.0 to 1.0, default is 0.0
- +Edge Softness:
- Feathering of the iris edge, as a fraction of the iris radius
- The default is also the floor the engine clamps to (about a two pixel ramp, so the mask never aliases), so asking for less has no effect. Softening the edge visibly weakens the starburst spikes, because those come from the sharpness of that edge
- Syntax: Float, default is 0.0039
Aperture imperfections
Three optional layers darken the iris on top of the blade shape, for a dirty or damaged lens. All are off by default, and each takes its strength on the $-line followed by optional + sub-options.
Note that the starburst is normalized against its own brightest value, so these layers dim the core spikes as they add speckle around them, rather than only adding to what was already there.
- $Aperture Grating:
- A diffraction grating around the rim of the iris: radial ridges that throw extra spikes into the starburst
- Syntax: Float, 0.0 to 1.0, strength; default is 0.0 (off)
- +Density:
- Fraction of the 360 possible ridges
- Syntax: Float, 0.0 to 1.0, default is 0.5
- +Length:
- How far in from the rim the ridges reach, as a fraction of the iris radius
- Syntax: Float, 0.0 to 1.0, default is 0.5
- +Width:
- Ridge width, as a duty cycle of the spacing between neighbouring ridges. Because it is relative, raising +Density: thins the ridges rather than merging them into a solid ring
- Syntax: Float, 0.0 to 1.0, default is 0.25
- +Softness:
- Syntax: Float, default is 0.0
- $Aperture Scratches:
- Scratches on the glass: randomly placed slivers
- Syntax: Float, 0.0 to 1.0, strength; default is 0.0 (off)
- +Density:
- Fraction of the 1000 possible scratches
- Syntax: Float, 0.0 to 1.0, default is 0.5
- +Length:
- Syntax: Float, 0.0 to 1.0, default is 0.5
- +Width:
- Syntax: Float, 0.0 to 1.0, default is 0.25
- +Rotation:
- Direction the scratches run, in degrees
- Syntax: Float, default is 0.0
- +Rotation Variation:
- 0 leaves every scratch parallel, 1 scatters them completely
- Syntax: Float, 0.0 to 1.0, default is 0.0
- +Softness:
- Syntax: Float, default is 0.0
- $Aperture Dust:
- Dust on the glass: randomly placed specks
- Syntax: Float, 0.0 to 1.0, strength; default is 0.0 (off)
- +Density:
- Fraction of the 1000 possible specks
- Syntax: Float, 0.0 to 1.0, default is 0.5
- +Radius:
- Syntax: Float, 0.0 to 1.0, default is 0.5
- +Softness:
- Syntax: Float, default is 0.0
Starburst and brightness
- $Starburst:
- Whether this lens draws the diffraction starburst around the suns themselves. For each sun that gets one, the sun's own bitmap and glow are skipped so the two do not stack. A sun the flare pass does not reach keeps its ordinary bitmap and glow — one that is occluded, one outside the flare's reach, and every sun in an environment map, since those are rendered without the post-processing pass that draws the starburst
- Syntax: Boolean, default is YES
- +Starburst Scale:
- Size of the starburst relative to the frame
- Syntax: Float, default is 1.0
- $Intensity:
- Overall brightness of this lens's flare
- This is the artistic control, and it is best set by comparing against the shipped lenses in the lab. An uncoated lens ($Coating Wavelength: 0) reflects far more light and needs a much smaller value to stay in the same range
- Syntax: Float, default is 0.2
- $Max Ghosts:
- How many of the brightest ghosts to draw. A lens with many elements can produce several hundred, so this caps the cost
- Values above 63 are clamped to 63
- Syntax: Integer, default is 40
Optical prescription
The rest of the entry is the lens itself: an ordered list of the surfaces light passes through, front element first. Every ordered pair of surfaces produces one ghost, so the number and arrangement of surfaces is what gives a lens its character.
These numbers are "lens prescriptions" as published in lens patents and optical design references, and can be transcribed directly, one element per $Surface: row. Scaling all radii and thicknesses by the same factor changes the focal length. The engine derives the focal length, the sensor distance, the ghost list and each ghost's brightness and tint from this stack at table load.
- $Surface:
- One spherical glass surface
- Syntax: ( Float, Float, Float ) — curvature radius in millimetres, distance to the next surface in millimetres, and refractive index of the glass behind the surface (1.0 being air)
- A positive radius means the surface bulges toward the front of the lens, with its centre of curvature behind it; a negative radius bulges toward the sensor; 0 is a flat surface
- The distance on the last surface is ignored: the engine places the sensor at the focus it computes
- +Abbe:
- Abbe V-number of the glass behind the surface, which sets how much it disperses. Crown glasses are around 55-60, dense flints around 30-40. This only drives the chromatic fringing of the ghosts, so approximate values are fine
- Syntax: Float, default is 0.0 (no dispersion)
- +Coating Wavelength:
- Overrides $Coating Wavelength: for this surface alone
- Syntax: Float, defaults to the lens's own value
- $Stop:
- Marks the iris plane. It does not refract or reflect; it is where the aperture sits in the stack
- Syntax: ( Float ), distance to the next surface in millimetres
- A lens without a $Stop: uses its middle surface as the aperture plane
A lens system needs at least two surfaces, and its prescription must actually form an image. One that does not (for instance an afocal stack) is dropped with a warning at table load and cannot be referenced.
Using a lens
- Mount a lens on a mission with $Camera Lens: in its info section (as in
$Camera Lens: tessar_50mm), naming a lens system from this table. It sits alongside $Lighting Profile: and is the same kind of setting: one global render choice belonging to one mission- The option takes a lens name, or one of two tokens in place of one: <none> for no flares at all, and <default> for the table's $Default Lens:. These are the same values set-camera-lens accepts
- A mission that omits the option entirely gets the table's $Default Lens:, which is what keeps existing content unaffected. An unknown name warns and falls back to that default as well — only <none> turns the flares off, so that a typo can never silently read as "this mod wanted none"
- Both FRED and qtFRED expose it as a Camera lens drop-down in the background editor. Default leaves the mission silent so it follows the table, None writes <none> — these are different answers whenever a $Default Lens: is declared, and the drop-down keeps them apart so a saved mission never loses an explicit "no flares"
- Every visible sun in the background flares through the mounted lens — there is no per-sun setting on the lens. What differs between suns is only where each one sits in the frame and how bright it is
- A sun only flares if its Stars.tbl entry says so. The sun entry decides whether a sun flares and the mounted lens only decides how it is drawn, so mounting a lens never invents flares on suns that were deliberately tabled without one. A sun that does not ask keeps its ordinary bitmap and glow and gets nothing from the lens
- +Camera Lens Flare: (boolean) is the direct way to say it. It goes in the $Sun: entry, after any $Flare: block and before $NoGlare:
- With the option absent, a legacy sprite $Flare: block stands in for it, since that was the only way to declare a flare before the option existed — so tables written earlier keep working untouched. Where both are present the option wins, which is the only way to keep a sun's sprite flare while leaving it out of the physically-based one
- This matters because $Flare: is expensive to write: it requires a full set of sprite fields (+FlareCount:, $FlareTexture1:, $FlareGlow1: and so on) that are never drawn while a lens is mounted. +Camera Lens Flare: YES opts a sun in on its own, with none of them
- Retail's stars.tbl declares no $Flare: at all. The MediaVPs add one to the six standard suns (SunWhite, SunRed, SunGreen, SunBlue, SunGold, SunViolet) and to many of the named stars, but not all of them — so if a background's sun shows no flare with a lens mounted, check its sun entry first, and add +Camera Lens Flare: YES in a -str.tbm to opt it in
- Missions can swap the lens and edit the iris at runtime with the lens SEXPs
- The F3 lab (Render options -> Lens flare options) can override the mission's lens and adjust every aperture setting live, which is the practical way to dial in $Intensity:, the anamorphic settings and the imperfection layers. It also exposes the global ghost and starburst brightness calibration and the HDR headroom, reports the mounted lens's ghost count, computed focal length and f-number, and lists what the last flare pass actually drew for each sun (visibility, off-axis angle, instance count). Lab edits are undone the same way mission edits are
- The flare is suppressed in full-nebula missions, in subspace, in VR, when post-processing is disabled, and when the Planets/Backgrounds detail setting is off
SEXPs
- set-camera-lens — mount a different lens system. Also accepts <none> for no flares at all and <default> for the table's $Default Lens:
- set-lens-aperture — blade count, rotation, curvature and edge softness
- set-lens-grating, set-lens-scratches, set-lens-dust — the imperfection layers
The four aperture operators take no lens argument: they restyle the iris of whatever lens is mounted, so a mission cannot edit a lens it is not looking through. With no lens mounted they do nothing and warn — use set-camera-lens first.
Note that these operators take percentages (0 to 100) and whole degrees where the table takes fractions (0.0 to 1.0) and floats; +Blade Curvature: 0.3 in the table is an argument of 30 to set-lens-aperture.
Both the mounted lens and any iris edits are undone when the mission ends, so nothing carries into the next mission. These operators are not sent over the network, so in multiplayer they only affect the host.
The lens name given to set-camera-lens is validated when the mission loads, and a name that does not resolve aborts the load. This is safe because lens_flares.tbl is an engine default — the built-in lenses always resolve — but a mission naming a lens from a xxx-lens.tbm must ship with that .tbm.
Default lens systems
The built-in table ships eight lens systems, transcribed from published patents. All of them are spherical designs that leave the imperfection layers and both anamorphic options off — for an anamorphic look, set $Anamorphic Squeeze: and $Anamorphic Streak: on one of these in a xxx-lens.tbm.
- angenieux_100mm — double-Gauss cine prime, f/2.2. The reference prescription from the research this renderer is based on, and the lens the others are calibrated against
- tessar_50mm — classic Tessar, f/3.5. Few elements, so a sparse and subtle ghost set
- canon_70_200mm — modern multicoated telephoto zoom, f/2.8. The busiest shipped lens: a dense, strongly tinted ghost train
- kodak_100mm — symmetric double Gauss, f/3.8, single-coated. A sparse, orderly ghost set that stays stable as the sun moves off-axis
- leica_35mm — fast aspherical wide-angle prime, f/1.4. The shortest focal length shipped, so its ghosts sweep the furthest
- nikon_50_135mm — multicoated telephoto zoom, f/3.5
- color_heliar_105mm — uncoated vintage prime, f/3.5. The uncoated reference: few, large, colourless, obvious ghosts
- zeiss_master_prime_50mm — modern multicoated cine prime, T1.3. Many large, bright, strongly tinted ghosts; the closest to a contemporary cinema look
Sample
#Lens Systems ; Classic Tessar, f/3.5, f=50mm, with a little dust on the front element. $Name: tessar_50mm $Entrance Pupil Radius: 7.0 $Aperture Radius: 5.0 $Sensor Width: 36.0 $Coating Wavelength: 520 $Aperture Blades: 8 +Blade Rotation: 0.0 +Blade Curvature: 0.3 $Aperture Dust: 0.4 +Density: 0.3 +Radius: 0.25 $Starburst: YES +Starburst Scale: 0.8 $Intensity: 0.2 $Max Ghosts: 24 $Surface: ( 16.25, 2.90, 1.6116 ) +Abbe: 56.9 $Surface: ( -285.90, 0.29, 1.0 ) $Surface: ( -30.05, 1.20, 1.6053 ) +Abbe: 43.6 $Surface: ( 17.47, 1.38, 1.0 ) $Stop: ( 1.15 ) $Surface: ( 31.55, 1.20, 1.5123 ) +Abbe: 51.0 $Surface: ( 21.30, 3.50, 1.6116 ) +Abbe: 56.9 $Surface: ( -23.70, 40.0, 1.0 ) #End
To use it, name it from the info section of a mission (or pick it in the background editor, which writes the same line):
$Camera Lens: tessar_50mm
To put a whole campaign on it instead, without touching a single mission, declare it as the default in a xxx-lens.tbm:
#Lens Systems $Default Lens: tessar_50mm #End