Files
SashegDev 874b6f20c2 Клиент: начальный импорт кодовой базы
Основа — Horizon (MIT). История апстрима не переносится: этот репозиторий ведёт свою.
2026-10-29 22:04:28 +03:00

107 lines
6.0 KiB
Markdown

# Shader API
Horizon has no shader packs today: the earlier implementation was removed on 2026-10-24. Two things will replace it,
designed separately: a **Horizon shader API**, described here, and a clean-room loader for the existing pack format
(its own spec; it is not part of this API). Both sit on the same renderer hooks, agreed between the two.
## Overview: what a shader author will be able to do
Write WGSL against documented stages of Horizon's renderer, with typed inputs, options the player can change, a
reload as soon as a file is saved and an overlay that shows what each pass costs and draws. The renderer keeps
everything that makes it fast (culling, batching, LOD, the mesher); a pack changes how surfaces and light look, not
how the world is fed to the GPU.
## The design
- **A pack** is a folder or a zip with `horizon-shaders.toml` (id, name, version, the `api` line, the stages it
uses, its options) and WGSL files. No preprocessor and no other shading language: WGSL is what wgpu validates and
compiles for Vulkan, Metal and DirectX 12.
- **Stages, not pipelines.** A stage is a function with a fixed signature that the renderer calls inside its own pass,
for example a terrain material (`fn material(input: TerrainInput) -> Surface`), the lighting of the visible
surfaces, the sky, an optional shadow pass, and a chain of full-screen post passes ending in the frame. A pack
that leaves a stage out gets vanilla's look for it.
- **Typed inputs.** Each stage receives structs (the frame: time, camera, sun and moon, weather, fog; the surface:
position, normal, block and its light) whose WGSL is generated from the Rust types the renderer uploads. The
generated reference lists every field with its unit and range, and a test fails when it drifts.
- **Options are WGSL `override` constants.** The manifest declares each option (on/off, a number in a range, a choice)
with its default; the game shows them on the pack's settings screen and sets them when it builds the pipeline. No
text substitution, and every option combination is validated the same way.
- **Hot reload.** The game watches the pack's folder. A saved file is validated with naga and the stage rebuilt; on an
error the last good version keeps drawing and the error, with its file and line, is shown in the overlay.
- **Debug overlay.** GPU time per stage and pass (timestamp queries), the targets each pass writes (show any of them
full-screen), the pack's options and its compile errors.
- **Budgets.** A pack declares the targets and passes it needs; the renderer refuses more than its limits, and the
benchmark ([benchmark-report.md](../benchmark-report.md)) records the pack and its cost, so "fast" stays measured.
- **Off by default.** Without a pack the renderer is vanilla's look, and no pack code runs.
## The pack format (schema 1)
A pack is a folder, or the same files zipped as a `.hshader`, with `horizon-shaders.toml` at its root
(crate `horizon-shader-api`; the sample with every key is
`crates/horizon-shader-api/tests/samples/schema-1/`):
```toml
schema = 1 # the manifest's format; a reader refuses schemas newer than it knows
id = "soft_light" # [a-z0-9_]{1,64}: the settings key and the registry id
name = "Soft Light"
version = "1.0.0"
api = "0.1" # the shader API line the WGSL is written for
description = "..." # optional, like authors and license
shared = ["common.wgsl"] # optional: WGSL put before every stage's file, in order
[sky] # each stage is optional, but a pack has at least one
file = "sky.wgsl"
[material]
file = "material.wgsl"
[[post]] # full-screen passes, in the order they run (8 at most)
file = "post/grade.wgsl"
name = "Colour grade" # optional: the GPU time overlay's label
[[options]] # 64 at most; `id` is the WGSL `override` it sets
id = "saturation"
name = "Saturation"
type = "float" # bool, float (min, max, step), int (min, max), choice (values)
default = 1.1
min = 0.0
max = 2.0
step = 0.05
[budget]
gpu_ms = 1.5 # optional: the GPU time the pack aims to add (0 to 16 ms)
```
An option's `override` has the type of its kind: `bool`, `f32`, `i32`, or `u32` for a choice (the index of the
value). The pack holds only the manifest, the `.wgsl` files it names (each used, UTF-8, 256 KiB at most),
`README.md`, `LICENSE` (`.md`, `.txt`) and `icon.png`, under plain paths, 8 MiB in all. A `.hshader` is built
the same way every time (files in path order, fixed dates), so a pack's SHA-256 depends only on its files.
## Guide, reference and examples
- [shaders-reference.md](shaders-reference.md): every stage's signature, input and output structs, resources and
helpers, the frame's fields with their units, option types and limits, generated from `crates/horizon-shader-api`.
- [The guide](../shaders.md): making a pack with `horizon-shader new`, `check` and `pack`; the templates and the
example pack (`crates/horizon-shader-api/packs/golden_hour`).
## Stability
Not started. The first stages will be experimental (opt-in), then preview once a reference, an example and a test
pack exist ([stability.md](stability.md)).
## Not there yet
Option values other than the defaults (the three stages run, with hot reload), then the overlay, lighting and shadow
stages.
## Changelog
- 2026-10-26: the material stage in the game: terrain's surfaces through the pack's `material`.
- 2026-10-26: the sky stage in the game: the pack's `sky` gets vanilla's colour along each ray.
- 2026-10-26: the post stage in the game (`HORIZON_SHADER_PACK`, hot reload with the last good pack kept).
- 2026-10-25: `horizon-shader` (`new`, `check`, `pack`), three templates, the example pack and the guide.
- 2026-10-25: the check (naga validation, signatures, options, budgets, SPIR-V/Metal/HLSL translation).
- 2026-10-25: the stages of API 0.1 (sky, material, post), their inputs and the generated reference.
- 2026-10-25: the pack format, schema 1: `horizon-shaders.toml` and the `.hshader` package.
- 2026-10-24: the earlier shader pack code was removed; this API is designed from scratch.