LLMSkillHub
mirroredCopied from dylanroscover/Embody under MIT. dylanroscover has not claimed this page, and is not affiliated with LLM SkillHub.

dylanroscover / glsl-shaders

MUST READ before writing GLSL or creating a glslTOP, glslmultiTOP, glslMAT or glslPOP: docked DATs, uniforms and the Colors page, TD's built-in functions and samplers, feedback and multi-pass, reading compile errors. Every built-in named here compiled on TD 2025.33230.

0
SKILL.md
8.6 KB

<!-- Generated by Embody/Envoy - Do not remove this comment - sha:ba697c6b4d3a77c7 -->

GLSL Shaders

Three hosts: glslTOP/glslmultiTOP (pixels, or compute over an image), glslMAT (vertex + pixel over geometry), glslPOP (compute over points; the POP side lives in /pop-networks). Every function and parameter below compiled live on TD 2025.33230 (probed 2026-09-25). Anything you add beyond them: check the parameter with describe_op_type and the function with the docked info DAT before trusting it.

The docked-DAT contract

  • Creating a glslTOP/glslmultiTOP docks <name>_pixel, <name>_compute, <name>_info, with pixeldat/computedat already pointing at them. A glslMAT docks <name>_vertex, <name>_pixel, <name>_info (vdat/pdat). A glslPOP docks <name>_compute and <name>_info.
  • Name the operator at creation (glsl_<purpose>): dock names and the *dat references are snapshots taken then and do not follow a later rename.
  • Write the shader INTO the docked DAT (set_dat_content / edit_dat_content). Delete the dock you do not use (_compute for a pixel shader) so it does not ship as dead weight. One exception: several GLSL ops running identical code point at ONE shared DAT and differ by uniforms (tdxn-economy.md).
  • create_op hugs the docks under the host; an execute_python build must place them itself (/create-operator).
  • Read compile results from <name>_info: op.errors() says only "Compile failed". get_op_errors returns them as shaderErrors, and every DAT write to a shader rides back _effects.new_shader_errors. Fix those before building further.

What TD gives you (never redeclare, never paste an alternative)

  • No #version line: TD injects one, and writing your own fails with "'#version' : must occur first in shader". texture(), never texture2D() ("function not supported in this version; use texture() instead").
  • Inputs: sTD2DInputs[i], sTD3DInputs[i], sTD2DArrayInputs[i], sTDCubeInputs[i], indexed per TYPE, not per connector. TD_NUM_2D_INPUTS (and the 3D/array/cube twins) bound a loop and guard a dynamic index. uTD2DInfos[i].res and uTDOutputInfo.res are (1/w, 1/h, w, h). vUV.st is the 0-1 texture coordinate when there is no custom vertex shader. uTDPass is the multi-pass index, uTDCurrentDepth the 3D slice.
  • Lookups: sTDNoiseMap (256x256 random), sTDSineLookup.
  • Functions: TDOutputSwizzle(vec4) on EVERY color you write out (channel order is wrong without it), TDDither, TDPerlinNoise(vec2|vec3|vec4) and TDSimplexNoise(vec2|vec3|vec4) (both in -1..1, available in TOP, MAT and glslPOP shaders on this build), TDHSVToRGB, TDRGBToHSV, TDRotateOnAxis(rad, axis), TDRotateX/Y/Z(rad).
  • Compute in a glslTOP (mode=compute): declare layout(local_size_x = 8, local_size_y = 8) in;, write with TDImageStoreOutput(0, ivec3(gl_GlobalInvocationID.xy, 0), TDOutputSwizzle(color)), read the output back with TDImageLoadOutput(0, ivec3(...)).
  • glslTOP has exactly 3 input connectors. glslmultiTOP takes more and adds POP buffer reads (buffer0pop, buffer0attr, buffer0name -> TDBuffer_<Name>(idx) in the shader). Reach for glslmultiTOP whenever you need a fourth input or a POP attribute.

Uniforms

  • Vectors page: vec0name + vec0valuex/y/z/w, a sequence (grow it with op.seq.vec.numBlocks = N). On a TOP or MAT the SHADER declares the uniform and TD infers the type from the declaration (uniform vec4 uParams;); there is no vec0type here, and an undeclared name silently reads nothing. Pack four values per vec; the values take expressions (absTime.seconds * parent.Fx.par.Speed).
  • Colors page: color0name + color0rgbr/g/b + color0alpha -> uniform vec4 uTint; with a colour swatch in the dialog. Use it for colours instead of a raw vec.
  • Constants page: const0name/const0value are baked in at compile time, so every change RECOMPILES the shader. Runtime values belong on Vectors; constants only for true compile-time switches.
  • glslPOP inverts one rule: its uniforms are AUTO-DECLARED from the Vectors page (uniform highp float uSpeed; by default). Declaring them again is a "Redeclaration" error, and the type comes from vec0type (float, vec2..vec4, int, uint, ...). Samplers, Arrays, Matrices and Buffers pages follow the same shape on every host.

Pixel shader minimum

uniform vec4 uParams;           // Vectors page: vec0name = uParams
layout(location = 0) out vec4 fragColor;
void main() {
    vec4 c = texture(sTD2DInputs[0], vUV.st);
    fragColor = TDOutputSwizzle(c * uParams.x);
}

Output format and resolution are parameters, not shader code: format (rgba8fixed clamps to 0-1 -- data, feedback and HDR need rgba16float or rgba32float), outputresolution (useinput, custom with resolutionw/resolutionh, fit, ...). There is no resolution parameter. premultrgbbyalpha defaults ON and multiplies RGB by your alpha -- turn it off on an op whose alpha carries data. Multiple render targets: numcolorbufs, declare layout(location = 1) out vec4 fragField;, and pull buffer N with a Render Select TOP (set its format to float).

glslMAT

One combined DAT with #ifdef TD_VERTEX_SHADER / #ifdef TD_PIXEL_SHADER guards, set as BOTH vdat and pdat; keep _info.

  • Vertex: TDDeform(TDPos()) gives the world position (never raw TDPos() -- instancing and deformers ride on TDDeform), TDDeformNorm(TDNormal()) the world normal, TDWorldToProj(worldPos) is gl_Position, TDCameraIndex() goes out as a flat int varying, TDPointColor() / TDInstanceColor(c) carry point and instance colour.
  • Pixel: TDCheckDiscard() first; uTDMats[cam].camInverse[3].xyz is the camera position; loop TD_NUM_LIGHTS with TDLightingPBR(i, diffuseColor, specularColor, worldPos, normal, shadowStrength, shadowColor, viewDir, roughness) (a TDPBRResult with .diffuse/.specular) and TD_NUM_ENV_LIGHTS with TDEnvLightingPBR(inout diffuse, inout specular, i, diffuseColor, specularColor, normal, viewDir, roughness, ambientOcclusion); TDFog(color, worldPos, cam); then TDOutputSwizzle(TDDither(color)) into oFragColor[0], declared layout(location = 0) out vec4 oFragColor[TD_NUM_COLOR_BUFFERS];.
  • Transparency needs blending ON and honest srcblend/destblend (one, zero, sa, omsa, ...) with the alpha pair srcblenda/destblenda; cullface=neither shows both faces of filled POP geometry.
  • Extending a PBR look: start from a pbrMAT and pulse outputshader -- TD writes its own vertex and pixel code into a new glslMAT for you to edit.

Feedback and multi-pass

  • Feedback: Constant TOP (clear) -> Feedback TOP -> glsl -> Null TOP; the Feedback TOP's top names the null that closes the loop, resetpulse resets it. Close the loop BEFORE compiling shaders that depend on the fed-back texture. Bound every loop per performance.md: fixed resolution inside it, decay below 1, reset wired, bypassed while wiring.
  • One feedback is one iteration per frame. Iterative solvers use npasses on the GLSL op instead: pass N+1 sees pass N on input 0, uTDPass tells you which.
  • 3D output: type=texture3d, depth=custom, customdepth=N; the shader runs once per slice with uTDCurrentDepth. constantTOP and noiseTOP have no customdepth, so seed a volume from a small glslTOP, not from them.

Discipline

  • A built-in operator beats a shader when one exists (Noise, Ramp, Lookup, Composite, Level TOPs; Math and Lookup CHOPs). GLSL is for what they cannot express: advection, solvers, custom lighting, per-point compute.
  • Bound every loop with a constant and guard dynamic sampler or array indexes with TD_NUM_*: an out-of-bounds index can take TD down (/td-api-reference, Heavy-Build Safety).
  • centroid is a reserved word in GLSL 4.60. me.time.step does not exist: delta time is absTime.stepSeconds (or 1.0 / me.time.rate).
  • Externalize shader DATs with externalize_op (tag glsl) so they diff in git; edit the file, TD recompiles.
  • Verify by looking: capture_top the output (a Quality: FAIL is a black or flat frame) and read <name>_info after every edit. A shader that compiles and renders TD's fallback pattern still reads as an error in the info DAT.

Topics cross-checked against Derivative's TDMCPSkills td-glsl-shaders with permission; every claim above was recompiled live on 2025.33230 before it was written down.