Shader Spec
Reference for writing effect shaders in Arshes. Shaders are written in Slang and compiled to Metal on device. User code is self-contained — there are no modules to import.
Entry Points
Fragment
Entry point. Receives UV (0.0-1.0) or custom VertexOutput, returns RGBA.
[shader("fragment")]
float4 fragmentMain(float2 uv : TEXCOORD) : SV_Target {
return float4(uv, 0.0, 1.0);
}
Vertex (Optional)
Custom vertex shader with [primitive(type, count)]. Overrides default fullscreen quad.
struct VertexOutput {
float4 position : SV_Position;
float4 color : COLOR;
};
[primitive(4, 1000)]
[shader("vertex")]
VertexOutput vertexMain(uint vid : SV_VertexID, uint iid : SV_InstanceID) {
Particle p = particles[iid];
// vid: 0~3 (quad corners)
// iid: 0~999 (which particle)
}
Compute (Optional)
Runs before fragment, in declaration order. Multiple compute shaders can be declared. Use [dispatch] and [numthreads] to set thread count.
struct State {
float value;
};
[size(1)]
RWStructuredBuffer<State> state;
[dispatch(1, 1, 1)]
[numthreads(1, 1, 1)]
[shader("compute")]
void computeMain(uint3 id : SV_DispatchThreadID) {
state[0].value = lerp(state[0].value, microphone, 0.1);
}
Built-in Uniforms
Values and textures provided by the engine. Declare them with the exact names below and they are bound automatically.
time
Elapsed time in seconds since the shader started.
uniform float time;
deltaTime
Time in seconds since the last frame.
uniform float deltaTime;
frame
Frame count since the shader started. Resets on recompile.
uniform int frame;
resolution
Screen resolution in pixels (width, height). RESOLUTION_X/Y macros are also available as int.
uniform float2 resolution;
cameraTex
Camera RGB texture in linear color space (no color grading applied). The filter (color grading) and sRGB encoding are applied after your effect.
uniform Texture2D<float3> cameraTex;
depthTex
Depth texture. Available with LiDAR or dual wide camera. DEPTH_RESOLUTION_X / DEPTH_RESOLUTION_Y macros expose its dimensions as int.
uniform Texture2D<float> depthTex;
backbuffer
Previous frame buffer.
uniform Texture2D<float4> backbuffer;
blueNoiseTex
256x256 single-channel blue noise texture. Read exact texels with .Load(int3(px % 256, py % 256, 0)) to preserve the noise (no sampler filtering). Tileable across the 256x256 boundary.
uniform Texture2D<float> blueNoiseTex;
sampler
Sampler state for texture sampling. Any name can be used.
uniform SamplerState sampler;
microphone
Microphone input volume (RMS). Ranges from 0.0 to 1.0.
uniform float microphone;
touch
Touch input. xy: position (0,0)-(1,1), z: 1.0 while touching, 0.0 when released. xy retains last position.
uniform float3 touch;
cameraPosition
Camera world position. Available when AR is enabled.
uniform float3 cameraPosition;
invViewMatrix
Inverse view matrix of the camera. Available when AR is enabled.
uniform float4x4 invViewMatrix;
invProjectionMatrix
Inverse projection matrix of the camera. Available when AR is enabled.
uniform float4x4 invProjectionMatrix;
Read-Write Resources
Persistent resources you declare yourself (any name). Their contents survive across frames.
RWStructuredBuffer
Persistent read-write buffer for compute shaders. Supports custom structs. Use [size(N)] to set element count.
[size(4)]
RWStructuredBuffer<float4> state;
RWTexture2D
Persistent read-write 2D texture. Use [size2d(w, h)] for dimensions. Optionally declare a matching Texture2D (sans "RW" prefix) for bilinear sampling.
[size2d(RESOLUTION_X, RESOLUTION_Y)]
RWTexture2D<float4> canvasRW;
// read-only view of canvasRW
Texture2D<float4> canvas;
Attributes
[range(min, max, default)]
Exposes a uniform float/int as a slider.
[range(0.0, 1.0, 0.5)]
uniform float brightness;
[rgb(r, g, b)]
Exposes a uniform float3 as a color picker. Colors are authored in sRGB and automatically converted to linear before reaching your shader (your effect works in linear space), so the picked color appears as-is.
[rgb(1.0, 0.0, 0.0)]
uniform float3 tintColor;
[rgba(r, g, b, a)]
Exposes a uniform float4 as a color picker with alpha. RGB is authored in sRGB and converted to linear automatically; alpha is passed through unchanged.
[rgba(1.0, 1.0, 1.0, 0.5)]
uniform float4 bgColor;
[toggle(default)]
Exposes a uniform bool as a toggle.
[toggle(true)]
uniform bool useEffect;
[size(N)]
Sets the element count for RWStructuredBuffer. Default: 1.
[size(64)]
RWStructuredBuffer<float4> particles;
[size2d(w, h)]
Sets the texture dimensions for RWTexture2D. Use RESOLUTION_X/Y for screen-linked sizing, or DEPTH_RESOLUTION_X/Y for depth-linked sizing.
[size2d(RESOLUTION_X / 2, RESOLUTION_Y / 2)]
RWTexture2D<float4> canvas;
[dispatch(x, y, z)]
Sets threadgroup count for a compute shader. Total threads = dispatch × numthreads.
[dispatch(RESOLUTION_X / 8, RESOLUTION_Y / 8, 1)]
[numthreads(8, 8, 1)]
[shader("compute")]
void computeMain(uint3 id : SV_DispatchThreadID) { }
[primitive(type, count)]
Defines geometry for a custom vertex shader. type: verts per primitive (1=point, 3=tri, 4=quad). count: instances.
[primitive(4, 1000)]
[shader("vertex")]
VertexOutput vertexMain(uint vid : SV_VertexID, uint iid : SV_InstanceID) {
// vid: 0~3 (quad corners), iid: 0~999 (particle index)
}
[pass(index)]
Defines multi-pass rendering. Passes render sequentially (pass 0 clears, 1+ preserves). Max 8.
[pass(0)]
[shader("fragment")]
float4 background(float2 uv : TEXCOORD) : SV_Target {
return float4(uv, 0.5, 1.0);
}
[pass(1)]
[primitive(3, 1)]
[shader("vertex")]
VertexOutput triVert(uint vid : SV_VertexID, uint iid : SV_InstanceID) { ... }
[pass(1)]
[shader("fragment")]
float4 triangle(VertexOutput input) : SV_Target {
return input.color;
}
[blend(blendMode)]
Sets blend mode: BlendMode.None (overwrite), BlendMode.Additive (src+dst), BlendMode.Alpha (standard alpha blend).
[blend(BlendMode.Alpha)]
[shader("fragment")]
float4 overlay(float2 uv : TEXCOORD) : SV_Target {
float d = length(uv - 0.5);
float alpha = smoothstep(0.3, 0.2, d);
return float4(1.0, 0.5, 0.0, alpha);
}