Aetheria release: hull materials as owned graphs
Blender-authored material graphs judged by AetherDb into a catalog record, lowered to a CultMath expression IR, generated into compute kernels and baked per (hull, livery) with per-ship wear only. Body facts M19-M25 (Blender pin, Cycles point oracle, dump, interpreter bench, compute substrate, faction key clash, CultMath seams), the authority map, parity chain, tape relation, cuts and rationale. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
97bf1b8e03
commit
b643b0a464
1 changed files with 449 additions and 0 deletions
|
|
@ -947,6 +947,8 @@ image whose pixels are `(0.5, 0.25, 1.0, 0.5)`, saved as PNG.
|
|||
|
||||
#### The hull material model
|
||||
|
||||
*Superseded in part by "Hull materials as owned graphs" below: the mask semantics, `HullPaint`, the shader rules and the livery resolution. Kept as the record of revision 2.*
|
||||
|
||||
**What a package carries.**
|
||||
- **The GLB's core PBR slots,** baked by the operator onto her clean UV0:
|
||||
- base colour;
|
||||
|
|
@ -1055,6 +1057,8 @@ The texture cap stays because it bounds runtime memory.
|
|||
|
||||
#### Cuts
|
||||
|
||||
*Revised by "Hull materials as owned graphs" below: `ships-hull-material` r3, `ships-addon-paint` r3 and `ships-hull-livery` r2 replace the revisions named here.*
|
||||
|
||||
- **`ships-hull-material` r2:** the shader, the generator, `HullPaint` with
|
||||
`Mask`, the mask's PNG checks in `Bind`, the linear DXT5 load and `ApplyPaint`.
|
||||
- **`ships-hull-livery` r1** (unchanged): `Faction.Livery`. It waits on
|
||||
|
|
@ -1126,6 +1130,451 @@ over. Each `ships-addon-*` operator check asks which helper earned its place.
|
|||
- A radiator's faces are drawn with the radiator material. Leaving them in the hull
|
||||
would draw the surface twice.
|
||||
|
||||
### Hull materials as owned graphs
|
||||
|
||||
This section designs the hull material system as one piece. It replaces the
|
||||
mask semantics, the `HullPaint` shape, the shader rules and the livery
|
||||
resolution of "The hull material model" above. M13 to M18 and the per-hull steps
|
||||
stand, except P6, which is restated below.
|
||||
|
||||
The operator's words, in order:
|
||||
1. `hull-runtime-materials`: "we want more runtime material control than just a
|
||||
single baked map. See how MechWarrior does it".
|
||||
2. `hull-paint-mask-texture`: "I want a mask map per ship for livery, I'll be
|
||||
rebuilding the nonsense geometry and unwrapping anyway".
|
||||
3. `mask-channels-place-materials`: "If each channel determines placement of one
|
||||
material, then factions can fly their colors by setting parameters on those
|
||||
hull materials (primary, secondary, trim) and we'd ship eventual faction skins
|
||||
as their own material map... If we also want procedural wear and buildup, we
|
||||
can bake input maps for that, too."
|
||||
4. `clean-break-from-substance`: "Let's make a clean break from substance, it's
|
||||
dead".
|
||||
5. Not yet a ruling: "Authoring materials as graphs in blender is pretty
|
||||
intuitive, if we're owning material generation, could we not set things up so
|
||||
that we can evaluate the same graph?"
|
||||
6. Not yet a ruling: "We may not be allowed to pull blenders math into our
|
||||
runtime, but nothing prevents us from putting our math in blender".
|
||||
7. `materials-baked-per-ship-incremental`: "triggering texture bakes per ship
|
||||
only when they spawn or change, and then also only recomputing the parts of
|
||||
the graph that change, which would be just wear for most dynamic changes".
|
||||
8. `shaders-own-every-pixel`: "our shaders own every pixel".
|
||||
|
||||
Surveys: `F:\Projects\blender-graph-runtime-prior-art.md`,
|
||||
`F:\Projects\aetheria-texture-graph-prior-art.md` and
|
||||
`F:\Projects\aetheria-hull-materials-prior-art.md` (Eyes, 2026-10-03). Anchors are
|
||||
against Aetheria `239f3599` (origin/master, which contains `ships-mounts` and the
|
||||
render fixes) and CultLib `a7966142`. Probe scripts are in this pass's scratch
|
||||
(`matprobe/probe_bake.py`, `probe_dump.py`, `bench/Program.cs`).
|
||||
|
||||
#### Body facts
|
||||
|
||||
**M19. The operator's Blender is 5.2.2 LTS from Steam, and Steam updates it.**
|
||||
- `C:\Program Files (x86)\Steam\steamapps\common\Blender\blender.exe` reports
|
||||
`5.2.2 LTS`, build hash `d13f752e3b9c`, built 2026-09-15. It is the only
|
||||
Blender in the uninstall registry. A stale 5.0.1 sits in
|
||||
`D:\Steam\SteamApps\common\Blender`.
|
||||
- Steam replaces the build when a new one ships. Node semantics changed in 5.0
|
||||
(Voronoi hashing), so a silent update can move her previews away from the game.
|
||||
|
||||
**M20. A Cycles Emit bake is an exact point oracle.** Probe `probe_bake.py`,
|
||||
Blender 5.2.2, a 64×64 float input image of coordinates read with Closest
|
||||
interpolation into a graph, baked by Emit into a 64×64 float image (margin 0):
|
||||
|
||||
| Probe | CPU | OptiX (GTX 1070) |
|
||||
|---|---|---|
|
||||
| P1 identity: the input texel reads back | 4096/4096 exact | 4096/4096 exact |
|
||||
| P2 `a*b + c` in two Math nodes | 4096/4096 equal float32 `(a*b)+c`; fused would differ at 1011 | same |
|
||||
| P3 CultMath's float-only `mod289((x*34+10)*x)` as Math nodes | 4096/4096 exact | 4096/4096 exact |
|
||||
| P4 Noise Texture (3D, detail 0): two bakes | bit-identical; 0.5 at integer points | bit-identical |
|
||||
| P5 an OSL Script node (`In[0]*3+1`) in the bake | 4096/4096 within 1e-6 | no result: killed after 4.5 minutes, apparently compiling OSL |
|
||||
|
||||
- CPU and OptiX noise agree at 2,764 of 4,096 texels, at most 1.19e-7 apart
|
||||
(1 ulp near 1). Arithmetic agrees bit for bit. So the oracle is CPU Cycles,
|
||||
and noise parity is a ULP tolerance, never bit equality, once a GPU is in the
|
||||
chain.
|
||||
- Cycles' CPU kernels do not contract multiply-add (P2), so float-only
|
||||
arithmetic is reproducible from C#.
|
||||
|
||||
**M21. The add-on can dump a node group faithfully.** Probe `probe_dump.py`,
|
||||
Blender 5.2.2:
|
||||
- Group interfaces have panels. A socket reports its panel, type, default,
|
||||
min, max and a stable identifier (`Socket_3`). Panels are typed structure, so
|
||||
a socket's scope (Livery, Ship, Maps) needs no name parsing.
|
||||
- `ColorRamp.evaluate(t)` and `CurveMapping.evaluate(curve, t)` run in Python,
|
||||
so ramps and curves export as sampled tables in Blender's own evaluation (a
|
||||
B-spline ramp gives 0.1667, not 0, at t = 0).
|
||||
- A group instance is `ShaderNodeGroup` with `node_tree`. Mix exposes
|
||||
`data_type`, `blend_type` and both clamps. Noise exposes dimensions, type and
|
||||
normalize. Math has 41 operations.
|
||||
- Shader nodes have no Bit Math or Integer Math in 5.2.2.
|
||||
`FunctionNodeBitMath` exists for geometry nodes only. PCG hashes cannot be
|
||||
built in shader nodes.
|
||||
|
||||
**M22. A C# tape interpreter is cheap for arithmetic and slow for noise.**
|
||||
Probe `bench`, .NET 10 RyuJIT on Starfire (Ryzen 3 3100, 4 cores), a scalar SSA
|
||||
tape interpreted over 256-texel batches at 2048²:
|
||||
- 154 arithmetic instructions: 788 ms on one thread (1.2 ns per
|
||||
instruction-texel).
|
||||
- Adding 24 CultMath `snoise(float3)` calls: 23.5 s on one thread, 7.1 s on four
|
||||
(about 230 ns per noise call per texel).
|
||||
- Unity runs Mono, which is slower than RyuJIT. That was not measured.
|
||||
|
||||
A full-resolution noise graph costs seconds per bake on the CPU. Aetheria
|
||||
already dispatches compute shaders at runtime (M23), where the same work takes
|
||||
milliseconds.
|
||||
|
||||
**M23. Aetheria's compute and CultMath substrate.**
|
||||
- Runtime compute already ships: `ShieldPanel.cs:293-439` dispatches
|
||||
`ShieldSim.compute`; Stardust, Slime and Lightning have compute kernels under
|
||||
`Assets/Shaders/Compute/`.
|
||||
- `Packages/manifest.json:57` pins `org.gamecult.cultmath` at
|
||||
`cultmath-unity-v0.2.4`. CultLib has tagged `cultmath-unity-v0.3.0`.
|
||||
`Aetheria.Shared.csproj:27` compiles CultMath from source.
|
||||
- No Shader Graph or SRP package is in the manifest.
|
||||
|
||||
**M24. Faction key 16 is taken twice.** `ships-hull-livery` r1 puts `Livery` at
|
||||
`Faction` key 16. Rulings `faction-relations-field` and `faction-doctrine-typed`
|
||||
put Relations at 16 and Doctrine at 17. `Corporations.cs` uses keys up to 15.
|
||||
The livery takes key 18.
|
||||
|
||||
**M25. CultMath's seams for new shader code.**
|
||||
- `CultMath.hlsl:509-510` includes Phacelle and Interval.
|
||||
- `GlslLowering.SeparateFiles` (`GlslLowering.cs:19-24`) lowers a
|
||||
separately-licensed include into its own GLSL file. Its one entry is MPL-2.0
|
||||
Phacelle.
|
||||
- C# has `asuint` and `asfloat` (`math.cs:390-391`) but no `uint2/3/4` types.
|
||||
Cycles' hashes are scalar `uint`, so they port without new vector types.
|
||||
|
||||
#### The system in brief
|
||||
|
||||
```
|
||||
Blender (author, preview) AetherDb (judge) Aetheria.cc
|
||||
node group "Hull Standard" --> material-graph put ----------> MaterialGraph record
|
||||
+ per-hull wrapper material whitelist, contract, cones (truth)
|
||||
|
|
||||
v lowering (Aetheria.Shared)
|
||||
CultMath expression IR --> HLSL kernels: pair, frontier, wear
|
||||
| (generated, committed, dxc-checked)
|
||||
v reference evaluator (C#, tests only)
|
||||
Unity: MaterialBakes -- dispatch per (hull, livery) and per wear set --> baked textures
|
||||
Aetheria/Hull -- samples Surface, Worn, Wear, plus the GLB's normal, occlusion, emission
|
||||
```
|
||||
|
||||
**A material graph is one per-texel function:**
|
||||
- **Inputs:**
|
||||
- image roles sampled on UV0 from two package PNGs:
|
||||
- `ship.mask.png`: R, G, B place the primary, secondary and trim materials; A is
|
||||
an authored wear hint.
|
||||
- `ship.maps.png`: R ambient occlusion, G curvature (0.5 flat), B cavity, A grunge.
|
||||
- parameters in two scopes. Livery parameters are set per faction, with a
|
||||
factory default per hull. Ship parameters are set per ship, such as wear level.
|
||||
- **Outputs**, a closed vocabulary:
|
||||
- Surface Color, Surface Metallic and Surface Roughness: the finished livery;
|
||||
- Worn Color, Worn Metallic and Worn Roughness: what wear reveals;
|
||||
- Wear, from 0 to 1.
|
||||
|
||||
**Authoring in Blender.**
|
||||
- A library `.blend` holds node groups built from whitelisted nodes. The interface
|
||||
panels are `Livery`, `Ship` and `Maps`. A Maps socket's name is a role from the
|
||||
closed vocabulary.
|
||||
- The per-hull material her add-on sets up is a wrapper:
|
||||
- the group instance;
|
||||
- Image Texture nodes for her mask and maps;
|
||||
- a preview that mixes Surface and Worn by Wear into a Principled BSDF, the same
|
||||
combination the game's shader makes.
|
||||
- The wrapper is display only. Only the group is exported.
|
||||
|
||||
**The release whitelist** is Blender's primitive and converter nodes, with
|
||||
Cycles semantics ported into CultMath:
|
||||
- Math (all 41 operations), Vector Math (component-wise operations), Clamp,
|
||||
Map Range (Float, all four modes);
|
||||
- Mix (Float, Vector, and Color with every blend mode);
|
||||
- Color Ramp and Float Curve, as tables sampled in Python;
|
||||
- Separate and Combine XYZ and Color (RGB mode), RGB to BW, Invert;
|
||||
- Value, RGB, Reroute, Frame, Group Input and Output, and nested groups (flattened).
|
||||
|
||||
Procedural textures (Noise, White Noise, Voronoi, Wave, Gradient) follow the
|
||||
release, as question `release-procedural-noise` proposes. Per ruling 3, release
|
||||
wear comes from baked maps. Grunge is baked into `ship.maps.png` A.
|
||||
|
||||
**Bakes, dirty sets and the memory budget.**
|
||||
- The judge computes each output's cone (the nodes it reads) and each node's
|
||||
scope: hull (reads only images), livery, or ship. Surface and Worn cones may
|
||||
not read a Ship parameter; the judge refuses that. So every per-ship cost is
|
||||
the Wear output alone.
|
||||
- The **frontier** is the set of values in Wear's cone that read no Ship
|
||||
parameter but feed one that does. At most four scalars, or the judge refuses
|
||||
the graph, so they fit one RGBA16F texture.
|
||||
- Three kernels per graph, generated from the record:
|
||||
- **pair**: Surface at R and Worn at R/2, for each (hull, skin, livery). R is
|
||||
2048 by default and 1024 at low quality.
|
||||
- **frontier**: the frontier values at wear resolution, once per pair.
|
||||
- **wear**: only the ship-scope nodes of Wear's cone, reading the frontier,
|
||||
per distinct set of Ship parameters.
|
||||
- A Ship parameter change re-runs only the wear kernel. That is ruling 7: cost
|
||||
in proportion to the nodes that changed. A livery change is a different pair.
|
||||
- Caches are content-addressed. A pair key hashes the graph record, both PNGs,
|
||||
the skin, the livery bindings and R. A wear key hashes the pair key and the
|
||||
Ship parameter values, quantised to 1/64. Ships with identical inputs share
|
||||
every texture. Entries are refcounted by live bodies and released at zero.
|
||||
- Budget, at R = 2048, with BC1 (DXT1) through `Texture2D.Compress` after an async
|
||||
readback:
|
||||
|
||||
| Texture | Per | Size with mips |
|
||||
|---|---|---|
|
||||
| Surface Color and Surface MR (R metal, G roughness) | pair | 2 × 2.7 MiB |
|
||||
| Worn Color and Worn MR at 1024² | pair | 2 × 0.67 MiB |
|
||||
| Frontier, 512² RGBA16F, no mips | pair | 2 MiB |
|
||||
| Wear, 512² R8 | wear set | 0.33 MiB |
|
||||
|
||||
- That is about 8.7 MiB per pair and 0.33 MiB per ship. At R = 1024 a pair is
|
||||
about 2.6 MiB.
|
||||
- A zone with 20 ships in 6 (hull, livery) pairs holds about 59 MiB. Per-ship
|
||||
full bakes would hold about 320 MiB.
|
||||
- Each bake also needs about 70 MiB of transient upload and render textures,
|
||||
released once its readback completes.
|
||||
- Until the compressed copy exists, the ship samples the render textures directly.
|
||||
|
||||
**The runtime shader.**
|
||||
- `Aetheria/Hull` is `GlowFade`'s surface shader: the same `noambient` volumetric
|
||||
ambient, the same dither fade by `_Fade` and the same edge colour.
|
||||
- The albedo, metallic and roughness are `lerp(Surface, Worn, Wear)`. The normal,
|
||||
occlusion and emission come from the GLB's slots.
|
||||
- It has no paint logic, no keywords beyond GlowFade's own, and nothing evaluated
|
||||
per frame but that one lerp. The lerp is fixed by the output contract.
|
||||
|
||||
**The livery.**
|
||||
- `HullPaint` (ShipAuthoring key 5) names:
|
||||
- the graph;
|
||||
- the two PNGs;
|
||||
- the factory livery: bindings of the graph's Livery parameters.
|
||||
- `Faction.Livery` (key 18) holds bindings of the same parameters and wins over the
|
||||
factory livery when that faction flies the hull. `HullPaint.Resolve` is the one
|
||||
resolution.
|
||||
- A binding names a parameter by its interface identifier. The catalog test checks
|
||||
every binding against the graph: it must exist, be in scope and be in range.
|
||||
- Faction skins (another mask per hull) are a later key on `HullPaint`, chosen by
|
||||
the livery.
|
||||
|
||||
#### Authority map
|
||||
|
||||
- **Owner.** The `MaterialGraph` record in `Aetheria.cc` owns what a hull material
|
||||
computes. CultMath owns what each node means: Cycles semantics ported once, in
|
||||
HLSL with a C# mirror. `MaterialBakes` owns when and at what resolution a graph
|
||||
is evaluated. `HullPaint.Resolve` owns which livery a body shows.
|
||||
`Aetheria/Hull` owns how the three outputs and the GLB slots become a pixel.
|
||||
- **Inputs.**
|
||||
- The judge reads the Blender dump.
|
||||
- The lowering reads the record.
|
||||
- `MaterialBakes` reads:
|
||||
- the generated kernels;
|
||||
- the package PNGs;
|
||||
- the resolved livery;
|
||||
- the body's Ship parameters.
|
||||
- **Outputs.** The record; the generated kernels; the baked textures per pair and
|
||||
per wear set; one property block per hull renderer.
|
||||
- **Derived state.**
|
||||
- The kernels are derived from the record and committed. A test fails when they
|
||||
differ from the lowering.
|
||||
- Baked textures are cache only.
|
||||
- The Blender wrapper and its preview are display only.
|
||||
- Cones, scopes and the frontier are recomputed by every judge and lowering.
|
||||
- **Forbidden writers.**
|
||||
- Unity Shader Graph, Mixture and any glTF/ shader on a mod hull.
|
||||
- Any per-frame graph evaluation in the hull shader.
|
||||
- Python encoding a `MaterialGraph` or `HullPaint`.
|
||||
- Blender's GPL EEVEE (`gpu_shader_material_*`) or blenlib noise code in any
|
||||
CultLib or Aetheria file.
|
||||
- A material, role or output chosen by a name outside the closed vocabularies.
|
||||
- A second livery resolution.
|
||||
- `Faction.PrimaryColor` and `SecondaryColor`, which stay map colours.
|
||||
- **Shared paths.** Editor play, the preview smoke, the play smoke and the built
|
||||
player all bake through `MaterialBakes` from the same kernels. Every AetherDb
|
||||
path (`put`, `check`, the catalog test) judges through one `MaterialGraphJudge`.
|
||||
- **Deletion line.**
|
||||
- r2's region tint (`_PaintStrength`, `RegionLuminance`, a tiling `_WearNoise`)
|
||||
and its `Livery` of three colours are never built.
|
||||
- Revision 1's vertex mask is gone.
|
||||
- The 41 `.sbsar` files go with follow-up `remove-sbsar-files`.
|
||||
|
||||
#### Parity
|
||||
|
||||
1. **Node semantics, in CultMath.**
|
||||
- Each ported function's HLSL mirrors its C# with bit equality, through the
|
||||
existing mirror tests.
|
||||
- It compiles under dxc and lowers to GLSL through the existing
|
||||
`GlslLowering`. Each new licence file gets a `SeparateFiles` entry.
|
||||
- The C# matches a **Cycles oracle fixture**. A GPL-headed tool script, run only
|
||||
under the pinned Blender (5.2.2 LTS, hash `d13f752e3b9c`), bakes each family
|
||||
on the CPU the M20 way. It refuses any other version. The fixture records the
|
||||
version and hash.
|
||||
- Tolerance is per family: exact for arithmetic (M20 P2, P3), and a stated ULP
|
||||
bound wherever Cycles uses library transcendentals.
|
||||
2. **Lowering, in Aetheria.**
|
||||
- A test graph uses every whitelisted node and blend mode. The add-on's test
|
||||
script dumps it and bakes all seven outputs on a 64² fixture under the pinned
|
||||
Blender. The fixture (dump, inputs, outputs) is committed.
|
||||
- The test lowers the dump and runs CultMath's reference evaluator, then
|
||||
compares per output within the family tolerances.
|
||||
- This pins the node-to-function mapping. Neither side's unit tests can see that
|
||||
mapping.
|
||||
3. **Kernels.**
|
||||
- The generated HLSL is committed and must equal the lowering's output.
|
||||
- Each kernel compiles under dxc.
|
||||
- A Unity batch smoke on Starfire dispatches the fixture graph on the GPU and
|
||||
reads back. It compares with the reference evaluator within 2 ulp plus the
|
||||
family tolerance. M20 shows a GPU and a CPU Cycles already differ by 1 ulp.
|
||||
4. **Drift.**
|
||||
- The add-on stamps the Blender version into each dump.
|
||||
- The judge refuses a dump from a different major and minor version than the
|
||||
pinned semantics, naming both.
|
||||
- Updating Blender is a deliberate cut: regenerate the oracle fixtures, read the
|
||||
diff, and move the pin.
|
||||
- Before then, the operator stops Steam updating Blender, or keeps a pinned
|
||||
portable 5.2.2 for authoring.
|
||||
|
||||
#### The tape
|
||||
|
||||
The material evaluator is not a second tape if it owns no evaluation semantics.
|
||||
- It lowers into CultMath's scalar expression IR: SSA values, operations that
|
||||
are CultMath functions, named inputs, parameters and several outputs, with each
|
||||
instruction's input-dependence mask.
|
||||
- Two backends exist now: an HLSL emitter, and a reference evaluator for tests.
|
||||
- The tape target's step 2 adds bytecode with point, interval and gradient
|
||||
evaluators over the same IR. Step 4 adds an HLSL interpreter of that bytecode.
|
||||
Neither is built now. Ruling `tape-target-unparks-when-asura-stable` stands
|
||||
for both.
|
||||
- What lands now is the IR the tape will consume. Its point evaluator is only a
|
||||
test reference, not a runtime path.
|
||||
|
||||
A minimal evaluator is needed now, because ruling 7 requires bakes at spawn and
|
||||
at change, and the release hulls need faction colours (`content-bar-one-per-concept`).
|
||||
|
||||
Mod-authored graphs need the tape's GPU interpreter, because Unity cannot compile
|
||||
a shader at runtime. Until then a mod package uses the shipped graphs with its
|
||||
own PNGs and livery values: the MWO model, per the operator's ruling 3.
|
||||
|
||||
Question `material-ir-in-cultmath` asks whether this IR may land in CultMath
|
||||
while the tape stays parked.
|
||||
|
||||
#### Cuts
|
||||
|
||||
CultLib, campaign `cultmath-tapes`:
|
||||
- **`cycles-converters`.** The Cycles oracle tool and fixture harness. Ports of
|
||||
Cycles' Math, Map Range, Clamp, Mix (every blend mode), RGB to BW and ramp-table
|
||||
lookup, in an Apache-2.0 file pair.
|
||||
- **`expr-ir`.** The scalar expression IR, dependence masks, cones and frontier,
|
||||
the reference evaluator and the HLSL emitter.
|
||||
- **`cycles-noise`.** Ports of Cycles' hash, Perlin, fBM, the Noise Texture node
|
||||
and White Noise (BSD-3 and Apache file pairs). This follows the release.
|
||||
- The CultMath Unity release that ships the new HLSL is a release cut (follow-up
|
||||
`cultmath-unity-material-release`). Aetheria's Unity pin must move to it before
|
||||
`hull-bakes`, whose kernels include those files.
|
||||
|
||||
Aetheria, campaign `aetheria-release`:
|
||||
- **`material-graph`.** The record, the dump, `MaterialGraphJudge` (whitelist,
|
||||
vocabularies, scopes, the contract, the version pin), and AetherDb
|
||||
`material-graph put|check`.
|
||||
- **`material-lowering`.** Lowering to the IR, the generated kernels and their
|
||||
equality test, and the whole-graph Blender oracle.
|
||||
- **`material-library-export`.** The add-on's dumper, Export and Check calling
|
||||
AetherDb, and the library `.blend` convention.
|
||||
- **`hull-bakes`.** `MaterialBakes`: dispatch, the content-addressed tiers,
|
||||
refcounts, readback and compression, and a GPU parity smoke.
|
||||
- **`ships-hull-material` r3.** `HullPaint` reshaped, the PNG checks in Bind,
|
||||
`Aetheria/Hull`, the generator and `ApplyBakes` from `SetEntity`.
|
||||
- **`ships-addon-paint` r3.** The maps bake into `ship.maps.png`, the mask tools,
|
||||
Set Up Hull Material (the wrapper), and Package writing both PNGs and `Paint`.
|
||||
- **`ships-hull-livery` r2.** `Faction.Livery` at key 18, as bindings checked
|
||||
against the graph.
|
||||
|
||||
Order:
|
||||
- `cycles-converters`, then `expr-ir`, then the CultMath Unity release.
|
||||
- Then `material-graph` (it may start at once; it needs neither CultLib cut),
|
||||
`material-lowering`, `hull-bakes`, `ships-hull-material` r3 and
|
||||
`ships-hull-livery` r2.
|
||||
- `material-library-export` follows `material-graph`.
|
||||
- `ships-addon-paint` r3 needs `ships-addon-mounts`, `material-library-export`
|
||||
and `ships-hull-material` r3.
|
||||
- `ships-player` keeps its dependency on `ships-hull-material`.
|
||||
|
||||
**What blocks the release hulls:** every cut above except `cycles-noise`.
|
||||
|
||||
**What can follow:**
|
||||
- `cycles-noise` and Voronoi, Wave and Gradient;
|
||||
- CultMath-native nodes in Blender;
|
||||
- the tape's GPU interpreter for mod graphs;
|
||||
- faction skins;
|
||||
- follow-ups `hull-damage-wear` (the first real Ship parameter), `hull-decals`
|
||||
and `hull-player-paint`;
|
||||
- detail normals per material;
|
||||
- a GPU BC encoder, if the readback-and-compress hitch measures badly.
|
||||
|
||||
#### Model page rows
|
||||
|
||||
| Kind | Identity | Lifecycle | Authority |
|
||||
|---|---|---|---|
|
||||
| Material graph | `MaterialGraph` in `Aetheria.cc`, keyed by its stable id (the group's name lowered, as ship ids are) | Exported from the library `.blend` by `material-graph put`. Re-exported whole on change, never edited in place. The kernels are regenerated in the same command | `MaterialGraphJudge` admits it. The record is truth and the kernels are derived |
|
||||
| Hull paint | `ShipAuthoring.Paint` (key 5) in the package | Written at Package. A graph id, two PNG paths and the factory livery bindings | `ship-authoring paint`; Validate, and the catalog test for bindings |
|
||||
| Mask and maps PNGs | `ship.mask.png`, `ship.maps.png` in the package, named by `Paint` | Authored and baked in Blender; exported every Package | The operator. `Bind` judges the headers |
|
||||
| Faction livery | `Faction.Livery` (key 18) | Authored in the inspector; null keeps the factory livery | The catalog; checked against the hull's graph |
|
||||
| Pair bake | Content hash of graph, PNGs, skin, livery and R | Baked when the first body needs it; released when the last is gone | `MaterialBakes`. Cache only |
|
||||
| Wear bake | Content hash of the pair key and quantised Ship parameters | Re-baked when a body's Ship parameters change | `MaterialBakes`. Cache only |
|
||||
| Cycles oracle fixture | A file per family in CultMath tests, stamped with the Blender version | Regenerated only by a pin-moving cut | The tool script under the pinned Blender |
|
||||
|
||||
#### Rationale
|
||||
|
||||
**Why generated compute kernels and not a CPU interpreter.** M22 puts a
|
||||
noise-bearing full-resolution bake at seconds on the operator's CPU, under a
|
||||
faster JIT than Unity's. Aetheria already ships runtime compute (M23). The graphs
|
||||
are game-owned, so kernels can be generated ahead of time and compiled into the
|
||||
build, where a runtime shader compile is impossible. The cost is that mods cannot
|
||||
bring graphs until the tape's GPU interpreter exists. That is question
|
||||
`material-evaluator-backend`.
|
||||
|
||||
**Why the per-ship cost is the Wear output alone.** Prior art bounds memory one of
|
||||
two ways:
|
||||
- a shared base with a small per-instance mask, as in Destiny's gearstack wear
|
||||
mask, MW5's wear masks and Star Citizen's vertex-alpha wear;
|
||||
- a cap on instance count.
|
||||
|
||||
Making it a rule of the output contract, enforced by the judge, makes the budget
|
||||
structural rather than a convention. The lerp in the shader is the contract's one
|
||||
fixed line, so the shader owns no material meaning.
|
||||
|
||||
**Why the frontier is cached at wear resolution.** Ruling 7 asks that a wear change
|
||||
recompute only what depends on wear. Caching every node at full resolution is
|
||||
Mixture's documented failure: memory linear in node count. One RGBA16F texture at
|
||||
512² per pair costs 2 MiB and makes a wear bake a few dozen instructions over
|
||||
262k texels.
|
||||
|
||||
**Why Cycles semantics are ported, not reimplemented from the manual.**
|
||||
- The manual leaves Mix's blend modes, Map Range's smooth modes, ramp
|
||||
interpolation and Smooth Min unspecified (Eyes §3d).
|
||||
- The Cycles kernel files are Apache-2.0, and `noise.h` is BSD-3.
|
||||
- Porting them into licence-headed CultMath files, as Phacelle is kept under
|
||||
MPL-2.0, gives the exact semantics with provenance.
|
||||
- Ramps and curves need no port: Python samples Blender's own evaluation into
|
||||
tables (M21).
|
||||
|
||||
**Why the oracle is a CPU bake.** It is exact for arithmetic and reproducible
|
||||
(M20). A GPU bake differs by an ulp on noise, and OSL on OptiX did not finish.
|
||||
|
||||
**Why the record holds the authored graph, not the IR.** The lowering will change
|
||||
as ports are added and the tape arrives. The authored graph is what she made, and
|
||||
the IR is a cache of one lowering of it.
|
||||
|
||||
**Rejected.**
|
||||
- Unity Shader Graph: its Lit target adds Unity's ambient, and ruling 8 makes our
|
||||
shaders own every pixel.
|
||||
- Mixture: it adds Shader Graph and SRP Core, and its memory grows with node count.
|
||||
- Material Maker: a second authoring application with no runtime parameter path.
|
||||
- MaterialX: it has no HLSL generator, Blender's export is partial, and its noise
|
||||
is not Blender's.
|
||||
- OSL as an authoring route: Cycles only, no EEVEE preview, and no result on OptiX
|
||||
(M20 P5).
|
||||
- Region-luminance tint (r2): every channel now places a whole material.
|
||||
|
||||
### S3: the first playable mod ship in a built player
|
||||
|
||||
- **First hull: Headliner.**
|
||||
|
|
|
|||
Loading…
Reference in a new issue