@ericrisco/rsc 0.1.35 → 0.1.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/manifest.json +241 -2
- package/package.json +1 -1
- package/scripts/lib/domains.js +1 -0
- package/scripts/lib/recommend.js +4 -0
- package/skills/game-design/SKILL.md +170 -0
- package/skills/game-design/evals/README.md +13 -0
- package/skills/game-design/evals/cases.yaml +47 -0
- package/skills/game-design/references/mechanics-and-loops.md +78 -0
- package/skills/game-design/references/playtesting-and-scope.md +58 -0
- package/skills/game-design/references/progression-and-economy.md +70 -0
- package/skills/game-storytelling/SKILL.md +159 -0
- package/skills/game-storytelling/evals/README.md +28 -0
- package/skills/game-storytelling/evals/cases.yaml +51 -0
- package/skills/game-storytelling/references/branching-and-state.md +134 -0
- package/skills/game-storytelling/references/dialogue-tools.md +117 -0
- package/skills/game-storytelling/references/environmental-storytelling.md +71 -0
- package/skills/gamedev-multiplayer/SKILL.md +250 -0
- package/skills/gamedev-multiplayer/evals/README.md +12 -0
- package/skills/gamedev-multiplayer/evals/cases.yaml +44 -0
- package/skills/gamedev-multiplayer/references/godot-high-level-multiplayer.md +133 -0
- package/skills/gamedev-multiplayer/references/prediction-and-latency.md +104 -0
- package/skills/gamedev-multiplayer/references/unity-and-unreal-netcode.md +166 -0
- package/skills/gamedev-pathing/SKILL.md +242 -0
- package/skills/gamedev-pathing/evals/README.md +14 -0
- package/skills/gamedev-pathing/evals/cases.yaml +49 -0
- package/skills/gamedev-pathing/references/navmesh-workflow.md +110 -0
- package/skills/gamedev-pathing/references/search-algorithms.md +135 -0
- package/skills/gamedev-pathing/references/steering-and-avoidance.md +120 -0
- package/skills/gamedev-physics/SKILL.md +225 -0
- package/skills/gamedev-physics/evals/README.md +12 -0
- package/skills/gamedev-physics/evals/cases.yaml +54 -0
- package/skills/gamedev-physics/references/character-controllers.md +120 -0
- package/skills/gamedev-physics/references/determinism-and-queries.md +124 -0
- package/skills/gamedev-physics/references/layers-and-masks.md +115 -0
- package/skills/gamedev-shaders/SKILL.md +252 -0
- package/skills/gamedev-shaders/evals/README.md +14 -0
- package/skills/gamedev-shaders/evals/cases.yaml +45 -0
- package/skills/gamedev-shaders/references/effect-recipes.md +205 -0
- package/skills/gamedev-shaders/references/godot-shading-language.md +133 -0
- package/skills/gamedev-shaders/references/unity-and-unreal-shaders.md +169 -0
- package/skills/gamedev-shipping/SKILL.md +236 -0
- package/skills/gamedev-shipping/evals/README.md +9 -0
- package/skills/gamedev-shipping/evals/cases.yaml +55 -0
- package/skills/gamedev-shipping/references/mobile-and-desktop.md +127 -0
- package/skills/gamedev-shipping/references/stores-and-ci.md +162 -0
- package/skills/gamedev-shipping/references/web-export-headers.md +140 -0
- package/skills/godot/SKILL.md +319 -0
- package/skills/godot/evals/README.md +13 -0
- package/skills/godot/evals/cases.yaml +50 -0
- package/skills/godot/references/export-and-testing.md +102 -0
- package/skills/godot/references/gdscript-style.md +84 -0
- package/skills/godot/references/godot3-to-4-traps.md +89 -0
- package/skills/godot/references/nodes-scenes-resources.md +109 -0
- package/skills/level-design/SKILL.md +175 -0
- package/skills/level-design/evals/README.md +35 -0
- package/skills/level-design/evals/cases.yaml +58 -0
- package/skills/level-design/references/blockout-to-art.md +118 -0
- package/skills/level-design/references/guidance-and-readability.md +152 -0
- package/skills/level-design/references/pacing-and-encounters.md +142 -0
- package/skills/roast-me/tools/adapters/__pycache__/__init__.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/base.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/claude.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/codex.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/gemini.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/registry.cpython-312.pyc +0 -0
- package/skills/unity/SKILL.md +282 -0
- package/skills/unity/evals/README.md +8 -0
- package/skills/unity/evals/cases.yaml +43 -0
- package/skills/unity/references/build-and-platforms.md +65 -0
- package/skills/unity/references/input-system.md +102 -0
- package/skills/unity/references/lifecycle-deep-dive.md +75 -0
- package/skills/unreal/SKILL.md +270 -0
- package/skills/unreal/evals/README.md +12 -0
- package/skills/unreal/evals/cases.yaml +45 -0
- package/skills/unreal/references/blueprint-cpp-parity.md +109 -0
- package/skills/unreal/references/gameplay-framework.md +95 -0
- package/skills/unreal/references/packaging.md +83 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gamedev-shaders
|
|
3
|
+
description: "Use when writing shaders, materials, VFX, or post-processing for a game engine, or asking \"how do I make this effect\" — covers the vertex→fragment pipeline, UVs / normals / coordinate spaces, and per-engine authoring in Godot 4.x (shader_type spatial/canvas_item/particles, source_color, hint_screen_texture, ShaderMaterial), Unity 6 (Shader Graph vs HLSL, URP/HDRP, ShaderLab), and Unreal 5.x (Material graph, material domains, Custom HLSL node). Includes recipes for dissolve, rim/outline, toon/cel, water/flow, force field, hologram; full-screen post-process; and shader performance (overdraw, texture-sample cost, branching, mobile). Triggers: \"write a dissolve shader\", \"rim light\", \"toon shading\", \"screen-space effect\", \"my shader is slow on mobile\", \"cómo hago un shader de agua\". NOT gameplay or engine-API code (→ godot / unity / unreal) and NOT physics simulation, collision, or rigid bodies (→ gamedev-physics)."
|
|
4
|
+
tags: [shaders, vfx, materials, post-processing, shadergraph]
|
|
5
|
+
recommends: [godot, unity, unreal, gamedev-shipping]
|
|
6
|
+
profiles: [full]
|
|
7
|
+
origin: risco
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Shaders & VFX (game engines)
|
|
11
|
+
|
|
12
|
+
Author shaders, materials, and full-screen effects across Godot, Unity, and Unreal. One
|
|
13
|
+
mental model — the GPU pipeline — mapped onto each engine's authoring surface, plus recipes
|
|
14
|
+
for the effects people actually ask for. Fires on writing/debugging a shader or material,
|
|
15
|
+
building a VFX/post-process effect, or "how do I make X look like Y".
|
|
16
|
+
|
|
17
|
+
## Version contract — read first
|
|
18
|
+
|
|
19
|
+
Target the current stable line of each engine and never emit its retired APIs. If unsure a
|
|
20
|
+
symbol is current, say so rather than guess.
|
|
21
|
+
|
|
22
|
+
| Engine | Target | Never emit → use instead |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| **Godot** | 4.x (4.4/4.5 stable) | `SCREEN_TEXTURE`/`DEPTH_TEXTURE`/`NORMAL_TEXTURE` built-ins → declare a `uniform sampler2D … : hint_screen_texture` / `hint_depth_texture` / `hint_normal_roughness_texture`. `hint_color`/`hint_albedo` → `source_color`. `hint_white`/`hint_black` → `hint_default_white`/`hint_default_black`. GLES2-era guides. |
|
|
25
|
+
| **Unity** | 6 (6000.x LTS), URP/HDRP | Surface shaders (`#pragma surface`) — Built-in-RP only, they do **not** compile under URP/HDRP. `CGPROGRAM`+`UnityCG.cginc`, `UnityObjectToClipPos`, `mul(UNITY_MATRIX_MVP, v)` → `HLSLPROGRAM` + URP `Core.hlsl` and `TransformObjectToHClip(posOS)`. `OnRenderImage`/`Graphics.Blit` post FX → URP Renderer Feature / Fullscreen Shader Graph. |
|
|
26
|
+
| **Unreal** | 5.x (5.4+) | `SceneTexture:PostProcessInput0` outside a Post Process material; Opacity without a translucent blend mode; Opacity Mask without a Masked blend mode. Prefer graph nodes; drop to a Custom HLSL node only for logic nodes can't express. |
|
|
27
|
+
|
|
28
|
+
`shader_type` tokens in Godot 4 are exact: `spatial`, `canvas_item` (underscore), `particles`
|
|
29
|
+
(plural), `sky`, `fog`.
|
|
30
|
+
|
|
31
|
+
## When to use / When NOT to use
|
|
32
|
+
|
|
33
|
+
**Use when:** writing or debugging a `.gdshader`/`ShaderMaterial`, a `.shader`/Shader Graph, or
|
|
34
|
+
a UE Material; building a VFX look (dissolve, rim, toon, water, shield, hologram, trails);
|
|
35
|
+
authoring post-processing / screen-space effects; a shader is slow, flickers, or looks wrong;
|
|
36
|
+
choosing per-vertex vs per-pixel; converting an effect between engines.
|
|
37
|
+
|
|
38
|
+
**When NOT to use (delegate):**
|
|
39
|
+
|
|
40
|
+
- Gameplay logic, nodes/components, input, engine APIs, scene setup → [`godot`](../godot/SKILL.md) /
|
|
41
|
+
[`unity`](../unity/SKILL.md) / [`unreal`](../unreal/SKILL.md). This skill owns the *shading*, not the C#/GDScript/Blueprint around it.
|
|
42
|
+
- Physics simulation, collisions, rigid bodies, character controllers → [`gamedev-physics`](../gamedev-physics/SKILL.md).
|
|
43
|
+
(A shader that *fakes* refraction is here; simulating fluid dynamics is not.)
|
|
44
|
+
- Shipping, platform export, shader-variant stripping in the build pipeline → [`gamedev-shipping`](../gamedev-shipping/SKILL.md)
|
|
45
|
+
(this skill keeps the per-shader performance work).
|
|
46
|
+
|
|
47
|
+
## Shader fundamentals (the pipeline)
|
|
48
|
+
|
|
49
|
+
Every engine compiles your material into the same GPU stages. Two you write:
|
|
50
|
+
|
|
51
|
+
- **Vertex stage** — runs **once per vertex**. Transforms position into clip space and passes
|
|
52
|
+
interpolated data (UVs, normals, custom `varying`s) down. Cheap; scales with mesh vertex count.
|
|
53
|
+
- **Rasterizer** (fixed) turns triangles into fragments and *interpolates* the vertex outputs.
|
|
54
|
+
- **Fragment / pixel stage** — runs **once per covered pixel** (× overdraw). Samples textures,
|
|
55
|
+
does lighting, writes the final color. Expensive; scales with screen coverage.
|
|
56
|
+
|
|
57
|
+
**Per-vertex vs per-pixel is the core performance lever:** compute anything that interpolates
|
|
58
|
+
linearly (position offsets, un-normalized directions, scalar masks) in the vertex stage and pass
|
|
59
|
+
it as a `varying`; keep only what must be exact per-pixel (normalizing interpolated normals,
|
|
60
|
+
texture sampling, lighting, fresnel) in the fragment stage.
|
|
61
|
+
|
|
62
|
+
**UVs** are per-vertex 2D texture coordinates (0–1), interpolated across the face — you sample
|
|
63
|
+
textures and drive scrolling/tiling/masks with them. **Normals** are surface directions used for
|
|
64
|
+
lighting and rim; interpolated normals must be re-normalized per pixel. **Normal maps** store
|
|
65
|
+
directions in **tangent space** (unpack with `×2−1`); respect handedness.
|
|
66
|
+
|
|
67
|
+
**Coordinate spaces** — know which space each value is in before you do math on it:
|
|
68
|
+
|
|
69
|
+
| Space | Meaning | Typical use |
|
|
70
|
+
| --- | --- | --- |
|
|
71
|
+
| Object / model | mesh-local, origin at the pivot | authoring positions/normals start here |
|
|
72
|
+
| World | scene-global | world-space effects, triplanar, lighting |
|
|
73
|
+
| View / camera | relative to the camera | Godot spatial `NORMAL`/`VIEW` live here |
|
|
74
|
+
| Clip / NDC | post-projection homogeneous coords | the vertex stage's required output |
|
|
75
|
+
| Tangent | per-fragment surface basis (T,B,N) | normal maps are decoded here |
|
|
76
|
+
| Screen / UV | 0–1 across the framebuffer | post-process sampling (`SCREEN_UV`) |
|
|
77
|
+
|
|
78
|
+
## Per-engine authoring
|
|
79
|
+
|
|
80
|
+
### Godot 4.x
|
|
81
|
+
|
|
82
|
+
Godot ships its own GLSL-like language (`.gdshader`). Pick a `shader_type`, declare `uniform`s
|
|
83
|
+
(exposed as material parameters), pass data with `varying`, write `vertex()`/`fragment()`
|
|
84
|
+
(+`light()`). A **ShaderMaterial** binds the shader to a node and holds uniform values; set them
|
|
85
|
+
from code with `material.set_shader_parameter("name", value)`. Uniform hints: `source_color`
|
|
86
|
+
(sRGB→linear color pickers), `hint_range(a,b)`, `hint_default_white`, `hint_screen_texture`,
|
|
87
|
+
plus texture filters/repeats (`filter_linear_mipmap`, `repeat_enable`).
|
|
88
|
+
|
|
89
|
+
Small **canvas_item** (2D) shader — scroll and tint a texture:
|
|
90
|
+
|
|
91
|
+
```glsl
|
|
92
|
+
shader_type canvas_item;
|
|
93
|
+
uniform sampler2D noise : repeat_enable;
|
|
94
|
+
uniform vec4 tint : source_color = vec4(1.0);
|
|
95
|
+
uniform float speed = 0.1;
|
|
96
|
+
|
|
97
|
+
void fragment() {
|
|
98
|
+
vec2 uv = UV + vec2(TIME * speed, 0.0); // UV is the node's texcoord
|
|
99
|
+
COLOR = texture(noise, uv) * tint * COLOR; // in COLOR = vertex/modulate color
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Small **spatial** (3D) shader — a fresnel rim glow (`NORMAL` and `VIEW` are **view-space** here):
|
|
104
|
+
|
|
105
|
+
```glsl
|
|
106
|
+
shader_type spatial;
|
|
107
|
+
render_mode blend_add, cull_back;
|
|
108
|
+
uniform vec3 rim_color : source_color = vec3(0.2, 0.6, 1.0);
|
|
109
|
+
uniform float power : hint_range(0.0, 8.0) = 3.0;
|
|
110
|
+
|
|
111
|
+
varying vec3 v_normal;
|
|
112
|
+
void vertex() { v_normal = NORMAL; } // pass to fragment via varying
|
|
113
|
+
void fragment() {
|
|
114
|
+
float f = pow(1.0 - dot(normalize(v_normal), normalize(VIEW)), power);
|
|
115
|
+
EMISSION = rim_color * f;
|
|
116
|
+
ALPHA = f;
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Deep dive (built-in variables per type, render_modes, particles/sky/fog, screen/depth reads) →
|
|
121
|
+
`references/godot-shading-language.md`.
|
|
122
|
+
|
|
123
|
+
### Unity 6
|
|
124
|
+
|
|
125
|
+
Two authoring paths, both on the Scriptable Render Pipeline (**URP** for most projects, **HDRP**
|
|
126
|
+
for high-end):
|
|
127
|
+
|
|
128
|
+
- **Shader Graph** — visual node graph feeding a *master stack* (Vertex + Fragment blocks).
|
|
129
|
+
Artist-friendly, URP/HDRP only, compiles to HLSL. Default choice for surface looks and VFX.
|
|
130
|
+
- **Hand-written HLSL** — a `Shader "…" { … }` (ShaderLab) wrapping `Properties` and `Pass`
|
|
131
|
+
blocks; the program goes in an `HLSLPROGRAM … ENDHLSL` block that `#include`s URP's `Core.hlsl`
|
|
132
|
+
/ `Lighting.hlsl`. Use for full control, custom lighting, or compute-driven effects.
|
|
133
|
+
|
|
134
|
+
**Surface shaders are Built-in-RP only** — under URP/HDRP write a lit HLSL pass or a Shader Graph;
|
|
135
|
+
use `TransformObjectToHClip` for the clip transform, not the retired `UnityObjectToClipPos`. Set
|
|
136
|
+
parameters at runtime through a `MaterialPropertyBlock` or `Material.SetFloat/SetColor/SetTexture`.
|
|
137
|
+
Full URP unlit + lit HLSL pass and a Shader Graph mapping → `references/unity-and-unreal-shaders.md`.
|
|
138
|
+
|
|
139
|
+
### Unreal 5.x
|
|
140
|
+
|
|
141
|
+
A **Material** is a node graph the engine compiles to HLSL. You wire outputs on the main result
|
|
142
|
+
node — Base Color, Metallic, Roughness, Emissive Color, Normal, Opacity / Opacity Mask, World
|
|
143
|
+
Position Offset. Key knobs on the material:
|
|
144
|
+
|
|
145
|
+
- **Material Domain** — what the material drives: *Surface* (default meshes), *Deferred Decal*,
|
|
146
|
+
*Light Function*, *Volume*, *Post Process* (full-screen), *User Interface*.
|
|
147
|
+
- **Blend Mode** (Opaque/Masked/Translucent/Additive…) and **Shading Model** (Default Lit,
|
|
148
|
+
Unlit, Subsurface, …). Opacity needs Translucent; Opacity Mask needs Masked.
|
|
149
|
+
- **Material Instances** expose parameters (scalar/vector/texture/switch) for cheap variants and
|
|
150
|
+
runtime tweaks via a Dynamic Material Instance (`SetScalarParameterValue`, …).
|
|
151
|
+
- **Custom node** — a raw HLSL escape hatch: set Output Type, add named Inputs, `return …;`.
|
|
152
|
+
Reach for it only when the node set can't express the logic (loops, bitops). Reuse via Material
|
|
153
|
+
Functions. UE5.5+ adds *Substrate* as an opt-in shading system; the standard material is still default.
|
|
154
|
+
|
|
155
|
+
Custom-node HLSL, domains, and a Godot↔Unreal recipe mapping → `references/unity-and-unreal-shaders.md`.
|
|
156
|
+
|
|
157
|
+
## Common effect recipes (concepts)
|
|
158
|
+
|
|
159
|
+
Each is a *technique*, engine-agnostic — the reference has full per-engine code.
|
|
160
|
+
|
|
161
|
+
| Effect | Core idea |
|
|
162
|
+
| --- | --- |
|
|
163
|
+
| **Dissolve** | Threshold a noise texture against an animated cutoff; `discard`/clip below it; add an emissive band at the edge. |
|
|
164
|
+
| **Rim / outline** | Rim = fresnel `pow(1 − N·V, p)`. Outline = inverted-hull pass (scale along normals, flip culling) **or** a post-process depth/normal edge detect. |
|
|
165
|
+
| **Toon / cel** | Quantize diffuse `N·L` into bands (`step`/`smoothstep` or a ramp texture); hard-stepped specular. |
|
|
166
|
+
| **Water / flow** | Scroll two normal maps at different speeds (or advect a flow-map's RG); refract the screen texture; depth-difference foam at shorelines. |
|
|
167
|
+
| **Force field** | Fresnel + scrolling hex/pattern texture + intersection glow from a scene-depth difference; additive. |
|
|
168
|
+
| **Hologram** | Scanlines `sin(worldY·f + TIME)` + fresnel + flicker + slight RGB channel offset; additive/translucent. |
|
|
169
|
+
|
|
170
|
+
**Worked example — dissolve (Godot spatial):**
|
|
171
|
+
|
|
172
|
+
```glsl
|
|
173
|
+
shader_type spatial;
|
|
174
|
+
render_mode cull_disabled;
|
|
175
|
+
uniform sampler2D dissolve_noise : hint_default_white;
|
|
176
|
+
uniform float threshold : hint_range(0.0, 1.0) = 0.0; // animate 0 → 1
|
|
177
|
+
uniform float edge = 0.05;
|
|
178
|
+
uniform vec3 edge_color : source_color = vec3(1.0, 0.4, 0.0);
|
|
179
|
+
|
|
180
|
+
void fragment() {
|
|
181
|
+
float n = texture(dissolve_noise, UV).r;
|
|
182
|
+
if (n < threshold) discard; // cut the hole
|
|
183
|
+
float e = smoothstep(threshold, threshold + edge, n);
|
|
184
|
+
EMISSION = edge_color * (1.0 - e); // glowing burn ring
|
|
185
|
+
ALBEDO = vec3(0.6);
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Drive `threshold` from an `AnimationPlayer` or `set_shader_parameter`. The same math ports to
|
|
190
|
+
Unity (`clip(n - threshold)`) and Unreal (Opacity Mask + a threshold parameter). All six recipes,
|
|
191
|
+
per engine → `references/effect-recipes.md`.
|
|
192
|
+
|
|
193
|
+
## Post-processing / full-screen effects
|
|
194
|
+
|
|
195
|
+
- **Godot** — a `canvas_item` shader on a full-rect `ColorRect` reading `hint_screen_texture`, or
|
|
196
|
+
a spatial unshaded full-screen quad reading `hint_screen_texture`/`hint_depth_texture`; or a
|
|
197
|
+
`CompositorEffect` (4.3+) for a custom render pass. Environment already covers glow/tonemap/SSAO.
|
|
198
|
+
- **Unity (URP)** — a **Full Screen Pass Renderer Feature** driving a *Fullscreen* Shader Graph
|
|
199
|
+
(or a Blit pass). HDRP uses Custom Pass / Fullscreen. Legacy `OnRenderImage` is Built-in-RP only.
|
|
200
|
+
- **Unreal** — a **Post Process Material** (Material Domain = Post Process) on a Post Process
|
|
201
|
+
Volume; read the frame with **SceneTexture** nodes (SceneColor, SceneDepth, custom stencil).
|
|
202
|
+
Blendable Location orders it against tonemapping.
|
|
203
|
+
|
|
204
|
+
## Performance
|
|
205
|
+
|
|
206
|
+
- **Overdraw** is the top cost: transparent/additive layers each re-shade the same pixels. Prefer
|
|
207
|
+
opaque, sort and minimize overlap, keep particle fill low. `discard`/`clip` **disables early-Z**
|
|
208
|
+
— don't use it as a cheap "invisible".
|
|
209
|
+
- **Texture sampling** = a memory fetch + filter each call; *dependent* reads (UV derived from a
|
|
210
|
+
prior sample) stall the pipeline. Pack masks into channels, atlas, and cache samples in locals.
|
|
211
|
+
- **Branching**: a divergent `if` across a GPU warp can execute *both* sides. Prefer
|
|
212
|
+
`step`/`mix`/`clamp`; branches on a **uniform** (same value for all pixels) are cheap; static
|
|
213
|
+
branches compile out.
|
|
214
|
+
- **LOD & precision**: use mipmaps, shader LOD variants, and `mediump`/half precision on mobile;
|
|
215
|
+
full `float` only where banding shows. Move linear work to the vertex stage.
|
|
216
|
+
- **Mobile / tile GPUs**: bandwidth-bound — keep render targets small, avoid mid-pass framebuffer
|
|
217
|
+
reads, and note that `discard` and large full-screen passes break tile hidden-surface removal.
|
|
218
|
+
|
|
219
|
+
## Guardrails / gotchas
|
|
220
|
+
|
|
221
|
+
- Godot 4: the `SCREEN_TEXTURE`/`DEPTH_TEXTURE` built-ins are gone — declare `hint_screen_texture`
|
|
222
|
+
/ `hint_depth_texture` uniforms. `hint_color` → `source_color`. Author colors as `source_color`
|
|
223
|
+
so sRGB→linear conversion is correct.
|
|
224
|
+
- Unity: don't write a surface shader or include `UnityCG.cginc` for a URP/HDRP project.
|
|
225
|
+
- Unreal: `SceneTexture` post-process nodes only work in the Post Process domain; match Opacity to
|
|
226
|
+
the blend mode.
|
|
227
|
+
- Normalize interpolated normals per pixel; unpack normal maps (`×2−1`) and mind tangent handedness.
|
|
228
|
+
- Watch color space (linear vs sRGB) at every texture read and color output — the #1 "looks washed
|
|
229
|
+
out / too dark" bug.
|
|
230
|
+
|
|
231
|
+
## Related skills
|
|
232
|
+
|
|
233
|
+
- [`godot`](../godot/SKILL.md) / [`unity`](../unity/SKILL.md) / [`unreal`](../unreal/SKILL.md) — the
|
|
234
|
+
engine skills own gameplay code, nodes/components, and scene wiring; this skill owns the shaders/materials.
|
|
235
|
+
- [`gamedev-physics`](../gamedev-physics/SKILL.md) — simulation, collision, rigid bodies (a shader that *fakes* an effect stays here).
|
|
236
|
+
- [`gamedev-shipping`](../gamedev-shipping/SKILL.md) — platform export and shader-variant stripping in the build.
|
|
237
|
+
|
|
238
|
+
## Checklist
|
|
239
|
+
|
|
240
|
+
- [ ] Correct engine + version idiom (no banned API from the Version contract table).
|
|
241
|
+
- [ ] Right `shader_type` / render pipeline / material domain for the target (2D vs 3D, URP vs HDRP, Surface vs Post Process).
|
|
242
|
+
- [ ] Work placed in the right stage: linear math per-vertex via `varying`, exact math per-pixel.
|
|
243
|
+
- [ ] Colors authored in the correct space (`source_color` / sRGB handling); normals normalized and unpacked.
|
|
244
|
+
- [ ] Uniforms/parameters exposed and driven from code or an animation track — not hard-coded.
|
|
245
|
+
- [ ] Performance sanity: overdraw, sample count, and branching considered; mobile precision set if targeted.
|
|
246
|
+
- [ ] Post-process uses the engine's supported full-screen path (not a retired Built-in-RP mechanism).
|
|
247
|
+
|
|
248
|
+
## References
|
|
249
|
+
|
|
250
|
+
- `references/godot-shading-language.md` — shader types, built-ins per type, render_modes, `varying`, screen/depth reads, ShaderMaterial from code.
|
|
251
|
+
- `references/unity-and-unreal-shaders.md` — Unity URP HLSL pass + Shader Graph mapping; Unreal domains, Custom node HLSL, Material Instances.
|
|
252
|
+
- `references/effect-recipes.md` — dissolve, rim/outline, toon/cel, water/flow, force field, hologram — full code per engine.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Eval harness — `gamedev-shaders` skill
|
|
2
|
+
|
|
3
|
+
These cases are run by the rsc skill-eval harness (a Claude agent with the full catalog loaded),
|
|
4
|
+
or read manually. They assert two things: **triggering** — the description fires on shader /
|
|
5
|
+
material / VFX / post-process / "how do I make X effect" prompts (including Spanish and
|
|
6
|
+
symptom-only phrasings like "slow on mobile") and stays quiet on near-misses, routing each to the
|
|
7
|
+
right sibling (`godot`/`unity`/`unreal` for gameplay-or-setup, `gamedev-physics` for simulation,
|
|
8
|
+
`gamedev-shipping` for variant stripping, `sql` for the false-friend "optimize"); and
|
|
9
|
+
**capability** — that with `SKILL.md` and its references loaded, the generated Godot 4 dissolve
|
|
10
|
+
shader satisfies the rubric (valid `shader_type`, `discard` against an animatable threshold, an
|
|
11
|
+
emissive `smoothstep` edge, `source_color` hints, no removed `SCREEN_TEXTURE`/`hint_color` APIs,
|
|
12
|
+
code-driven animation, and an overdraw note). Run 3–5 trials per prompt since routing is
|
|
13
|
+
non-deterministic; a prompt passes on a majority. No network needed — the capability rubric is
|
|
14
|
+
judged by reading the output against the points.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
skill: gamedev-shaders
|
|
2
|
+
|
|
3
|
+
should_trigger:
|
|
4
|
+
- prompt: "Write me a dissolve shader in Godot 4 that burns an object away from bottom to top with a glowing orange edge."
|
|
5
|
+
why: "Dissolve is a named recipe and the core use case; Godot 4 .gdshader authoring is owned here."
|
|
6
|
+
- prompt: "How do I make a rim light / fresnel glow on a 3D character in Unity URP?"
|
|
7
|
+
why: "Rim/fresnel is a named recipe; 'how do I make X effect' is an explicit trigger; Unity shader authoring is per-engine mapped here."
|
|
8
|
+
- prompt: "My translucent particle shader tanks the framerate on mobile. How do I fix the overdraw?"
|
|
9
|
+
why: "Shader performance — overdraw, transparency, mobile — is a dedicated section; symptom-only trigger routes here, not to a generic profiler."
|
|
10
|
+
- prompt: "Set up a full-screen post-process effect in Unreal that reads scene depth and draws outlines."
|
|
11
|
+
why: "Post-processing / full-screen effects per engine is a core section; Unreal Post Process material + SceneTexture is covered."
|
|
12
|
+
- prompt: "Cómo hago un shader de agua con refracción y espuma en los bordes."
|
|
13
|
+
why: "Spanish water/flow recipe request; the description carries the Spanish 'cómo hago un shader de agua'."
|
|
14
|
+
- prompt: "Convert this toon/cel shading effect from my Godot project to a Unity Shader Graph."
|
|
15
|
+
why: "Toon/cel is a named recipe and cross-engine conversion is an explicit use case; the skill carries a Godot↔Unity↔Unreal map."
|
|
16
|
+
- prompt: "What coordinate space are NORMAL and VIEW in inside a Godot spatial fragment shader, and why does my world-space fresnel look wrong?"
|
|
17
|
+
why: "Coordinate-spaces / fundamentals plus a Godot-specific gotcha (view-space normals) both live in this skill."
|
|
18
|
+
|
|
19
|
+
should_not_trigger:
|
|
20
|
+
- prompt: "Write the GDScript that spawns enemies on a timer and tracks the player's score."
|
|
21
|
+
route_to: "godot"
|
|
22
|
+
why: "Gameplay logic and engine APIs belong to the engine skill; this skill only owns the shading, not the script around it."
|
|
23
|
+
- prompt: "My rigid body tunnels through thin walls at high speed — how do I fix the collision detection?"
|
|
24
|
+
route_to: "gamedev-physics"
|
|
25
|
+
why: "Physics simulation and collision (continuous collision detection) is gamedev-physics; a shader has nothing to do with it."
|
|
26
|
+
- prompt: "My build has 40k shader variants and takes an hour to compile — how do I strip variants for the console ship?"
|
|
27
|
+
route_to: "gamedev-shipping"
|
|
28
|
+
why: "Shader-variant stripping in the build/ship pipeline is gamedev-shipping; this skill keeps per-shader authoring performance."
|
|
29
|
+
- prompt: "Optimize this SQL query that's doing a full table scan on every page load."
|
|
30
|
+
route_to: "sql"
|
|
31
|
+
why: "'Shader is slow' overlaps the word 'optimize' but this is database work with zero GPU/material surface."
|
|
32
|
+
- prompt: "Set up the URP asset, camera stack, and renderer features for my Unity project's rendering settings."
|
|
33
|
+
route_to: "unity"
|
|
34
|
+
why: "Project-level render pipeline configuration is engine setup (unity), not writing a shader/material; this skill starts once you're authoring the shader itself."
|
|
35
|
+
|
|
36
|
+
capability:
|
|
37
|
+
- scenario: "Author a Godot 4.x spatial dissolve shader that burns an object away with a glowing edge, and expose it to be animated from code."
|
|
38
|
+
must_include:
|
|
39
|
+
- "Starts with 'shader_type spatial;' (a valid Godot 4 shader type token)"
|
|
40
|
+
- "Samples a noise texture and uses discard (or ALPHA_SCISSOR) below an animatable threshold uniform to cut the pixels"
|
|
41
|
+
- "Adds an emissive edge band via smoothstep around the threshold so the burn edge glows (uses EMISSION)"
|
|
42
|
+
- "Declares color uniforms with the ': source_color' hint (NOT the removed Godot 3 'hint_color')"
|
|
43
|
+
- "Does NOT use the removed SCREEN_TEXTURE/DEPTH_TEXTURE built-ins; if a screen/depth read is needed it declares a 'hint_screen_texture'/'hint_depth_texture' uniform"
|
|
44
|
+
- "Explains driving the threshold uniform from code via set_shader_parameter or an AnimationPlayer track (not hard-coded)"
|
|
45
|
+
- "Notes that discard disables early-Z / costs overdraw, or otherwise addresses the performance implication"
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# Effect recipes
|
|
2
|
+
|
|
3
|
+
Full per-engine detail behind SKILL.md's recipe table. Each recipe: the technique, then code.
|
|
4
|
+
Godot examples are `.gdshader` (4.x); Unity is URP HLSL/Shader Graph; Unreal is Material graph
|
|
5
|
+
described as node chains (drop to a Custom node only where noted).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Dissolve
|
|
10
|
+
|
|
11
|
+
**Technique.** Sample a noise texture, compare to an animated `threshold`; cut pixels below it;
|
|
12
|
+
add an emissive band in a thin range above the threshold so the edge glows as the object burns.
|
|
13
|
+
|
|
14
|
+
**Godot (spatial):**
|
|
15
|
+
|
|
16
|
+
```glsl
|
|
17
|
+
shader_type spatial;
|
|
18
|
+
render_mode cull_disabled;
|
|
19
|
+
uniform sampler2D noise : hint_default_white;
|
|
20
|
+
uniform float threshold : hint_range(0.0, 1.0) = 0.0;
|
|
21
|
+
uniform float edge = 0.05;
|
|
22
|
+
uniform vec3 edge_color : source_color = vec3(1.0, 0.4, 0.0);
|
|
23
|
+
void fragment() {
|
|
24
|
+
float n = texture(noise, UV).r;
|
|
25
|
+
if (n < threshold) discard;
|
|
26
|
+
float e = smoothstep(threshold, threshold + edge, n);
|
|
27
|
+
ALBEDO = vec3(0.6);
|
|
28
|
+
EMISSION = edge_color * (1.0 - e) * 4.0; // >1 for bloom
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Unity URP (fragment):** `float n = SAMPLE_TEXTURE2D(_Noise, s, uv).r; clip(n - _Threshold);`
|
|
33
|
+
then `emission = _EdgeColor * (1 - smoothstep(_Threshold, _Threshold + _Edge, n));`. In Shader
|
|
34
|
+
Graph: Sample Texture → Step/Smoothstep → Alpha Clip Threshold + Emission.
|
|
35
|
+
|
|
36
|
+
**Unreal:** Blend Mode = Masked. Noise Texture → Subtract Threshold parameter → **Opacity Mask**.
|
|
37
|
+
For the glow, `Smoothstep` around the threshold → multiply EdgeColor → **Emissive Color**. Animate
|
|
38
|
+
Threshold via a Dynamic Material Instance or a Curve.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 2. Rim light & outline
|
|
43
|
+
|
|
44
|
+
**Rim (fresnel).** Brightens grazing angles: `rim = pow(1 - saturate(dot(N, V)), power)`. Cheap,
|
|
45
|
+
per-pixel, great for shields/highlights.
|
|
46
|
+
|
|
47
|
+
**Godot:**
|
|
48
|
+
|
|
49
|
+
```glsl
|
|
50
|
+
shader_type spatial;
|
|
51
|
+
uniform vec3 rim_color : source_color = vec3(0.4, 0.7, 1.0);
|
|
52
|
+
uniform float power : hint_range(0.5, 8.0) = 3.0;
|
|
53
|
+
void fragment() {
|
|
54
|
+
float f = pow(1.0 - dot(normalize(NORMAL), normalize(VIEW)), power);
|
|
55
|
+
EMISSION = rim_color * f;
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Unity:** Fresnel Effect node (Power input) → multiply color → Emission. **Unreal:** Fresnel node
|
|
60
|
+
→ multiply → Emissive Color.
|
|
61
|
+
|
|
62
|
+
**Outline** — two approaches:
|
|
63
|
+
- **Inverted hull** (mesh outline): a second pass that pushes vertices along their normals and
|
|
64
|
+
renders only back faces in the outline color. Godot: a second material pass with
|
|
65
|
+
`render_mode cull_front;` and `VERTEX += NORMAL * width;` in `vertex()`. Unity: an extra Pass
|
|
66
|
+
with `Cull Front` offsetting `positionOS` along the normal. Unreal: post-process, or a second
|
|
67
|
+
mesh scaled along normals.
|
|
68
|
+
- **Post-process edge detect** (screen outline): compare neighboring **depth** and **normal**
|
|
69
|
+
samples; large deltas = an edge. Domain = Post Process (UE) / Full Screen (URP) / ColorRect
|
|
70
|
+
reading `hint_depth_texture` (Godot). Best for uniform-width screen outlines regardless of mesh.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 3. Toon / cel
|
|
75
|
+
|
|
76
|
+
**Technique.** Replace smooth diffuse `N·L` with quantized bands (a hard `step`, a few
|
|
77
|
+
`smoothstep` bands, or a 1D ramp texture lookup). Add a stepped specular and optional rim.
|
|
78
|
+
|
|
79
|
+
**Godot (custom lighting via `light()`):**
|
|
80
|
+
|
|
81
|
+
```glsl
|
|
82
|
+
shader_type spatial;
|
|
83
|
+
uniform sampler2D ramp : hint_default_white, filter_linear;
|
|
84
|
+
void light() {
|
|
85
|
+
float ndl = clamp(dot(NORMAL, LIGHT), 0.0, 1.0);
|
|
86
|
+
float band = texture(ramp, vec2(ndl, 0.5)).r; // ramp = your toon gradient
|
|
87
|
+
DIFFUSE_LIGHT += ATTENUATION * LIGHT_COLOR.rgb * band;
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Cheaper hard cut without a ramp: `float band = step(0.5, ndl);` or two-step
|
|
92
|
+
`smoothstep(0.48, 0.5, ndl)`. **Unity:** compute `NdotL` in a lit HLSL pass and quantize, or a
|
|
93
|
+
Shader Graph with the main light direction + Step. **Unreal:** custom shading is limited without
|
|
94
|
+
engine mods — approximate with a Post Process banding of scene color, or `CustomLighting`-style
|
|
95
|
+
math in an Unlit material driven by a light vector parameter.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 4. Water / flow
|
|
100
|
+
|
|
101
|
+
**Technique.** Two scrolling normal maps at different speeds/scales summed for waves; refract the
|
|
102
|
+
scene behind by offsetting the screen UV with the normal; add depth-based foam where scene depth
|
|
103
|
+
is close to the surface. A **flow map** (RG = 2D flow direction) advects UVs for rivers.
|
|
104
|
+
|
|
105
|
+
**Godot (spatial, refraction + normals):**
|
|
106
|
+
|
|
107
|
+
```glsl
|
|
108
|
+
shader_type spatial;
|
|
109
|
+
render_mode cull_disabled;
|
|
110
|
+
uniform sampler2D normal_map : hint_normal, repeat_enable;
|
|
111
|
+
uniform sampler2D screen_tex : hint_screen_texture, filter_linear_mipmap;
|
|
112
|
+
uniform sampler2D depth_tex : hint_depth_texture;
|
|
113
|
+
uniform float speed = 0.03;
|
|
114
|
+
uniform float strength = 0.02;
|
|
115
|
+
void fragment() {
|
|
116
|
+
vec2 uv1 = UV + vec2(TIME * speed, 0.0);
|
|
117
|
+
vec2 uv2 = UV - vec2(0.0, TIME * speed * 0.7);
|
|
118
|
+
vec3 n = normalize(texture(normal_map, uv1).xyz + texture(normal_map, uv2).xyz - 1.0);
|
|
119
|
+
vec2 refr = SCREEN_UV + n.xy * strength;
|
|
120
|
+
ALBEDO = texture(screen_tex, refr).rgb;
|
|
121
|
+
NORMAL_MAP = n * 0.5 + 0.5;
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Foam: compare linearized `depth_tex` at `SCREEN_UV` to the surface's own depth; where the
|
|
126
|
+
difference is small, `mix` toward white. **Unity:** two Sample Texture 2D (normal) with
|
|
127
|
+
Time-driven offsets → combine → Scene Color offset by normal; Scene Depth node difference for
|
|
128
|
+
foam. **Unreal:** Panner nodes on normal maps, Refraction pin, and `SceneDepth − PixelDepth` for a
|
|
129
|
+
foam mask; Single Layer Water shading model for oceans.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 5. Force field / shield
|
|
134
|
+
|
|
135
|
+
**Technique.** Fresnel base + a scrolling hex/pattern texture, boosted where the mesh intersects
|
|
136
|
+
other geometry (scene-depth difference), additive/translucent. Optional hit ripples from a
|
|
137
|
+
world-space impact point parameter.
|
|
138
|
+
|
|
139
|
+
**Godot:**
|
|
140
|
+
|
|
141
|
+
```glsl
|
|
142
|
+
shader_type spatial;
|
|
143
|
+
render_mode blend_add, cull_disabled, unshaded, depth_draw_never;
|
|
144
|
+
uniform sampler2D pattern : repeat_enable;
|
|
145
|
+
uniform sampler2D depth_tex : hint_depth_texture;
|
|
146
|
+
uniform vec3 color : source_color = vec3(0.2, 0.7, 1.0);
|
|
147
|
+
uniform float power : hint_range(0.5, 8.0) = 2.0;
|
|
148
|
+
void fragment() {
|
|
149
|
+
float fres = pow(1.0 - dot(normalize(NORMAL), normalize(VIEW)), power);
|
|
150
|
+
float hex = texture(pattern, UV + TIME * 0.05).r;
|
|
151
|
+
// intersection glow
|
|
152
|
+
float scene = texture(depth_tex, SCREEN_UV).x;
|
|
153
|
+
vec4 v = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, scene, 1.0);
|
|
154
|
+
float edge = smoothstep(0.0, 1.0, abs(-v.z / v.w - (-VERTEX.z)));
|
|
155
|
+
EMISSION = color * (fres + hex * 0.3 + (1.0 - edge));
|
|
156
|
+
ALPHA = clamp(fres + hex * 0.3, 0.0, 1.0);
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Unity/Unreal:** Fresnel + Panner on a pattern texture, additive/translucent blend, and a Scene
|
|
161
|
+
Depth vs pixel-depth difference (Unity Scene Depth node; UE `SceneDepth − PixelDepth`) for the
|
|
162
|
+
intersection band.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 6. Hologram
|
|
167
|
+
|
|
168
|
+
**Technique.** Scanlines from `sin(worldY * freq + TIME)`, fresnel edge glow, periodic flicker
|
|
169
|
+
(noise or `sin`), a small per-channel UV offset for chromatic fringing, additive or translucent.
|
|
170
|
+
|
|
171
|
+
**Godot:**
|
|
172
|
+
|
|
173
|
+
```glsl
|
|
174
|
+
shader_type spatial;
|
|
175
|
+
render_mode blend_add, cull_disabled, unshaded;
|
|
176
|
+
uniform vec3 color : source_color = vec3(0.3, 0.9, 1.0);
|
|
177
|
+
uniform float lines = 120.0;
|
|
178
|
+
uniform float speed = 2.0;
|
|
179
|
+
varying vec3 wpos;
|
|
180
|
+
void vertex() { wpos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; }
|
|
181
|
+
void fragment() {
|
|
182
|
+
float scan = 0.5 + 0.5 * sin(wpos.y * lines + TIME * speed);
|
|
183
|
+
float fres = pow(1.0 - dot(normalize(NORMAL), normalize(VIEW)), 2.0);
|
|
184
|
+
float flicker = 0.9 + 0.1 * sin(TIME * 30.0);
|
|
185
|
+
EMISSION = color * (scan * 0.6 + fres) * flicker;
|
|
186
|
+
ALPHA = (scan * 0.5 + fres) * flicker;
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Unity:** world-position Y into a Sine → scanlines; Fresnel node; Time-driven flicker; additive.
|
|
191
|
+
**Unreal:** `WorldPosition.B` (Z-up) → Sine → scanlines, Fresnel, Time flicker → Emissive; Blend
|
|
192
|
+
Mode Translucent/Additive, Unlit. Chromatic fringing: sample the effect at slightly offset UVs per
|
|
193
|
+
R/G/B channel.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Cross-cutting notes
|
|
198
|
+
|
|
199
|
+
- **Additive/translucent** effects (shield, hologram, force field) stack overdraw — keep them
|
|
200
|
+
small on screen and unshaded (`render_mode unshaded` / Unlit / Emissive-only).
|
|
201
|
+
- **Depth-based** recipes (foam, intersection glow, screen outline) need the engine's depth
|
|
202
|
+
texture enabled: URP *Depth Texture* toggle; UE reads SceneDepth natively; Godot's
|
|
203
|
+
`hint_depth_texture` is available in the forward+ / mobile renderers.
|
|
204
|
+
- Author tunables (speed, power, colors, thresholds) as **parameters/uniforms** and drive them
|
|
205
|
+
from an animation track or code — never bake magic numbers you'll want to tweak live.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Godot 4.x shading language
|
|
2
|
+
|
|
3
|
+
Depth behind SKILL.md's Godot section. Targets Godot 4.4/4.5. Godot ships its own GLSL-like
|
|
4
|
+
language in `.gdshader` files; a `ShaderMaterial` binds a shader to a node and stores uniform values.
|
|
5
|
+
|
|
6
|
+
## The five shader types
|
|
7
|
+
|
|
8
|
+
Every `.gdshader` starts with exactly one `shader_type`:
|
|
9
|
+
|
|
10
|
+
| `shader_type` | Drives | Key entry points |
|
|
11
|
+
| --- | --- | --- |
|
|
12
|
+
| `spatial` | 3D materials on `MeshInstance3D` etc. | `vertex()`, `fragment()`, `light()` |
|
|
13
|
+
| `canvas_item` | 2D (`Sprite2D`, `TextureRect`, `Control`, …) | `vertex()`, `fragment()`, `light()` |
|
|
14
|
+
| `particles` | GPU particle process (`GPUParticles2D/3D`) | `start()`, `process()` |
|
|
15
|
+
| `sky` | `Sky` resource in an `Environment` | `sky()` |
|
|
16
|
+
| `fog` | `FogVolume` local volumetric fog | `fog()` |
|
|
17
|
+
|
|
18
|
+
Tokens are exact: `canvas_item` has an underscore, `particles` is plural.
|
|
19
|
+
|
|
20
|
+
## Uniforms and hints
|
|
21
|
+
|
|
22
|
+
`uniform`s become material parameters (editable in the inspector, settable from code). Hints tell
|
|
23
|
+
the engine how to treat them:
|
|
24
|
+
|
|
25
|
+
```glsl
|
|
26
|
+
uniform vec4 albedo : source_color = vec4(1.0); // sRGB→linear color picker
|
|
27
|
+
uniform float amount : hint_range(0.0, 1.0, 0.01) = 0.5;// slider min,max,step
|
|
28
|
+
uniform sampler2D tex : source_color, filter_linear_mipmap, repeat_enable;
|
|
29
|
+
uniform sampler2D mask : hint_default_white; // default when unbound (also _black, _transparent)
|
|
30
|
+
uniform sampler2D screen_tex : hint_screen_texture, filter_linear_mipmap;
|
|
31
|
+
uniform sampler2D depth_tex : hint_depth_texture;
|
|
32
|
+
uniform sampler2D nr_tex : hint_normal_roughness_texture;
|
|
33
|
+
global uniform float game_time; // shared project-wide global
|
|
34
|
+
instance uniform vec4 tint : source_color; // per-instance override
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Migration from Godot 3 (never emit the left side): `hint_color`/`hint_albedo` → `source_color`;
|
|
38
|
+
`hint_white`/`hint_black` → `hint_default_white`/`hint_default_black`; the `SCREEN_TEXTURE`,
|
|
39
|
+
`DEPTH_TEXTURE`, `NORMAL_TEXTURE` **built-ins** → `hint_screen_texture` / `hint_depth_texture` /
|
|
40
|
+
`hint_normal_roughness_texture` **uniforms**.
|
|
41
|
+
|
|
42
|
+
Texture filter/repeat qualifiers: `filter_nearest`, `filter_linear`, `filter_nearest_mipmap`,
|
|
43
|
+
`filter_linear_mipmap`, `filter_linear_mipmap_anisotropic`; `repeat_enable`, `repeat_disable`.
|
|
44
|
+
|
|
45
|
+
## varying — vertex → fragment
|
|
46
|
+
|
|
47
|
+
Declare at file scope, write in `vertex()`, read (interpolated) in `fragment()`:
|
|
48
|
+
|
|
49
|
+
```glsl
|
|
50
|
+
varying vec3 world_pos;
|
|
51
|
+
void vertex() { world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; }
|
|
52
|
+
void fragment() { /* use world_pos */ }
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Add an interpolation qualifier when needed: `varying flat int id;` (no interpolation),
|
|
56
|
+
`varying smooth vec3 n;` (default).
|
|
57
|
+
|
|
58
|
+
## render_mode
|
|
59
|
+
|
|
60
|
+
Comma-separated flags right after `shader_type`. Common spatial modes:
|
|
61
|
+
|
|
62
|
+
```glsl
|
|
63
|
+
render_mode blend_add, cull_disabled, unshaded, depth_draw_opaque, depth_test_disabled, shadows_disabled;
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`blend_mix|add|sub|mul`; `cull_back|front|disabled`; `unshaded` (skip lighting); `depth_draw_*`;
|
|
67
|
+
`fog_disabled`. canvas_item supports `blend_*`, `unshaded`, `light_only`, etc.
|
|
68
|
+
|
|
69
|
+
## Built-ins by type (most-used)
|
|
70
|
+
|
|
71
|
+
**spatial `fragment()` — inputs:** `UV`, `UV2`, `NORMAL` (view space), `VIEW` (view space, toward
|
|
72
|
+
camera), `VERTEX` (view-space position), `COLOR` (vertex color), `SCREEN_UV`, `TIME`,
|
|
73
|
+
`FRAGCOORD`, matrices `MODEL_MATRIX`, `VIEW_MATRIX`, `INV_VIEW_MATRIX`, `PROJECTION_MATRIX`,
|
|
74
|
+
`INV_PROJECTION_MATRIX`. **outputs:** `ALBEDO`, `ALPHA`, `METALLIC`, `ROUGHNESS`, `SPECULAR`,
|
|
75
|
+
`EMISSION`, `NORMAL_MAP` (tangent-space, expects 0–1), `NORMAL_MAP_DEPTH`, `AO`, `RIM`,
|
|
76
|
+
`CLEARCOAT`, `ALPHA_SCISSOR_THRESHOLD`.
|
|
77
|
+
|
|
78
|
+
**spatial `vertex()`:** read/write `VERTEX`, `NORMAL`, `TANGENT`, `UV`, `COLOR`; write `POSITION`
|
|
79
|
+
directly (in clip space) to bypass the standard transform — used for full-screen quads:
|
|
80
|
+
`POSITION = vec4(VERTEX.xy, 1.0, 1.0);`.
|
|
81
|
+
|
|
82
|
+
**canvas_item `fragment()`:** inputs `UV`, `COLOR` (vertex×modulate), `SCREEN_UV`, `TEXTURE`
|
|
83
|
+
(the node's texture), `TEXTURE_PIXEL_SIZE`, `TIME`; output `COLOR`. `MODULATE` exposes the
|
|
84
|
+
CanvasItem modulate separately.
|
|
85
|
+
|
|
86
|
+
**particles `process()`:** `TRANSFORM`, `VELOCITY`, `COLOR`, `CUSTOM`, `LIFETIME`, `DELTA`,
|
|
87
|
+
`RESTART`, `EMISSION_TRANSFORM`, `ATTRACTOR_FORCE`.
|
|
88
|
+
|
|
89
|
+
## Screen and depth reads
|
|
90
|
+
|
|
91
|
+
`SCREEN_TEXTURE` is gone — declare a uniform:
|
|
92
|
+
|
|
93
|
+
```glsl
|
|
94
|
+
shader_type canvas_item;
|
|
95
|
+
uniform sampler2D screen_tex : hint_screen_texture, filter_linear_mipmap;
|
|
96
|
+
void fragment() { COLOR = texture(screen_tex, SCREEN_UV); } // what's behind this node
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Depth to view/world position in a spatial full-screen pass:
|
|
100
|
+
|
|
101
|
+
```glsl
|
|
102
|
+
uniform sampler2D depth_tex : hint_depth_texture;
|
|
103
|
+
void fragment() {
|
|
104
|
+
float d = texture(depth_tex, SCREEN_UV).x;
|
|
105
|
+
vec4 ndc = vec4(SCREEN_UV * 2.0 - 1.0, d, 1.0);
|
|
106
|
+
vec4 view = INV_PROJECTION_MATRIX * ndc; view.xyz /= view.w; // view-space position
|
|
107
|
+
float linear_depth = -view.z;
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## ShaderMaterial from code (GDScript)
|
|
112
|
+
|
|
113
|
+
```gdscript
|
|
114
|
+
var mat := ShaderMaterial.new()
|
|
115
|
+
mat.shader = preload("res://dissolve.gdshader")
|
|
116
|
+
mesh.material_override = mat
|
|
117
|
+
mat.set_shader_parameter("threshold", 0.7)
|
|
118
|
+
mat.set_shader_parameter("edge_color", Color(1, 0.4, 0))
|
|
119
|
+
# animate a uniform each frame
|
|
120
|
+
func _process(delta): mat.set_shader_parameter("threshold", t)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
C# parity: `mat.SetShaderParameter("threshold", 0.7f);`. Prefer an `AnimationPlayer` track on the
|
|
124
|
+
material's `shader_parameter/<name>` for authored animations.
|
|
125
|
+
|
|
126
|
+
## Common gotchas
|
|
127
|
+
|
|
128
|
+
- `NORMAL` and `VIEW` in a spatial `fragment()` are **view space**, not world — transform with
|
|
129
|
+
`INV_VIEW_MATRIX` if you need world space (e.g. triplanar, world-space fresnel toward a point).
|
|
130
|
+
- Re-`normalize()` interpolated normals per pixel.
|
|
131
|
+
- `discard` (and `ALPHA_SCISSOR_THRESHOLD`) disables early depth — costs overdraw; use only for cutouts.
|
|
132
|
+
- Set `render_mode unshaded` on pure-emissive/effect materials to skip the lighting cost.
|
|
133
|
+
- Precompute in `vertex()` and pass a `varying` whenever the quantity interpolates linearly.
|