DreamShader 插件
DreamShader Unreal 插件的版本更新记录,取自插件自带的 CHANGELOG,新版本在前。
Unreal 插件的版本更新记录,新版本在前。这里记录会影响使用者的语言、生成器、编辑器工具和引擎兼容性变化。
| 当前版本 | 1.8.0 —— 2026-08-21 |
| 引擎 | Unreal Engine 5.3 到 5.8,Win64 |
| 记录来源 | 插件目录内自带的 CHANGELOG.md |
1.8.0 - 2026-08-21
一个关于不把东西弄丢的版本。生成器过去是无条件推倒重建的:手改过的资产被悄悄覆盖、失败的重建把资产 清空、开着材质编辑器的资产在下一次 Apply 时被悄悄回滚。这一版把这几条路全部堵上 —— 手改指纹、原子重建、 编辑器占用闸门、按依赖排序的批编译,以及一个真正覆盖「什么决定编译产物」的构建键。
手改检测 —— 三个出口
- 每次成功生成都会在资产上写一个
DreamShader.OutputDigest指纹,下一次重建在清空资产之前先比对它。 对不上就拒绝编译,资产保持你离开时的样子 —— 没有清空,也没有半成品。见 重新生成。 - 指纹恰好覆盖重建会摧毁的东西:节点、连线、生成节点上的属性、reset 属性集、材质函数的资产级字段、 ThinCustom 实例的参数覆盖。重建本来就不碰的东西被刻意排除在外 —— 节点位置、你自己写的注释框、 pin GUID、reset 列表之外的材质属性。护着一个本来就没危险的属性,只会白白拒掉一次重建。
- 三个出口都在资产右键菜单的 DreamShader 下:Revert to Source(丢掉手改、按源码重建)、
Adopt Into Source(用资产反写
.dsm/.dsf,旧文件先备份成<source>.bak)、 Detach From DreamShader(保留资产、从此不再管它)。 -Force绕不过它。bForce回答的是「源码哈希过期了吗」,而编辑器的启动扫描对每个文件都置了这个标志 —— 认它就等于在编辑器唯一常驻的模式里让闸门直接失效。只有 Revert 能覆盖一次手改判定,因为只有人能做这个决定。- 纯内存资产也会被打上指纹和源码路径(但不打源码哈希,那会把跳过重建 也一起打开)。没有这条路径,内存资产会被判成「外来资产」,闸门在编辑器的默认模式里根本不会触发。
重建是原子的
- 步骤要么全部生效、要么一条都不生效。旧图现在是被摘下来而不是被销毁,重建完整成功之后才真正销毁;
中途失败会从一份序列化快照把资产放回去 —— 渲染状态、材质函数 usage、节点图、连线,以及
FunctionInput/FunctionOutput的 pin GUID 都会回来,所以既有调用点仍然连着。 - 这件事非做不可,是因为不是所有失败都能提前拦住:整文件解析、
Settings校验和Outputs校验 都在资产被碰之前,但Graph块是由图构建器一句一句编的,跑在拆除之后。在1.8.0之前, 这类失败会留下一个被清空的资产 —— 材质如此已经很糟,材质函数更糟:调用点是从活着的资产上读 pin 的, 一个坏掉的.dsf会把每一个调用它的材质一起带走,而且没有 undo(生成资产刻意不是RF_Transactional的)。 - 顺带两个结果:拆除的两套删除策略合并成一套(逐节点删除是为了断开入边,而图整体离开时这件事没有意义),
原来 1200 个节点的阈值消失,每次重建都走快路径;
DependentFunctionExpressionCandidates—— 那份会在 函数编译失败后给整个会话装上一颗空指针雷的第二份序列化节点表 —— 改在提交时重置。
资产开着编辑器时拒绝重建
- 材质编辑器并不编辑资产本身:
FMaterialEditor把它复制成一个临时UPreviewMaterial,在 Apply 或 Save 时再把副本盖回原件;材质实例编辑器则通过UMaterialEditorInstanceConstant包装写回。一个跨越了重建仍然 开着的编辑器,手里握的是重建之前的副本,下一次 Apply 会把重建做的一切静默还原 —— 然后以一次 「手改检测」的形式出现在再下一次编译里,离病因已经很远。 - 现在编译直接停下并说明:
Asset '{ObjectPath}' is open in an asset editor, so it was NOT rebuilt. … - Revert to Source 和 Adopt Into Source 是例外:它们自己关掉编辑器、动手、再打开。两者都挂在 那个编辑器自己的工具栏上,一个在最有用的地方永远是灰的菜单项不是保护,是 bug。
构建键取代了单纯的源码哈希
DreamShader.SourceHash现在是一把构建键:准备好的源码文本、Default Compiler Backend、三张映射表、 插件版本加一个手动 bump 的格式标签、以及引擎版本。此前它只哈希源码文本,于是任何别的东西发生变化时, 已经生成的资产统统看起来仍是最新的。- 原来专为 backend 设置外挂的那次「强制全量重扫」因此可以删掉了:受影响的资产各自过不了跳过检查, 而不受影响的资产仍然被跳过,不做无谓重建。
- 改变构建键的组成会让所有既有 stamp 作废 —— 每个资产重建一次,一次而已,这正是预期效果。
一批文件按依赖顺序编译
- 一个调用
ShaderFunction的.dsm会把调用节点绑到活着的UMaterialFunction资产上 ——SetMaterialFunction是从对象而不是从源码上读 pin 的 —— 所以先编调用方就意味着绑到了那个函数上一版的接口。 改一个函数输入的名字、两个文件一起保存就能撞上,而谁赢取决于一个TMap的遍历顺序。 - 现在两个入口(watcher 的待编译批次和全工程扫描)都按 import 图做拓扑排序。只有批次内部的边被考虑, 成环则留给 import 加载器用自己的诊断拒绝。
一个工程只有一个编辑器持有 bridge
- bridge 目录是按工程而不是按进程的:一个
Requests目录、一个status.json、一个心跳。两个开在同一 工程上的编辑器于是都在轮询同一个队列,也都在用自己的 pid 覆写status.json。 - 归属现在写在锁文件
Bridge/owner.lock里,带着持有者的 pid 和心跳:进程还活着且心跳不超过 30 秒 才算持有。两个条件缺一不可 —— 只看 pid,会在持有者正在编译(编译阻塞游戏线程)时把 bridge 交出去; 只看心跳,会在硬崩溃后留下一段无主窗口。退出时主动释放。 - 非持有者仍然编译自己的内存材质,但不消费请求、不写
status.json,也不把生成资产写到磁盘。 最后这条是「存储决定如何持久化」的直接推论:否则两个编辑器会SavePackage同一个文件,而这场竞争的 输家不是合并,是一个损坏的 package 或一个死掉的编辑器。commandlet 不受影响。见 编辑器工具。
磁盘上存在的资产就在磁盘上重建
- 存储决定一次重建怎么落地,而不是发起编译的那一方决定。 编辑器每次要的都是纯内存编译,而当它落在一个 已经存在的 package 上时,旧行为是就地在内存里重建、然后清掉脏标记 —— 得到一个既不等于磁盘上的文件、 也不等于将来会被写出的任何东西、还自称干净的对象。一次 Save All 就能落下一个谁也没选过的状态, 而你在编辑器里看到的版本会在重启后消失。全部信号只有一条日志 warning。
- 现在由
IsGeneratedAssetPersisted说了算:背后有文件的资产走持久化路径(stamp、保存、脏标记绝不作假), 没有文件的留在内存。「这个资产到底是什么」重新只有一个答案。见 内存材质。 - 与之配套,启动扫描不再强制重建。在每个内存资产无论如何都会重建时,强制是免费的;一旦磁盘资产开始被 保存,它就不免费了 —— 每次启动都会重写每一个持久化的生成资产。改 Default Compiler Backend 仍然强制, 因为哈希看不见那个设置。
修复
Domain="Volume"的材质自带bUsedWithVolumetricCloud,反编译也不会再把它打开。 标志现在从 domain 推导,显式写bUsedWithVolumetricCloud = "false";仍然胜出 —— 只喂体积雾的 Volume 材质可以拒绝云的 shader 排列。写入走UMaterial::SetUsageByFlag(UE 5.8 弃用了所有bUsedWith*字段),并且移出了Domain分支、改为回读材质的 domain,因为ResetMaterialToDefaults不清 usage 标志。反向也一样: 两个方向现在都经过同一个GetDefaultUsedWithVolumetricCloud,所以UMaterial→.dsm→UMaterial重新是恒等的。见 材质设置。issue #27- swizzle 能活着穿过材质编辑器了。
CustomStencil.r这样的分量选择过去被写成连接上的内联 mask (OutputIndex=0加Mask/MaskR)—— HLSL 翻译器认,但材质图编辑器画不出来:pin 对应的是表达式的Outputs条目,而「没有 pin」意味着「output 0,只取红通道」。UMaterialGraph::GetValidOutputIndex一见到带 mask 的OutputIndex 0就不信任它(那个组合过去表示OutputIndex之前的老式连接), 找不到 mask 匹配的 pin,就回退到节点的最后一个输出。第一次 Apply/Save 会把这条线写回去。 在SceneTexture(Color / Size / InvSize)上,这把CustomStencil.r变成了InvSize—— 静默、 没有任何报错,然后 stencil 比较对每个像素都失败,被它 gate 的效果直接不出现了。任何被材质编辑器碰过的 生成资产都中招,先复制一份也没用(副本第一次保存就被同样地毁掉)。 现在分量选择按图能 round-trip 的形式发射:只有在编辑器能把内联 mask 解析回它已经指名的那个 pin 时才保留 内联 mask;表达式通过多个带 mask 的输出发布同一个值时(TextureSample的RGB/R/G/B/A/RGBA、VertexColor等),直接指名对应的输出;其余情况发射一个真的ComponentMask节点。像SceneTexture这种输出集合混杂的(各个输出是不同的值,而不是同一个值的不同视图)永远不改指。构建键标签升到DSK2, 所以每个生成资产都会按新形式重建一次。 Properties里的UE.CollectionParam(...) Name;宽度跟着集合参数走。 parser 只能把声明形式记成标量 (它打不开集合),而生成器过去照单全收,于是一个 vector MPC 参数喂给float4输入时会被加宽规则补三次AppendVector,材质以Can't append float4 to float4编译失败。现在建节点时从加载好的集合读宽度 (vector → 4,scalar → 1);声明上显式写的OutputType=仍然胜出。见 Properties 类型。- render target 可以喂给期待对应维度纹理的地方。 维度检查过去比的是资产类,现在读
UTexture::GetMaterialType()—— 和材质编译器在 texture-object pin 上给出的答案是同一个 —— 所以UTextureRenderTargetVolume、UTextureRenderTarget2D、UTextureRenderTargetCube、UTextureRenderTarget2DArray都能通过各自维度的检查,UTexture2DDynamic之类也一样。 - cook 生成的资产会注册进 AssetRegistry,因此能进包。 cook 请求是经
IAssetRegistry::DoesPackageExistOnDisk解析的,而这个函数只查 registry 的内存状态、没有文件系统兜底;生成跑在 post-engine-init,也就是 registry 枚举完内容目录之后,于是刚写出的 package 对那次查询是不可见的 —— 材质根本没进 pak,LoadObject在 Shipping 构建里失败,全程没有任何报错。现在生成过程记录自己实际写了哪些 package,并在 commandlet 的Main收集初始请求之前交给IAssetRegistry::ScanModifiedAssetFiles。 issue #26 - ThinCustom 实例路径也跑归属检查了。 它过去只看目标路径上那个对象的类、不看来历,于是往一个手写的
UDreamShaderMaterialInstance上生成会直接接管它、并清掉它的参数覆盖。ThinCustom 是默认 backend, 这是三条创建路径里覆盖面最广、却唯一没有这个检查的一条。 DreamShaderGraphDecompilerHelpers.h能单独编译了 —— 它声明了吃EMaterialDomain和EBlendMode的函数却没 include 对应的头,unity 构建靠邻居的翻译单元蒙混过关,非 unity 编译(-SingleFile)才暴露。
新增
Function体顶部的#include会被提升到文件作用域。Function块的 HLSL 过去原样发射在生成的DreamShaderFn_*定义的花括号之间,于是任何#include都落在了函数内部 —— 只有宏的头文件没事, 定义了函数的头文件就是编译错误。现在开头的#include "…"/#include <…>(前面只允许空白和注释) 会被从函数体里摘出来、按首次出现顺序在生成.ush的 guard 之后发射一次;SelfContained内嵌和GraphFunction体则把它们放到 Custom 节点的IncludeFilePaths上,排在生成的 include 之前。 第一条语句之后的指令保持旧行为。这正是让一个 C++ 与 HLSL 共用的头文件能被.dsf直接消费的东西。 见 函数。
1.7.1 - 2026-08-16
修复
- 用过 Graph 断点之后关编辑器会崩。
UMaterial::GetExpressionInputDescription里读0x3b0的访问违例, 来自预览探针自己的析构函数,在模块卸载期间经由FDreamShaderPreviewWebSocketServer::Shutdown触发。 模块卸载发生在退出路径内部:EngineExit()抬起退出请求,FEngineLoop::Exit()先跑 purge, 之后才调UnloadModulesAtShutdown()—— 所以此时拆自己状态的模块,拆的是已经消失的对象。TStrongObjectPtr能让预览材质躲开 GC 的可达性扫描,却不能豁免退出 purge:指针还非空、对象已经没了, 这就是既有的空指针检查全部通过、解引用却仍然爆掉的原因。 值得点名的是它爆在哪:UMaterial::GetExpressionInputDescription和GetExpressionCollection都不加检查地 解引用GetEditorOnlyData(),所以 purge 之后去够材质的输入或表达式,是一次无条件的空指针加偏移读取, 而不是一次可恢复的失败。现在引擎开始退出时直接跳过这次拆除 —— 这不只是「安全」而是正确: 释放共享表达式集合的目的是让预览材质之后碰不到图材质的节点,而在退出时没有「之后」,两者都在被销毁。 客户端断开而编辑器继续运行的那条常规路径不变,仍然照常释放。
1.7.0 - 2026-08-16
新增
- 实时预览里的 Graph 断点 —— 给文本源码的「Start Previewing Node」。 在
Graph的某一行上打断点, 预览网格就显示那一行绑定的值,而不是成品材质。这和在材质编辑器里右键节点选 Start Previewing Node 是同一个想法,只不过这里的「节点」是 DreamShaderLang 的一行。 实现是复用引擎自己的机制:生成器现在为每个源文件发布一张调试表,把每个(行号, 名字)绑定映射到它 产生的那个UMaterialExpression/ 输出 / 通道 mask;一个临时UPreviewMaterial—— 共享生成材质的表达式 集合,把被探测的节点接到它的 emissive(值是MaterialAttributes/FrontMaterial时接到对应输入, 纹理对象则用默认坐标采样一次)—— 经FMaterialUpdateContext重新编译。UPreviewMaterial::ShouldCache把这次重编译限制在少数几个 shader 上,和节点缩略图走的是同一条路。 空行或注释行上的断点会向前吸附到下一个绑定了值的行;在源码还没生成过时打的断点会被记住,并在下一次编译时 挂上;重新编译之后探针自动重解析,并把落在哪一行告诉客户端。协议是setProbe/clearProbe/probeState。 见 编辑器工具。
变更
- 流式预览现在发原始 RGBA8 帧,而不是每帧一张 PNG。 新的
encoding: "raw"会话把 render target 读回来、 把像素作为一个自描述的二进制帧发出(24 字节头 —— 尺寸、标志位、相机、解析后的探针行号 —— 之后是像素), 编辑器侧完全没有 PNG 编码。浏览器 / webview 客户端把它直接画到 canvas 上。这就是流畅 30–60 FPS 的 绝大部分成本所在:每 tick 给一张 512² 的帧做 PNG 编码,是几十毫秒的游戏线程时间。旧的encoding: "png"路径(JSONpreviewFrame加带 tag 的 PNG)对老客户端保持不变。 - 画面不动时流式预览变便宜了。 相同的帧会被丢弃,连续几帧都相同之后渲染时钟退到一个很低的空闲速率,
直到一次编辑、一次相机 / 网格变化或一次探针变化把它重新唤醒(shader 还在编译时渲出的帧不会触发退避)。
省略了某个字段的
previewControl—— 包括frameRate—— 现在保持当前值而不是重置回 2 FPS, 并且可以携带width/height/mesh,客户端不必重发完整请求就能驱动渲染尺寸和形状。previewMaterial上的force标志用来区分显式刷新(重新生成)和相机 / 网格重新请求(复用上次生成结果)。
1.6.0 - 2026-08-15
语言 —— 十个新的数学内置
Graph里补齐step、smoothstep、length、cross、asin、acos、atan、atan2、reflect、refract。它们每一个原本都有节点(reflect/refract是四行定义),却都没有写法 —— 想写step(0.5, x)只能写成UE.Expression(Class="Step", OutputType="float1", Y=0.5, X=x),而按 HLSL 的写法写出来时, 报错是Unknown Graph function 'step'包在参数所属的那次调用里面。内置写法从 19 个增加到 29 个。 见 数学内置。- 其中三个的输入 pin 不叫
Input,这正是这份映射值得写清楚的原因:Step和Arctangent2把 pin 叫Y和X,SmoothStep叫Min/Max/Value。参数顺序在每种情况下都保持 HLSL 的顺序, 所以step(edge, x)把参数 1 连到Y、参数 2 连到X,含义仍然是x >= edge。 length和cross与dot一样是返回宽度固定的内置(1 和 3 分量,且是权威宽度)。reflect和refract是头两个不是一个节点的内置。Unreal 两者都没有对应表达式,所以它们被降级成 HLSL 对它们的定义:i - 2 * dot(i, n) * n是四个节点,折射连同处理全内反射的If一共十四个。 两者都精确,也都很贵;周围代码本来就是 HLSL 时,写在Function体里一个节点就够了。
这拓宽了一个保留命名空间。 这十个名字现在和原来那十九个一样会静默遮蔽用户代码 —— 叫 length、
step 或 cross 的 Function、property 或 ShaderFunction,从 Graph 块里将无法被调用到,
而且没有任何诊断。既有源码里声明了同名符号的需要改名。
矩阵不在其中,而且加不了:Unreal 材质图根本没有矩阵值类型,所以无论 DSL 怎么做,mul(M, v) 都没有
Graph 写法 —— 空间转换用 UE.Expression(Class="Transform"/"TransformPosition", …),其余的用 Function
的 HLSL 体。仍然缺席但可以经 UE.Expression 触达(各自都有节点)的还有:指数、对数、tan、sign、
round、trunc 和 distance。反编译器未做改动,所以新节点导出成通用的 UE.Expression(Class="…", …)
调用,而不是回到内置写法 —— 和 Fmod 一样的不对称;reflect / refract 则根本无法 round-trip,
因为它们留下的是普通算术节点,没有任何东西标记它们的来历。
诊断 —— DSHnnnn 错误码
- 在此之前,唯一标识一条 DreamShader 失败的东西是它的英文措辞。现在 parser 的全部 120 个抛出点都改为
携带一个错误码:
DSH1xxx路径解析、DSH2xxx词法与语法、DSH3xxxsection 与声明、DSH7xxxproperties / 参数 / 设置。码随FText一起挂在FDreamShaderTextError上。 见错误速查。 - 线上格式没有任何变化 ——
FDreamShaderDiagnosticRecord::Code和diagnostics.json里的"code"字段本来就存在。 - 生成器一侧还没有码:
Docs/diagnostics/覆盖 112 个码,而全部 659 条消息的权威目录仍然是按阶段分组的 那份清单,直到生成器剩下的约 561 个抛出点也被标注。
本地化 —— 编辑器 UI 说你的语言,线上格式不说
- 编辑器界面文本 —— DreamShader Gen 页、设置分区、慢任务进度、parser 与反编译诊断 —— 从
FString字面量迁到LOCTEXT/NSLOCTEXT,承载它们的诊断记录也改成FText。简体中文随之附带:Content/Localization/DreamShader/zh-Hans/DreamShader.locres,经DreamShader.uplugin的LocalizationTargets条目以Editor加载策略载入。每个改过的签名旁边都保留了FString重载。 感谢 @youli42 —— PR #24。 diagnostics.json、diagnostics/*.json、bridge.db和预览 WebSocket 在任何编辑器语言下都保持英文。 VSCode 和 Rider 扩展要解析它们,所以一个被翻译的编辑器不能改动其中的任何一个字节。FTextInspector::GetSourceString只解决了一半问题:它对普通LOCTEXT返回源字符串,但对FText::Format的结果返回的是已本地化的替换结果 —— 只要有一个消息点改用FText::Format, 翻译过的文本就会漏到线上。ToInvariantWireString改为重放FText的历史 format 数据:源模板、 每个参数按 invariant 文化渲染、嵌套 format 递归处理、关掉数字分组以免12345变成12,345, 每一次 JSON / SQLite / WebSocket 写入都过它。
插件源码根
- 每个带
DShader目录的已启用插件现在都贡献一个自己的源码根,所以插件可以自带那些构建它材质的.dsm/.dsf/.dsh,而不必把它们停在工程的树里。Root="Plugin.<Name>"从1.2.0起就能写 资产到插件里,缺的一直是源码这一半。发现、依赖图和全量生成都无需额外配置就能认到插件根。见 工程结构。 - Project Settings ▸ DreamPlugin ▸ Dream Shader ▸ Paths ▸ Scan Plugin Source Directories
(
bScanPluginSourceDirectories,默认开)可以关掉插件扫描。 - 插件根下的文件默认落到它自己插件的挂载点。
Plugins/MoonToon/DShader下没写Root=的.dsm现在生成到/MoonToon而不是/Game—— 源码和资产留在同一个插件里。只有缺失或全空白的Root才会被 默认化,所以Root="/"可以显式选回/Game。 - import 永不跨根。 一个文件只针对自己所在的根及该根的
Packages目录解析 import。两个插件带同样 相对路径的文件不会再互相遮蔽,禁用一个插件也不会静默改变另一个根里 import 的含义。 - 带根限定的 import ——
import "Plugin.MoonToon:Shared/Toon.dsh";—— 是刻意跨根的唯一方式。 限定符是Project、Plugin.<Name>或Plugins.<Name>(/和.等价),大小写不敏感。 那个:是承重的:Plugin.MoonToon/Shared/Common.dsh无法与「经过一个同名文件夹的相对路径」区分开。 见 Import。 - 源码目录 watcher 为每个根注册一个监视,
DreamShader.code-workspace为每个根列一个folders条目, DreamShader Gen 页在行副标题里标出插件根的名字,搜索框也匹配根名。
编辑器与生成
- 内存材质也会跑自动布局了。 交互式编译是纯内存的,而布局环节过去对它们整个跳过 —— 所以保存之后你看到的
不是「布局很糟的图」,而是一张没有布局过的图:一根用构造坐标堆起来的高柱子,线横穿其间。
Project Settings ▸ … ▸ Compiler ▸ Lay Out In-Memory Graphs(
bLayoutInMemoryGraphs,默认开) 可以关掉。见项目设置。 - 自动布局按节点的真实尺寸摆放。 过去每个节点都被当成
320 × 150、按固定的420 × 220网格排布, 于是任何画得比 220 高的节点都挤到邻居身上、并从本该框住它们的注释框里顶出去(光是TextureSample的 预览缩略图就有 106,Custom节点每多一个 pin 长一行)。现在尺寸从节点控件实际拼出来的东西估算。 - 长边有专用泳道,链路会被拉直。 跨多个 rank 的边现在在它穿过的每一列里预留一个占位槽 —— 交叉消减 只比较相邻 rank,没有泳道就根本看不见这些边,这正是「每一列单看都很整齐、整张图却像一团线」的原因。 之后跑四遍拉直,每遍把节点拉向邻居的平均中心并用保序回归修复该列。
- 块按列打包,不再堆成一条。 有多个输出的材质过去会变成几万单位高的一条带子,只有完全缩到最小才读得懂。
现在块围绕各自的原点布局,并按
max(2400, sqrt(总面积 / 1.6))的高度预算打包成列。 - DreamShader Gen 页改从 bridge 读诊断,而不是重新解析 bridge 刚写完的
diagnostics.json。 一个值得知道的后果:这些记录活在编辑器会话里,所以在你重新编译之前,页面不再显示上一次会话遗留的错误。
修复
- 插件在 UE 5.5 和 5.6 上重新能编了。 五个 UE 5.7 API 用得没有版本门,于是插件只能在它被写出来的那个
引擎上编译。五个现在都走
DreamShaderVersionCompat.h:Materials/MaterialParameters.h(5.7 起)、UMaterialExpression::ShouldShowPreview()(5.7)、UMaterialExpressionScalarParameter::ControlType等三个属性(5.7)、UMaterialExpressionCustomOutput::GetInputValueType(5.6), 以及六个没有导出宏的引擎表达式类(SceneDepth、SceneColor、ObjectRadius、ObjectBounds、PerInstanceRandom、PerInstanceFadeAmount)—— 5.6 之前它们的StaticClass()在插件里根本解析不到。 最后这个是LNK2019而不是编译错误:它能通过每一项编译期检查,只有一次完整的RunUAT BuildPlugin能看见它。5.6 以下改为按 script path 查类,所以UE.*内置行为不变。 - 两处 unity 构建掩盖的缺失 include(
UObject/Package.h、Engine/EngineTypes.h),非 unity 编译才暴露。
工具
- 编辑器 bridge 现在会回答,也会说明自己活着。 它过去只有入站的一半:一个请求不产生回复、不产生错误文件、
也没有日志行 —— 格式错误的请求直接消失,而客户端想知道编辑器是否在运行,唯一的办法是找
bridge.db然后 祈祷。现在 bridge 发布Bridge/status.json(protocol、pid、工程、插件版本、busy/busyAction、lastResult、心跳),每 2 秒重写一次,并在退出时删除 —— 所以文件缺失确定地意味着「没在运行」, 而不是「超时了」。任何带requestId的请求都会在Bridge/Responses/<requestId>.json里得到ok、durationMs、message和本次编译的诊断。新增ping动作;错误的 scope、缺失的sourceFile和未知动作现在是错误响应而不是静默无操作。见 编辑器工具。 .skill/build-plugin.ps1—— 在一串引擎根上跑RunUAT BuildPlugin,每个一行PASS/FAIL, 退出码等于失败的个数。上面那五个没加版本门的新引擎 API 就是它抓到的:一次针对单一引擎的编辑器构建做不到, 任何编译期检查也做不到,因为五个里有一个是链接错误。Tools/Localization/localization_lint.ps1—— 检查LOCTEXT_NAMESPACE的 define / undef 配对、 拒绝它出现在头文件里,并标出 gather 看不见的字面量,带一个I18N-EXEMPT逃生口。
1.5.1 - 2026-08-02
只有文档和工具变化,插件代码没有改动,所以停在 1.5.0 的工程不需要任何迁移。
新增
.skill/—— 一套 DreamShaderLang 的 agent skill,采用 Claude Code 的SKILL.md格式:dream-shader-create(一段描述变成一个能证明编译通过的.dsm)、dream-shader-optimize(反编译输出变成一份人会写的源码)、dream-shader-decompile、dream-shader-verify和dream-shader-diagnose。.skill/dsc.ps1—— 包在-run=DreamShader外面的无头驱动。它从.uproject的EngineAssociation解析引擎、向上走找到工程、去掉每条LogDreamShader被LogInit重复回显的那一份,并对照 git 分类本次 运行写出的每个资产。-CleanNew随后精确删除其中未被跟踪的那些,并清掉空掉的文件夹。.skill/sync-skills.ps1—— 把这棵树发布到.claude/skills,同时按目标位置改写相对的Docs/链接和 驱动路径。-Check在有漂移时以1退出。
变更
- 两份 README 围绕参考手册重构。那些已经变成
Docs/页面缩略副本的章节 —— Properties、Graph、 MaterialAttributes、Substrate、Material Layers、VirtualFunction、配置、发布 —— 改为链接到真正拥有它、 也真正会被维护的那一页。459 行 → 279 行,两种语言保持结构一致。
修复
- 发布归档现在会带上
Shaders/、README.zh-CN.md和.skill/。到1.5.0为止,打包步骤复制的是一份 七项白名单,并且静默跳过缺失的条目,所以归档安装出来的插件没有Shaders/DreamShaderBuiltins.ush可以给/Plugin/DreamShader虚拟着色器目录解析。
1.5.0 - 2026-08-02
统一编译路径的一个版本。两条旧 backend 合并成唯一的 ThinCustom;编辑器里生成的材质默认只活在内存里,
新增的 Material Content Browser 页签就是查看它们的地方。语言侧拿到了可省略的 section =、Group()
作用域和 Slider()。
语言(DreamShaderLang 1.5)
- section 的
=现在是可选的:Properties { … }、Settings { … }和Graph { … }都可以不写赋值号。 两种写法都有效 —— 见 Section。 Properties Group("Name") { … }把一个 group 打在它包住的每个参数上。group 可以嵌套、可以组合,Group("Outer") { Group("Inner") { … } }得到Outer|Inner—— 见 元数据与分组。Slider(min, max)简写用于设置标量参数的 UI 范围。它展开成反射属性SliderMin/SliderMax, 也是唯一一个不带=的 metadata 条目。- 资产路径可以直接跟在
=后面,裸的带引号路径也被接受 —— 见 Path 资产引用。 - 单输出函数可以作为返回值使用(
x = Fn(…)),Graph内置也补齐到与Function路径一致:fract、mod和fmod—— 见 数学内置。 - live preview 流式推送让编辑器和语言服务器的预览在你输入时保持同步。
true/false是 graph 字面量,会落成StaticBool节点,因此opt StaticBool X = false这样的输入 默认值能生成 Unreal 所要求的 Preview pin 节点 —— 它对 static-bool 输入会忽略PreviewValue。StaticBool在调用点按单分量类型解析。- token 本身不带维度的纹理参数类型(
TextureObjectParameter)从赋给它的默认资产上取维度,因此Texture2DArray、TextureCube或VolumeTexture默认值都能被接受。Texture2D、Texture2DArray这类显式 token 仍然严格校验。
Backend —— 统一为一条编译路径
Graph和实验性的Instance两条 backend 合并成唯一的 ThinCustom 路径:DreamShaderLang 编译成 一张真实的节点图,构建在隐藏的 baseUMaterial上,外面包一层薄的UDreamShaderMaterialInstance。 引擎按原生方式编译和枚举这个材质,因此 Substrate、static switch、virtual texture、MaterialAttributes 和 cook 正确性全部来自那张真实的图。见 Backend。- 与旧
Graphbackend 的 SM6 渲染结果逐位一致,已在 Unlit、带纹理和 DefaultLit MaterialAttributes 三类用例上验证。 - 隐藏 base 是实例的子对象 —— 一个资产、一个 package,在 Content Browser 里不可见,没有独立的
MB_DreamThinBase_*兄弟资产,cook 时也没有跨 package 的父级 import 可丢。见 内存材质。 - 单个 Default Compiler Backend 项目设置取代了旧的 In-Memory 开关。见 项目设置。
已弃用 自 1.5.0 起
请改用 ThinCustom。
Backend = "Instance" 和 DefaultBackend = Instance 保留为 ThinCustom 的别名。旧的无图 instance
backend 已经退役,运行时不再存在 Instance backend。这个写法保留一个弃用窗口,让既有源码继续编译,
并且不产生任何诊断。
编辑器 —— Material Content Browser
- 新增 DreamShader Material Content Browser 页签,位于 Tools ▸ DreamShader,包含两个页面:
Project 用于浏览、过滤和检视
/Game下的每个材质与材质实例,含完整继承链; Dream Shader Gen 是源文件列表,带实时预览、搜索、过滤、全量编译和加载期错误展示。见 编辑器工具。 - 可以从任意材质出发、通过文件夹选择器创建材质实例,也可以按需把纯内存(仅预览)材质 materialize 到磁盘。
- 新增 Content Browser 右键菜单操作,以及显示 / 隐藏 DreamShader 纯内存材质的开关。
Decompiler
- Substrate 材质和被重命名的 graph 通道现在能忠实 round-trip:导出器从写入 mask 推导通道 swizzle, 而不是从通道名,因此重新编译出的材质与源码逐位一致。见 反编译导出。
反编译一个手写材质、再生成回去,在一些 Unreal 本身完全接受的图形状上会失败。这批问题是在 LGUI 的
LexUI_ImageAndFont、LexUI_RectBlock 和 MF_LexUI_SDF_Font 上发现的。
- switch 类节点 ——
StaticSwitch、FeatureLevelSwitch、QualitySwitch、ShadingPathSwitch、VertexInterpolator等 —— 不报告输出值类型,于是「按 float4 处理」的兜底把它们连同整条下游一起放大。 由 float3 材质函数输出喂入的AppendVector会被写成float5(...);现在 append 会钳到 float4, 分量数仍然对不上时发出警告。 VertexColor按 float4 导出,alpha pin 的 swizzle 才成立。此前它按 RGB pin 定型,会在三分量值上写出.a。- 输入自身的通道 mask 现在替换所连 pin 的 mask,而不是叠加在上面。图里连的是 RGB pin 却 mask alpha 时,
不会再出现
.rgb.a。 StaticBool函数输入保留StaticBool类型 token。bool声明的是标量 pin,此前这种输入会变回 float, 并拒绝传给它的每一个 static-bool 值。- 注释、
#Region和 description 文本里的换行与制表符会被转义,多行注释不再把指令拆到多行。 - Custom 节点的 additional output 现在在该节点的每一次发射中都会声明,读取其中一个也不再改写节点自身的
返回类型。此前没有选中额外输出的那次发射会产出一个缺少该输出的节点,而给它赋值的代码体会在 shader 编译阶段
以
use of undeclared identifier失败 —— 远在生成报告成功之后。
修复
- Cook:资产只在 cook director 上落盘,生成错误现在会让 cook 失败,而不是发出一个陈旧资产。
- 生成过程拒绝覆盖不是 DreamShader 生成的资产,并在清空目标材质之前先校验图语法。
- 生成 include 的身份改为对项目相对源路径取哈希;记录的源路径也是项目相对的,不再携带生成时间戳。
- 运行时构建:给编辑器专用的
UEnum::HasMetaData调用加了保护,非编辑器和 Shipping(商店)构建可以编译(#12)。 - Bridge:为 UE 5.8 改用
FCoreDelegates::GetOnPostEngineInit,并把 Clean Generated Shaders 限制在Intermediate内、改成逐文件删除。
兼容性
- Unreal Engine
5.3到5.8(Win64)。
源码快照 - 2026-06-10
介于 1.4.0 和 1.5.0 之间进入源码树的改动。
Automation Baseline
- 新增 DreamShader automation 测试基线,覆盖最小材质解析、最小材质生成、
.dsf+import生成、 Substrate 材质生成、source-hash skip 和 commandlet 单源编译 smoke。 - 测试会在
DShader/Tests/Automation下写入临时.dsm/.dsf/.dsh,并在/Game/DreamShaderTests/Automation/…下生成临时资产,运行后清理。 source hash is unchanged是未变更源文件跳过重复生成的稳定断言文本。- 针对 automation 运行新增显式桥接关闭开关
-NoDreamShaderEditorBridge,用于避免 Bridge 启动扫描噪声 干扰测试日志。
1.4.0 - 2026-06-06
Compatibility
- 新增 Unreal Engine
5.3到5.7的兼容覆盖说明。 - 已在 Windows 上通过单插件
RunUAT BuildPlugin验证 UE5.3、5.4、5.5、5.6和5.7。 - 仍以 UE
5.7作为主要开发版本;UE5.3/5.4在 Windows 上可能需要 MSVC14.38工具链。
Substrate
- 补齐 Substrate 生成链路,支持
Substrate图值、Base.FrontMaterial输出绑定和Substrate.*wrapper。 Substrate 本身需要 UE 5.4 或更新版本并在项目中启用 —— 见 Substrate 节点。 - 生成器、反编译、类型传播和编辑器 manifest 会识别 Substrate 类型与相关 wrapper。
Material Preview
- 编辑器 Bridge 新增材质预览能力,可根据
.dsm源文件生成预览材质并写入Saved/DreamShader/Bridge/preview.json与Preview/*.png。 - 新增本机 WebSocket 预览服务,默认监听
127.0.0.1:17864,用于 VSCode 预览面板接收结果和连续帧。
1.3.9 - 2026-05-29
Maintenance
- 插件版本元数据更新到
1.3.9。 - README、发布说明和文档引用同步到当前语言能力。
1.3.8 - 2026-05-25
Texture Support
- 新增
VolumeTextureproperty 解析、代码生成和默认纹理处理。 - 生成 HLSL / Custom 节点输入时保留纹理对象子类型,
Texture2D、Texture2DArray和VolumeTexture会以正确 Unreal 纹理类型传入。
Plugin Cleanup
- 移除项目设置和文档中的内置 shader library path 支持。
1.3.7 - 2026-05-18
Decompiler
- 泛型
UE.Expression(...)反编译会导出更多 reflected literal property,减少少见MaterialExpression节点的状态丢失。 - 连接了 UV 等 graph 输入的
TextureSampleParameter2D会导出为 graph 表达式,而不是简单Properties声明。 - 修复带动态命名输入和自定义输出类型 metadata 的
MaterialExpressionCustom反编译。
Performance
- 优化大型反编译材质的 import 性能,减少逐节点 package dirty、降低进度文本刷新频率,并在大型生成图上跳过自动布局。
1.3.6 - 2026-05-12
Build Fixes
DreamShaderSettings.h显式包含MaterialDomain.h,让直接包含设置头的项目能稳定解析EMaterialDomain。
1.3.5 - 2026-05-11
ShaderFunction Calls
Graph支持 statement-style 多输出ShaderFunction和VirtualFunction调用:位置输入参数在前, 输出目标变量在后。
Dream Shader Function Files
- 新增
.dsfDream Shader Function 文件,用于可复用生成ShaderFunction资产。 .dsm和.dsf可以 import.dsf,便于在不同 DreamShader 源文件间复用生成函数。- 增加
.dsf源文件发现、依赖追踪和 VSCode workspace 文件关联。
Decompiler
- Content Browser 增加
UMaterial导出.dsm、UMaterialFunction导出.dsf的入口。 - 反编译文件会写入
DShader/Decompiled/Materials或DShader/Decompiled/Functions,并使用唯一文件名。 - 常见常量、参数、算术节点、swizzle、纹理采样、Custom 节点和 MaterialFunction call 会尽量导出为 DreamShader
graph 文本;少见 reflected 节点回退为
UE.Expression(...)。
1.3.4 - 2026-05-11
Output Initializers
Outputs支持初始化声明,例如vec3 Color = Tint;。Shader可以使用已初始化 output declaration 配合空Graph = {}。
1.3.3 - 2026-05-11
Graph Swizzles
- 修复 vector property 分量数,声明为
vec2/vec3时生成RG/RGB,不再总是按RGBA绑定。 - 修复
.gbr这类非顺序 swizzle,通过显式ComponentMask和AppendVector节点生成。
1.3.2 - 2026-05-11
Material Function Generation
- 插件版本更新到
1.3.2。 - 重新生成
ShaderFunction时保留生成输入和输出 ID,普通 Unreal 材质中的既有MaterialFunctionCall节点会尽量保持连接。 - Graph 和 Custom/HLSL 生成路径会跳过未使用的生成 property 节点。
- 改进生成节点摆放,并避免对 DreamShader 生成的材质图执行 Unreal 全量自动布局。
- 修复重新生成已打开 Material Function 资产时,编辑器仍持有 expression root 导致的崩溃。
1.3.1 - 2026-05-09
Function Calls
- 单输出
Function和GraphFunction调用现在可以作为值表达式使用,例如Color = Texture::Sample2DRGB(BaseTex, UV0);—— 见 调用。 - 多输出
Function和GraphFunction仍然需要显式 out 变量,例如Texture::Sample2D(BaseTex, UV0, Color, Alpha);。
Graph Functions
- 新增顶层和 namespaced
GraphFunctionblock,用于复用 HLSL Custom 节点逻辑。 GraphFunction仍按 HLSL 风格书写,但 body 中的UE.*调用会转换成材质节点,并作为生成输入传入 Custom 节点。- 新增 GraphFunction 参数验证、递归调用检测和显式 out 变量写回。
1.3.0 - 2026-05-08
Shader Layer Functions
- 新增顶层
ShaderLayer(Name="...", Root="...")和ShaderLayerBlend(Name="...", Root="...")。 - 生成的 layer 资产使用 Unreal 原生
UMaterialFunctionMaterialLayer/UMaterialFunctionMaterialLayerBlend类。 ShaderLayer/ShaderLayerBlend复用现有Properties、Inputs、Outputs、Settings和Graphsections。- 新增验证:Shader Layer block 必须输出且只输出一个
MaterialAttributes,Shader Layer Blend block 必须 声明至少两个MaterialAttributes输入。 - Vector parameter property 在 Graph 中保留 RGBA 输出,
.a/.w可读取 alpha,低分量赋值会自动取前置通道。
已弃用 自 1.3.0 起
请改用 ShaderLayer。
MaterialLayer / MaterialLayerBlend 保留为兼容别名并产生警告。新源码应使用 ShaderLayer /
ShaderLayerBlend。
1.2.10 - 2026-05-08
VSCode MaterialExpression Manifest
- 新增编辑器侧 reflected
UMaterialExpressionmetadata 导出,路径为Saved/DreamShader/Bridge/material-expressions.json。 - manifest 会在编辑器 bridge 启动和打开 DreamShader VSCode workspace 时刷新。
- 导出内容包含 expression class 名称、可编辑反射属性、expression inputs、output pins 和推断的 DreamShader
OutputType提示。 - Release workflow 会下载最新
dreamshader-language-supportGitHub Release 资产并附加到 DreamShader release。
1.2.8 - 2026-05-05
项目设置与编辑器入口
- 插件版本更新到
1.2.8。 DreamShader.uplugin的文档链接改为https://lang.64hz.cn/,支持链接改为 GitHub 主页。- Unreal Project Settings 中的插件分类从
Plugins调整到DreamPlugin,section 显示名为 Dream Shader,说明文本为Dream Shader Settings—— 见 项目设置。 - 新增
Editor分类下的OpenInNewWindow配置。默认开启时,从 Unreal 打开 DreamShader VSCode workspace 会新开窗口;关闭时会追加--reuse-window,复用已有 VSCode 窗口。
1.2.7 - 2026-05-05
Unreal 5.7 兼容性
- 插件版本更新到
1.2.7。 - 生成器补齐
UMaterialExpressionFunctionInput/UMaterialExpressionFunctionOutput相关头文件依赖, 适配新版 Unreal 材质函数输入输出节点的编译环境。 - Moon Engine 专属的
MooaEncodedAttribute0到MooaEncodedAttribute4输出现在包在MOON_ENGINE条件编译内,普通引擎构建不会再依赖这些自定义材质属性。 - 该版本不改变
.dsm/.dsh语法;主要是输出目标和引擎兼容性修正。
1.2.6 - 2026-04-30
ShaderFunction Properties
ShaderFunction新增Propertiessection,用于声明只属于生成材质函数内部的 property/helper 节点。Properties支持const标记,可生成不可外部调参的标量、向量或 Texture Object helper 节点。ShaderFunction的Inputs预览默认值可以引用同一函数的Properties,例如opt Texture2D BaseColorTex = PreviewTex;。
1.2.5 - 2026-04-30
Material Attributes
- 新增
MaterialAttributes图值类型,可用于Shader输出声明、ShaderFunction输出和VirtualFunction输出签名。 Graph支持Attrs.BaseColor = Color;、Attrs.Roughness = Roughness;这类成员写入,生成器会创建 Material Attributes 相关节点。Shader可以将聚合值绑定到Base.MaterialAttributes,生成材质会自动启用 Unreal 的 Use Material Attributes。MaterialAttributes值可以从生成的或已有的 Material Function 返回,并继续在 Graph 中传递、分支或读取成员。
1.2.4 - 2026-04-30
Parameter Reflection
- 声明尾部的 metadata 文档写法切换为分号式
[...]反射属性块。 Properties中的显式 Parameter 节点现在可以通过属性块写入任意可反射的UMaterialExpression属性。float/ 向量 / 纹理简写生成的 Scalar / Vector / Texture Object Parameter 也使用同一套反射属性块。TextureSampleParameter2D等纹理采样参数可以配置SamplerType、SamplerSource、MipValueMode、AutomaticViewMipBias、ConstCoordinate、ConstMipValue等字段。
1.2.3 - 2026-04-29
Parameters
Properties和函数输入输出声明支持[Group="...", SortPriority=32, Description="..."]元数据。Properties支持显式 Parameter 节点类型,包括ScalarParameter、VectorParameter、TextureObjectParameter、纹理采样参数节点、StaticBoolParameter和StaticSwitchParameter—— 见 Properties 类型。StaticSwitchParameter可以在Graph中用同名函数调用,例如UseDetail(True=detailColor, False=baseColor)。- 新增
UE.CollectionParam(Collection=Path(...), Parameter="..."),用于读取 Material Parameter Collection。
Function Defaults
ShaderFunction和VirtualFunction的输入支持opt,用于表示该输入可使用 Unreal FunctionInput 的预览默认值。- 调用
ShaderFunction/VirtualFunction时支持default参数,显式跳过可选输入并沿用预览默认值。 - 生成
ShaderFunction资产时会把输入输出的 description 和 sort priority 写入 FunctionInput / FunctionOutput 节点。 VirtualFunction的复制、创建和启动同步现在会尽量带上可选输入、预览默认值和 pin 元数据。
1.2.2 - 2026-04-29
VirtualFunction 工作流
CreateVirtualFunction会先查找DShader中已有的同资产声明,不再重复创建多个相同定义文件。- 如果当前 Material Function 已经有对应
VirtualFunction定义,菜单只显示OpenVirtualFunction和Copy Virtual Function Reference。 OpenVirtualFunction会优先用 VSCode 打开并跳转到定义位置。Copy Virtual Function Reference会复制可直接粘贴到Shader/ShaderFunction的Graph块中的调用表达式。- 插件启动时会扫描
DShader下的VirtualFunction声明,检查对应UMaterialFunction是否存在, 并在签名变化时刷新定义。
import 兼容性
- Unreal 生成器现在支持无分号 import,例如
import "VirtualFunctions/MF_Test.dsh"。 - 带分号写法
import "VirtualFunctions/MF_Test.dsh";仍然兼容。
1.2.1 - 2026-04-29
编辑器工作流
- Material Function 编辑器工具栏和资产右键菜单中的 VirtualFunction 相关操作统一收进
DreamShader下拉菜单。 - 新增
CopyVirtualFunction,用于复制完整VirtualFunction声明。 - 新增
CreateVirtualFunction,用于在DShader/VirtualFunctions下创建.dsh定义文件,并打开到默认外部编辑器。 - 新增
CopyVirtualFunctionCall,用于复制可直接粘贴到Graph的调用示例。 - 编辑器 Tools 菜单和 DreamShader 工具栏新增 Open Dream Shader Workspace (VSCode)。它会写出
DShader/DreamShader.code-workspace,可用时用 VSCode 打开,否则回退到默认编辑器或记事本。
Release
- 新增 GitHub Actions 发布工作流,打包插件源码并从版本标签或手动触发发布 GitHub Release。
1.2.0 - 2026-04-28
VirtualFunction
- 新增
VirtualFunction(Name="..."),用于声明项目、引擎或插件中已经存在的UMaterialFunction资产。 VirtualFunction可在Graph中像ShaderFunction一样作为值函数调用,但不会生成、保存或覆盖对应资产。Options.Asset支持Path(Game, "...")、Path(Engine, "...")、Path(Plugin.PluginName, "...")/Path(Plugins.PluginName, "..."),也支持完整 Unreal object path。- Material Function 资产右键菜单和 Material Function 编辑器工具栏新增 VirtualFunction 定义复制能力,
可自动生成包含
Inputs、Outputs和Options的声明。
Asset Roots
Root="Plugin.PluginName"映射到项目插件内容根,生成资产物理保存在[Project]/Plugins/PluginName/Content。Plugins.PluginName和Plugins/PluginName保留为兼容写法。
工具链
- VSCode 扩展同步支持
VirtualFunction高亮、补全、Hover、Snippet、签名提示和诊断。 Path(Plugins.)内的项目内容插件名也会参与自动补全。
1.1.4 - 2026-04-28
资产生成
Root="Plugins.PluginName"/Root="Plugins/PluginName"现在作为兼容写法支持,解析结果与Root="Plugin.PluginName"相同。- 这避免
Plugins.MoonToon被当作普通/Game/Plugins_MoonToon子目录保存 —— 见 资产路径。
1.1.3 - 2026-04-28
资产生成
- 明确
Root="Plugin.PluginName"只指向已启用的项目内容插件。 Plugin.MoonToon会解析到 UE package 根/MoonToon,物理保存位置是[Project]/Plugins/MoonToon/Content。- 生成器会校验目标插件位于项目
Plugins目录、已启用、可包含内容且存在Content目录。
1.1.2 - 2026-04-28
语言与生成
Shader和ShaderFunction顶层属性新增Root,用于指定生成资产根路径。Root默认是Game,也支持Plugin.PluginName,用于把生成的UMaterial或UMaterialFunction保存到已启用的项目内容插件根。ShaderFunction在Graph中被调用时,会按该函数自己的Root解析并加载生成的UMaterialFunction资产。
文档
- 更新插件 README、语言参考和网站文档中的资产生成说明。
1.1.1 - 2026-04-26
修复
- 修复
Graph中调用带多个out参数的Function时,Custom 节点后续输出 pin 没有收到值的问题。 - 多输出
Function的第一个out仍通过 Custom 节点主return输出;第二个及后续out现在会生成 显式赋值,把__ds_*_outN临时变量写回对应 Additional Output 参数,例如Output_ToonA = __ds_xxx_out1;。
兼容性
- 这是一个 patch 版本,不需要修改
.dsm/.dsh写法。
1.1.0 - 2026-04-22
语言与 Graph
- 将材质和材质函数中的
Code = { ... }区块重命名为Graph = { ... },让图 DSL 与 HLSL helper 层更容易区分。 Graph增加基础if/else支持,可以在图层表达简单条件分支 —— 见 if / else。- 改进输出表达式处理:输出绑定从只记录变量名改为记录 source text,可用于更灵活地解析 Graph 输出。
- 增强类型转换和
UE.*通用 MaterialExpression 参数处理,减少手动补节点时的摩擦。
Function 与生成
- 新增
Function SelfContained/Function Inline,可以把 helper 依赖嵌入 Custom 节点,便于把生成材质 交给未安装 DreamShader 插件的项目使用。 - 普通
Function继续生成.ushhelper include,并通过 Custom 节点引用。 - 增加清理生成 shader 文件的工作流,减少历史 include 残留。
Package 与工作流
- 新增 Package 系统,用 GitHub 分发和安装可复用
.dsh共享库 —— 见 Package。 - 增加 import dependency graph,保存共享
.dsh后可以找到受影响的.dsm并增量刷新;后续版本也覆盖.dsf依赖。 - 缓存配置目录,减少重复解析项目设置带来的开销。
诊断与兼容性
- 诊断信息增加 stage、platform、quality 等上下文,便于区分解析、生成和材质编译阶段的问题 —— 见 错误速查。
- 移除 Toon shading model 的默认映射,避免生成结果意外依赖项目自定义 shading model。
- 配套更新 README、语言参考和示例文档。
1.0.0 - 2026-04-21
初始版本
- 提供
.dsm/.dsh文件模型,用文本源文件描述 Unreal 材质和共享 helper。 - 支持
Shader(Name="...")生成UMaterial,支持ShaderFunction(Name="...")生成UMaterialFunction。 - 支持
Properties、Settings、Outputs和早期图构建语法。 - 支持 HLSL 风格
Functionhelper,并生成 Custom 节点代码。 - 支持基础文档和示例,作为 DreamShaderLang 的第一版公开基线。