User Pixel Shaders¶
EdenSpark supports custom pixel shaders authored in Daslang. A pixel shader is a GPU program that runs once per fragment and determines the final color output for that pixel, with full access to interpolated vertex attributes, material properties, and global engine state.
Quick Start¶
PBR shader — the surface is shaded by the scene lighting (directional light, point lights, global illumination):
require engine.render.shader_dsl
var {
@color tint = float3(0.2, 0.8, 1.0) // editable color picker in material inspector
speed = 2.0
}
[pixel_shader]
def hologram_effect(inp : PbrInput) {
let n = noise(inp.worldPos)
let pulse = sin(g_Time * speed) * 0.5 + 0.5
return PbrOutput(
albedo = tint * n,
emission = tint * pulse,
emissionStrength = pulse * 0.5,
metalness = 0.0,
roughness = 1.0,
ao = 1.0
)
}
Unlit shader — no lighting, direct color output:
require engine.render.shader_dsl
var @color color = float3(1.0, 0.5, 0.0)
[pixel_shader]
def flat_color(inp : UnlitInput) {
return UnlitOutput(
color = color,
alpha = 1.0
)
}
Files and Hot-Reload¶
Create a
foo.shaderfile anywhere in the project folder.Assign the shader to a material via the Material inspector by selecting it in the shader slot — you can replace the built-in shader on any material or create a new
.materialfile that references it.Hot-reload is triggered when you save from within the editor (Ctrl+S). Saving from an external editor may not trigger a rebuild.
Material Properties¶
Module-level var declarations become per-material properties editable in
the inspector and overridable per mesh instance.
var {
speed = 2.0 // float
offset = float2(0.5, 0.0) // float2
@color tint = float3(1.0, 1.0, 1.0) // float3 with color picker
blend = float4(1.0, 0.0, 0.0, 1.0) // float4
albedoTex : Sampler2D = Sampler2D("assets/default.png") // texture
}
Type |
Notes |
|---|---|
|
Single scalar |
|
Two-component vector; default as |
|
Three-component vector; default as |
|
Four-component vector; default as |
|
Texture reference; default as |
|
Same storage as |
Defaults must be constant literals. References to other module-level let
constants are also allowed.
Note
Only variables declared in the same module as the [pixel_shader]
function become material properties. Variables from other modules cannot
be accessed.
Shader Types¶
The shader type is determined by the function signature: the parameter type selects what geometry data is available as input, and the return type selects which outputs are written.
PBR Shader (PbrInput → PbrOutput)¶
Physically-based rendering — the surface is lit by the engine’s full lighting
pipeline: directional light, point lights, spot lights, and global illumination.
The lighting model applies NdotL and BRDF on top of albedo automatically.
Do not pre-multiply your own lighting into albedo — use emission
for self-lit additive effects instead.
PbrInput fields — access as inp.fieldName:
Field |
Type |
Description |
|---|---|---|
|
float2 |
Texture UV coordinates |
|
float3 |
World-space position of the current fragment |
|
float3 |
World-space surface normal (normalized) |
|
float3 |
Direction from the fragment toward the camera (world-space, normalized) |
|
float3 |
Object-space position of the current fragment |
|
float3 |
Object-space surface normal (normalized) |
PbrOutput fields — all optional; specify only what you need:
Field |
Type |
Default |
Description |
|---|---|---|---|
|
float3 |
float3(0) |
Base color (diffuse reflectance). Modulated by scene lighting. |
|
float |
1.0 |
Opacity [0, 1] |
|
float |
0.0 |
Alpha-test threshold. Fragments below are discarded. |
|
float |
0.0 |
PBR metalness [0, 1] |
|
float |
1.0 |
PBR roughness [0, 1] |
|
float3 |
float3(0) |
Additive emissive color. Not affected by lighting. |
|
float |
1.0 |
Multiplier on |
|
float3 |
float3(0, 0, 1) |
Tangent-space normal. Decode from a texture with |
|
float |
1.0 |
Ambient occlusion [0, 1] |
Unlit Shader (UnlitInput → UnlitOutput)¶
No lighting — direct color output. Use for HUD quads, UI meshes, additive particle effects, and any surface that must be lighting-independent.
UnlitInput has the same fields as PbrInput.
UnlitOutput fields:
Field |
Type |
Default |
Description |
|---|---|---|---|
|
float3 |
float3(0) |
Output color |
|
float |
1.0 |
Opacity [0, 1] |
|
float |
0.0 |
Alpha-test threshold |
Global Inputs¶
Available directly by name in any shader, without using the input struct:
Name |
Type |
Description |
|---|---|---|
|
float |
Global time in seconds since the application started |
|
float3 |
Main directional light direction — pointing toward the sun, world-space, normalized |
Built-in Functions¶
All functions are overloaded for float, float2, float3, and
float4 unless noted otherwise. Operations are component-wise.
Arithmetic¶
Signature |
Description |
|---|---|
|
Absolute value: |x| |
|
Component-wise minimum |
|
Component-wise maximum |
|
Clamp each component to [lo, hi] |
|
Clamp to [0, 1] |
|
Fractional part: x − floor(x) |
|
Round down to the nearest integer |
|
Round up to the nearest integer |
|
Multiply-add: a × b + c. Fused into a single instruction automatically. |
|
Linear interpolation: a + t × (b − a). |
|
Step function: 0 if x < edge, 1 otherwise |
|
Smooth Hermite interpolation between lo and hi |
|
1 − x |
|
Remap x from inRange to outRange. inRange and outRange are |
Transcendentals¶
All component-wise:
Function |
Description |
|---|---|
|
Square root |
|
Power: x^y |
|
Sine (radians) |
|
Cosine (radians) |
|
Arc-tangent of y/x |
|
Natural logarithm |
|
Natural exponentiation: e^x |
|
Sign: −1, 0, or +1 |
Vector Operations¶
Dimension-specific:
Signature |
Description |
|---|---|
|
Dot product (float2/3/4 × float2/3/4 → float) |
|
Cross product (float3 × float3 → float3) |
|
Vector length (float2/3/4 → float) |
|
Normalize to unit length (float2/3/4 → same type) |
Lighting¶
- fresnel(power: float; worldNorm: float3; viewDir: float3): float¶
Schlick-style Fresnel approximation. Returns values close to 0 at the surface center and close to 1 at glancing angles. Increase
powerto tighten the rim. Passinp.worldNormalandinp.viewDirdirectly:let rim = fresnel(3.0, inp.worldNormal, inp.viewDir) return PbrOutput(emission = float3(rim))
Texture Sampling¶
- tex2d(sampler: Sampler2D; uv: float2): float4¶
Sample a 2D texture at the given UV coordinates. Declare the texture as a material property and pass it here:
var albedoTex : Sampler2D = Sampler2D("assets/base_color.png") [pixel_shader] def textured(inp : PbrInput) { let c = tex2d(albedoTex, inp.uv) return PbrOutput(albedo = c.xyz, alpha = c.w) }
Use
.rgba,.rgb,.aswizzles to extract channels from the returnedfloat4.
Noise¶
- noise(pos: float2): float
2D Perlin noise. Returns values in [0, 1].
- noise(pos: float3): float
3D Perlin noise. Returns values in [0, 1].
Normal Map Utility¶
- unpack_normal(sample: float4): float3¶
Decode a tangent-space normal from a standard RGB normal-map texture sample. Input is the
float4returned bytex2d; output is afloat3in [−1, 1]:var normalTex : Sampler2D = Sampler2D("assets/normal.png") [pixel_shader] def with_normalmap(inp : PbrInput) { let n = unpack_normal(tex2d(normalTex, inp.uv)) return PbrOutput(normalMap = n) }
Language Subset¶
The shader DSL is a strict subset of Daslang. The [pixel_shader]
macro walks the AST at compile time and rejects unsupported constructs.
Supported:
Arithmetic operators
+-*/(unary-→ Negate node)Swizzle access:
v.xyz,v.zyx,v.xxxx, etc.Field reads on the input struct:
inp.uv,inp.worldPos, etc.letlocal declarations — type must befloat/float2/float3/float4, value must be initializedFloat and vector literals (
1.0,float3(0.2, 0.8, 1.0))Integer literals — auto-promoted to float
Module-level
vardeclarations → material propertiesAll built-in functions listed above
Not supported:
Mutable
varlocals — useletControl flow:
if,for,while— the shader graph is a pure DAG with no branchesTernary operator
?:Heap allocations (
new)Strings, arrays, tables, variants
Pointer types and
unsafebool,int,uintlocals (integer literals are auto-promoted to float)Multiple
[pixel_shader]functions in one module — one.shader= one entry point
See Shader and Shader Graph Compiler for details on how the compiler enforces these restrictions.