HLSL passes
The HLSL a compute pass, or a fullscreen pass without a material, runs — written in an hlsl block of the .dsp or in a .usf, the names its bindings make, the fixed parameters and helpers of DreamPass.ush, and how the code reaches the engine through a pre-check and a snapshot. Needs UE 5.8.
DreamShaderBuiltins.ush
DreamShader » Builtins »
DreamShaderBuiltins.ush
An HLSL header shipped with the plugin, defining DS_* macros and functions that mirror the HLSL the
material translator emits for the corresponding UE.* builtin nodes.
| Kind | shipped HLSL header |
| On disk | <Plugin>/Shaders/DreamShaderBuiltins.ush |
| Virtual shader path | /Plugin/DreamShader/DreamShaderBuiltins.ush |
| Include guard | DREAMSHADER_BUILTINS_USH |
| Defines | 25 DS_* symbols — 22 macros and 3 functions |
| Emitted by the plugin | no — see Reachability |
Synopsis
#include "/Plugin/DreamShader/DreamShaderBuiltins.ush"The virtual path
At module startup DreamShader registers a shader source directory mapping from the virtual directory
/Plugin/DreamShader to the plugin's Shaders folder, unless a mapping for that virtual directory
already exists. The mapping is unconditional — it does not depend on any project setting, backend
choice or engine version — so /Plugin/DreamShader/DreamShaderBuiltins.ush always resolves for the
engine's shader preprocessor.
This is a separate mapping from the generated shader virtual directory, /DreamShaderGenerated,
which the module also registers. Since 2.0.0 DreamShader writes no per-source helper .ush there: the
HLSL of a Function is embedded in the code of its Custom node. See
Generated HLSL.
Reachability
Nothing in the plugin emits an include for this header, and nothing in the plugin references any
DS_* symbol. The only occurrence of the name outside the file itself is a source comment.
| Path | Includes this header? |
|---|---|
A Custom node made from a Function block | no — the body is the node's code, other Functions it calls are embedded as DreamShaderFn_* members of a generated wrapper struct, and the node's include list holds only the #include lines at the head of the body (since 2.0.0; 1.x wrote a per-source helper .ush) |
The Graph backend | no — it emits material nodes, not HLSL |
The ThinCustom backend | no |
A hand-written #include in a Function HLSL body | yes — the virtual path resolves |
The header's own comment describes it as being included by generated DSI_*.ush files inside the
material translation unit. That was the arrangement used by the Instance backend, which has been
retired: the resolved backend set is now Graph and ThinCustom, and Backend = "Instance" is an
alias for ThinCustom (deprecated in 1.5.0). No DSI_*.ush file is produced any more, so the
comment describes a path that no longer runs. See Backend.
Every state read the header exposes now has a material-node equivalent in the
UE.* catalogue, and SampleTexture2D(tex, uv) in a Graph block desugars directly to a
TextureSample node. Reaching for this header is therefore only useful inside hand-written HLSL.
Symbols
Parameters is the material parameter struct in scope at the include site; Tex is a texture
parameter identifier, from which the sampler name is derived by token pasting (Tex##Sampler).
| Symbol | Kind | Expansion | Node equivalent |
|---|---|---|---|
DS_TIME | macro | (View.GameTime) | UE.Time() |
DS_REAL_TIME | macro | (View.RealTime) | — |
DS_DELTA_TIME | macro | (View.DeltaTime) | — |
DS_PERIODIC_TIME(Period) | macro | (fmod(View.GameTime, (Period))) | UE.Time(Period=…) |
DS_TexCoord(Parameters, CoordinateIndex) | float2 function | Parameters.TexCoords[CoordinateIndex].xy, or float2(0, 0) when NUM_TEX_COORD_INTERPOLATORS is 0 | UE.TexCoord |
DS_VertexColor(Parameters) | float4 function | Parameters.VertexColor | UE.VertexColor |
DS_CameraVector(Parameters) | macro | ((Parameters).CameraVector) | UE.CameraVector |
DS_ReflectionVector(Parameters) | macro | ((Parameters).ReflectionVector) | UE.ReflectionVector |
DS_PixelNormalWS(Parameters) | macro | ((Parameters).WorldNormal) | UE.PixelNormalWS |
DS_VertexNormalWS(Parameters) | macro | ((Parameters).TangentToWorld[2]) | UE.VertexNormalWS |
DS_TwoSidedSign(Parameters) | macro | ((Parameters).TwoSidedSign) | UE.TwoSidedSign |
DS_ViewportUV(Parameters) | macro | (GetViewportUV(Parameters)) | UE.ViewportUV |
DS_PixelDepth(Parameters) | macro | (GetPixelDepth(Parameters)) | UE.PixelDepth |
DS_WorldPosition(Parameters) | macro | (WSDemote(GetWorldPosition(Parameters))) | UE.WorldPosition |
DS_TranslatedWorldPosition(Parameters) | macro | (GetTranslatedWorldPosition(Parameters)) | UE.TranslatedWorldPosition |
DS_ObjectPosition(Parameters) | macro | (WSDemote(GetObjectWorldPosition(Parameters))) | UE.ObjectPosition |
DS_ObjectRadius(Parameters) | macro | (GetPrimitiveData(Parameters).ObjectRadius) | UE.ObjectRadius |
DS_ObjectBounds(Parameters) | macro | (float3(GetPrimitiveData(Parameters).ObjectBoundsX, …ObjectBoundsY, …ObjectBoundsZ)) | UE.ObjectBounds |
DS_CameraPosition(Parameters) | macro | (WSDemote(GetWorldCameraOrigin(Parameters))) | UE.CameraPosition |
DS_PerInstanceRandom(Parameters) | macro | (GetPerInstanceRandom(Parameters)) | UE.PerInstanceRandom |
DS_PerInstanceFadeAmount(Parameters) | macro | (GetPerInstanceFadeAmount(Parameters)) | UE.PerInstanceFadeAmount |
DS_Panner(UV, Time, Speed) | float2 function | UV + float2(frac(Time * Speed.x), frac(Time * Speed.y)) | UE.Panner |
DS_SampleTexture2D(Tex, UV) | macro | Texture2DSample(Tex, Tex##Sampler, UV) | SampleTexture2D(tex, uv) in a Graph block |
DS_SampleTexture2DLod(Tex, UV, Lod) | macro | Texture2DSampleLevel(Tex, Tex##Sampler, UV, Lod) | — |
DS_SampleTexture2DBias(Tex, UV, Bias) | macro | Texture2DSampleBias(Tex, Tex##Sampler, UV, Bias) | — |
The WSDemote calls lower the engine's large-world-coordinate vectors to float3. The translated
(camera-relative) position form is already float3 and keeps precision near the camera.
The header's comment notes that the DSL used to write the unprefixed spellings
SampleTexture2D / SampleTexture2DLod / SampleTexture2DBias and have the generator lower them to
these macros. No such rewrite is performed today. SampleTexture2D is still a reserved name in a
Graph block, where it desugars to a TextureSample node — see
UE.Expression — but the Lod and Bias spellings have no
Graph equivalent.
Notes
[!NOTE] Put the
#includefirst. An#includewritten at the top of aFunctionbody (only whitespace and comments before it) is taken out of the body and put on the Custom node's include list, which the engine includes outside the generated function — see Function ▸ Includes — so the header's function definitions compile normally. An#includethat comes after a statement, or after any other#line, stays in the body, which the engine pastes inside a function; there the 22 macros still work (a#defineis legal anywhere) but the three function definitions (DS_TexCoord,DS_VertexColor,DS_Panner) are not legal inside another function body.
[!WARNING]
DS_TexCoordandDS_VertexColordepend on translator side effects that nothing arranges any more.DS_TexCoordreadsParameters.TexCoords[…], which only exists when at least one interpolator slot was allocated during material translation (NUM_TEX_COORD_INTERPOLATORS> 0); with no slot allocated the function compiles and returnsfloat2(0, 0).DS_VertexColorreadsParameters.VertexColor, which is only fed when the material was translated with vertex-colour usage set. The retired Instance backend arranged both by compiling matching dummy input chunks. Under theGraphandThinCustombackends nothing does, so useUE.TexCoordandUE.VertexColor— or a wiredFunctioninput — instead of these two.
- The remaining reads are side-effect free. Every field and
Get*(Parameters)helper they touch is populated unconditionally at pixel entry, so they compile in any opaque Surface pixel evaluation with no usage flag or interpolator request. DS_PerInstanceRandomandDS_PerInstanceFadeAmountare meaningful only for instanced or GPU-culled draws. On a plain mesh they read back safe constants (0and1respectively) with no compile error.- The header is guarded by
DREAMSHADER_BUILTINS_USH, so including it more than once in the same translation unit is harmless. - Inside a
Functionbody the GLSL-alias pass rewrites whole identifiers before the body is emitted —vec3→float3,mix→lerp,fract→frac,mod→fmod, and so on. It skips string literals and comments, so the include path in#include "…"is never rewritten.
Example
A top-level Function whose HLSL body uses only the macro half of the header:
Function vec2 Wobble(in vec2 uv, in float speed)
{
#include "/Plugin/DreamShader/DreamShaderBuiltins.ush"
float t = DS_TIME * speed;
return uv + float2(sin(t), cos(t)) * 0.02;
}The include resolves through the registered virtual directory, and DS_TIME expands to
(View.GameTime).
The node-based equivalent, which needs no include and no HLSL helper at all:
GraphFunction vec2 Wobble(in vec2 uv, in float speed)
{
float t = UE.Time() * speed;
return uv + vec2(sin(t), cos(t)) * 0.02;
}See also
- Builtins — the call surfaces available inside
Graph UE.*catalogue — the node equivalent of every symbol on this pageUE.Expression— reaching any otherUMaterialExpression- Math builtins — the unprefixed numeric call surface in
Graph - Transform builtins —
UE.TransformVector/UE.TransformPosition Function— HLSL bodies and how they are emittedGraphFunction— the node-based alternative to an HLSL body- Generated HLSL — the per-source
.ushthe plugin does emit - Backend —
Graph,ThinCustom, and the retiredInstancebackend - Contributing — the plugin's source and content layout
Custom Pass runtime
What happens to a compiled .dsp pipeline at run time — what makes it apply to a view, when its passes run, what its buffers hold, how exported buffers reach materials, Blueprints, UMG and Niagara, and how to see what it did. Needs UE 5.8.
Evaluation Model
What a Graph block actually is, how the legacy front end of the 2.0 compiler builds it into nodes, and why it is a different language from the declarations around it.