Describe shader functions (#303)
Shaders gets the section Shader functions, three node rows and the code notes. Concepts names the new asset type, Development the e2e total 1728.
1 parent
986aad5bd7
commit
9823f414cd
3 files changed
+59
-4
No files matched your search
+2
-2
@@ -1,12 +1,12 @@
|
||||
| Term | Meaning |
|
||||
|---|---|
|
||||
| **Account** | Who you are signed in as. The editor asks for a user name and a password before it loads anything, and every project belongs to one account — see [Accounts](Accounts). The **Account** menu is at the far right of the toolbar and holds the name, *Change password* and *Logout*; signing in and out changes what the canvas draws, it never reloads the page. |
|
||||
| **Asset** | Named thing with a type (`scene`, `camera`, `clip`, `sprite`, `text`, `behavior`, `collider`, `container`, `texture`, `animation`, `statemachine`, `shader`, `font`, `sound`, `particles`, `variables`) and typed properties. Assets have **no position**. |
|
||||
| **Asset** | Named thing with a type (`scene`, `camera`, `clip`, `sprite`, `text`, `behavior`, `collider`, `container`, `texture`, `animation`, `statemachine`, `shader`, `shaderfunction`, `font`, `sound`, `particles`, `variables`) and typed properties. Assets have **no position**. |
|
||||
| **Texture** | An uploaded image. Scenes, textures, animations, state machines, shaders, fonts, sounds and Variables assets are the eight types that cannot be placed: a texture has no position, it is *worn* by a sprite through the ordinary property `texture`. See [Textures](Textures). |
|
||||
| **Font** | An uploaded typeface, worn by a text through the ordinary property `font`; no font means the editor's own. Uploaded and picked exactly like a texture, and stored the same way. See [Fonts](Fonts). |
|
||||
| **Sound** | An uploaded audio file. Uploaded, picked and stored exactly like a typeface — but nothing *wears* it: it is neither on screen nor in the scene, and a graph plays it with `Play sound`. Its own rows say how loud it is and whether it loops; the node scales the one and can overrule the other either way. See [Sounds](Sounds). |
|
||||
| **State machine** | A named set of **states**, edited as nodes in its own tab. A behavior puts it into a state with `Set state`, moves it along a named transition with `State transition` and branches on it with `State branch`. Its **Scope** says where the current state lives: **Local** gives every behavior instance one of its own, **Global** keeps a single one for the whole run. See [State machines](State-machines). |
|
||||
| **Shader** | A node graph that becomes the GLSL a sprite is drawn with, edited in its own tab. A sprite, a text or a particle source wears it through `shader`; the numbers the graph declares are rows below that dropdown. See [Shaders](Shaders). |
|
||||
| **Shader** | A node graph that becomes the GLSL a sprite is drawn with, edited in its own tab. A sprite, a text or a particle source wears it through `shader`; the numbers the graph declares are rows below that dropdown. A **shader function** is a part of such a graph kept on its own and used as a node in other shaders. See [Shaders](Shaders). |
|
||||
| **Particles** | A node graph that says what *one* particle is as a function of its age and of a random number drawn once for it — no forces, no simulation. Unlike the other graph assets it **is** placeable: the object made from it is a source, whose rows say how many go out and for how long they live. Because a particle is a formula, the same second always draws the same picture and the tab's slider can jump to any of them exactly. See [Particles](Particles). |
|
||||
| **Text** | An asset that draws a line of text (`text`, `font`, `fontSize`, `color`, `align`) — titles, HUD readouts, button labels. Its content is an ordinary property, so a `Properties` node of type Text with `text` switched to Set changes it while playing. |
|
||||
| **Enabled** | Every placeable asset has the switch `enabled` (default on). A disabled object is not drawn, does not collide and its behavior does not run — **and neither does anything parented below it**. Switching one instance off is a normal override, which makes a container a *screen*: switch it on to show it, off to hide it. From a graph, `Properties` with `enabled` switched to Set does it, and `Is enabled` asks (including the parents); a behavior hears the switch as `On enable` / `On disable`. |
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ php tests/php/accounts.test.php # the API's accoun
|
||||
# has and the web server's container has not (SKIP there)
|
||||
php tests/php/snapshots.test.php # the snapshot store (#231), the same way
|
||||
php tests/php/releases.test.php # the release store (#266), the same way
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1725 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1728 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step
|
||||
./e2e.sh start [GM_STEPS] # the same run detached, see below
|
||||
./e2e.sh status # live progress, or the last run's result
|
||||
|
||||
+56
-1
@@ -96,6 +96,9 @@ plugged into a colour port, straight from a `Number` or a `Luminance` as well.
|
||||
| **Pow** | in `value` (any), `exponent` (number) · out `result` | `value` to the power of `exponent`: 2 squares it, 0.5 is the square root; an easing curve on `u`, a gamma on a colour. Below 0 the value counts as 0, because GLSL leaves `pow` undefined there (0 to a power of 0 or less is undefined too). Per channel for colours. |
|
||||
| **Sqrt** | in `value` (any) · out `result` | The square root: 0.25 becomes 0.5, 4 becomes 2. The same as `Pow` with exponent 0.5, in one node. Below 0 the value counts as 0, because GLSL leaves `sqrt` undefined there. Per channel for colours. |
|
||||
| **Clamp** | in `value` (any), `min`, `max` (number) · out `result` | Holds the value inside `min`..`max`, per channel for colours. The Output clamps the colour it is given anyway; this one holds a value *inside* the graph, before it is added to or multiplied. |
|
||||
| **Function input** | out: what you declare | Only in a shader function: the values a shader calling the function hands in. Every input declared in the inspector (`+ Input`, a number or a colour) is an output here and an input on every call. One per function. See *Shader functions*. |
|
||||
| **Function output** | in: what you declare | Only in a shader function: what it hands back. Every output declared here is an output on every call; unconnected, it is the value typed on it. One per function. |
|
||||
| *a shader function* | its declared inputs · its declared outputs | Listed in the palette under the function's name: the function's graph, set in here. A double-click opens it. |
|
||||
|
||||
An input with nothing to type on it (the Output's two, Luminance's colour) that is left unconnected
|
||||
reads the texel: its colour for a colour port, its alpha for the Output's `alpha`. That is why the
|
||||
@@ -294,6 +297,47 @@ Pass and blurred down, is the same 5x5 spot of 1/25 each that a `Blur` *Both* dr
|
||||
231/60/60, red once halved in each; two Passes in a row, the first the very program of an earlier
|
||||
graph's only Pass, still show the picture and not white.
|
||||
|
||||
## Shader functions
|
||||
|
||||
A **shader function** (#303) is a part of a shader graph kept as an asset of its own, so the same
|
||||
calculation (a greyscale, a noise, a vignette, an outline of eight samples) is built once and used in
|
||||
any number of shaders. `+` in the Assets panel → **Shader function** makes one; it opens in the
|
||||
Shader tab like a shader. It has no Output, no wearer and no preview of its own: the panel beside
|
||||
the graph says *A function shows in the shaders calling it*, and the readout counts its inputs and
|
||||
outputs.
|
||||
|
||||
- **Its ports** are declared on its two ends: **Function input** says what a caller hands in,
|
||||
**Function output** what comes back. Select one and add ports in the inspector, each a *Number* or
|
||||
a *Color*; nothing else can be declared. Every port is at once a port of every node calling the
|
||||
function, in every shader: a new input grows those nodes, a renamed one keeps their edges, a removed
|
||||
one takes its edges along, and an undo takes all of it back.
|
||||
- **Calling it:** every shader function is in the Shader tab's palette under its own name, and can be
|
||||
dragged in from the Assets panel. The node carries the function's name; an input left unconnected is
|
||||
the value typed on it. A double-click on the node opens the function.
|
||||
- **Set in, not called.** The compiler copies the function's graph into the shader where the node
|
||||
stands, as if its nodes had been placed there, so it costs exactly what the same nodes cost in place.
|
||||
Calling a function twice copies it twice. The nodes that read the picture (`Texture color`,
|
||||
`Sample texture`, `Blur`, ...) read the picture of whatever wears the calling shader, and `Time` is the
|
||||
same clock. A Pass inside a function is a pass of the calling shader (a wide blur can be a function).
|
||||
- **What it may hold:** everything a shader holds except the Output, the Vertex output, `Property` and
|
||||
`Color property`. Values come in through the inputs; the calling shader hangs its own properties on
|
||||
them, so it stays clear whose row a property is. Those nodes are not in a function's palette, and one
|
||||
pasted or left in says *A function cannot hold ...*. The two ends are not in a shader's palette.
|
||||
- **Changes reach every caller.** Every shader calling a function compiles again when the function
|
||||
changes, however deep the call sits.
|
||||
- **Problems** inside a function show on its own nodes in its tab, and at every call, in the
|
||||
function's words: *In Grayscale: "level" needs a number, not a color*. A function calling itself,
|
||||
directly or through another, says *A function cannot call itself* and is not set in; the palette
|
||||
does not offer such a call in the first place.
|
||||
|
||||
A function is part of the shader graph only: a behavior cannot call it, since a behavior runs on the
|
||||
processor and a shader on the graphics card.
|
||||
|
||||
Measured in the checks (step 28): a function "Grayscale" (a colour in, `Luminance` out as a colour),
|
||||
called between `Texture color` and the Output, draws the same pixels as the same nodes in place, byte
|
||||
for byte; a `Multiply` by 0.5 put into the function halves the sprite's grey without the shader being
|
||||
touched; a double-click on the call opens the function, and a call of itself inside it is marked.
|
||||
|
||||
## Moving the corners
|
||||
|
||||
Everything above decides what colour a pixel gets. A **Vertex output** node decides where the
|
||||
@@ -571,8 +615,19 @@ transform from world units to that picture. The Game tab and the game link then
|
||||
off the stage and let the picture stand in for it; the Scene tab leaves it drawn, since it shows
|
||||
more than the frame, and lays the picture over it below the symbols (`shadingCamera` and
|
||||
`keepsWorldAroundShader` in `WorldViewport`).
|
||||
A shader function (`src/core/shader/functions.ts`) never reaches the walk as a node:
|
||||
`inlineFunctions` first replaces every call by a copy of the function's graph, its node ids prefixed
|
||||
with the call's (`<call>/<node>`), wires what fed the call's inputs to what the Function input fed,
|
||||
and what read its outputs to what fed the Function output; an unconnected port becomes a `Number` or
|
||||
`Color` node with the typed value. Everything after that (passes, Time, the Edge cut, the corner
|
||||
walk) sees a plain graph. A problem on a copied node is moved back onto the call
|
||||
(`problemsAtCalls`). The function's own tab walks it from its Function output with any value at its
|
||||
input (`checkShaderFunction`). The call's ports come from the function through `GraphLookup`
|
||||
(`shaderFunction`), and the port commands mirror a change at a function's end into every call, as
|
||||
they do for a behavior's Start and End.
|
||||
`src/viewport/ShaderLibrary.ts` caches the compiled graph per asset, keyed by a fingerprint of what
|
||||
the fragment depends on — node ids, types, params, declared ports, and which port feeds which — so
|
||||
the fragment depends on — node ids, types, params, declared ports, and which port feeds which, and
|
||||
the same of every function it calls (`functionsFingerprint`) — so
|
||||
moving, collapsing or folding compiles nothing again; a changed param or link does, once
|
||||
(`__gm.shaderCompiles()` counts it for the checks). A sprite's picture is a `Mesh`
|
||||
(a unit quad sized by its scale, `symbols.ts`), a sibling of the sprite's `Graphics` node under the
|
||||
|
||||
Reference in new issue
Block a user