DreamShaderLang
Generation

Asset Paths

How Name= and Root= become an Unreal package path, an object path, and a file on disk — including the Plugin.X roots.

Every block that generates an asset carries the same two header attributes, and one resolver turns them into a destination.

AspectValue
Applies toShader, ShaderFunction, ShaderLayer, ShaderLayerBlend — identical for all four
Kindheader attributes
Root="Plugin.X"since 1.2.0

Synopsis

NotationMeaningExample
<x>Placeholder — substitute a real value; the angle brackets are not typed.Name = <string>
[ x ]Optional — the whole group may be left out.[, Root = <string>]
{ a | b }Choice — take exactly one of the alternatives separated by |.{ Node( … ) | Comment( … ) }
Repetition — the preceding item may appear any number of times.<property-declaration> …
Shader        (Name = "<name-path>" [, Root = "<root>"]) { … }
ShaderFunction(Name = "<name-path>" [, Root = "<root>"]) { … }

<name-path> := [<folder> /] … <leaf>
<root>      := "" | Game | Plugin.<PluginName> | Plugins.<PluginName>
             | Plugin / <PluginName> | Plugins / <PluginName>
             | / <MountRoot> [/ <folder>] …
             | <folder> [/ <folder>] …

Name is required. A missing one fails with Shader(Name="...") is required., or {Kind}(Name="...") is required. for the function blocks. Root is optional and defaults to the empty string. Attribute keys are matched case-insensitively, so name= and ROOT= both resolve.

Resolution order

  1. Root becomes a root package path. Trim; \ becomes /; remember whether the string began with /; strip leading and trailing /; split on /. An empty result at any point yields /Game.
  2. Name becomes folders plus a leaf. Trim; \ becomes /; strip all leading and trailing /; split on /. The last segment is the asset name; every preceding segment is a folder appended to the root.
  3. Every segment passes through ObjectTools::SanitizeObjectName. Empty segments are skipped silently.
  4. PackageName = <root>/<folders…>/<Leaf> and ObjectPath = <PackageName>.<Leaf>.
  5. PackageName is validated with FPackageName::IsValidObjectPath.

The Root= dispatch

Dispatch is on the first segment of Root, compared case-insensitively.

First segmentExtra conditionRoot packageFolders taken from Root
(absent, empty, /, or all whitespace)/Game
Game/Game1
Plugin.<Name>the plugin's mount point1
Plugins.<Name>the plugin's mount point1
Plugina second segment existsthe plugin named by segment 12
Pluginsa second segment existsthe plugin named by segment 12
anything elsethe Root string began with //<segment 0>, verbatim1
anything elseno leading //Game, and segment 0 becomes a folder0

Omitted or empty

RootNamePackageObject path
(omitted)M_Flat/Game/M_Flat/Game/M_Flat.M_Flat
""Materials/M_Flat/Game/Materials/M_Flat/Game/Materials/M_Flat.M_Flat
"/"M_Flat/Game/M_Flat/Game/M_Flat.M_Flat

Game

RootNamePackage
GameM_Flat/Game/M_Flat
/GameMaterials/M_Flat/Game/Materials/M_Flat
Game/MaterialsM_Flat/Game/Materials/M_Flat
game/materialsM_Flat/Game/Materials/M_Flat

The comparison is case-insensitive, but the emitted root is always the literal /Game.

Plugin.<Name> and Plugins.<Name>

The dotted form names the plugin in a single segment; everything after it is folders.

RootNamePackageOn disk
Plugin.MoonToonMat/Test/MoonToon/Mat/Test<Project>/Plugins/MoonToon/Content/Mat/Test.uasset
Plugins.MoonToonTest/MoonToon/Test<Project>/Plugins/MoonToon/Content/Test.uasset
Plugin.MoonToon/SharedTest/MoonToon/Shared/Test<Project>/Plugins/MoonToon/Content/Shared/Test.uasset

Plugin/<Name> and Plugins/<Name>

The slash form spends two segments on the plugin reference.

RootNamePackage
Plugin/MoonToonTest/MoonToon/Test
Plugins/MoonToonMat/Test/MoonToon/Mat/Test
Plugins/MoonToon/SharedTest/MoonToon/Shared/Test

Root="Plugin" and Root="Plugins" with no second segment do not name a plugin. They fall through to the last dispatch row and are treated as ordinary folder names, producing /Game/Plugin and /Game/Plugins. No diagnostic is emitted — the asset simply lands somewhere you did not intend.

An explicit mount root

A Root that begins with / and is not one of the forms above is taken verbatim as a mount point.

RootNamePackage
/MyMountTest/MyMount/Test
/MyMount/SubTest/MyMount/Sub/Test
/EngineTest/Engine/Test

The first segment must survive SanitizeObjectName unchanged, otherwise DreamShader Root '{Root}' has an invalid package root. The mount point itself is not checked for existence here — an unmounted root fails later, at the IsValidObjectPath gate.

A bare relative path

Any other Root without a leading / becomes folders under /Game.

RootNamePackage
FooTest/Game/Foo/Test
Foo/BarTest/Game/Foo/Bar/Test
Foo/BarDeep/Test/Game/Foo/Bar/Deep/Test

The difference between this branch and the previous one is exactly the leading slash: Root="Foo/Bar" is /Game/Foo/Bar, Root="/Foo/Bar" is /Foo/Bar.

Plugin-root requirements

Both plugin forms resolve through the same validator. Every gate below must pass, in this order, and each has its own message.

#RequirementMessage when it fails
1The plugin name is non-empty and unchanged by SanitizeObjectNameDreamShader Root '{Root}' has an invalid plugin name.
2A plugin with that name is known to the plugin managerDreamShader Root '{Root}' references project plugin '{Plugin}', but no enabled plugin with that name was found.
3It is a project plugin, with its base directory under the project's Plugins directoryDreamShader Root '{Root}' must reference a project plugin under '{PluginsDir}'.
4It is enabledDreamShader Root '{Root}' references project plugin '{Plugin}', but the plugin is not enabled.
5It can contain contentDreamShader Root '{Root}' references project plugin '{Plugin}', but the plugin cannot contain content.
6Its Content directory exists on diskDreamShader Root '{Root}' references project plugin '{Plugin}', but its Content directory does not exist: '{ContentDir}'.
7Its content is mounted since UE 5.6DreamShader Root '{Root}' references project plugin '{Plugin}', but the plugin content is not mounted.

Gate 7 does not exist on UE 5.3 – 5.5; on those engines an unmounted plugin is caught later, by the object-path validation.

The root package path is the plugin's own mounted asset path — normalized to forward slashes, no trailing slash, a forced leading slash. If that degenerates to empty or /, /<PluginName> is used.

Engine plugins, and marketplace plugins installed under the engine directory, are rejected by gate 3 even when they are enabled and mounted. Only plugins physically under <Project>/Plugins are accepted. To write into an engine-side mount, use the explicit mount-root branch (Root="/SomeMount"), which skips the plugin validator entirely.

Per asset kind

Path resolution is identical for all four block kinds. What differs is the class created and, for the function kinds, the material-function usage stamped on it.

Source blockAsset classMaterial function usage
Shader, Graph backendUMaterial
Shader, ThinCustom backend since 1.5.0UDreamShaderMaterialInstance plus a hidden UMaterial subobject
ShaderFunctionUMaterialFunctionDefault
ShaderLayer since 1.3.0UMaterialFunctionMaterialLayerMaterialLayer
ShaderLayerBlend since 1.3.0UMaterialFunctionMaterialLayerBlendMaterialLayerBlend

When an asset already exists at the resolved path, its class must match:

KindMatch rule
ShaderFunctionexact class match — a UMaterialFunctionMaterialLayer at that path is rejected
ShaderLayer, ShaderLayerBlendIsA the expected class
Shader, Graph backendthe existing object must be a UMaterial
Shader, ThinCustom backendthe existing object must be a UDreamShaderMaterialInstance

A class match is not the same as an ownership check. For everything except the ThinCustom path, DreamShader additionally refuses to overwrite an asset it did not generate — see Regeneration.

On-disk mapping

Package rootOn-disk directory
/Game/…<Project>/Content/…
/<PluginName>/…<Project>/Plugins/<PluginName>/Content/…
/<MountRoot>/…wherever that mount is registered

The file is <directory>/<Leaf>.uasset, and it is written only in persist mode. During ordinary editor work nothing reaches disk at all — see In-memory Materials.

Notes

  • Name may contain folders; Root is only a prefix. Name="A/B/C" under Root="Game" yields /Game/A/B/C, and the asset is named C.
  • A duplicate attribute key silently overwrites the earlier one. Shader(Name="A", Name="B") resolves to B, with no diagnostic.
  • Every segment is sanitized independently, so Name="My Mat" resolves to a leaf named My_Mat without a diagnostic.
  • Empty segments are dropped: Name="A//B" is A/B, and Root="Game//Sub" is /Game/Sub.
  • This is the resolver the Content Browser status column and the Materialize action use, so a path that fails here also shows as unresolvable in the editor tools.
  • Do not confuse this with Path(Root, "…"), the other path grammar — that one references an existing asset rather than naming a destination. See Asset References.

Diagnostics

MessageCauseFix
Shader(Name="...") is required.A Shader header with no Name attribute.
{Kind}(Name="...") is required.A ShaderFunction / ShaderLayer / ShaderLayerBlend header with no Name attribute.
DreamShader asset name must resolve to a non-empty asset path.Name is empty after trimming and slash-stripping.
DreamShader asset name '{Name}' produced an invalid asset name.The leaf segment is empty after sanitization.
DreamShader asset name '{Name}' contains an invalid folder segment.A non-empty folder segment of Name sanitized away to nothing.
DreamShader asset path '{Path}' is not a valid Unreal object path.The assembled path failed IsValidObjectPath and the engine reported no reason of its own.Check for an unmounted mount root.
DreamShader Root '{Root}' contains an invalid folder segment.A non-empty folder segment of Root sanitized away to nothing.
DreamShader Root '{Root}' has an invalid plugin name.The plugin name is empty, or was altered by sanitization.
DreamShader Root '{Root}' has an invalid package root.An explicit mount root was altered by sanitization.
DreamShader Root '{Root}' references project plugin '{Plugin}', but no enabled plugin with that name was found.Unknown plugin name.
DreamShader Root '{Root}' must reference a project plugin under '{PluginsDir}'.An engine plugin, or a plugin outside the project's Plugins directory.Use Root="/SomeMount" to target an engine-side mount instead.
DreamShader Root '{Root}' references project plugin '{Plugin}', but the plugin is not enabled.A disabled plugin.
DreamShader Root '{Root}' references project plugin '{Plugin}', but the plugin cannot contain content.A code-only plugin.
DreamShader Root '{Root}' references project plugin '{Plugin}', but its Content directory does not exist: '{ContentDir}'.Missing Content folder.
DreamShader Root '{Root}' references project plugin '{Plugin}', but the plugin content is not mounted.An unmounted plugin. UE 5.6+ only.
Failed to create package '{Package}'.Package creation failed.
Asset '{ObjectPath}' already exists and is not a Material.Graph backend, wrong class at the path.
Asset '{ObjectPath}' already exists and is not a DreamShader instance material. Delete it (or remove Backend="Instance") before switching backends.ThinCustom backend, wrong class at the path.Details
Asset '{ObjectPath}' already exists and is not a MaterialFunction asset.A function kind, wrong class at the path.
Asset '{ObjectPath}' already exists as '{ActualClass}', but {Kind} generation requires '{ExpectedClass}'. Delete or move the existing asset and regenerate it.A function kind, wrong material-function subclass.
Asset '{ObjectPath}' already exists and was not generated by DreamShader. Rename your shader or move/delete the existing asset before regenerating.The ownership guard, on a material.Details
Asset '{ObjectPath}' already exists and was not generated by DreamShader. Rename your function or move/delete the existing asset before regenerating.The ownership guard, on a material function.Details

Worked example

Shader(Name="Mat/Test", Root="Plugin.MoonToon")
{
    Properties { vec3 Tint = vec3(1.0, 0.2, 0.2); }
    Settings   { Domain = "UI"; ShadingModel = "Unlit"; }
    Outputs    { vec3 Color; Base.EmissiveColor = Color; }
    Graph      { Color = Tint; }
}

Resolved destination:

Root      "Plugin.MoonToon"  ->  /MoonToon                       (plugin mount point)
Name      "Mat/Test"         ->  folders "Mat", leaf "Test"
package                          /MoonToon/Mat/Test
object path                      /MoonToon/Mat/Test.Test
on disk                          <Project>/Plugins/MoonToon/Content/Mat/Test.uasset

Where next

On this page